#!E:\Pycharm Projects\Waytous
# -*- coding: utf-8 -*-
# @Time : 2022/5/30 16:32
# @Author : Opfer
# @Site :
# @File : alg.py
# @Software: PyCharm

from para_config import *
from equipment import ExcavatorInfo, DumpInfo, TruckInfo
# from core.group import Group
from core.schedule import PreSchedule


class AlgorithmBase:
    """
    Base class for dispatch alg.
    """

    def __init__(self):
        pass

    def solve(self, *args, **kwargs):
        """
        Dispatching calculation for subgroups.
        """
        raise NotImplementedError


class Congestion(AlgorithmBase):
    """
    class for congestion alg.
    """

    def __init__(self, group, truck, pre_sch):
        super().__init__()
        self.group = group
        self.truck = truck
        self.pre_sch = pre_sch
        self.logger = get_logger("zxt.algorithm.congestion")

    def solve(self, truck_id):
        """
        Receive a truck_id and calculate the associated route congestion.
        :param truck_id: (uuid)
        :return: congestion_value
        """

        try:

            truck_index = self.truck.truck_uuid_to_index_dict[truck_id]

            trip = self.truck.get_truck_current_trip()[truck_index]

            task = self.truck.get_truck_current_task()[truck_id]

            group_dynamic_excavator_num = len(self.group.dump)

            group_dynamic_dump_num = len(self.group.excavator)

        except Exception as es:
            self.logger.error("车辆调度信息读取异常")
            self.logger.error(es)

        if task == -2:
            ################################################ 矿卡启动 ###############################################
            try:
                self.logger.info("矿卡状态：矿卡启动或故障恢复")
                self.logger.info(f"涉及挖机：{list(DeviceMap.excavator_uuid_to_index_dict.keys())}")
            except Exception as es:
                self.logger.error(f"矿卡{truck_id}状态不匹配")
                self.logger.error(es)

            try:
                transport_value = self.group.park_to_excavator_congestion

            except Exception as es:
                transport_value = np.zeros(group_dynamic_excavator_num)
                self.logger.info(es)

        if task in [0, 1, 2]:
            ################################################ 矿卡空载 ###############################################

            try:
                self.logger.info("矿卡状态：矿卡空载")
                self.logger.info(f"涉及卸载设备：{list(DumpInfo.dump_uuid_to_index_dict.keys())}")
            except Exception as es:
                self.logger.error(f"矿卡{truck_id}状态不匹配")
                self.logger.error(es)

            try:
                # 车辆所在挖机 uuid
                excavator_id = DeviceMap.excavator_index_to_uuid_dict[int(trip[1])]

                # 挖机所在分组序号 index
                excavator_group_index = self.group.excavator_uuid_index_dict[excavator_id]

                transport_value = self.group.to_dump_congestion[excavator_group_index, :]
            except Exception as es:
                self.logger.error("矿卡空载调度异常")
                self.logger.error(es)
                transport_value = np.zeros(group_dynamic_dump_num)

        elif task in [3, 4, 5]:
            ################################################ 矿卡重载 ###############################################

            try:
                self.logger.info("矿卡状态：矿卡重载")
                self.logger.info(f"涉及挖机设备：{list(DeviceMap.excavator_uuid_to_index_dict.keys())}")
            except Exception as es:
                self.logger.error(f"矿卡{truck_id}状态不匹配")
                self.logger.error(es)

            try:
                # 车辆所在卸点
                dump_id = DeviceMap.dump_index_to_uuid_dict[int(trip[1])]

                # 卸点对应分组编号
                dump_group_index = self.group.dump_uuid_index_dict[dump_id]

                transport_value = self.group.to_excavator_congestion[dump_group_index, :]
            except Exception as es:
                self.logger.error("矿卡重载调度异常")
                self.logger.error(es)
                transport_value = np.zeros(group_dynamic_excavator_num)

        return transport_value


