import random
import numpy as np


class Encode:
    def __init__(self, Matrix, Pop_size, J, J_num, M_num):
        """
        :param Matrix: 机器加工时间矩阵
        :param Pop_size: 种群数量
        :param J: 各工件对应的工序数字典
        :param J_num: 工件数
        :param M_num: 机器数
        """
        self.Matrix = Matrix
        self.J = J
        self.J_num = J_num
        self.M_num = M_num
        self.CHS = []
        # 调整初始化比例：增加随机选择比例到50%
        self.GS_num = int(0.3 * Pop_size)  # 全局选择初始化
        self.LS_num = int(0.2 * Pop_size)  # 局部选择初始化
        self.RS_num = int(0.5 * Pop_size)  # 随机选择初始化（提高比例）
        self.Len_Chromo = 0
        for i in J.values():
            self.Len_Chromo += i  # 遍历字典J的所有值并求和，即工序数之和

    # 生成工序准备的部分（工件排列，天然满足工序顺序约束）
    def OS_List(self):
        OS_list = []
        for k, v in self.J.items():  # 遍历字典J的所有键值对，初始化工序矩阵
            OS_add = [k - 1 for j in range(v)]  # 工件索引从0开始
            OS_list.extend(OS_add)
        return OS_list

    # 生成初始化矩阵
    def CHS_Matrix(self, C_num):
        return np.zeros([C_num, self.Len_Chromo * 2], dtype=int)  # 工件排列+机器索引

    # 定位每个工件的每道工序的位置，Job第几个工件，Operation第几道工序
    def Site(self, Job, Operation):
        O_num = 0
        for i in range(len(self.J)):
            if i == Job:
                return O_num + Operation
            else:
                O_num = O_num + self.J[i + 1]
        return O_num

    # 全局初始化
    def Global_initial(self):
        CHS = self.CHS_Matrix(self.GS_num)
        OS_list = self.OS_List()
        for i in range(self.GS_num):
            random.shuffle(OS_list)
            OS = OS_list.copy()
            MS = [0] * self.Len_Chromo

            Machine_time = np.zeros(self.M_num, dtype=int)
            GJ_list = [i_1 for i_1 in range(self.J_num)]
            random.shuffle(GJ_list)

            for g in GJ_list:
                h = self.Matrix[g]
                for j in range(len(h)):
                    D = h[j]
                    List_Machine_weizhi = [k for k, val in enumerate(D) if val != 9999]
                    Machine_Select = [Machine_time[m] + D[m] for m in List_Machine_weizhi]
                    Min_time = min(Machine_Select)
                    K = Machine_Select.index(Min_time)
                    MS[self.Site(g, j)] = K
                    Machine_time[List_Machine_weizhi[K]] += D[List_Machine_weizhi[K]]

            CHS[i] = np.hstack((OS, MS))  # 工件排列 + 机器索引（紧凑编码）
        return CHS

    # 局部初始化
    def Local_initial(self):
        CHS = self.CHS_Matrix(self.LS_num)
        OS_list = self.OS_List()
        for i in range(self.LS_num):
            random.shuffle(OS_list)
            OS = OS_list.copy()
            MS = [0] * self.Len_Chromo

            GJ_List = [i_1 for i_1 in range(self.J_num)]
            for g in GJ_List:
                Machine_time = np.zeros(self.M_num, dtype=int)
                h = self.Matrix[g]
                for j in range(len(h)):
                    D = h[j]
                    List_Machine_weizhi = [k for k, val in enumerate(D) if val != 9999]
                    Machine_Select = [Machine_time[m] + D[m] for m in List_Machine_weizhi]
                    Min_time = min(Machine_Select)
                    K = Machine_Select.index(Min_time)
                    MS[self.Site(g, j)] = K
                    Machine_time[List_Machine_weizhi[K]] += D[List_Machine_weizhi[K]]

            CHS[i] = np.hstack((OS, MS))
        return CHS

    # 随机初始化（提高比例到50%）
    def Random_initial(self):
        CHS = self.CHS_Matrix(self.RS_num)
        OS_list = self.OS_List()
        for i in range(self.RS_num):
            random.shuffle(OS_list)
            OS = OS_list.copy()
            MS = [0] * self.Len_Chromo

            for g in range(self.J_num):
                h = self.Matrix[g]
                for j in range(len(h)):
                    D = h[j]
                    List_Machine_weizhi = [k for k, val in enumerate(D) if val != 9999]
                    # 随机选择可用机器
                    selected = random.choice(List_Machine_weizhi)
                    K = List_Machine_weizhi.index(selected)
                    MS[self.Site(g, j)] = K

            CHS[i] = np.hstack((OS, MS))
        return CHS