#!E:\Pycharm Projects\Waytous
# -*- coding: utf-8 -*-
# @Time : 2021/8/4 15:50
# @Author : Opfer
# @Site :
# @File : para_config.py
# @Software: PyCharm

from static_data_process import *
from settings import *
import numpy as np

# 全局参数设定

# 空载任务集合
empty_task_set = [0, 1, 5]

# 重载任务集合
heavy_task_set = [2, 3, 4]

# 任务集合
task_set = [-2, 0, 1, 2, 3, 4, 5]

# Big integer
M = 100000000

logger = get_logger("zxt.para")

# # 装载区、卸载区、备停区在调度算法运行器件默认不发生改变，提前计算部分参量
# # (uuid,index(id)映射关系, 装载区数量, 卸载区数量, 备停区数量, 以及初次统计动态调度矿卡)
# (
#     load_area_uuid_to_index_dict,
#     unload_area_uuid_to_index_dict,
#     load_area_index_to_uuid_dict,
#     unload_area_index_to_uuid_dict,
# ) = build_work_area_uuid_index_map()
#
# load_area_num, unload_area_num = len(load_area_uuid_to_index_dict), len(
#     unload_area_uuid_to_index_dict
# )
#
# park_uuid_to_index_dict, park_index_to_uuid_dict = build_park_uuid_index_map()
#
# park_num = len(park_uuid_to_index_dict)
#
# truck_uuid_to_name_dict, truck_name_to_uuid_dict = build_truck_uuid_name_map()
#
# excavator_uuid_to_name_dict, dump_uuid_to_name_dict = build_equipment_uuid_name_map()
#
# # 矿卡集合
# truck_set = set(update_total_truck())
#
# # 固定派车矿卡集合
# fixed_truck_set = set(update_fixdisp_truck())
#
# # 动态派车矿卡集合
# # dynamic_truck_set = truck_set.difference(fixed_truck_set)
# dynamic_truck_set = update_dynamic_truck()
#
# dynamic_truck_num = len(dynamic_truck_set)
#
# logger.info("可用于动态派车的矿卡：")
# logger.info(dynamic_truck_set)
#
# # 用于动态调度的挖机及卸载设备
# dynamic_excavator_set = set(update_autodisp_excavator())
# dynamic_excavator_num = len(dynamic_excavator_set)
#
# dynamic_dump_set = set(update_autodisp_dump())
# dynamic_dump_num = len(dynamic_dump_set)
#
# global global_dict

global_dict = {}

# global_dict["dynamic_truck_set"] = dynamic_truck_set
# global_dict["dynamic_truck_num"] = dynamic_truck_num
# global_dict["dynamic_excavator_set"] = dynamic_excavator_set
# global_dict["dynamic_excavator_num"] = dynamic_excavator_num
# global_dict["dynamic_dump_set"] = dynamic_dump_set
# global_dict["dynamic_dump_num"] = dynamic_dump_num
# global_dict["park_num"] = park_num


def get_value(name):
    return global_dict[name]


