def mutate_number_of_superchargers_remove_distance(solutions, init_parameters):
    new_solutions = copy.deepcopy(solutions)
    index_list = [0, 0]
    print('usuwanie ladowarki dystans set')
    for solution in new_solutions:
        print(solution)

    for solution in new_solutions:
        if len(solution) > 3:
            max_distance = 0
            for i in range(len(solution) - 2):
                if i == 0:  # od pkt startowego do pierwszej ladowarki
                    distance = calculate_distance(init_parameters[0], [
                        stations_coords[solution[i + 1][1]]['lat'],
                        stations_coords[solution[i + 1][1]]['lng']
                    ])[0]

                elif i == len(solution
                              ) - 3:  # od ostatniej ladowarki do pkt koncowego
                    distance = calculate_distance(init_parameters[1], [
                        stations_coords[solution[i - 2][1]]['lat'],
                        stations_coords[solution[i - 2][1]]['lng']
                    ])[0]

                elif i > 0 and i < len(
                        solution) - 4:  # od ladowarki do ladowarki
                    # print("pierwsza ladowarka ", stations_id[solution[i-1][1]])
                    # print("druga ladowarka ", stations_id[solution[i][1]])
                    # print('blad',stations_distances['matrix'][stations_id[solution[i - 1][1]]][stations_id[solution[i][1]]])
                    if stations_distances['matrix'][stations_id[solution[
                            i - 1][1]]][stations_id[solution[i + 1][1]]] == -1:
                        distance = stations_distances['matrix'][stations_id[
                            solution[i + 1][1]]][stations_id[solution[i -
                                                                      1][1]]]
                    else:
                        distance = stations_distances['matrix'][stations_id[
                            solution[i - 1][1]]][stations_id[solution[i +
                                                                      1][1]]]
                if distance < max_distance:
                    max_distance = distance
                    index = i
                    index_list[1] = index_list[0]
                    index_list[0] = index

            index = random.randint(0, 1)
            print('sol', solution[index_list[index]])
            solution.remove(solution[index_list[index]])
        # calkowity czas i kary sie gdzies indziej potem zmieniaja czy to trzeba tutaj jeszcze uwzglednic?
        # nie trzeba, to i tak jest usuwane do rysowania

    print('usuwanie ladowarki dystans wynik')
    for solution in new_solutions:
        print(solution)
    return new_solutions
def display(best_solution, init_parameters, iteration):
    map_style = 'streets-v9'
    with open("tools/parameters.json") as f:
        parameters = json.load(f)

    if 'penalty_multiplier' in parameters['config1'].keys():
        penalty_multiplier = parameters['config1']['penalty_multiplier']
    else:
        penalty_multiplier = parameters['default']['penalty_multiplier']

    print('BEST SOLUTION : ', best_solution)
    icons = create_path(best_solution, init_parameters)
    #icons = test_line(generation, init_parameters)
    print("ICONS :", icons)

    map = StaticStyle(
        access_token=
        'pk.eyJ1IjoiYW5kcmV3MTAxMSIsImEiOiJjamprcDVnOWE0YjBsM2t0ZThqa3Nvb3JsIn0.SKdRIieUwaw7Fbhke3jVMw'
    )

    response = map.image(username='******',
                         style_id=map_style,
                         features=icons,
                         width=1279,
                         height=700)

    string = 'Iteration: ' + str(iteration) + '\n' + str('Superchargers \n')
    for i in range(len(best_solution) - 3):
        segment_str = str(i + 1) + ': ' + str(
            best_solution[i][1]) + '\n' + 'Speed: ' + str(
                best_solution[i][0]) + ' km/h, charge: ' + str(
                    best_solution[i][2]) + ' minutes'
        string += segment_str + '\n'
    string += 'Destination: speed: ' + str(
        best_solution[len(best_solution) - 3][0]) + ' km/h \n' + 'Total time :'
    time_hours = best_solution[len(best_solution) - 2] / 60
    time_minutes = best_solution[len(best_solution) - 2] % 60
    string += str(
        int(time_hours)) + ' hours,' + str(time_minutes) + ' minutes \n'
    str_time = str(best_solution[len(best_solution) - 2]) + ' | '
    k = best_solution[len(best_solution) - 2]
    for x in best_solution[len(best_solution) - 1]:
        if x > 0:
            k += penalty_multiplier * x
    str_function = str(int(k)) + ' | '

    string += 'Distance: ' + str(
        calculate_distance(init_parameters[0], init_parameters[1])[0] /
        1000) + ' km \n'
    energy = best_solution[len(best_solution) - 1]
    en = []
    print(energy)
    for x in range(len(energy)):
        print(energy[x] * (-1))
        en.append(energy[x] * (-1))
    string_energy = str(en[::-1])
    print('energia', string_energy)

    return [response.content, string, string_energy, str_time, str_function]
