#!E:\Pycharm Projects\Waytous
# -*- coding: utf-8 -*-
# @Time : 2021/8/3 10:41
# @Author : Opfer
# @Site :
# @File : traffic_flow_info.py
# @Software: PyCharm

# import
from path_plan.path_plannner import *
from para_config import *
from equipment.excavator import ExcavatorInfo
from equipment.dump import DumpInfo
from equipment.truck import TruckInfo

truck = TruckInfo()
excavator = ExcavatorInfo()
dump = DumpInfo()

# 车流规划类
class Traffic_para(WalkManage):
    def __init__(self, num_of_load_area, num_of_unload_area, num_of_excavator, num_of_dump):
        self.num_of_dump = num_of_dump
        self.num_of_excavator = num_of_excavator
        self.num_of_load_area = num_of_load_area
        self.num_of_unload_area = num_of_unload_area

        self.walk_time_to_load_area = np.zeros((num_of_unload_area, num_of_load_area))  # 空载运输路线距离
        self.walk_time_to_unload_area = np.zeros((num_of_load_area, num_of_unload_area))  # 重载运输路线距离

        # self.avg_goto_excavator_weight = np.zeros((num_of_load_area, num_of_unload_area))
        self.avg_goto_excavator_weight = np.full((num_of_unload_area, num_of_load_area), 1)

        # self.avg_goto_dump_weight = np.zeros((num_of_load_area, num_of_unload_area))
        self.avg_goto_dump_weight = np.full((num_of_load_area, num_of_unload_area), 1)
        self.walk_time_to_excavator = np.zeros((num_of_dump, num_of_excavator))  # 逻辑空载运输路线距离
        self.walk_time_to_dump = np.zeros((num_of_excavator, num_of_dump))  # 逻辑重载运输路线距离

        # self.payload = 200  # 有效载重(不同型号矿卡载重不同，这里暂时认为车队是同质的)
        self.payload = np.mean(truck.get_payload())

        try:
            self.empty_speed = sum(truck.empty_speed.values()) / truck.get_truck_num()  # 空载矿卡平均时速
            self.heavy_speed = sum(truck.heavy_speed.values()) / truck.get_truck_num() # 重载矿卡平均时速
        except Exception as es:
            self.empty_speed = 25
            self.heavy_speed = 22
            logger.warning("矿卡速度设置为默认值")
            logger.warning(es)

        self.min_throughout = 1000  # 最小产量约束
        self.truck_total_num = 0

        self.excavator_strength = np.zeros(num_of_excavator)  # 用于保存电铲的工作强度,单位是t/h
        self.dump_strength = np.zeros(num_of_dump)  # 卸载点的工作强度，单位是t/h

        self.path_planner = PathPlanner()
        self.path_planner.walk_cost()

        self.excavator_priority_coefficient = np.ones(num_of_excavator)  # 每个电铲的优先级系数
        self.excavator_material_priority = np.ones(num_of_excavator) # 每个电铲的物料优先级系数
        self.grade_loading_array = np.zeros(num_of_excavator)  # 用于保存电铲挖掘矿石的品位
        self.dump_priority_coefficient = np.ones(num_of_dump)  # 每个卸载点的优先级系数
        self.dump_material_priority = np.ones(num_of_excavator)  # 每个卸载点的物料优先级系数
        # 卸载道路的运输系数：卸载道路上，每运输1吨货物需要一辆卡车运行时长,等于（该卸载道路上车辆平均运行时长/卡车平均实际装载量）
        self.goto_unload_area_factor = np.full((num_of_load_area, num_of_unload_area), 10, dtype=float)
        # 装载道路的运输系数，装载道路上，每提供1吨的装载能力需要一辆卡车运行时长,等于（该装载道路上车辆平均运行时长/卡车平均装载能力）
        self.goto_load_area_factor = np.full((num_of_unload_area, num_of_load_area), 10, dtype=float)
        self.goto_dump_factor = np.full((num_of_excavator, num_of_dump), 10, dtype=float) # 逻辑卸载道路的运输系数
        self.goto_excavator_factor = np.full((num_of_dump, num_of_excavator), 10, dtype=float)  # 逻辑装载道路的运输系数
        self.priority_coefficient_goto_dump = np.ones((num_of_excavator, num_of_dump))  # 卸载道路的优先级系数
        self.priority_coefficient_goto_excavator = np.ones((num_of_dump, num_of_excavator))  # 装载道路的优先级系数
        self.grade_lower_dump_array = np.zeros(num_of_dump)  # 卸载点矿石品位下限
        self.grade_upper_dump_array = np.zeros(num_of_dump)  # 卸载点矿石品位上限

        # 装/卸区的物料类型
        self.load_area_material_type = {}
        self.unload_area_material_type = {}

        self.excavator_target_mass = np.zeros(self.num_of_excavator)
        self.dump_target_mass = np.zeros(self.num_of_dump)


    def get_target_excavator_mass(self):
        return self.excavator_target_mass

    def get_target_dump_mass(self):
        return self.dump_target_mass
    # 设置卸载点信息
    def extract_dump_info(self):
        dynamic_dump_num = get_value("dynamic_dump_num")
        try:
            rule3 = session_mysql.query(DispatchRule).filter_by(id=3).first()
            if not rule3.disabled:
                for dump_index in range(dynamic_dump_num):
                    unload_area_id = unload_area_index_to_uuid_dict[self.dump_index_to_unload_area_index_dict[dump_index]]

                    unload_ability = session_postgre.query(DumpArea).filter_by(Id=unload_area_id).first().UnloadAbililty
                    self.dump_strength[dump_index] = unload_ability # 卸载设备最大卸载能力，单位吨/小时
                    self.dump_target_mass[dump_index] = 8*unload_ability
                    if unload_ability < 200:
                        raise Exception("卸载点卸载能力异常")
            else:
                self.dump_strength = np.full(self.num_of_dump, 5000)

            for dump_index in range(dynamic_dump_num):
                # self.dump_strength[dump_index] = 10000  # 卸载设备最大卸载能力，单位吨/小时
                self.grade_upper_dump_array[dump_index] = 100  # 卸点品位上限
                self.grade_lower_dump_array[dump_index] = 100  # 卸点品位下限
                self.dump_priority_coefficient[dump_index] = 1  # 卸载设备优先级

        except Exception as es:
            logger.error(es)
            logger.error("卸载点信息设置异常")

    # 设置挖机信息
    def extract_excavator_info(self):
        try:
            rule4 = session_mysql.query(DispatchRule).filter_by(id=4).first()
            if not rule4.disabled:
                for excavator_index in range(len(self.excavator_index_to_uuid_dict)):
                    load_ability = session_mysql.query(EquipmentSpec.mining_abililty).\
                        join(Equipment, Equipment.equipment_spec == EquipmentSpec.id).\
                        filter(Equipment.id == self.excavator_index_to_uuid_dict[excavator_index]).first()
                    self.excavator_strength[excavator_index] = load_ability.mining_abililty
                    self.excavator_target_mass[excavator_index] = 8 * load_ability.mining_abililty
                    if load_ability.mining_abililty < 200:
                        raise Exception("挖机装载能力异常")
            else:
                self.excavator_strength = np.full(self.num_of_excavator, 5000)
            for excavator_index in range(len(self.excavator_index_to_uuid_dict)):
                # self.excavator_strength[excavator_index] = 1000  # 挖机最大装载能力，单位吨/小时
                self.grade_loading_array[excavator_index] = 100  # 挖机装载物料品位
                self.excavator_priority_coefficient[excavator_index] = 1  # 挖机优先级

        except Exception as es:
            logger.error(es)
            logger.error("挖机信息设置异常")

    def extract_walk_time_info(self):
        try:
            # 车流规划部分矩阵格式与其余两个模块不同
            cost_to_load_area = self.path_planner.cost_to_load_area
            cost_to_unload_area = self.path_planner.cost_to_unload_area

            distance_to_load_area = self.path_planner.distance_to_load_area
            distance_to_unload_area = self.path_planner.distance_to_unload_area

            # 路网信息读取
            for unload_area_index in range(unload_area_num):
                for load_area_index in range(load_area_num):
                    self.goto_load_area_factor[unload_area_index][load_area_index] = \
                        (cost_to_load_area[unload_area_index][load_area_index] / (empty_speed * 1000)) / self.payload

                    self.goto_unload_area_factor[load_area_index][unload_area_index] = \
                        (cost_to_unload_area[unload_area_index][load_area_index] / (heavy_speed * 1000)) / self.payload

            logger.info("goto_unload_area_factor")
            logger.info(self.goto_unload_area_factor)
            logger.info("cost_to_unload_area")
            logger.info(cost_to_unload_area)
        except Exception as es:
            logger.error(es)
            logger.error("车流规划信息计算异常")