# 设备映射类, 存储除工作区以外的映射关系
# 其余设备类继承该类
class DeviceMap:
    excavator_uuid_to_index_dict = {}
    dump_uuid_to_index_dict = {}
    excavator_index_to_uuid_dict = {}
    dump_index_to_uuid_dict = {}

    dump_uuid_to_unload_area_uuid_dict = {}
    excavator_uuid_to_load_area_uuid_dict = {}
    excavator_index_to_load_area_index_dict = {}
    dump_index_to_unload_area_index_dict = {}

    truck_uuid_to_index_dict = {}
    truck_index_to_uuid_dict = {}

    # def __init__(cls):
    #     cls.excavator_uuid_to_index_dict = {}
    #     cls.dump_uuid_to_index_dict = {}
    #     cls.excavator_index_to_uuid_dict = {}
    #     cls.dump_index_to_uuid_dict = {}
    #
    #     cls.dump_uuid_to_unload_area_uuid_dict = {}
    #     cls.excavator_uuid_to_load_area_uuid_dict = {}
    #     cls.excavator_index_to_load_area_index_dict = {}
    #     cls.dump_index_to_unload_area_index_dict = {}
    #
    #     cls.truck_uuid_to_index_dict = {}
    #     cls.truck_index_to_uuid_dict = {}

    # def get_excavator_uuid_to_index_dict(cls):
    #     return cls.excavator_uuid_to_index_dict
    #
    # def get_dump_uuid_to_index_dict(cls):
    #     return cls.dump_uuid_to_index_dict
    #
    # def get_excavator_index_to_uuid_dict(cls):
    #     return cls.excavator_index_to_uuid_dict
    #
    # def get_dump_index_to_uuid_dict(cls):
    #     return cls.dump_index_to_uuid_dict
    #
    # def get_dump_uuid_to_unload_area_uuid_dict(cls):
    #     return cls.dump_uuid_to_unload_area_uuid_dict
    #
    # def get_excavator_uuid_to_load_area_uuid_dict(cls):
    #     return cls.excavator_uuid_to_load_area_uuid_dict
    #
    # def get_excavator_index_to_load_area_index_dict(cls):
    #     return cls.excavator_index_to_load_area_index_dict
    #
    # def get_dump_index_to_unload_area_index_dict(cls):
    #     return cls.dump_index_to_unload_area_index_dict
    #
    # def get_truck_uuid_to_index_dict(cls):
    #     return cls.truck_uuid_to_index_dict
    #
    # def get_truck_index_to_uuid_dict(cls):
    #     return cls.truck_index_to_uuid_dict

    @classmethod
    def reset(cls):
        cls.excavator_uuid_to_index_dict = {}
        cls.dump_uuid_to_index_dict = {}
        cls.excavator_index_to_uuid_dict = {}
        cls.dump_index_to_uuid_dict = {}

        cls.dump_uuid_to_unload_area_uuid_dict = {}
        cls.excavator_uuid_to_load_area_uuid_dict = {}
        cls.excavator_index_to_load_area_index_dict = {}
        cls.dump_index_to_unload_area_index_dict = {}

        cls.truck_uuid_to_index_dict = {}
        cls.truck_index_to_uuid_dict = {}

    @classmethod
    def period_map_para_update(cls):
        cls.reset()

        device_map_dict = update_deveices_map(
            unload_area_uuid_to_index_dict, load_area_uuid_to_index_dict
        )

        cls.excavator_uuid_to_index_dict = device_map_dict[
            "excavator_uuid_to_index_dict"
        ]

        cls.dump_uuid_to_index_dict = device_map_dict["dump_uuid_to_index_dict"]
        cls.excavator_index_to_uuid_dict = device_map_dict[
            "excavator_index_to_uuid_dict"
        ]
        cls.dump_index_to_uuid_dict = device_map_dict["dump_index_to_uuid_dict"]

        cls.dump_uuid_to_unload_area_uuid_dict = device_map_dict[
            "dump_uuid_to_unload_area_uuid_dict"
        ]
        cls.excavator_uuid_to_load_area_uuid_dict = device_map_dict[
            "excavator_uuid_to_load_area_uuid_dict"
        ]
        cls.excavator_index_to_load_area_index_dict = device_map_dict[
            "excavator_index_to_load_area_index_dict"
        ]
        cls.dump_index_to_unload_area_index_dict = device_map_dict[
            "dump_index_to_unload_area_index_dict"
        ]

        truck_map_dict = update_truck_uuid_index_map(get_value("dynamic_truck_set"))

        cls.truck_uuid_to_index_dict = truck_map_dict["truck_uuid_to_index_dict"]

        cls.truck_index_to_uuid_dict = truck_map_dict["truck_index_to_uuid_dict"]

    # def period_map_para_load(cls):
    #     # 装载关系映射
    #     cls.excavator_uuid_to_index_dict = device_map.excavator_uuid_to_index_dict
    #     cls.dump_uuid_to_index_dict = device_map.dump_uuid_to_index_dict
    #     cls.excavator_index_to_uuid_dict = device_map.excavator_index_to_uuid_dict
    #     cls.dump_index_to_uuid_dict = device_map.dump_index_to_uuid_dict
    #
    #     cls.dump_uuid_to_unload_area_uuid_dict = (
    #         device_map.dump_uuid_to_unload_area_uuid_dict
    #     )
    #     cls.excavator_uuid_to_load_area_uuid_dict = (
    #         device_map.excavator_uuid_to_load_area_uuid_dict
    #     )
    #     cls.excavator_index_to_load_area_index_dict = (
    #         device_map.excavator_index_to_load_area_index_dict
    #     )
    #     cls.dump_index_to_unload_area_index_dict = (
    #         device_map.dump_index_to_unload_area_index_dict
    #     )
    #
    #     cls.truck_uuid_to_index_dict = device_map.truck_uuid_to_index_dict
    #     cls.truck_index_to_uuid_dict = device_map.truck_index_to_uuid_dict