def generatePoints2(start_coords, end_coords, number_of_stations,
                    starting_soc):
    path = calculate_distance(start_coords, end_coords, 90)[1]
    if number_of_stations > 0:
        print('path', len(path))
        print('il stacji', number_of_stations)
        print('skok', int((len(path) / (number_of_stations + 1))))
        path = path[0:len(path):int((len(path) / (number_of_stations + 1)))]
    elif number_of_stations == 0:
        path = path[0] + path[len(path) - 1]

    if starting_soc > 70:
        path = path[1:len(path) - 1]
    else:
        path = path[0:len(path) - 1]

    for p in range(len(path)):
        path[p] = [path[p][0], path[p][1]]
    return path
def evaluate(solutions, init_parameters, add_penalties=False, display=False):
    with open('tools/stations_coords.json') as f:
        stations = json.load(f)

    with open('tools/stations_id.json') as ff:
        stations_id = json.load(ff)

    battery_capacity = 85  # pojemnosc baterii -> 85 kWh
    with open('tools/stations_distances_matrix.json') as f:
        stations_distances = json.load(f)

    with open("tools/parameters.json") as f:
        parameters = json.load(f)

    if 'penalty_multiplier' in parameters['config1'].keys():
        penalty_multiplier = parameters['config1']['penalty_multiplier']
    else:
        penalty_multiplier = parameters['default']['penalty_multiplier']

    penalty = []
    new_solutions = []
    if add_penalties == False:
        for solution in solutions:
            new_solutions.append(copy.deepcopy(solution[0:len(solution) - 2]))
    else:
        new_solutions = copy.deepcopy(solutions)

    for solution in new_solutions:

        starting_SOC = init_parameters[2]
        # trzeba ogarnac jak wczytuje ta zmienna, czy jak argument funkcji evaluate czy inaczej
        evaluation = 0
        previous_section = [0, 0, 0]
        segment_penalty = []
        # print("dlugosc", len(solution))
        for i in range(0, len(solution)):
            # print("i ", i)
            # print(solution[i][1])
            # print("starting soc", starting_SOC)
            if starting_SOC < 0:
                starting_SOC = 0
            elif starting_SOC > 99:
                starting_SOC = 99
            start_SOC_and_charged_SOC = soc_time(starting_SOC,
                                                 previous_section[2])
            #print(starting_SOC)
            if i == 0 and len(
                    solution) != 1:  # od pkt startowego do pierwszej ladowarki
                distance = calculate_distance(init_parameters[0], [
                    stations[solution[i][1]]['lat'],
                    stations[solution[i][1]]['lng']
                ])[0]

            elif i == 0 and len(
                    solution
            ) == 1:  # od pkt startowego do koncowego bez ladowania
                distance = calculate_distance(init_parameters[0],
                                              init_parameters[1])[0]

            elif i == len(solution) - 1 and len(
                    solution) > 1:  # od ostatniej ladowarki do pkt koncowego
                distance = calculate_distance(init_parameters[1], [
                    stations[solution[i - 1][1]]['lat'],
                    stations[solution[i - 1][1]]['lng']
                ])[0]

            else:  # od ladowarki do ladowarki
                # print("pierwsza ladowarka ", stations_id[solution[i-1][1]])
                # print("druga ladowarka ", stations_id[solution[i][1]])
                # print('blad',stations_distances['matrix'][stations_id[solution[i - 1][1]]][stations_id[solution[i][1]]])
                if stations_distances['matrix'][stations_id[solution[
                        i - 1][1]]][stations_id[solution[i][1]]] == -1:
                    distance = stations_distances['matrix'][stations_id[
                        solution[i][1]]][stations_id[solution[i - 1][1]]]
                else:
                    distance = stations_distances['matrix'][stations_id[
                        solution[i - 1][1]]][stations_id[solution[i][1]]]

            # print("distance", distance)
            used_SOC = cons_speed(
                solution[i][0]
            ) * distance / 1000 / battery_capacity * 100  # return percentage
            starting_SOC = float("{0:.2f}".format(start_SOC_and_charged_SOC -
                                                  used_SOC))

            # print("used soc", used_SOC)
            # print("charged soc", start_SOC_and_charged_SOC)
            if starting_SOC < 0:
                penalty = (-1) * starting_SOC
                penalty1 = (-1) * starting_SOC
                # gdy zuzyje wiecej energi na tym odcinku niz mial dostepne
            elif starting_SOC >= 0:
                penalty1 = 0
                penalty = (-1) * starting_SOC
            segment_penalty.append(penalty)

            if display == False:
                evaluation = int(evaluation + solution[i][2] +
                                 (distance / 1000 * 60 / solution[i][0]) +
                                 (penalty1 * penalty_multiplier))
            elif display == True:
                evaluation = int(evaluation + solution[i][2] +
                                 (distance / 1000 * 60 / solution[i][0]))

            previous_section = solution[i]
        solution.append(evaluation)
        if add_penalties == True:
            solution.append(segment_penalty)
    return new_solutions