class ExpectedTime(AlgorithmBase):
    """
    class for expected traveling time alg.
    """

    def __init__(self, group, truck, pre_sch):
        super().__init__()

        self.group = group
        self.truck = truck
        self.pre_sch = pre_sch
        self.logger = get_logger("zxt.algorithm.expected")

    def solve(self, truck_id):
        """
        Receive a truck_id and calculate the associated route travelling time.
        :param truck_id: (uuid)
        :return: travel_time_value
        """

        try:

            truck_index = self.truck.truck_uuid_to_index_dict[truck_id]

            trip = self.truck.get_truck_current_trip()[truck_index]

            task = self.truck.get_truck_current_task()[truck_id]

            truck_avl_time = self.pre_sch.get_truck_avl_time(truck_id=truck_id)

            group_dynamic_excavator_num = len(self.group.dump)

            group_dynamic_dump_num = len(self.group.excavator)

        except Exception as es:
            self.logger.error("车辆调度信息读取异常")
            self.logger.error(es)

        if task == -2:
            ################################################ 矿卡启动 ###############################################

            try:
                self.logger.info("矿卡状态：矿卡启动或故障恢复")
                self.logger.info(f"涉及挖机：{list(DeviceMap.excavator_uuid_to_index_dict.keys())}")
            except Exception as es:
                self.logger.error(f"矿卡{truck_id}状态不匹配")
                self.logger.error(es)

            # try:
            # 挖机可用时间
            excavator_val_time_global = self.pre_sch.get_excavator_avl_time()

            excavator_val_time = np.full(len(self.group.excavator), 0)

            for excavator_id, excavator_index in self.group.excavator_uuid_index_dict.items():
                excavator_val_time[excavator_index] = excavator_val_time_global[excavator_id]

            # 车辆驶往各目的地时间
            truck_reach_time = 60 * self.group.park_to_excavator_distance[0, :] / 1000 / \
                               self.truck.empty_speed[truck_id] + truck_avl_time

            # 计算车辆得到服务时间
            truck_service_time = np.maximum(truck_reach_time, excavator_val_time)

            # 计算行程时间
            transport_value = truck_service_time - truck_avl_time

            self.logger.info("expected_travelling_schedule-truck_avl_time")
            self.logger.info(truck_avl_time)

            self.logger.info("expected_travelling_schedule-truck_service_time")
            self.logger.info(truck_service_time)

            self.logger.info("expected_travelling_schedule-truck_reach_time")
            self.logger.info(truck_reach_time)

            self.logger.info("expected_travelling_schedule-excavator_val_time")
            self.logger.info(excavator_val_time)

            # except Exception as es:
            #     self.logger.error("矿卡启动调度异常")
            #     self.logger.error(es)
            #     transport_value = np.zeros(group_dynamic_excavator_num)

        if task in [0, 1, 2]:
            ################################################ 矿卡空载 ###############################################

            try:
                self.logger.info("矿卡状态：矿卡空载")
                self.logger.info(f"涉及卸载设备：{list(DeviceMap.dump_uuid_to_index_dict.keys())}")
            except Exception as es:
                self.logger.error(f"矿卡{truck_id}状态不匹配")
                self.logger.error(es)

            try:
                # 全局卸点可用时间 dict
                dump_val_time_global = self.pre_sch.get_dump_avl_time()

                # 局部卸点可用时间 list
                dump_val_time = np.full(len(self.group.dump), 0)
                for dump_id, dump_index in self.group.dump_uuid_index_dict.items():
                    dump_val_time[dump_index] = dump_val_time_global[dump_id]

                # 车辆所在挖机 uuid
                excavator_id = DeviceMap.excavator_index_to_uuid_dict[int(trip[1])]

                # 挖机所在分组序号 index
                excavator_group_index = self.group.excavator_uuid_index_dict[excavator_id]

                # 车辆驶往各目的地时间
                truck_reach_time = 60 * self.group.to_dump_distance[excavator_group_index, :] \
                                   / 1000 / self.truck.heavy_speed[truck_id] + truck_avl_time

                # 车辆得到服务时间
                truck_service_time = np.maximum(truck_reach_time, dump_val_time)

                # 计算行程时间
                transport_value = truck_service_time - truck_avl_time

                self.logger.info("expected_travelling_schedule-truck_avl_time")
                self.logger.info(truck_avl_time)

                self.logger.info("expected_travelling_schedule-truck_service_time")
                self.logger.info(truck_service_time)

                self.logger.info("expected_travelling_schedule-truck_reach_time")
                self.logger.info(truck_reach_time)

                self.logger.info("expected_travelling_schedule-dump_val_time")
                self.logger.info(dump_val_time)

            except Exception as es:
                self.logger.error("矿卡空载调度异常")
                self.logger.error(es)
                transport_value = np.zeros(group_dynamic_dump_num)

        elif task in [3, 4, 5]:
            ################################################ 矿卡重载 ###############################################

            try:
                self.logger.info("矿卡状态：矿卡重载")
                self.logger.info(f"涉及挖机设备：{list(DeviceMap.excavator_uuid_to_index_dict.keys())}")
            except Exception as es:
                self.logger.error(f"矿卡{truck_id}状态不匹配")
                self.logger.error(es)

            try:
                # 挖机可用时间
                excavator_val_time_global = self.pre_sch.get_excavator_avl_time()

                excavator_val_time = np.full(len(self.group.excavator), 0)

                for excavator_id, excavator_index in self.group.excavator_uuid_index_dict.items():
                    excavator_val_time[excavator_index] = excavator_val_time_global[excavator_id]

                # 车辆所在卸点
                dump_id = DeviceMap.dump_index_to_uuid_dict[int(trip[1])]

                # 卸点对应分组编号
                dump_group_index = self.group.dump_uuid_index_dict[dump_id]

                # 车辆驶往各目的地时间
                truck_reach_time = 60 * self.group.to_excavator_distance[dump_group_index, :] \
                                   / 1000 / self.truck.empty_speed[truck_id] + truck_avl_time

                # 计算车辆得到服务时间
                truck_service_time = np.maximum(truck_reach_time, excavator_val_time)

                # 计算行程时间
                transport_value = truck_service_time - truck_avl_time

            except Exception as es:
                self.logger.error("矿卡重载调度异常")
                self.logger.error(es)
                transport_value = np.zeros(group_dynamic_dump_num)

        return transport_value