# 路网信息类
class WalkManage(DeviceMap):
    # def __init__(cls):
    #     # # 工作区和设备不具备一一对应关系, 为方便就计算, 算法维护两套路网: 面向路网和面向设备
    #
    #     # 路网真实距离
    #     cls.walk_time_to_excavator = np.full((dynamic_dump_num, dynamic_excavator_num), M, dtype=float)
    #     cls.walk_time_to_dump = np.full((dynamic_dump_num, dynamic_excavator_num), M, dtype=float)
    #     cls.walk_time_park_to_excavator = np.full((park_num, dynamic_excavator_num), M, dtype=float)
    #     cls.walk_time_park_to_load_area = np.full((park_num, load_area_num), M, dtype=float)
    #     cls.walk_time_to_load_area = np.full((unload_area_num, load_area_num), M, dtype=float)
    #     cls.walk_time_to_unload_area = np.full((unload_area_num, load_area_num), M, dtype=float)
    #
    #     # 路网行驶时间
    #     cls.distance_to_excavator = np.full((dynamic_dump_num, dynamic_excavator_num), M, dtype=float)
    #     cls.distance_to_dump = np.full((dynamic_dump_num, dynamic_excavator_num), M, dtype=float)
    #     cls.distance_park_to_excavator = np.full((park_num, dynamic_excavator_num), M, dtype=float)
    #     cls.distance_park_to_load_area = np.full((park_num, load_area_num), M, dtype=float)
    #     cls.distance_to_load_area = np.full((unload_area_num, load_area_num), M, dtype=float)
    #     cls.distance_to_unload_area = np.full((unload_area_num, load_area_num), M, dtype=float)

    # # 工作区和设备不具备一一对应关系, 为方便就计算, 算法维护两套路网: 面向路网和面向设备

    # 路网真实距离
    walk_time_to_excavator = None
    walk_time_to_dump = None
    walk_time_park_to_excavator = None
    walk_time_park_to_load_area = None
    walk_time_to_load_area = None
    walk_time_to_unload_area = None

    # 路网行驶时间
    distance_to_excavator = None
    distance_to_dump = None
    distance_park_to_excavator = None
    distance_park_to_load_area = None
    distance_to_load_area = None
    distance_to_unload_area = None

    # def get_walk_time_to_load_area(cls):
    #     return cls.walk_time_to_load_area
    #
    # def get_walk_time_to_unload_area(cls):
    #     return cls.walk_time_to_unload_area
    #
    # def get_walk_time_to_excavator(cls):
    #     return cls.walk_time_to_excavator
    #
    # def get_walk_time_to_dump(cls):
    #     return cls.walk_time_to_dump
    #
    # def get_walk_time_park_to_load_area(cls):
    #     return cls.walk_time_park_to_load_area
    #
    # def get_walk_time_park_to_excavator(cls):
    #     return cls.walk_time_park_to_excavator
    #
    # def get_distance_to_load_area(cls):
    #     return cls.distance_to_load_area
    #
    # def get_distance_to_unload_area(cls):
    #     return cls.distance_to_unload_area
    #
    # def get_distance_to_excavator(cls):
    #     return cls.distance_to_excavator
    #
    # def get_distance_to_dump(cls):
    #     return cls.distance_to_dump
    #
    # def get_distance_park_to_load_area(cls):
    #     return cls.distance_park_to_load_area
    #
    # def get_distance_park_to_excavator(cls):
    #     return cls.distance_park_to_excavator

    @classmethod
    def reset(cls):

        # dynamic_excavator_num
        # dynamic_dump_num
        # park_num

        # 路网真实距离
        cls.walk_time_to_excavator = np.full(
            (dynamic_dump_num, dynamic_excavator_num), M
        )
        cls.walk_time_to_dump = np.full((dynamic_dump_num, dynamic_excavator_num), M)
        cls.walk_time_park_to_excavator = np.full((park_num, dynamic_excavator_num), M)
        cls.walk_time_park_to_load_area = np.full((park_num, load_area_num), M)
        cls.walk_time_to_load_area = np.full((unload_area_num, load_area_num), M)
        cls.walk_time_to_unload_area = np.full((unload_area_num, load_area_num), M)

        # 路网行驶时间
        cls.distance_to_excavator = np.full((dynamic_dump_num, dynamic_excavator_num), M)
        cls.distance_to_dump = np.full((dynamic_dump_num, dynamic_excavator_num), M)
        cls.distance_park_to_excavator = np.full((park_num, dynamic_excavator_num), M)
        cls.distance_park_to_load_area = np.full((park_num, load_area_num), M)
        cls.distance_to_load_area = np.full((unload_area_num, load_area_num), M)
        cls.distance_to_unload_area = np.full((unload_area_num, load_area_num), M)

    @classmethod
    def period_walk_para_update(cls):

        cls.reset()

        cls.period_map_para_update()

        # 计算路网距离及行走时间
        try:
            # 处理距离
            for item in session_postgre.query(WalkTime).all():
                load_area = str(item.load_area_id)
                unload_area = str(item.unload_area_id)
                load_area_index = load_area_uuid_to_index_dict[load_area]
                unload_area_index = unload_area_uuid_to_index_dict[unload_area]
                cls.distance_to_load_area[unload_area_index][load_area_index] = float(
                    item.to_load_distance
                )
                cls.walk_time_to_load_area[unload_area_index][load_area_index] = float(
                    60 / 1000 * item.to_load_distance / empty_speed
                )
                cls.distance_to_unload_area[unload_area_index][
                    load_area_index
                ] = float(item.to_unload_distance)
                cls.walk_time_to_unload_area[unload_area_index][
                    load_area_index
                ] = float(60 / 1000 * item.to_unload_distance / heavy_speed)
        except Exception as es:
            logger.error("路网信息异常")
            logger.error(es)
            session_postgre.rollback()
            session_mysql.rollback()

        # 计算设备路网距离及行走时间
        try:
            n = dynamic_dump_num
            m = dynamic_excavator_num
            for i in range(dynamic_dump_num):
                for j in range(dynamic_excavator_num):
                    cls.distance_to_excavator[i][j] = cls.distance_to_load_area[cls.dump_index_to_unload_area_index_dict[i]][cls.excavator_index_to_load_area_index_dict[j]]

                    cls.walk_time_to_excavator[i][j] = cls.walk_time_to_load_area[cls.dump_index_to_unload_area_index_dict[i]][cls.excavator_index_to_load_area_index_dict[j]]

                    cls.distance_to_dump[i][j] = cls.distance_to_unload_area[cls.dump_index_to_unload_area_index_dict[i]][cls.excavator_index_to_load_area_index_dict[j]]

                    cls.walk_time_to_dump[i][j] = cls.walk_time_to_unload_area[cls.dump_index_to_unload_area_index_dict[i]][cls.excavator_index_to_load_area_index_dict[j]]
        except Exception as es:
            logger.error("设备路网信息异常")
            logger.error(es)

        try:
            for item in session_postgre.query(WalkTimePark).all():
                load_area = str(item.load_area_id)
                park_area = str(item.park_area_id)
                load_area_index = load_area_uuid_to_index_dict[load_area]
                park_index = park_uuid_to_index_dict[park_area]
                cls.distance_park_to_load_area[park_index][load_area_index] = float(
                    item.park_load_distance
                )
                cls.walk_time_park_to_load_area[park_index][load_area_index] = float(
                    60 / 1000 * item.park_load_distance / empty_speed
                )
        except Exception as es:
            logger.error("备停区路网信息异常")
            logger.error(es)
            session_postgre.rollback()
            session_mysql.rollback()
        try:
            for i in range(park_num):
                for j in range(dynamic_excavator_num):
                    cls.distance_park_to_excavator[i][j] = cls.distance_park_to_load_area[
                        i
                    ][cls.excavator_index_to_load_area_index_dict[j]]
                    cls.walk_time_park_to_excavator[i][
                        j
                    ] = cls.walk_time_park_to_load_area[i][
                        cls.excavator_index_to_load_area_index_dict[j]
                    ]
        except Exception as es:
            logger.error("备停区设备路网信息异常")
            logger.error(es)

        logger.info("distance_park_to_excavator")
        logger.info(cls.distance_park_to_excavator)