def initialise(coords):
    with open("tools/parameters.json") as f:
        parameters = json.load(f)

    if 'generation_size' in parameters['config1'].keys():
        generation_size = parameters['config1']['generation_size']
    else:
        generation_size = parameters['default']['generation_size']

    start_coords = coords[0]
    end_coords = coords[1]
    solution = []
    solutions = []
    max_range = 350  # range in km
    # TODO
    # ogarnac przlicznik minut katawych (wspolrzedne) na km
    min_speed = 60
    max_speed = 100
    average_speed = 70
    max_charging_time = 50
    # number_of_stations = math.ceil(radius(start_coords[0], start_coords[1], end_coords[0], end_coords[1]) / max_range)
    number_of_stations = math.ceil(
        (calculate_distance(start_coords, end_coords)[0]) / 1000 / max_range)
    print('DISTANCE = ',
          calculate_distance(start_coords, end_coords)[0] / 1000)

    # zmienic zeby nie losowalo tych samych ladowarek, np lista uzytych ladowek ktore beda usuwane z available_stations
    # Glowna petla
    for j in range(generation_size):
        solution = []
        # tworzymy np. 50 rozw z czego jaksa ilosc jest tworzona dla n ladowarek
        number_of_stations_temp = 0
        number_of_stations_temp = number_of_stations + random.randint(
            0, math.ceil(number_of_stations / 5))
        center_points = generatePoints2(start_coords, end_coords,
                                        number_of_stations_temp, coords[2])
        used_stations = []
        if number_of_stations_temp > 0:
            for i in range(len(center_points)):
                available_stations = findStations(center_points[i][0],
                                                  center_points[i][1],
                                                  end_coords[0], end_coords[1])

                # when circles with available stations overlap
                for station in used_stations:
                    available_stations.pop(station, None)

                if len(list(available_stations)) != 0:

                    drawn_station = random.choice(list(available_stations))
                    available_stations.pop(drawn_station, None)
                    solution.append([
                        random.randint(min_speed, max_speed), drawn_station,
                        random.randint(10, max_charging_time)
                    ])
                    used_stations.append(drawn_station)
                elif len(list(available_stations)) == 0:
                    print('no available stations')

        solution.append([random.randint(min_speed, max_speed), end_coords, 0])

        solutions.append(solution)

    return solutions
