import numpy as np
import random
import math
import operator
import pickle
import time
import matplotlib.pyplot as plt
import power_ga
from matplotlib.patches import Circle
import progressbar
import csv
from ray import *
import GAfunction
#import local_opt

numbs = 0
UAV_R = 18  # UAV对UE的覆盖范围
UAV_CON_R = 64  # UAV与UAV的覆盖范围
UAV_SEC_R = 10
ROW = 100
COL = 100
#UE_TOTAL = 100
POP_SIZE = 200
UAV_R2 = UAV_R ** 2
UAV_CON_R2 = UAV_CON_R ** 2
UAV_SEC_R2 = UAV_SEC_R ** 2
glo_hight = 18
R_forest = 18
R_LOS = UAV_R
ue_space = []
uav_space = []
uav_power_upper = 4
power_aver_upper = 0.2
h = 200
r_th = 0 #dB
# ----------------------fspl
f = 1.4e3 #MHz
d0 = 1
c = 3e8
alpha = 3.5
pi = math.pi

X_SIZE = 100
def fspl(dist):
    # d单位是米
    if dist ==0:
        return 20*np.log10(4*pi*f*d0/c)
    else:
        return 20*np.log10(4*pi*f*d0/c)+10*alpha*math.log10(dist/d0)
A = 0.25
C = 0.39
E = 0.25
G = 0
H = 0.05
dep_tree = 2 # 植被深度
glo_pl_f = (20 * math.log10(2000000000)) + 20 * math.log10(4 * (math.pi) / 3 / 100000000)
def pl_slant(dist):
    theta = math.atan2(h,dist)
    return A*np.power(f,C)*np.power(dep_tree,E)*np.power(theta+G,H)

# 服务上限的矩阵
def connectionUavUe(us_p, uav_posi, numMax):
    numuav = len(uav_posi[0])
    numue = len(us_p[0])

    # distance matrix
    uelinked = np.zeros(numue)
    distUavUe = np.zeros([numue, numuav])
    for i in range(numue):
        for j in range(numuav):
            dist = math.sqrt((uav_posi[0][j] - us_p[0][i]) ** 2 + (uav_posi[1][j] - us_p[1][i]) ** 2)
            distUavUe[i][j] = dist if dist <= R_LOS else 200  # 这里假设200是个很大的距离
    # connection matrix
    # element: ue index
    linked = []
    for i in range(numuav):
        linked.append([])
    for i in range(numue):
        while (uelinked[i] == 0):  # 第i个用户没有连接无人机
            minDistIdx = np.argmin(distUavUe[i])  # 与用户i最近的无人机
            if distUavUe[i][minDistIdx] > R_LOS:
                break
            if (len(linked[minDistIdx]) < numMax):  # 建立连接
                linked[minDistIdx].append(i)
                uelinked[i] = 1
            else:
                distUavUe[i][minDistIdx] = 200

    return uelinked, linked
def calc_coverate(uav_list,ue_list,R=R_forest):
    uav_x, uav_y = [], []
    us_px, us_py = [], []
    for i in range(ue_list.__len__()):
        us_px.append(ue_list[i][0])
        us_py.append(ue_list[i][1])

    for i in range(uav_list.__len__()):
        uav_x.append(uav_list[i][0])
        uav_y.append(uav_list[i][1])

    uecovered = np.zeros(len(us_px))
    for i in range(len(us_px)):
        for j in range(len(uav_x)):
            dist = math.sqrt((uav_x[j] - us_px[i]) ** 2 + (uav_y[j] - us_py[i]) ** 2)
            if dist <= R:
                uecovered[i] = 1
    return len(uecovered.nonzero()[0]) / len(us_px)

def pathlossA2G(dist2,h):
    '''
    :param dist2: 基站在水平面的投影与用户的距离
    :param h:高度
    :return:空地倾斜路径损耗
    '''
    f = 1.4e9  # MHz
    d0 = 1
    c = 3e8
    alpha = 3.5
    pi = math.pi
    A = 0.25
    C = 0.39
    E = 0.25
    G = 0
    H = 0.05
    dep_tree = 2  # 植被深度
    dist3d = math.sqrt((dist2*100)**2 + h**2)
    fspl = 20 * np.log10(4 * pi * f * d0 / c) + 10 * alpha * math.log10(dist3d / d0)
    theta = math.atan2(h, dist2)
    slant =  A * np.power(f / math.pow(10, 6), C) * np.power(dep_tree, E) * np.power(theta + G, H)
    return fspl + slant