# 初始化车流规划类
def Traffic_para_init(num_of_load_area, num_of_unload_area, num_of_excavator, num_of_dump):

    # try:

    tra_para = Traffic_para(num_of_load_area, num_of_unload_area, num_of_excavator, num_of_dump)

    tra_para.period_map_para_load()

    tra_para.period_walk_para_load()

    tra_para.extract_excavator_info()

    tra_para.extract_dump_info()

    tra_para.extract_walk_time_info()

    truck.update_truck_payload()

    tra_para.payload = np.mean(truck.get_payload())

    # 全部矿卡设备集合
    truck_set = set(update_total_truck())

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

    # 动态派车矿卡集合
    tra_para.truck_total_num = len(truck_set.difference(fixed_truck_set))

    # 计算逻辑道路因子
    for i in range(num_of_excavator):
        for j in range(num_of_dump):
            # 查找挖机绑定的装载区, 卸载设备绑定的卸载区
            load_area_index = tra_para.excavator_index_to_load_area_index_dict[i]
            unload_area_index = tra_para.dump_index_to_unload_area_index_dict[j]

            # 逻辑道路因子赋值, 来自实际道路因子
            tra_para.goto_excavator_factor[j][i] = \
                tra_para.goto_load_area_factor[unload_area_index][load_area_index]

            tra_para.goto_dump_factor[i][j] = \
                tra_para.goto_unload_area_factor[load_area_index][unload_area_index]

    # print("cout", tra_para.priority_coefficient_goto_dump, tra_para.priority_coefficient_goto_excavator)

    # except Exception as es:
    #     logger.error(es)
    #     logger.error("车流规划类比初始化异常")
    return tra_para