def mutate_supercharger_distance_too_close(solutions, init_parameters):
    new_solutions = copy.deepcopy(solutions)
    index_list = [0, 0]
    print('ladowarki za bisko dystans set')
    for solution in new_solutions:
        print(solution)

    for solution in new_solutions:
        if len(solution) > 3:
            max_distance = 0
            for i in range(len(solution) - 2):
                if i == 0:  # od pkt startowego do pierwszej ladowarki
                    distance = calculate_distance(init_parameters[0], [
                        stations_coords[solution[i][1]]['lat'],
                        stations_coords[solution[i][1]]['lng']
                    ])[0]
                    print('start-ladow')

                elif i == len(solution
                              ) - 3:  # od ostatniej ladowarki do pkt koncowego
                    distance = calculate_distance(init_parameters[1], [
                        stations_coords[solution[i - 1][1]]['lat'],
                        stations_coords[solution[i - 1][1]]['lng']
                    ])[0]
                    print('ladow-koniec')

                elif i > 0 and i < len(
                        solution) - 3:  # od ladowarki do ladowarki
                    # print("pierwsza ladowarka ", stations_id[solution[i-1][1]])
                    # print("druga ladowarka ", stations_id[solution[i][1]])
                    # print('blad',stations_distances['matrix'][stations_id[solution[i - 1][1]]][stations_id[solution[i][1]]])
                    print('ladow-ladow')
                    if stations_distances['matrix'][stations_id[solution[
                            i - 1][1]]][stations_id[solution[i][1]]] == -1:
                        distance = stations_distances['matrix'][stations_id[
                            solution[i][1]]][stations_id[solution[i - 1][1]]]
                    else:
                        distance = stations_distances['matrix'][stations_id[
                            solution[i - 1][1]]][stations_id[solution[i][1]]]
                if distance < max_distance:
                    max_distance = distance
                    index = i
                    index_list[1] = index_list[0]
                    index_list[0] = index

            index = random.randint(0, 1)
            index = index_list[index]
            print('index', index)
            print('sol', solution[index])
            # DISTANCE BEETWEN START AND FIRST SUPERCHARGER
            if index == 0:
                center = [(init_parameters[0][0] +
                           stations_coords[solution[index + 1][1]]["lat"]) / 2,
                          (init_parameters[0][1] +
                           stations_coords[solution[index + 1][1]]["lng"]) / 2]
                print('0')
            # DISTANCE BEETWEN LAST SUPERCHARGER AND END
            elif index == len(solution) - 3:
                center = [(stations_coords[solution[index - 2][1]]["lat"] +
                           init_parameters[1][0]) / 2,
                          (stations_coords[solution[index - 2][1]]["lng"] +
                           init_parameters[1][1]) / 2]
                print('1')
            elif index == len(solution) - 4:
                center = [(stations_coords[solution[index - 1][1]]["lat"] +
                           init_parameters[1][0]) / 2,
                          (stations_coords[solution[index - 1][1]]["lng"] +
                           init_parameters[1][1]) / 2]
                print('1 ostatnia ladow')
            # DISTANCE BEETWEN 2 SUPERCHARGERS
            else:
                center = [(stations_coords[solution[index + 1][1]]["lat"] +
                           stations_coords[solution[index - 1][1]]["lat"]) / 2,
                          (stations_coords[solution[index + 1][1]]["lng"] +
                           stations_coords[solution[index - 1][1]]["lng"]) / 2]
                print('2')

            available_stations = findStations(center[0], center[1],
                                              init_parameters[1][0],
                                              init_parameters[1][1], radius)

            if len(available_stations) != 0:
                for i in range(len(solution) - 4):
                    available_stations.pop(solution[i][1], None)
                if len(available_stations) != 0:
                    drawn_station = random.choice(list(available_stations))

                    solution[index] = [100, drawn_station, 40]
        # calkowity czas i kary sie gdzies indziej potem zmieniaja czy to trzeba tutaj jeszcze uwzglednic?
        # nie trzeba, to i tak jest usuwane do rysowania

    print('ladowarki za blisko dystans wynik')
    for solution in new_solutions:
        print(solution)
    return new_solutions