def calc_var_pl(uav_list,origin_ue_loc_list,power_scheme):

    uav_x,uav_y = [],[]
    us_px, us_py = [], []
    for i in range(origin_ue_loc_list.__len__()):
        us_px.append(origin_ue_loc_list[i][0])
        us_py.append(origin_ue_loc_list[i][1])
    us_p = us_px,us_py
    for i in range(uav_list.__len__()):
        uav_x.append(uav_list[i][0])
        uav_y.append(uav_list[i][1])
    uav_posi = uav_x,uav_y
    numuav, usernum = len(uav_x), len(us_px)

    uelinked,linked = connectionUavUe(us_p, uav_posi,numMax=100)
    # 吞吐量
    p_n = -115
        # 用户的吞吐量
    throughput = 0
    for i in range(usernum):

        for j in range(numuav):
            if i in linked[j]:
                dist = math.sqrt((uav_x[j] - us_px[i]) ** 2 + (uav_y[j] - us_py[i]) ** 2)
                snr = power_scheme[j][i] - pathlossA2G(dist, 200) - p_n
                throughput += math.log10(1 + np.power(10, snr / 10))

    return throughput

def calc_var_rsma_pl(uav_list,origin_ue_loc_list,power_scheme):

    uav_x,uav_y = [],[]
    us_px, us_py = [], []
    for i in range(origin_ue_loc_list.__len__()):
        us_px.append(origin_ue_loc_list[i][0])
        us_py.append(origin_ue_loc_list[i][1])
    us_p = us_px,us_py
    for i in range(uav_list.__len__()):
        uav_x.append(uav_list[i][0])
        uav_y.append(uav_list[i][1])
    uav_posi = uav_x,uav_y
    numuav, usernum = len(uav_x), len(us_px)

    uelinked,linked = connectionUavUe(us_p, uav_posi,numMax=100)

    # 吞吐量
    p_s = 40
    p_n = -115
        # 用户的吞吐量

    throughput = 0
    for i in range(usernum):

        for j in range(numuav):
            if i in linked[j]:
                dist = math.sqrt((uav_x[j] - us_px[i]) ** 2 + (uav_y[j] - us_py[i]) ** 2)
                ray = np.mean(get_rayleigh_gain())
                snr = power_scheme[j][i] - pathlossA2G(dist,200) - p_n - 10 * np.log10(ray)
                throughput += math.log10(1 + np.power(10,snr/10))


    return throughput
#

# 地面基站
def addGroundBS(us_1d, basenum):
    coveredplace = []
    density = GAfunction.user_density(us_1d, R_LOS)
    bs_x, bs_y = [], []
    for i in range(basenum):
        k = GAfunction.select_density_tournament(density)
        bs_x.append(int(k / X_SIZE))
        bs_y.append(k % X_SIZE)
        coveredplace.extend(GAfunction.base_coveredplace(int(k), R=R_LOS))
    bs = bs_x, bs_y

    return bs, coveredplace


class UE:
    def __init__(self):
        self.loc = [-1, -1]
        self.list_loc = []   # 所有部署UAV可覆盖该UE的位置


class UAV:
    def __init__(self):
        self.loc = [-1, -1]
        self.client_list = []
        self.los_sum = 0


class SOLUTIN:
    def __init__(self):
        self.mat = np.empty((ROW, COL))
        self.list = []
        self.fit = -1
        self.add = 0
        self.los_total = 0


# 计算两个坐标距离的平方
# input:     list_A=[x, y], list_B=[x, y]
def cal_distance2(list_A, list_B):
    return (list_A[0] - list_B[0]) ** 2 + (list_A[1] - list_B[1]) ** 2


