#Importing required modules
import math
import random
import matplotlib.pyplot as plt
import numpy as np

import Users
import tool
import GDOP
import time
import NSGA2 as ns
import TS as ts


#Function to find index of list
def index_of(a,list):
    for i in range(0,len(list)):
        if list[i] == a:
            return i
    return -1
#初始化无人机位置
def init(pop_size,k,users):
    min_pos=0
    max_pos=1000
    pos_solution=[]
    p_solution=[]
    for i in range(pop_size):
        uavs_pos=[[min_pos+(max_pos-min_pos)*random.random(),min_pos+(max_pos-min_pos)*random.random(),100] for i in range(k)]
        p_alloc=init_p(uavs_pos,users)
        pos_solution.append(uavs_pos)
        p_solution.append(p_alloc)
    # print(pos_solution)
    return pos_solution,p_solution

def init_p(uavs_pos,users):
    c_association=tool.get_c_association(users,uavs_pos,math.ceil(len(users)/len(uavs_pos)))
    uav_to_user=tool.get_uav_to_user(c_association,uavs_pos)
    # print(uav_to_user)
    p_association = tool.get_p_association(users, uavs_pos, c_association, len(users) * 2)
    p_rest=tool.get_rest_p(users,uavs_pos,p_association)
    # print(p_rest)
    p_alloc=[]
    for i in range(len(uavs_pos)):
        #平分功率
        # p=[random.randint(1,len(uav_to_user[i])) for i in range(len(uav_to_user[i]))]
        p_new=[0 for i in range(len(users))]
        for j in range(len(uav_to_user[i])):
            p_new[uav_to_user[i][j]]=1/len(uav_to_user[i])*p_rest[i]
            # p_new.append(p[j]/sum(p)*p_rest[i])
        p_alloc.append(p_new)
        # p_alloc.append(np.random.uniform(0, p_rest[i] / len(uav_to_user[i]), (len(uav_to_user[i]))))
    return p_alloc
def get_beta(crossover_param=2):
    u = random.random()
    if u <= 0.5:
        return (2 * u) ** (1 / (crossover_param + 1))
    return (2 * (1 - u)) ** (-1 / (crossover_param + 1))

def mutate(child,variables_range):
    u, delta = get_delta()
    child_new=[]
    if u < 0.5:
        for i in range(len(child)):
            pos=[]
            for j in range(len(child[i])):
                if j < len(child[i]) - 1:
                    x=child[i][j]+ delta * (child[i][j] - variables_range[0])
                    pos.append(x)
                else:
                    pos.append(100)
            child_new.append(pos)
    else:
        for i in range(len(child)):
            pos = []
            for j in range(len(child[i])):
                if j<len(child[i])-1:
                    x= child[i][j] +delta * (variables_range[1] - child[i][j])
                    pos.append(x)
                else:
                    pos.append(100)
            child_new.append(pos)
    for i in range(len(child_new)):
        for j in range(len(child_new[i])):
            if j<len(child_new[i])-1:
                if child_new[i][j] < variables_range[0]:
                    child_new[i][j] = variables_range[0]
                elif child_new[i][j] > variables_range[1]:
                    child_new[i][j] = variables_range[1]
    return child_new

def get_delta(mutation_param=5):
    u = random.random()
    if u < 0.5:
        return u, (2 * u) ** (1 / (mutation_param + 1)) - 1
    return u, 1 - (2 * (1 - u)) ** (1 / (mutation_param + 1))
def cross_over(pos_solution1,pos_solution2):
    child1=[]
    child2=[]
    for i in range(len(pos_solution1)):
        pos1 = []
        pos2=[]
        beta = get_beta()
        for j in range(len(pos_solution1[i])):
            if j<len(pos_solution1[i])-1:
                x1 = (pos_solution1[i][j] + pos_solution2[i][j]) / 2
                x2 = abs((pos_solution1[i][j] - pos_solution2[i][j]) / 2)
                x1=x1 + beta * x2
                x2=abs(x1 - beta * x2)
                pos1.append(x1)
                pos2.append(x2)
            else:
                pos1.append(100)
                pos2.append(100)
        child1.append(pos1)
        child2.append(pos2)
    u=random.random()
    if u>0.5:
        return child1
    else:
        return child2