def get_global_para_from_cache(cache):
    """ 优先从cache缓存读取global数据
    :param cache: 缓存器
    :return: None
    """
    global global_dict

    global_dict = cache.get("global_dict")

    if global_dict is None:
        global_period_para_update()
        cache.set("global_dict", global_dict, timeout=5 * 60)


def global_period_para_update():
    global load_area_uuid_to_index_dict, load_area_index_to_uuid_dict
    global unload_area_uuid_to_index_dict, unload_area_index_to_uuid_dict
    global load_area_num, unload_area_num, park_num
    global park_uuid_to_index_dict, park_index_to_uuid_dict
    global truck_uuid_to_name_dict, truck_name_to_uuid_dict
    global dynamic_truck_num, dynamic_excavator_num, dynamic_dump_num
    global excavator_uuid_to_name_dict, dump_uuid_to_name_dict
    global global_dict

    # 清空数据库缓存
    session_mysql.commit()
    session_mysql.flush()

    # 装载区、卸载区、备停区在调度算法运行器件默认不发生改变，提前计算部分参量
    # (uuid,index(id)映射关系, 装载区数量, 卸载区数量, 备停区数量, 以及初次统计动态调度矿卡)
    (
        load_area_uuid_to_index_dict,
        unload_area_uuid_to_index_dict,
        load_area_index_to_uuid_dict,
        unload_area_index_to_uuid_dict,
    ) = build_work_area_uuid_index_map()

    load_area_num, unload_area_num = len(load_area_uuid_to_index_dict), len(
        unload_area_uuid_to_index_dict
    )

    park_uuid_to_index_dict, park_index_to_uuid_dict = build_park_uuid_index_map()

    park_num = len(park_uuid_to_index_dict)

    truck_uuid_to_name_dict, truck_name_to_uuid_dict = build_truck_uuid_name_map()

    excavator_uuid_to_name_dict, dump_uuid_to_name_dict = build_equipment_uuid_name_map()

    global_dict = {"park_num": park_num, "load_area_num": load_area_num, "unload_area_num": unload_area_num,
                   "truck_uuid_to_name_dict": truck_uuid_to_name_dict,
                   "truck_name_to_uuid_dict": truck_name_to_uuid_dict,
                   "excavator_uuid_to_name_dict": excavator_uuid_to_name_dict,
                   "dump_uuid_to_name_dict": dump_uuid_to_name_dict,
                   "unload_area_uuid_to_index_dict": unload_area_uuid_to_index_dict,
                   "load_area_uuid_to_index_dict": load_area_uuid_to_index_dict,
                   "unload_area_index_to_uuid_dict": unload_area_index_to_uuid_dict,
                   "park_uuid_to_index_dict": park_uuid_to_index_dict,
                   "park_index_to_uuid_dict": park_index_to_uuid_dict}

    # 矿卡集合
    truck_set = set(update_total_truck())

    logger.info("truck_set")
    logger.info(truck_set)

    # 固定派车矿卡集合
    fixed_truck_set = set(update_fixdisp_truck())

    logger.info("fixed_truck_set")
    logger.info(fixed_truck_set)

    # 动态派车矿卡集合
    # dynamic_truck_set = truck_set.difference(fixed_truck_set)
    dynamic_truck_set = update_dynamic_truck()
    dynamic_truck_num = len(dynamic_truck_set)

    global_dict["dynamic_truck_set"] = dynamic_truck_set
    global_dict["dynamic_truck_num"] = dynamic_truck_num

    logger.info("可用于动态派车的矿卡：")
    logger.info(dynamic_truck_num)
    logger.info(dynamic_truck_set)

    # 用于动态调度的挖机及卸载设备
    dynamic_excavator_set = set(update_autodisp_excavator())
    dynamic_excavator_num = len(dynamic_excavator_set)

    dynamic_dump_set = set(update_autodisp_dump())
    dynamic_dump_num = len(dynamic_dump_set)

    global_dict["dynamic_excavator_set"] = dynamic_excavator_set
    global_dict["dynamic_excavator_num"] = dynamic_excavator_num
    global_dict["dynamic_dump_set"] = dynamic_dump_set
    global_dict["dynamic_dump_num"] = dynamic_dump_num

    DeviceMap.reset()

    DeviceMap.period_map_para_update()

    WalkManage.reset()

    WalkManage.period_walk_para_update()

    global_dict["distance_to_excavator"] = WalkManage.distance_to_excavator
    global_dict["distance_park_to_excavator"] = WalkManage.distance_park_to_excavator
    global_dict["distance_to_dump"] = WalkManage.distance_to_dump

    # logger.info("walk_manage_para")
    # logger.info("distance_to_excavator")
    # logger.info(walk_manage.distance_to_excavator)
    # logger.info("distance_park_to_excavator")
    # logger.info(walk_manage.distance_park_to_excavator)
    # logger.info("distance_to_dump")
    # logger.info(walk_manage.distance_to_dump)
    # logger.info("excavator_uuid_to_index_dict")
    # logger.info(walk_manage.excavator_uuid_to_index_dict)
    # logger.info("dump_uuid_to_index_dict")
    # logger.info(walk_manage.dump_uuid_to_index_dict)
    # logger.info("walk_manage.distance_park_to_excavator")
    # logger.info(walk_manage.distance_park_to_excavator)
    #
    # logger.info("walk_manage.truck_index_to_uuid_dict")
    # logger.info(walk_manage.truck_index_to_uuid_dict)
    # logger.info("walk_manage.dynamic_truck_set")
    # logger.info(dynamic_truck_set)