# 生成UAV部署的matrix和坐标list
# input:     list of class:UE
# output:    matrix of UAV       list of class:UAV
def Create_UAV_matrix(space):
    cache_list = []
    cache_uav_list = []
    matrix_c = np.zeros((ROW, COL))
    for i in range(len(space)):
        loc_cache = random.choice(space[i].list_loc)
        if not loc_cache in cache_list:
            cache_uav = UAV()
            cache_uav.loc = loc_cache[:]
            cache_list.append(loc_cache)
            cache_uav_list.append(cache_uav)
            matrix_c[loc_cache[0], loc_cache[1]] = 1
    return matrix_c, cache_uav_list


# 进行POP_SIZE次生成初始化种群
# input:     list of class:UE      list of class:SOLUTION
# 直接完成修改
def Create_solution_space(space, solution_list):
    for i in range(POP_SIZE):
        cache_item = SOLUTIN()
        cache_item.mat, cache_item.list = Create_UAV_matrix(space)
        solution_list.append(cache_item)


# 检查并修复UAV联通性
# input:     mat of UAV      loc_list of UAV
# output:    mat of UAV      loc_list of UAV
def Check_UAV_connection(mat, list_U):
    tarmat = np.copy(mat)
    tarlist = []
    # 将数据重新整理为list形式，可无需重新后续部分，最后转换回来即可(缺点：client_list失效)
    for i in range(len(list_U)):
        tarlist.append(list_U[i].loc)
    queue = []
    checked_list = []
    while len(tarlist) > 0:
        uav = random.choice(tarlist)
        # 第一个被检查
        if len(checked_list) == 0:
            queue.append(uav)
            tarmat[uav[0], uav[1]] = 0
            tarlist.remove([uav[0], uav[1]])
        # 与之前网络无连接
        else:
            uav_old = random.choice(checked_list)
            # distance = math.sqrt((uav[0]-uav_old[0])**2 + (uav[1]-uav_old[1])**2)   #UAV联通是两个半径距离
            distance = math.sqrt(cal_distance2(uav, uav_old))
            num_add = math.ceil(distance / UAV_CON_R)

            # 可能存在个数不够的问题
            num_add += 1
            delta_x = int((uav[0] - uav_old[0]) / num_add)
            delta_y = int((uav[1] - uav_old[1]) / num_add)
            # 简单的直线均匀分段补充
            for i in range(num_add - 1):
                uav_new = [uav_old[0] + delta_x * (i + 1), uav_old[1] + delta_y * (i + 1)]
                # 随机新增的UAV部署点可能与checked_list或tarlist重叠(在两个UAV距离较远需要添加多个UAV时容易发生)
                # 与checked_list重叠，则删除其中的该项，防止出现列表中有两个相同项的情况
                # 与tarlist重叠，则无需进行处理
                if uav_new in checked_list:
                    # print("Find a same one in checked_list")
                    checked_list.remove(uav_new)
                if not uav_new in tarlist:
                    tarlist.append(uav_new)
                    tarmat[uav_new[0], uav_new[1]] = 1
                    mat[uav_new[0], uav_new[1]] = 1
            queue.append(uav)
            tarmat[uav[0], uav[1]] = 0
            tarlist.remove([uav[0], uav[1]])

        while len(queue) > 0:
            uav = queue.pop(0)
            checked_list.append(uav)
            if len(tarlist) == 0:
                while len(queue) > 0:
                    uav = queue.pop(0)
                    checked_list.append(uav)
                break

            index_del = []
            for i in range(len(tarlist)):
                r = cal_distance2(uav, tarlist[i])
                if r <= UAV_CON_R2:
                    index_del.append(tarlist[i])
                    queue.append(tarlist[i])
                    tarmat[tarlist[i][0], tarlist[i][1]] = 0
            for i in range(len(index_del)):
                tarlist.remove(index_del[i])
    new_space = []
    for i in range(len(checked_list)):
        new_uav = UAV()
        new_uav.loc = checked_list[i]
        new_space.append(new_uav)
    return mat, new_space


# 计算适应度
# input:     mat of UAV      loc_list of UAV
# output:    fitness_num
def Fit_func(mat, list_U):

    re = mat.sum()
    if int(re) == len(list_U):
        # return n - len(list_U)
        return 100 - len(list_U)
    else:
        return -1