def create_path(solution, init_parameters):
    start_symbol = 'car'
    charger_symbol = 'fuel'
    end_symbol = 'marker'
    line_width = 5
    line_opacity = 0.8
    line_color = '#FF0000'
    path = []
    icons = []

    with open('tools/stations_coords.json') as f:
        stations_coords = json.load(f)

    with open('tools/stations_routes_matrix.json') as fff:
        routes_array = json.load(fff)

    with open('tools/stations_id.json') as fff:
        stations_id = json.load(fff)

    # create path, line from start to end through superchargers

    if len(solution) > 2:
        number_of_segments = len(solution) - 1
        path = calculate_distance(init_parameters[0], [
            stations_coords[solution[0][1]]['lat'],
            stations_coords[solution[0][1]]['lng']
        ])[1]
        # path = path[:len(path):int(len(path))]

        for i in range(0, number_of_segments - 3):

            if routes_array['matrix'][stations_id[solution[i][1]]][stations_id[
                    solution[i + 1][1]]] == 0:
                print('zzzero')
                print(routes_array['matrix'][stations_id[solution[i][1]]][
                    stations_id[solution[i + 1][1]]])
                print(routes_array['matrix'][stations_id[solution[i + 1][1]]][
                    stations_id[solution[i][1]]][::-1])
                segment = routes_array['matrix'][stations_id[solution[
                    i + 1][1]]][stations_id[solution[i][1]]][::-1]
            else:
                segment = routes_array['matrix'][stations_id[solution[i][1]]][
                    stations_id[solution[i + 1][1]]]

            # print(segment)
            start = segment[0]
            end = segment[len(segment) - 1]
            center = segment[int(len(segment) / 2)]
            # segment = segment[1:len(segment)-1:int(len(segment) / 2)]
            # segment.append(end)
            # segment.insert(0,start)
            seg = []
            seg.append(start)
            # seg.append(center)
            seg.append(end)

            print(seg)
            path = path + seg

        segment = calculate_distance(
            [
                stations_coords[solution[len(solution) - 4][1]]['lat'],
                stations_coords[solution[len(solution) - 4][1]]['lng']
            ],
            init_parameters[1],
        )[1]

        segment.append([init_parameters[1][1], init_parameters[1][0]])
        #segment = segment[:len(segment):int(len(segment))]
        path = path + segment

    if len(solution) == 2:
        path = calculate_distance(init_parameters[0], init_parameters[1])[1]

    print("PATH COORDS ", path)

    # for j in range(len(solution) - 1):

    generation = {
        'type': 'Feature',
        'properties': {
            'name': 'Path',
            "marker-symbol": "monument"
        },
        'geometry': {
            'type': 'LineString',
            'coordinates': path
        }
    }
    if len(solution) < 13:
        icons.append(generation)

    # ---------------------------------------------------------------------------------
    # Create markers for start,end and superchargers

    coords = [init_parameters[0][1], init_parameters[0][0]]
    icon_start = {
        'type': 'Feature',
        'properties': {
            "marker-symbol": start_symbol,
            "marker-color": "#FF0000"
        },
        'geometry': {
            'type': 'Point',
            'coordinates': coords
        }
    }
    icons.append(icon_start)

    if len(solution) > 1:
        for i in range(0, len(solution) - 3):
            charging_time = solution[i][2]
            coords = [
                stations_coords[solution[i][1]]['lng'],
                stations_coords[solution[i][1]]['lat']
            ]

            icon_supercharger = {
                'type': 'Feature',
                'properties': {
                    "marker-symbol": i + 1,
                },
                'geometry': {
                    'type': 'Point',
                    'coordinates': coords
                }
            }

            print('SUPERCHARGER-', i, ': ', solution[i][1])
            icons.append(icon_supercharger)

    coords = [init_parameters[1][1], init_parameters[1][0]]

    icon_end = {
        'type': 'Feature',
        'properties': {
            "marker-symbol": end_symbol,
            "marker-color": "#FF0000"
        },
        'geometry': {
            'type': 'Point',
            'coordinates': coords
        }
    }

    icons.append(icon_end)
    return icons