def main(users,pop_size,max_gen,k=3):
    pos_solution,p_solution=init(pop_size,k,users)
    # print(p_solution)
    # max_gen = 100
    gen_no = 0
    pos_range=[0,1000]
    best_pos=[]
    best_p=[]
    f1_best=[]
    f2_best=[]
    function1_best=[]
    function2_best=[]
    solution_num=[]
    while(gen_no<max_gen):
        function1_values,function2_values,punish_values=ns.get_function_values(pop_size,pos_solution,p_solution,users)
        non_dominated_sorted_solution,rank = ns.fast_non_dominated_sort(function1_values[:], function2_values[:])
        print(non_dominated_sorted_solution)
        crowding_distance_values=[]
        for i in range(0,len(non_dominated_sorted_solution)):
            crowding_distance_values.append(ns.crowding_distance(function1_values[:],function2_values[:],non_dominated_sorted_solution[i][:]))
        pos_solution2 = pos_solution[:]
        p_solution2=p_solution[:]
        #排序要考虑惩罚项
        #交叉变异生成子代
        while (len(pos_solution2) != 2 * pop_size):
            #锦标赛选择
            parent1 = ns.tournament(pos_solution,non_dominated_sorted_solution,rank,crowding_distance_values)
            parent2 = parent1
            while parent1== parent2:
                parent2 = ns.tournament(pos_solution,non_dominated_sorted_solution,rank,crowding_distance_values)
            #交叉变异
            # child = ns.cross_over_old(parent1, parent2)
            # child_mute = ns.mutate_old(child, pos_range)
            # child = cross_over(parent1, parent2,)
            # child_mute = mutate(child, pos_range)
            child = ns.cross_over(parent1, parent2, gen_no, max_gen)
            child_mute = ns.mutate(child, pos_range, gen_no, max_gen)
            child_p=init_p(child_mute,users)
            pos_solution2.append(child_mute)
            p_solution2.append(child_p)

        function1_values2, function2_values2, punish_values2 = ns.get_function_values(2*pop_size, pos_solution2, p_solution2,users)
        non_dominated_sorted_solution2,rank2 = ns.fast_non_dominated_sort(function1_values2[:], function2_values2[:])
        crowding_distance_values2 = []
        for i in range(0, len(non_dominated_sorted_solution2)):
            crowding_distance_values2.append(
                ns.crowding_distance(function1_values2[:], function2_values2[:], non_dominated_sorted_solution2[i][:]))
        new_solution = []
        for i in range(0, len(non_dominated_sorted_solution2)):
            non_dominated_sorted_solution2_1 = [
                index_of(non_dominated_sorted_solution2[i][j], non_dominated_sorted_solution2[i]) for j in
                range(0, len(non_dominated_sorted_solution2[i]))]
            front22 = ns.sort_by_values(non_dominated_sorted_solution2_1[:], crowding_distance_values2[i][:])
            front = [non_dominated_sorted_solution2[i][front22[j]] for j in
                     range(0, len(non_dominated_sorted_solution2[i]))]
            front.reverse()
            for value in front:
                new_solution.append(value)
                if (len(new_solution) == pop_size):
                    break
            if (len(new_solution) == pop_size):
                break
        pos_solution = [pos_solution2[i] for i in new_solution]
        p_solution=[p_solution2[i] for i in new_solution]

        function1_best,function2_best,_=ns.get_function_values(len(pos_solution),pos_solution,
                                                                p_solution,users)

        best_pos,rank=ns.fast_non_dominated_sort(function1_best[:], function2_best[:])
        solution_num.append(len(best_pos[0]))

        if len(best_pos[0]) == 60:
            break

        # if len(best_pos[0])> 30:
        # for index in range(len(pos_solution)):
        #     pos_solution[index] = ts.tabu_search(pos_solution[index], users, 5, rank[index], len(best_pos),gen_no,max_gen)
        #     p_solution[index] = ns.init_p(pos_solution[index], users)
            # for r in range(1,len(best_pos)):#取所有支配解
            #     for index in best_pos[r]:
            #         pos_solution[index] = ts.tabu_search(pos_solution[index], users, 5, rank[index], len(best_pos))
            #         p_solution[index] = ns.init_p(pos_solution[index], users)
        if len(best_pos[0])< 30:
            for r in range(1, len(best_pos)):
                for index in best_pos[r]:
                    pos_solution[index] = ts.tabu_search(pos_solution[index], users, 1, len(best_pos[0]), 60)
                    p_solution[index] = ns.init_p(pos_solution[index], users)
            # for index in range(len(pos_solution)):
            #     pos_solution[index] = ts.tabu_search(pos_solution[index], users, 5, gen_no, max_gen)
            #     p_solution[index] = ns.init_p(pos_solution[index], users)

        gen_no+=1
    for r in range(len(best_pos)):
        for i in range(len(best_pos[r])):
            f1_best.append(function1_best[best_pos[0][i]])
            f2_best.append(function2_best[best_pos[0][i]])

    return f1_best,f2_best,solution_num




if __name__ == '__main__':
    users = Users.getUsers("./data.csv")
    start_time = time.time()
    f1,f2,solution_num=main(users,60,150,3)
    end_time = time.time()
    run_time = end_time - start_time
    print(f1, f2)
    print("程序运行时间为：", run_time)
    print(solution_num)
    plt.xlabel('average snr', fontsize=12)
    plt.ylabel('average -gdop', fontsize=12)
    # plt.xlim(70, 81)
    # plt.ylim(0,0.1)
    plt.scatter(f1, f2, )

    plt.show()