# 计算适应度
# input:     space of class:SOLUTION
# output:    fitness_num
def cal_fit(space):
    for i in range(len(space)):
        fit_c = Fit_func(space[i].mat, space[i].list)
        space[i].fit = fit_c


# 根据适应度降序排列,add经过取反处理，增加数量越多add越小
def Sort_fitness(space):
    cmpfun = operator.attrgetter('fit', 'add')
    space.sort(key=cmpfun, reverse=True)


def RouletteWheelSelection(space):
    sum = 0
    for i in range(POP_SIZE):
        sum += space[i].fit
    pair1 = random.randint(1, sum - 1)
    pair2 = random.randint(0, sum - 1)
    while pair1 == pair2:
        pair2 = random.randint(0, sum - 1)
    i = 0
    while pair1 > 0:
        pair1 = pair1 - space[i].fit
        i += 1
    pair1 = i - 1
    j = 0
    while pair2 >= 0:
        pair2 = pair2 - space[j].fit
        j += 1
    pair2 = j - 1

    if pair1 == pair2:
        if pair1 > 0:
            pair1 -= 1
        else:
            pair2 -= 1
    return pair1, pair2


# 重写Rebuild_loc_list函数，尝试用np.where看是否有加速效果
def Rebuild_loc_list(solution_c):
    new_list = []
    cache_list = np.where(solution_c.mat > 0)
    for i in range(len(cache_list[0])):
        uav_cache = UAV()
        uav_cache.loc = [cache_list[0][i], cache_list[1][i]]
        new_list.append(uav_cache)
    solution_c.list = new_list


# 产生一对子代并加入子代解空间
# input:     space of class:SOLUTION     space for class:SOLUTION of children
def Rand_Exchange(space, children_space):
    pair1, pair2 = RouletteWheelSelection(space)
    c_row = random.randint(0, ROW - 1)
    c_col = random.randint(0, COL - 1)
    child1 = SOLUTIN()
    child2 = SOLUTIN()
    child1.mat = np.copy(space[pair2].mat)
    child2.mat = np.copy(space[pair1].mat)

    change_in = random.randint(1, 5)

    # 修改切片方式
    child1.mat[0:c_row, 0:c_col] = space[pair1].mat[0:c_row, 0:c_col]
    child1.mat[c_row:ROW, c_col:COL] = space[pair1].mat[c_row:ROW, c_col:COL]
    child2.mat[0:c_row, 0:c_col] = space[pair2].mat[0:c_row, 0:c_col]
    child2.mat[c_row:ROW, c_col:COL] = space[pair2].mat[c_row:ROW, c_col:COL]

    Rebuild_loc_list(child1)
    Rebuild_loc_list(child2)

    children_space.append(child1)
    children_space.append(child2)


# 产生整代的子代(已完成联通性检查)
# input:     space of class:SOLUTION     当前代数(仅用于显示)
# output:    space of class:SOLUTION of children
def Create_children(space):
    children_space = []
    size = math.ceil(POP_SIZE / 4)
    for i in range(size):
        Rand_Exchange(space, children_space)
    return children_space


# 安全距离检查并根据热点图随机删除一个(热点高的被删除概率小)
# input:     class:SOLUTION
# 直接完成修改
def Check_security_distance(c_solution, hot_map):
    list_cache = c_solution.list[:]

    while len(list_cache) > 0:
        loc_cache = list_cache.pop()
        for i in range(len(list_cache)):
            heat1 = hot_map[loc_cache.loc[0], loc_cache.loc[1]]
            heat2 = hot_map[list_cache[i].loc[0], list_cache[i].loc[1]]
            r = cal_distance2(loc_cache.loc, list_cache[i].loc)
            if r <= UAV_SEC_R2:
                n = random.randint(0, heat1 + heat2)
                # n > heat1 丢弃loc_cache 否则 丢弃被检查UAV
                if n <= heat1:
                    loc_cache2 = list_cache[i]
                    list_cache[i] = loc_cache
                    loc_cache = loc_cache2
                c_solution.mat[loc_cache.loc[0], loc_cache.loc[1]] = 0
                for j in range(len(c_solution.list)):
                    if c_solution.list[j].loc == loc_cache.loc:
                        del c_solution.list[j]
                        break
                break


