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


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

from data.dispatchInfo import DispatchInfo
from bidict import bidict
from alg.algorithm import AlgorithmBase




class Group:
    """
    class for group instance.
    """
    def __init__(self, group_id, truck):
        """ Generate a group obj.
        :param group_id: (uuid) group_id
        """
        self.to_dump_congestion = None
        self.group_id = group_id
        self.group_mode = 1
        self.truck = truck

        # group devices
        self.excavator_dict = {}    # excavator_id -> unload_area_id
        self.dump_dict = {}    # dump_id -> load_area_id
        self.truck_set = set()    # truck_id

        # road network info.
        self.to_excavator_distance = None
        self.to_dump_distance = None
        self.park_to_excavator_distance = None

        # self.to_excavator_congestion = None
        # self.to_dump_congestion = None
        # self.park_to_excavator_congestion = None

        # device map
        self.truck_uuid_index_dict = bidict()
        self.excavator_uuid_index_dict = bidict()
        self.dump_uuid_index_dict = bidict()


    def update_group_mode(self):
        """
        update group mode.
        :param group_mode:
        :return:
        """
        # DispatchInfo.update_group_mode()
        self.group_mode = DispatchInfo.get_group_mode(self.group_id)

    def update_group_device(self):
        """
        update group devices.
        :return:
        """
        # update group devices
        # DispatchInfo.update_device_group_structure()
        self.excavator_dict = DispatchInfo.get_excavator_dict(self.group_id)
        self.dump_dict = DispatchInfo.get_dump_dict(self.group_id)
        self.truck_set = DispatchInfo.get_truck_set(self.group_id)

    def update_group_road_network(self):
        """
        update group road network.
        :return:
        """
        # update group road network
        # DispatchInfo.update_route_distance()
        self.to_excavator_distance = DispatchInfo.get_to_excavator_distance(self.group_id)
        self.to_dump_distance = DispatchInfo.get_to_dump_distance(self.group_id)
        self.park_to_excavator_distance = DispatchInfo.get_park_to_excavator_distance(self.group_id)

    def update_group_device_map(self):
        """
        update group device map.
        :return:
        """
        # update device map
        excavator_index = 0
        for i in self.excavator_dict.keys():
            self.excavator_uuid_index_dict[i] = excavator_index + 1

        dump_index = 0
        for i in self.dump_dict.keys():
            self.dump_uuid_index_dict[i] = dump_index + 1

        truck_index = 0
        for i in self.truck_set:
            self.truck_uuid_index_dict[i] = truck_index + 1

        self.truck_uuid_index_dict = bidict(self.truck_uuid_index_dict)
        self.excavator_uuid_index_dict = bidict(self.excavator_uuid_index_dict)
        self.dump_uuid_index_dict = bidict(self.dump_uuid_index_dict)

        # group_excavator_dict = {group_1: {excavator_1: load_area_1}, group_2: {excavator_2: load_area_2}}

    def group_dispatch(self, solver: object):
        """
        Receive a alg obj. and output dispatch plan for trucks in this group.
        :param solver:
        :return:
            dispatch plan: Dict({truck_id: match_id})
        """
        truck_dispatch = {}

        assert issubclass(solver, AlgorithmBase)

        s = solver(self)  # algorithm init

        # update truck task type
        for i in self.truck_set:
            truck_trip = self.truck.get_truck_current_trip(i)
            truck_task = self.truck.get_truck_current_task(i)
            if truck_task in [-2, 3, 4]:
                next_excavator_list = s.solve(i)
                min_index = next_excavator_list.index(min(next_excavator_list)) + 1
                next_excavator_id = self.excavator_uuid_index_dict.inverse[min_index]
                next_dump_id = truck_trip[-1]
                truck_dispatch[i] = [next_excavator_id, next_dump_id]

            if truck_task in [0, 1]:
                next_dump_list = s.solve(i)
                min_index = next_dump_list.index(min(next_dump_list)) + 1
                next_dump_id = self.dump_uuid_index_dict.inverse[min_index]
                next_excavator_id = truck_trip[-1]
                truck_dispatch[i] = [next_excavator_id, next_dump_id]

        # return dispatch plan
        return truck_dispatch




# from data.dispatchInfo import DispatchInfo
# from bidict import bidict
# from alg.algorithm import AlgorithmBase
#
#
# class Group_0:
#     """
#     class for group instance.
#     """
#     def __init__(self, group_id):
#         """ Generate a group obj.
#         :param group_id: (uuid) group_id
#         """
#
#         self.group_id = group_id
#
#         # group devices
#         self.excavator_dict = {}    # excavator_id -> unload_area_id
#         self.dump_dict = {}    # dump_id -> load_area_id
#         self.truck_set = set()    # truck_id
#
#         # road network info.
#         self.to_excavator_distance = None
#         self.to_dump_distance = None
#         self.park_to_excavator_distance = None
#
#         self.to_excavator_congestion = None
#         self.to_dump_congestion = None
#         self.park_to_excavator_congestion = None
#
#         # device map
#         self.truck_uuid_index_dict = bidict()
#         self.excavator_uuid_index_dict = bidict()
#         self.dump_uuid_index_dict = bidict()
#
#     def update_xx_(self):
#         """
#         update above parameters.
#         :return:
#         """
#         pass
#
#     def group_dispatch(self, solver):
#         """
#         Receive a alg obj. and output dispatch plan for trucks in this group.
#         :param solver:
#         :return:
#             dispatch plan: Dict({truck_id: match_id})
#         """
#         assert isinstance(solver, AlgorithmBase)
#         s = solver(self)    # algorithm init
#         return s.solve()    # algorithm solve
