#!E:\Pycharm Projects\Waytous
# -*- coding: utf-8 -*-
# @Time : 2021/11/26 11:34
# @Author : Opfer
# @Site :
# @File : group_control.py    
# @Software: PyCharm

from settings import *
from para_config import *
from path_plan.path_plannner import PathPlanner
from traffic_flow.traffic_flow_planner import traffic_flow_plan

class Group(WalkManage):
    def __init__(self, dump, excavator, truck, traffic_flow):
        self.dump = dump
        self.excavator = excavator
        self.truck = truck
        self.traffic_flow = traffic_flow

        self.dispatch_truck_group = {}
        self.group_num = 1
        self.group_set = set()
        self.device_group = {}
        self.group_walk_to_excavator_cost = {}
        self.group_walk_to_dump_cost = {}
        self.group_park_to_excavator = {}

        self.group_opt_goto_dump_traffic_flow = {}
        self.group_opt_goto_excavator_traffic_flow = {}
        self.group_actual_goto_dump_traffic_flow = {}
        self.group_actual_goto_excavator_traffic_flow = {}

        self.group_excavator_uuid_to_index_dict = {}
        self.group_dump_uuid_to_index_dict = {}
        self.group_excavator_index_to_uuid_dict = {}
        self.group_dump_index_to_uuid_dict = {}

        self.group_excavator_exclude_modify = {}
        self.group_excavator_material_bind_modify = {}
        self.group_dump_material_bind_modify = {}

        self.path = PathPlanner()

    def update_dispatch_truck_group(self):
        # 更新矿卡-调度分组隶属关系
        self.dispatch_truck_group = {}
        dynamic_truck_set = get_value("dynamic_truck_set")
        print("dispatch_truck_group-dynamic_truck_set")
        print(dynamic_truck_set)
        # 动态派车数量没变，但是此时某条派车计划被删除，dispatch_truck_group 就会缺失矿卡
        for truck_id in dynamic_truck_set:
            item = session_mysql.query(Dispatch).filter_by(truck_id=truck_id, isauto=1, isdeleted=0).first()
            if item is None:
                print(truck_id)
                continue
            self.dispatch_truck_group[truck_id] = item.group_id

        print(self.dispatch_truck_group)

    def update_group_set(self):
        # 更新调度组
        self.group_set = set()
        for item in session_mysql.query(Dispatch).filter_by(isauto=1, isdeleted=0).all():
            if item.group_id is not None:
                self.group_set.add(item.group_id)
        self.group_num = len(self.group_set)

    def update_device_group(self):
        # 更新设备分组group_id -> {set(dump_id), set(excavator_id)}
        self.device_group = {}
        for group_id in self.get_group_set():
            if group_id not in self.device_group:
                self.device_group[group_id] = [set(), set()]
            else:
                continue
            for item in session_mysql.query(Dispatch).filter_by(group_id=group_id, isauto=1, isdeleted=0).all():
                self.device_group[group_id][0].add(item.dump_id)
                self.device_group[group_id][1].add(item.exactor_id)

    # 更新实际交通流
    def update_actual_traffic_flow(self):

        loading_task_time = self.excavator.get_loading_task_time()

        unloading_task_time = self.dump.get_unloading_task_time()

        truck_current_task = self.truck.get_truck_current_task()
        truck_current_trip = self.truck.get_truck_current_trip()
        payload = self.truck.get_payload()

        dynamic_dump_num = get_value("dynamic_dump_num")
        dynamic_excavator_num = get_value("dynamic_excavator_num")
        dynamic_truck_num = get_value("dynamic_truck_num")

        self.goto_dump_truck_num = np.zeros((dynamic_excavator_num, dynamic_dump_num))
        self.actual_goto_dump_traffic_flow = np.zeros(
            (dynamic_excavator_num, dynamic_dump_num)
        )
        self.goto_excavator_truck_num = np.zeros(
            (dynamic_dump_num, dynamic_excavator_num)
        )
        self.actual_goto_excavator_traffic_flow = np.zeros(
            (dynamic_dump_num, dynamic_excavator_num)
        )

        # try:
        logger.info("dynamic_truck_num")
        logger.info(dynamic_truck_num)

        print("truck.truck_index_to_uuid_dict")
        print(self.truck.truck_index_to_uuid_dict)

        print("truck_current_task")
        print(truck_current_task)

        for i in range(dynamic_truck_num):
            task = truck_current_task[DeviceMap.truck_index_to_uuid_dict[i]]
            end_area_index = truck_current_trip[i][1]
            start_area_index = truck_current_trip[i][0]

            if task in [3, 4]:    # 矿卡空载或正在入场装载区
                self.goto_dump_truck_num[start_area_index][end_area_index] += 1
                self.actual_goto_dump_traffic_flow[start_area_index][end_area_index] += float(payload[i])

            if task in [0, 1]:    # 矿卡重载或正在入场卸载区
                self.goto_excavator_truck_num[start_area_index][end_area_index] += 1
                self.actual_goto_excavator_traffic_flow[start_area_index][end_area_index] += float(payload[i])

        self.actual_goto_dump_traffic_flow = self.actual_goto_dump_traffic_flow / (
                self.distance_to_dump.reshape(dynamic_excavator_num, dynamic_dump_num)
                / (1000 * empty_speed)
                + np.expand_dims(unloading_task_time, axis=0).repeat(
            dynamic_excavator_num, axis=0
        )
        )

        self.actual_goto_excavator_traffic_flow = (
                self.actual_goto_excavator_traffic_flow
                / (
                        self.distance_to_excavator.reshape(
                            dynamic_dump_num, dynamic_excavator_num
                        )
                        / (1000 * heavy_speed)
                        + np.expand_dims(loading_task_time, axis=0).repeat(
                    dynamic_dump_num, axis=0
                )
                )
        )

    def update_group_truck_flow(self):

        # 更新调度分组内车实时/最佳车流

        global dispatcher

        actual_goto_excavator_traffic_flow, actual_goto_dump_traffic_flow = \
            self.traffic_flow.actual_goto_excavator_traffic_flow, self.traffic_flow.actual_goto_dump_traffic_flow

        opt_goto_dump_traffic_flow, opt_goto_excavator_traffic_flow = traffic_flow_plan(self.truck)

        try:

            # print("uuid_to_index_dict")
            # print(dump.dump_uuid_to_index_dict)
            # print(excavator.excavator_uuid_to_index_dict)

            for group_id in self.group_set:
                dump_group = self.device_group[group_id][0]        # group 类最后更新，读取派车计划及分组情况，和前面的uuid 可能不一致
                excavator_group = self.device_group[group_id][1]
                print("group")
                print(self.device_group)
                local_opt_goto_dump_traffic_flow = np.zeros((len(excavator_group), len(dump_group)))
                local_opt_goto_excavator_traffic_flow = np.zeros((len(dump_group), len(excavator_group)))
                local_actual_goto_dump_traffic_flow = np.zeros((len(excavator_group), len(dump_group)))
                local_actual_goto_excavator_traffic_flow = np.zeros((len(dump_group), len(excavator_group)))
                for excavator_id in excavator_group:
                    for dump_id in dump_group:
                        dump_group_index = self.group_dump_uuid_to_index_dict[group_id][dump_id]
                        excavator_group_index = self.group_excavator_uuid_to_index_dict[group_id][excavator_id]
                        local_opt_goto_dump_traffic_flow[excavator_group_index][dump_group_index] = \
                            opt_goto_dump_traffic_flow[DeviceMap.excavator_uuid_to_index_dict[excavator_id]][DeviceMap.dump_uuid_to_index_dict[dump_id]]

                        local_opt_goto_excavator_traffic_flow[dump_group_index][excavator_group_index] = \
                            opt_goto_excavator_traffic_flow[DeviceMap.dump_uuid_to_index_dict[dump_id]][DeviceMap.excavator_uuid_to_index_dict[excavator_id]]

                        local_actual_goto_dump_traffic_flow[excavator_group_index][dump_group_index] = \
                            actual_goto_dump_traffic_flow[DeviceMap.excavator_uuid_to_index_dict[excavator_id]][DeviceMap.dump_uuid_to_index_dict[dump_id]]

                        local_actual_goto_excavator_traffic_flow[dump_group_index][excavator_group_index] = \
                            actual_goto_excavator_traffic_flow[DeviceMap.dump_uuid_to_index_dict[dump_id]][DeviceMap.excavator_uuid_to_index_dict[excavator_id]]

                self.group_opt_goto_dump_traffic_flow[group_id] = local_opt_goto_dump_traffic_flow
                self.group_opt_goto_excavator_traffic_flow[group_id] = local_opt_goto_excavator_traffic_flow
                self.group_actual_goto_dump_traffic_flow[group_id] = local_actual_goto_dump_traffic_flow
                self.group_actual_goto_excavator_traffic_flow[group_id] = local_actual_goto_excavator_traffic_flow
        except Exception as es:
            logger.error(es)
            logger.error("分组车流更新异常")

        logger.info("group_opt_traffic_flow")
        logger.info(self.group_opt_goto_dump_traffic_flow)
        logger.info(self.group_opt_goto_excavator_traffic_flow)

    def update_group_walk_cost(self):

        # 更新调度分组路网行驶成本

        walk_to_excavator_cost, walk_to_dump_cost, park_to_excavator_cost = self.path.walk_cost_cal()

        try:

            for group_id in self.group_set:
                dump_group = self.device_group[group_id][0]
                excavator_group = self.device_group[group_id][1]
                local_walk_to_excavator_cost = np.zeros((len(dump_group), len(excavator_group)))
                local_walk_to_dump_cost = np.zeros((len(excavator_group), len(dump_group)))
                local_park_to_excavator_cost = np.zeros((park_num, len(excavator_group)))
                for excavator_id in excavator_group:
                    for dump_id in dump_group:
                        dump_group_index = self.group_dump_uuid_to_index_dict[group_id][dump_id]
                        excavator_group_index = self.group_excavator_uuid_to_index_dict[group_id][excavator_id]
                        print("dump_group")
                        print(dump_group)
                        local_walk_to_excavator_cost[dump_group_index][excavator_group_index] = \
                            walk_to_excavator_cost[DeviceMap.dump_uuid_to_index_dict[dump_id]][DeviceMap.excavator_uuid_to_index_dict[excavator_id]]

                        local_walk_to_dump_cost[excavator_group_index][dump_group_index] = \
                            walk_to_dump_cost[DeviceMap.dump_uuid_to_index_dict[dump_id]][DeviceMap.excavator_uuid_to_index_dict[excavator_id]]

                for park_index in range(park_num):
                    for excavator_id in excavator_group:
                        excavator_group_index = self.group_excavator_uuid_to_index_dict[group_id][excavator_id]
                        local_park_to_excavator_cost[park_index][excavator_group_index] = \
                            park_to_excavator_cost[park_index][DeviceMap.excavator_uuid_to_index_dict[excavator_id]]

                print("here1")
                print(park_to_excavator_cost)

                self.group_walk_to_excavator_cost[group_id] = local_walk_to_excavator_cost
                self.group_walk_to_dump_cost[group_id] = local_walk_to_dump_cost
                self.group_park_to_excavator[group_id] = local_park_to_excavator_cost
        except Exception as es:
            logger.info(es)
            logger.info("error-11")

    def update_group_device_map(self):
        # 更新调度分组内设备映射
        self.group_excavator_uuid_to_index_dict = {}
        self.group_dump_uuid_to_index_dict = {}
        self.group_excavator_index_to_uuid_dict = {}
        self.group_dump_index_to_uuid_dict = {}

        for group_id in self.group_set:
            excavator_num = 0
            dump_num = 0

            dump_group = self.device_group[group_id][0]
            excavator_group = self.device_group[group_id][1]

            self.group_excavator_uuid_to_index_dict[group_id] = {}
            self.group_excavator_index_to_uuid_dict[group_id] = {}
            self.group_dump_uuid_to_index_dict[group_id] = {}
            self.group_dump_index_to_uuid_dict[group_id] = {}

            for excavator_id in excavator_group:
                if excavator_id not in self.group_excavator_uuid_to_index_dict:
                    self.group_excavator_index_to_uuid_dict[group_id][excavator_num] = excavator_id
                    self.group_excavator_uuid_to_index_dict[group_id][excavator_id] = excavator_num

                    excavator_num = excavator_num + 1

            for dump_id in dump_group:
                if dump_id not in self.group_dump_uuid_to_index_dict:
                    self.group_dump_index_to_uuid_dict[group_id][dump_num] = dump_id
                    self.group_dump_uuid_to_index_dict[group_id][dump_id] = dump_num

                    dump_num = dump_num + 1

        logger.info("group_map")
        logger.info(self.group_dump_uuid_to_index_dict)
        logger.info(self.group_excavator_uuid_to_index_dict)

    def update_modify(self):
        try:

            dynamic_truck_set = get_value("dynamic_truck_set")

            print("update_modify")
            print(dynamic_truck_set)

            print("self.dispatch_truck_group")
            print(self.dispatch_truck_group)

            self.group_excavator_exclude_modify = {}
            self.group_excavator_material_bind_modify = {}
            self.group_dump_material_bind_modify = {}
            for truck_id in dynamic_truck_set:
                group_id = self.dispatch_truck_group[truck_id]
                group_dump_num = len(self.device_group[group_id][0])
                group_excavator_num = len(self.device_group[group_id][1])
                excavator_exclude_modify = np.zeros(group_excavator_num)
                excavator_material_bind_modify = np.zeros(group_excavator_num)
                dump_material_bind_modify = np.zeros(group_dump_num)

                truck_index = self.truck.truck_uuid_to_index_dict[truck_id]

                for group_excavator_index in range(group_excavator_num):
                    excavator_index = self.excavator.excavator_uuid_to_index_dict[self.group_excavator_index_to_uuid_dict[group_id][group_excavator_index]]
                    excavator_exclude_modify[group_excavator_index] = self.truck.excavator_exclude_modify[truck_index][excavator_index]

                for group_excavator_index in range(group_excavator_num):
                    excavator_index = self.excavator.excavator_uuid_to_index_dict[
                        self.group_excavator_index_to_uuid_dict[group_id][group_excavator_index]]
                    excavator_material_bind_modify[group_excavator_index] = self.truck.excavator_material_bind_modify[truck_index][excavator_index]

                for group_dump_index in range(group_dump_num):
                    dump_index = self.dump.dump_uuid_to_index_dict[self.group_dump_index_to_uuid_dict[group_id][group_dump_index]]
                    print(self.truck.dump_material_bind_modify, truck_index, dump_index)
                    print(self.truck.dump_material_bind_modify[truck_index][dump_index], truck_index, dump_index)
                    dump_material_bind_modify[group_dump_index] = self.truck.dump_material_bind_modify[truck_index][dump_index]

                self.group_excavator_exclude_modify[truck_id] = excavator_exclude_modify
                self.group_excavator_material_bind_modify[truck_id] = excavator_material_bind_modify
                self.group_dump_material_bind_modify[truck_id] = dump_material_bind_modify
        except Exception as es:
            logger.error(es)
            logger.error("modify update 异常")

    def update_excavator_hold_truck(self, excavator_hold_truck):
        '''
        更新调度分组内挖机保有矿卡
        :param excavator_hold_truck:
        :return:
        '''
        group_excavator_hold_truck = {}

        for group_id in self.group_set:
            excavator_group = self.device_group[group_id][1]
            group_excavator_hold_truck[group_id] = np.zeros(len(excavator_group))
            for excavator_id in excavator_group:
                group_excavator_index = self.group_excavator_uuid_to_index_dict[group_id][excavator_id]
                excavator_index = self.excavator.excavator_uuid_to_index_dict[excavator_id]
                group_excavator_hold_truck[group_id][group_excavator_index] = excavator_hold_truck[excavator_index]

        return group_excavator_hold_truck

    def update_dump_hold_truck(self, dump_hold_truck):
        group_dump_hold_truck = {}

        for group_id in self.group_set:
            dump_group = self.device_group[group_id][0]
            group_dump_hold_truck[group_id] = np.zeros(len(dump_group))
            for dump_id in dump_group:
                group_dump_index = self.group_dump_uuid_to_index_dict[group_id][dump_id]
                dump_index = self.dump.dump_uuid_to_index_dict[dump_id]
                group_dump_hold_truck[group_id][group_dump_index] = dump_hold_truck[dump_index]

        return group_dump_hold_truck

    def update_excavator_avl_time(self, excavator_avl_time):
        '''
        更新调度分组内挖机可用时间
        :param excavator_hold_truck:
        :return:
        '''
        group_excavator_avl_time= {}

        for group_id in self.group_set:
            excavator_group = self.device_group[group_id][1]
            group_excavator_avl_time[group_id] = np.zeros(len(excavator_group))
            for excavator_id in excavator_group:
                group_excavator_index = self.group_excavator_uuid_to_index_dict[group_id][excavator_id]
                excavator_index = self.excavator.excavator_uuid_to_index_dict[excavator_id]
                group_excavator_avl_time[group_id][group_excavator_index] = excavator_avl_time[excavator_index]

        return group_excavator_avl_time

    def update_dump_avl_time(self, dump_avl_time):
        '''
        更新调度分组内挖机可用时间
        :param dump_hold_truck:
        :return:
        '''
        group_dump_avl_time= {}

        for group_id in self.group_set:
            dump_group = self.device_group[group_id][0]
            group_dump_avl_time[group_id] = np.zeros(len(dump_group))
            for dump_id in dump_group:
                group_dump_index = self.group_dump_uuid_to_index_dict[group_id][dump_id]
                dump_index = self.dump.dump_uuid_to_index_dict[dump_id]
                group_dump_avl_time[group_id][group_dump_index] = dump_avl_time[dump_index]

        return group_dump_avl_time

    def update_allow_flow_to_excavator(self):
        group_allow_flow_to_excavator = {}

        for group_id in self.group_set:
            dump_group = self.device_group[group_id][0]
            group_allow_flow_to_excavator[group_id] = np.zeros(len(dump_group))
            for dump_id in dump_group:
                group_dump_index = self.group_dump_uuid_to_index_dict[group_id][dump_id]
                dump_index = self.dump.dump_uuid_to_index_dict[dump_id]
                group_allow_flow_to_excavator[group_id][group_dump_index] = self.excavator.excavator_strength[dump_index]

        return group_allow_flow_to_excavator

    def update_allow_flow_to_dump(self):
        group_allow_flow_to_dump = {}

        for group_id in self.group_set:
            dump_group = self.device_group[group_id][0]
            group_allow_flow_to_dump[group_id] = np.zeros(len(dump_group))
            for dump_id in dump_group:
                group_dump_index = self.group_dump_uuid_to_index_dict[group_id][dump_id]
                dump_index = self.dump.dump_uuid_to_index_dict[dump_id]
                group_allow_flow_to_dump[group_id][group_dump_index] = self.dump.dump_strength[dump_index]

        return group_allow_flow_to_dump

    def period_update(self):
        self.reset()
        self.update_dispatch_truck_group()
        self.update_group_set()
        self.update_device_group()
        self.update_group_device_map()
        self.update_group_walk_cost()
        # self.update_group_truck_flow()
        self.update_modify()

    def get_diaptch_truck_group(self):
        return self.dispatch_truck_group

    def get_group_num(self):
        return self.group_num

    def get_group_set(self):
        return self.group_set

    def reset(self):
        self.dispatch_truck_group = {}
        self.group_num = 1
        self.group_set = set()
        self.device_group = {}
        self.group_walk_to_excavator_cost = {}
        self.group_walk_to_dump_cost = {}
        self.group_park_to_excavator = {}

        self.group_opt_goto_dump_traffic_flow = {}
        self.group_opt_goto_excavator_traffic_flow = {}
        self.group_actual_goto_dump_traffic_flow = {}
        self.group_actual_goto_excavator_traffic_flow = {}

        self.group_excavator_uuid_to_index_dict = {}
        self.group_dump_uuid_to_index_dict = {}
        self.group_excavator_index_to_uuid_dict = {}
        self.group_dump_index_to_uuid_dict = {}

        self.group_excavator_exclude_modify = {}
        self.group_excavator_material_bind_modify = {}
        self.group_dump_material_bind_modify = {}