# 清空class:SOLUTION中的client_list
def Clear_client_list(class_solution):
    class_solution.add = 0
    for i in range(len(class_solution.list)):
        class_solution.list[i].client_list = []


# UE全覆盖检查修复
# input: space of UE     class:SOLUTION
# 直接完成修改
def All_UE_check(space_ue, class_solution):
    Clear_client_list(class_solution)
    un_list = []
    for i in range(len(space_ue)):
        loc_cache = space_ue[i].loc
        j = len(class_solution.list) - 1
        while j >= 0:
            r = cal_distance2(loc_cache, class_solution.list[j].loc)
            if r <= UAV_R2:
                class_solution.list[j].client_list.append(loc_cache)
                break
            else:
                j = j - 1
        if j < 0:
            class_solution.add = class_solution.add - 1
            loc_cache = random.choice(space_ue[i].list_loc)
            new_uav = UAV()
            new_uav.loc = loc_cache
            new_uav.client_list.append(space_ue[i].loc)
            class_solution.list.append(new_uav)
            class_solution.mat[loc_cache[0], loc_cache[1]] = 1


def Generation2pic(fit_list):
    plt.rcParams['font.sans-serif'] = ['SimHei']  # 指定默认字体
    plt.rcParams['axes.unicode_minus'] = False  # 解决保存图像是负号'-'显示为方块的问题
    fig = plt.figure()
    plt.plot(fit_list, color='black', linewidth=2.0)

    plt.xlabel('遗传代数')
    plt.ylabel('适应度')

    plt.xlim(0, 100)
    plt.grid()

    plt.show()
    fig.savefig("gen.png", dpi=600)


# 生成热点图部分
# input:     R1(联通半径)
# output:    mat_pattern(由联通半径生成的矩阵)
def Create_Boundary_pattern(R1):
    R_pattern = R1 * 2 + 1
    mat_pattern = np.zeros((R_pattern, R_pattern))
    for i in range(R_pattern):
        for j in range(R_pattern):
            if ((i - R1) ** 2 + (j - R1) ** 2) <= R1 ** 2:
                mat_pattern[i, j] = 1
    return mat_pattern


# input:     R1(联通半径)    row_in(全局行数)      col_in(全局列数)
# output:    matlist(生成的矩阵)
def Create_Boundary_list(R1, row_in, col_in, row_x, col_y, patt):
    mat_pattern = patt
    j = row_x
    i = col_y

    mat_main = np.zeros((row_in, col_in))
    if i - R1 < 0:
        col_left = R1 - i
        m_col_left = 0
    else:
        col_left = 0
        m_col_left = i - R1
    if i + R1 >= col_in:
        col_right = R1 + col_in - i
        m_col_right = col_in
    else:
        col_right = 2 * R1 + 1
        m_col_right = i + R1 + 1
    if j - R1 < 0:
        row_up = R1 - j
        m_row_up = 0
    else:
        row_up = 0
        m_row_up = j - R1
    if j + R1 >= row_in:
        row_down = R1 + row_in - j
        m_row_down = row_in
    else:
        row_down = 2 * R1 + 1
        m_row_down = j + R1 + 1

    mat_main[m_row_up:m_row_down, m_col_left:m_col_right] = mat_pattern[row_up:row_down, col_left:col_right]

    return mat_main


def Create_hot_map(space_ue, c_pattern):
    map_mat = np.zeros((ROW, COL))
    for i in range(len(space_ue)):
        map_mat += Create_Boundary_list(UAV_R, ROW, COL, space_ue[i].loc[0], space_ue[i].loc[1], c_pattern)
    return map_mat


# UE全覆盖检查修复(矩阵方式，但无法构建UAV服务UE的列表)
# input: space of UE     class:SOLUTION
# 直接完成修改
def All_UE_check_mat(space_ue, class_solution, c_pattern):
    class_solution.add = 0
    map_mat = np.zeros((ROW, COL))
    for i in range(len(class_solution.list)):
        map_mat += Create_Boundary_list(UAV_R, ROW, COL, class_solution.list[i].loc[0], class_solution.list[i].loc[1],
                                        c_pattern)
    for i in range(len(space_ue)):
        loc_cache = space_ue[i].loc
        if map_mat[loc_cache[0], loc_cache[1]] > 0:
            continue
        else:
            class_solution.add = class_solution.add - 1
            loc_cache = random.choice(space_ue[i].list_loc)
            map_mat += Create_Boundary_list(UAV_R, ROW, COL, loc_cache[0], loc_cache[1], c_pattern)
            new_uav = UAV()
            new_uav.loc = loc_cache
            class_solution.list.append(new_uav)
            class_solution.mat[loc_cache[0]][loc_cache[1]] = 1


def UAV_Serve_state(space_ue, class_solution):
    for i in range(len(space_ue)):
        loc_cache = space_ue[i].loc
        uav_index = []
        radius_list = []
        for j in range(len(class_solution.list)):
            r = cal_distance2(loc_cache, class_solution.list[j].loc)
            if r <= UAV_R2:
                uav_index.append(j)
                radius_list.append(r)
        if len(radius_list) == 0:
            print(radius_list,uav_index,r)


        else:
            index = radius_list.index(min(radius_list))
            class_solution.list[uav_index[index]].client_list.append(loc_cache)


def Save_result(class_solution,file_name):
    #file_name = 'uav_save.pickle'
    with open(file_name, "wb") as fp:
        pickle.dump(class_solution, fp, protocol=pickle.HIGHEST_PROTOCOL)


# solution_list转为csv
def Solution2csv(space_solution, file_name_csv):
    csv_name = file_name_csv
    csv_file = open(csv_name, 'w', newline='')
    writer = csv.writer(csv_file)
    in_data = [['x', 'y', 'number of UE']]
    for i in range(len(space_solution)):
        in_data = [['x', 'y', 'number of UE', 'fit', space_solution[i].fit, 'add', space_solution[i].add]]
        for j in range(len(space_solution[i].list)):
            c_l = [space_solution[i].list[j].loc[0], space_solution[i].list[j].loc[1],
                   len(space_solution[i].list[j].client_list)]
            in_data.append(c_l)
        in_data.append([])
        writer.writerows(in_data)
    csv_file.close()


def Cal_distance_3d(uav_loc, ue_loc, hight2):
    distance = math.sqrt(cal_distance2(uav_loc, ue_loc) + hight2)
    return distance


def cal_fspl(class_solution, pl_f):
    los_total = 0
    hight2 = glo_hight ** 2
    for i in range(len(class_solution.list)):
        uav_loc = class_solution.list[i].loc
        los_sum = 0
        for j in range(len(class_solution.list[i].client_list)):
            distance = Cal_distance_3d(uav_loc, class_solution.list[i].client_list[j], hight2)
            los = 20 * math.log10(distance / 10) + pl_f
            los_sum += los
        class_solution.list[i].los_sum = los_sum
        los_total += class_solution.list[i].los_sum
    class_solution.los_total = los_total


# solution_list转为csv
def Solution2csv_los(space_solution, file_name_csv, ue_num):
    csv_name = file_name_csv
    csv_file = open(csv_name, 'w', newline='')
    writer = csv.writer(csv_file)
    for i in range(len(space_solution)):
        in_data = [['x', 'y', 'number of UE', 'los_ave', 'fit', space_solution[i].fit, 'add', space_solution[i].add,
                    'los_total_ave', space_solution[i].los_total / ue_num]]
        for j in range(len(space_solution[i].list)):
            client_num = len(space_solution[i].list[j].client_list)
            c_l = [space_solution[i].list[j].loc[0], space_solution[i].list[j].loc[1], client_num,
                   (space_solution[i].list[j].los_sum) / client_num]
            in_data.append(c_l)
        in_data.append([])
        writer.writerows(in_data)
    csv_file.close()


# 将fit转换为UAV架数，将add重新归正
def Change_fit_UAV_num(class_solution):
    class_solution.fit = len(class_solution.list)
    class_solution.add = -class_solution.add


# 根据适应度降序排列
def Sort_fitness_los(space):
    cmpfun = operator.attrgetter('fit', 'add', 'los_total')
    space.sort(key=cmpfun)
    # space.sort(key = operator.attrgetter('add'), reverse=False)


def generation2csv(list_record):
    csv_name = "generation_record.csv"
    csv_file = open(csv_name, 'w', newline='')
    writer = csv.writer(csv_file)
    n_list = []
    n_list.append(["fit"])
    for i in range(len(list_record)):
        part = []
        part.append(list_record[i])
        n_list.append(part)
    writer.writerows(n_list)
    csv_file.close()


def Solve_process(ue_space, glo_pattern,numuav):
    widgets = ["task-schedule: ", progressbar.Percentage(), " ", progressbar.Bar(), " ", progressbar.Timer(), '   ',
               progressbar.ETA()]

    record_list = []  # 用于记录收敛状况
    solution_space = []  # 存放解空间

    print("Start create initial space...")
    # 生成热点图
    glo_hot_map = Create_hot_map(ue_space, glo_pattern)
    # 生成初始化种群
    Create_solution_space(ue_space, solution_space)
    print("Init finished.")

    # 修改为先检查安全距离，再检查联通性
    # 检查UAV联通性并作出修正 + 检查安全距离和全覆盖情况 + 计算每组适应度
    for i in range(len(solution_space)):
        # 检查安全距离
        Check_security_distance(solution_space[i], glo_hot_map)
        # 检查UAV联通性并作出修正
        solution_space[i].mat, solution_space[i].list = Check_UAV_connection(solution_space[i].mat,
                                                                             solution_space[i].list)
        # 检查全覆盖
        All_UE_check_mat(ue_space, solution_space[i], glo_pattern)
    # 计算适应度
    cal_fit(solution_space)

    # 排序
    Sort_fitness(solution_space)

    record_list.append(solution_space[0].fit)

    num_gen = 100

    #pbar = progressbar.ProgressBar(maxval=num_gen, widgets=widgets).start()
    # 进化的轮次
    for n in range(num_gen):
        if 100-solution_space[0].fit <= numuav:break
        #print(100-solution_space[0].fit,numuav)
        #pbar.update(n + 1)

        children_space = Create_children(solution_space)
        # 检查安全距离和全覆盖（联通性检查在生成子代时已经完成）
        for i in range(len(children_space)):
            children_space[i].mat, children_space[i].list = Check_UAV_connection(children_space[i].mat,
                                                                                 children_space[i].list)
            Check_security_distance(children_space[i], glo_hot_map)
            All_UE_check_mat(ue_space, children_space[i], glo_pattern)

        cal_fit(children_space)
        solution_space.extend(children_space)

        Sort_fitness(solution_space)
        solution_space = solution_space[:POP_SIZE]
        record_list.append(solution_space[0].fit)

    for i in range(len(solution_space)):
        UAV_Serve_state(ue_space, solution_space[i])

    #pbar.finish()

    return solution_space, record_list


def Los_fitness(solution_space):
    pl_f = (20 * math.log10(2000000000)) + 20 * math.log10(4 * (math.pi) / 3 / 100000000)
    for i in range(len(solution_space)):
        cal_fspl(solution_space[i], pl_f)
        Change_fit_UAV_num(solution_space[i])

    Sort_fitness_los(solution_space)


def Save_process(solution_space, record_list):
    # 适应度收敛曲线
    #Generation2pic(record_list)
    print("Start to save result...")
    # 保存部署结果(opt将直接读取该结果进行)
    Save_result(solution_space)
    # 保存部署结果为csv文件
    Solution2csv_los(solution_space, "uav_save.csv", UE_TOTAL)
    # 保存适应度值变化至csv文件
    #generation2csv(record_list)
    print("Save finished.")


def main(file,numuav):
    glo_pattern = Create_Boundary_pattern(UAV_R)
    file_name = file + ".pickle"
    # 从文件中读取ue_space
    #file_name = 'ue_save.pickle'
    with open(file_name, 'rb') as fp:
        ue_space = pickle.load(fp)

    # GA-process
    starttime = time.time()

    ue_list = []
    for i in range(len(ue_space)):
        ue_list.append(ue_space[i].loc)
    us_px, us_py = [], []
    for i in range(ue_list.__len__()):
        us_px.append(ue_list[i][0])
        us_py.append(ue_list[i][1])
    us_p = us_px, us_py
    us_1d = GAfunction.us1d(us_p)
    bs, coveredplace = addGroundBS(us_1d, numbs)

    #plt.figure()
    #plt.scatter(us_p[0], us_p[1], color='b', marker='x', s=40)

    delnum = 0
    ttmp = []
    for i in range(len(us_px)):
        # 保持这个序号
        for j in range(numbs):
            dist = math.sqrt((us_px[i] - bs[0][j]) ** 2 + (us_py[i] - bs[1][j]) ** 2)
            if dist <= R_LOS:
                ttmp.append(ue_list[i - delnum])
                del ue_list[i - delnum]
                delnum += 1
    for i in range(len(ttmp)):
        plt.scatter(ttmp[i][0], ttmp[i][1], color='yellow', marker='x', s=40)


    solution_space, record_list = Solve_process(ue_space, glo_pattern,numuav)
    for i in range(len(solution_space)):
        solution_space[i].list = solution_space[i].list[0:numuav]

    # 调整功率分配
    final_solution = solution_space[0]
    #uavnum = len(len(final_solution.list))
    uav_space = []
    for i in range(numuav):
        uav_space.append(final_solution.list[i].loc)
    UE_list, BS_list = listtrans(uav_space, ue_list)
    print('调整功率',len(uav_space))
    solution_space, record_list = power_ga.Solve_process(UE_list, BS_list)

    #print(record_list)
    power_scheme = solution_space[0].mat
    #print(power_scheme)
    throughput = record_list[-1]#solution_space[0].fit
    endtime = time.time()
    dtime = endtime - starttime
    """rate = []
    for i in range(len(record_list)):
        tmp = [i, record_list[i]]
        rate.append(tmp)
    csv_name = 'ga_joint_solution_March.csv'
    csv_file = open(csv_name, 'w', newline='')
    writer = csv.writer(csv_file)
    writer.writerows(rate)
    csv_file.close()

    coverate = calc_coverate(uav_space,ue_list,R_forest)
    #print(power_scheme)
    
    # file_store = file + "uavspace.pickle"
    # Save_result(solution_space,file_name=file_store)
    x = np.arange(len(record_list))
    plt.figure()
    plt.plot(x,record_list)
    plt.show()"""
    """
    for i in range(len(uav_space)):
        plt.scatter(uav_space[i][0], uav_space[i][1], color='k', marker='v', s=40)
    uav_x = []
    uav_y = []
    for i in range(len(uav_space)):
        uav_x.append(uav_space[i][0])
        uav_y.append(uav_space[i][1])
    for i in range(numbs):
        uav_x.append(bs[0][i])
        uav_y.append(bs[1][i])
    uav_posi = uav_x,uav_y

    print(uav_posi)
    DrawFunction.draw_uav_update(uav_posi, 'k', 1)
    plt.scatter(bs[0], bs[1], color='red', marker='v', s=40)
    plt.show()
    #print("程序运行时间(包含初始化)为：%.8s s" % dtime)  # 时间显示到微秒

    # 计算路径损耗
    #Los_fitness(solution_space)
    # 保存部署结果
    #Save_process(solution_space, record_list)
    #print("Save finished.")

    # 局部微调
    #print("Start to opt...")
    #local_opt.main()"""
    return numuav, dtime,  throughput

def listtrans(solve_list,ue_list):
    UE_list = []
    for i in range(len(ue_list)):
        ue = UE()
        ue.loc = [ue_list[i][0], ue_list[i][1], 0]
        ue.snr = dB2powerratio(2)
        ue.snrth = dB2powerratio(-5)
        UE_list.append(ue)
    BS_list = []
    for j in range(len(solve_list)):
        bs = UAV()
        bs.loc = [solve_list[j][0],solve_list[j][1],200]
        bs.power_aver = 0.1

        bs.power_upper = uav_power_upper
        bs.power_aver_upper = power_aver_upper
        BS_list.append(bs)
    return UE_list,BS_list

# pl(dB) = 10*log(pr/pt)
def dB2powerratio(dB):
    return np.power(10,dB/10)
def dBm2w(dBm):
    return 0.001*np.power(10,dBm/10)

if __name__ == '__main__':
    addr = r"D:\pycharm\deploy_algorithms\data\list_ue100_1"
    result = main(addr,7)
    print(result)