# -*- coding: utf-8 -*-
"""
/***************************************************************************
 Silanalyses
                                 A QGIS plugin
 Plugin for analysing networks created with or without the SilLCP tool
 Generated by Plugin Builder: http://g-sherman.github.io/Qgis-Plugin-Builder/
                             -------------------
        begin        : 2024-06-03
        git sha      : $Format:%H$
        copyright    : (C) 2024 by Thomas ANDRE
        email        : thomas.andre.archgeo@gmail.com
 ***************************************************************************/

/***************************************************************************
 *                                                                         *
 *   This program is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU General Public License as published by  *
 *   the Free Software Foundation; either version 2 of the License, or     *
 *   (at your option) any later version.                                   *
 *                                                                         *
 ***************************************************************************/
"""

import os
from math import *

from qgis import *
from qgis.PyQt import *
from qgis.core import *
from qgis.utils import *
from qgis.PyQt.QtGui import *
from qgis.PyQt.QtCore import *

from ..Fonctions.Utilitaires import *
from ..Fonctions.Fonctions_QGIS import *


# This loads your .ui file so that PyQt can populate your plugin with the elements from Qt Designer
FORM_CLASS, _ = uic.loadUiType(os.path.join(
    os.path.dirname(__file__), 'Silanalyses_dialog_base.ui'))


class SilanalysesDialog(QtWidgets.QDialog, FORM_CLASS):
    def __init__(self, parent=None):
        """Constructor."""
        super(SilanalysesDialog, self).__init__(parent)
        # Set up the user interface from Designer through FORM_CLASS.
        # After self.setupUi() you can access any designer object by doing
        # self.<objectname>, and you can use autoconnect slots - see
        # http://qt-project.org/doc/qt-4.8/designer-using-a-ui-file.html
        # #widgets-and-dialogs-with-auto-connect
        self.setupUi(self)
        self.setWindowFlags(Qt.WindowType.Window | Qt.WindowType.WindowCloseButtonHint)

        # Connecting the signal of closing the olugin to a function
        self.finished.connect(self.on_finished)

        """Initialisation of some functions and tools"""
        self.layer_list()
        self.combo_network.setFilters(QgsMapLayerProxyModel.LineLayer)
        self.combo_attribute.setFilters(QgsFieldProxyModel.Int | QgsFieldProxyModel.LongLong | QgsFieldProxyModel.Double | QgsFieldProxyModel.String)
        self.hour.setMaximum(23)
        self.minute.setMaximum(59)
        self.km.setMaximum(1000000)
        self.other.setMaximum(1000000)
        self.timefield.setFilters(QgsFieldProxyModel.Int | QgsFieldProxyModel.LongLong | QgsFieldProxyModel.Double)
        self.combo_network_GPS.setFilters(QgsMapLayerProxyModel.LineLayer)
        self.start.setFilters(QgsMapLayerProxyModel.PointLayer)
        self.inter.setFilters(QgsMapLayerProxyModel.PointLayer)
        self.end.setFilters(QgsMapLayerProxyModel.PointLayer)
        self.inter.setAllowEmptyLayer(True)
        self.start_point.setAllowNull(True)
        self.stops.setAllowNull(True)
        self.end_point.setAllowNull(True)
        self.inter.setCurrentIndex(0) 
        
        """Linking buttons and functions"""
        self.ok_network.clicked.connect(self.select_network)
        self.ok_attribute.clicked.connect(self.select_attribute)
        self.b_time.toggled.connect(self.select_unit)
        self.b_km.toggled.connect(self.select_unit)
        self.b_other.toggled.connect(self.select_unit)
        self.ok_resume.clicked.connect(self.resume)
        self.ok_new.clicked.connect(self.fusion)
        self.refresh.clicked.connect(self.layer_list)
        self.shortestpath.clicked.connect(self.switch)
        self.fastestpath.clicked.connect(self.switch)
        self.ok_path.clicked.connect(self.itinerary)
        self.combo_network_GPS.layerChanged.connect(self.prepa_list)
        self.start.layerChanged.connect(self.prepa_list)
        self.start_point.featureChanged.connect(self.prepa_list)
        self.inter.layerChanged.connect(self.prepa_list)
        self.stops.featureChanged.connect(self.prepa_list)
        self.end.layerChanged.connect(self.prepa_list)
        self.end_point.featureChanged.connect(self.prepa_list)
    
    """Gestion of the correct loading and unloading the plugin"""
    # Launching the reset of the parameters when the plugin is launched
    def showEvent(self, event: QShowEvent):
        self.recharge()
        self.boot = True
    
    # Launching the reset of the parameters when the plugin is closed
    def on_finished(self):   
        self.recharge()

    # Reseting the parameters of the plugin when it is shut down for the next uses
    def recharge(self):   
        # Initialisation of the loading bar
        window_bg = QApplication.instance().palette().window().color().name()
        if window_bg.lower() in ["#000000", "#1e1e1e", "#2b2b2b"]:
            self.color = "white"
        else:
            self.color = "black"

        message = "Avancement dans l'utilisation des outils"
        Utilitaires.progression(self.bar_2, self.message_progres, message, 0, self.color)
    
        self.layer_list()

        grass_provider = any(p.lower().startswith("grass") for p in QgsProviderRegistry.instance().providerList())
        grass_processing = any(p.id().lower().startswith("grass") for p in QgsApplication.processingRegistry().providers())

        if grass_provider and grass_processing:
            self.combo_network_GPS.setEnabled(True)
            self.shortestpath.setEnabled(True)
            self.fastestpath.setEnabled(True)
            self.label_15.show()
            self.timefield.show()

            self.start.setEnabled(True)
            self.start_point.setEnabled(True)
            self.inter.setEnabled(True)
            self.stops.setEnabled(True)
            self.end.setEnabled(True)
            self.end_point.setEnabled(True)
            self.ok_path.setEnabled(False)
        else:
            self.combo_network_GPS.setEnabled(False)
            self.shortestpath.setEnabled(False)
            self.fastestpath.setEnabled(False)
            self.label_15.hide()
            self.timefield.hide()

            self.start.setEnabled(False)
            self.start_point.setEnabled(False)
            self.inter.setEnabled(False)
            self.stops.setEnabled(False)
            self.end.setEnabled(False)
            self.end_point.setEnabled(False)

        self.combo_attribute.setEnabled(False)
        self.ok_attribute.setEnabled(False)
        self.b_time.setEnabled(False)
        self.b_km.setEnabled(False)
        self.b_other.setEnabled(False)
        self.day.setEnabled(False)
        self.hour.setEnabled(False)
        self.minute.setEnabled(False)
        self.km.setEnabled(False)
        self.other.setEnabled(False)
        self.ok_resume.setEnabled(False)
        self.shortestpath.setChecked(True)
        # self.fastestpath.setChecked(False)
        self.start_point.setEnabled(False)
        self.stops.setEnabled(False)
        self.end_point.setEnabled(False)
        self.ok_path.setEnabled(False)

        self.label_15.hide()
        self.timefield.hide() 
        self.stops.hide()
        self.indicator_start.hide()
        self.indicator_stops.hide()
        self.indicator_end.hide()

        self.setMinimumSize(0, 0)
        new_height = self.minimumSizeHint().height()
        self.resize(self.width(), new_height)
    
    @staticmethod
    def tr(message):
        return QCoreApplication.translate("SilanalysesDialogBase", message)
    

    def prepa_list(self):
        """
        Preparations for the GPS tool
        """
        if self.start.currentLayer() != None:
            dep = self.start.currentLayer()
            self.start_point.setLayer(dep)
            self.start_point.setEnabled(True)

            try:
                self.check_steps(self.start, self.start_point, self.indicator_start)
            except Exception:
                pass
        else:
            self.start_point.setEnabled(False)

        if self.inter.currentLayer() != None:
            inter = self.inter.currentLayer()
            self.stops.setLayer(inter)
            self.stops.setEnabled(True)
            self.stops.show()

            try:
                self.check_steps(self.inter, self.stops, self.indicator_stops)
            except Exception:
                pass
        else:
            self.stops.hide()

        if self.end.currentLayer() != None:
            fin = self.end.currentLayer()
            self.end_point.setLayer(fin)
            self.end_point.setEnabled(True)

            try:
                self.check_steps(self.end, self.end_point, self.indicator_end)
            except Exception:
                pass
        else:
            self.end_point.setEnabled(False)
        
        try:
            network = Utilitaires.layer_finder(self.combo_network_GPS)
            self.timefield.setLayer(network)
        except Exception:
            pass

        if not self.shortestpath.isChecked() and not self.fastestpath.isChecked():
            self.ok_path.setEnabled(False)
        else:
            self.ok_path.setEnabled(True)


    def check_steps(self, layer_combobox, feature_combobox, indicator):
        """
        Check if the layers and entities selected are compatible with the use of the GPS tool

        :param layer_combobox: Combobox with the layer selected
        :type layer_combobox: QgsMapLayerCombobox

        :param feature_combobox: Combobox with the entity selected
        :type feature_combobox: QgsFeaturePickerWidget

        :param feature_combobox: Indicator to show the analysis
        :type feature_combobox: QRadioButton
        """
        if feature_combobox.feature().hasGeometry():
            indicator.show()
            indicator.setChecked(True)
            indicator.setAutoExclusive(False)
            indicator.setEnabled(False)
            indicator.setStyleSheet("QRadioButton::indicator { background-color: green; }")
        elif not feature_combobox.feature().hasGeometry():
            layer = Utilitaires.layer_finder(layer_combobox)
            if indicator == self.indicator_stops:
                if len(layer.selectedFeatures()) == 0:
                    indicator.show()
                    indicator.setChecked(True)
                    indicator.setAutoExclusive(False)
                    indicator.setEnabled(False)
                    indicator.setStyleSheet("QRadioButton::indicator { background-color: gold; }")
                else:
                    indicator.show()
                    indicator.setChecked(True)
                    indicator.setAutoExclusive(False)
                    indicator.setEnabled(False)
                    indicator.setStyleSheet("QRadioButton::indicator { background-color: green; }")
            else:
                if len(layer.selectedFeatures()) == 1 or layer.featureCount() == 1:
                    indicator.show()
                    indicator.setChecked(True)
                    indicator.setAutoExclusive(False)
                    indicator.setEnabled(False)
                    indicator.setStyleSheet("QRadioButton::indicator { background-color: green; }")
                else:
                    indicator.show()
                    indicator.setChecked(False)
                    indicator.setAutoExclusive(False)
                    indicator.setEnabled(False)
                    indicator.setStyleSheet("QRadioButton::indicator { background-color: red; }")
        else:
            indicator.hide()
            indicator.setChecked(False)
            indicator.setAutoExclusive(False)
            indicator.setEnabled(False)
            indicator.setStyleSheet("")

        if self.indicator_start.isChecked() and self.indicator_end.isChecked():
            self.ok_path.setEnabled(True)
        else:
            self.ok_path.setEnabled(False)
        

    def layer_list(self):
        """
        Retrieve layers from the project to refresh the list and offer only vector layers
        """
        try:
            # Resetting the list to zero
            self.combo_layers.clear()

            # Récupération des couches du projet
            self.layers = QgsProject.instance().mapLayers().values()

            for layer in self.layers:
                # Tri des couches pour ne garder que les couches de vecteurs
                if (
                    layer.type() == QgsMapLayer.LayerType.VectorLayer and 
                    QgsWkbTypes.geometryType(layer.wkbType()) == QgsWkbTypes.GeometryType.LineGeometry
                ):
                    self.combo_layers.addItem(layer.name())
                    idx = self.combo_layers.findText(layer.name())
                    # Version 1 for QT6 (QGIS4)
                    try:
                        self.combo_layers.setItemCheckState(idx, Qt.CheckState.Unchecked)
                    # Version 2 for QT5 (QGIS3)
                    except Exception:
                        self.combo_layers.setItemCheckState(idx,Qt.CheckState.Unchecked)
        except Exception:
            pass


    def fusion(self):
        """
        Tool for merging different networks into a single harmonised network
        """
        # Retrieving selected layers
        layer_list = self.combo_layers.checkedItems()

        # Recovery of the given name
        name = self.name_network.text()
        if name == '':
            name = self.tr("Reseau_fusion")

        try:
            message = self.tr("Fusion des couches...")
            Utilitaires.progression(self.bar_2, self.message_progres, message, 25, "{}".format(self.color))

            progress_dialog = QProgressDialog(self.tr("Fusion des couches..."), None, 0, 0)
            progress_dialog.setWindowModality(Qt.WindowModality.WindowModal)
            progress_dialog.setWindowTitle(self.tr("Veuillez patienter"))
            progress_dialog.setWindowModality(Qt.WindowModality.ApplicationModal)
            progress_dialog.setCancelButton(None)
            progress_dialog.setValue(0)
            progress_dialog.show()
            QCoreApplication.processEvents()

            path_list = []

            for layer in layer_list:
                layer = QgsProject.instance().mapLayersByName(layer)[0]
                path = layer.dataProvider().dataSourceUri()
                path_list.append(path)

            fused_layer = Fonctions_QGIS.Fusion_cleaner(layer_list)

            attribute_list = fused_layer.fields().names()
            # print(str(attribute_list)) # debugtest
        except Exception:
            message = self.tr("Problème avec les couches utilisées... Veuillez recommencer ou changer de couches")
            Utilitaires.progression(self.bar_2, self.message_progres, message, 0, "red;")
            progress_dialog.close()
            return

        try:
            message = self.tr("Gestion des identifiants...")
            Utilitaires.progression(self.bar_2, self.message_progres, message, 75, "{}".format(self.color))

            if "ID" in attribute_list:
                id_field = "ID"
            elif "Id" in attribute_list:
                id_field = "Id"
            elif "id" in attribute_list:
                id_field="id"
            elif "fid" in attribute_list:
                id_field = "fid"
            elif "FID" in attribute_list:
                id_field = "FID"
            else:
                id_field = ""

            if id_field != "":
                fused_layer.startEditing()

                id = 0
                for feature in fused_layer.getFeatures():
                    fused_layer.changeAttributeValue(feature.id(), fused_layer.fields().indexOf(id_field), id)
                    id += 1

                fused_layer.commitChanges()
            
        except Exception:
            message = self.tr("Impossible de changer l'identifiant des entités, vérifiez que les couchent aient bien un champ id, Id, ID, fid ou FID")
            Utilitaires.progression(self.bar_2, self.message_progres, message, 0, "red;")
            progress_dialog.close()
            return

        message = self.tr("Gestion du style...")
        Utilitaires.progression(self.bar_2, self.message_progres, message, 90, "{}".format(self.color))
        
        fused_layer.setName(name)
        QgsProject.instance().addMapLayer(fused_layer)

        style_path = os.path.dirname(os.path.abspath(__file__)).replace('Silanalyses','Styles//Liens.qml')
        if os.path.exists(style_path):
            fused_layer.loadNamedStyle(style_path)
        else:
            pass
        self.name_network.clear()

        iface.messageBar().pushMessage(self.tr("Succès:"), self.tr("La couche fusionnée a été créée avec succès"), level=Qgis.MessageLevel.Success)
        message = self.tr("Avancement dans l'utilisation des outils")
        Utilitaires.progression(self.bar_2, self.message_progres, message, 0, self.color)
        progress_dialog.close()
        

    def select_network(self):
        """
        Selection of the layer containing the network to be simplified
        """
        # Search for the layer corresponding to the given name
        self.network = Utilitaires.layer_finder(self.combo_network)

        # Definition of the source of the drop-down list of entities in the selected layer
        self.combo_attribute.setLayer(self.network)
        self.combo_attribute.setEnabled(True)
        self.ok_attribute.setEnabled(True)


    def select_attribute(self):
        """
        Selecting an attribute field for selecting the point of origin of LCPs
        """
        self.attribute = self.combo_attribute.currentField()

        if self.network.fields().field(self.attribute).type() == QVariant.String:
            self.b_km.setChecked(False)
            self.b_km.setEnabled(False)
            self.b_other.setChecked(False)
            self.b_other.setEnabled(False)
            self.km.setEnabled(False)
            self.other.setEnabled(False)
            self.km.hide()
            self.other.hide()
        else:
            self.b_km.setEnabled(True)
            self.b_km.show()
            self.b_other.setEnabled(True)
            self.b_other.show()
            self.km.show()
            self.other.show()
        
        self.b_time.setEnabled(True)
        self.b_time.setChecked(True)
        self.day.setEnabled(True)
        self.hour.setEnabled(True)
        self.minute.setEnabled(True)

        self.choice=1

        self.ok_resume.setEnabled(True)


    def select_unit(self):
        """
        Choice of unit used for analyses
        """
        if self.b_time.isChecked():
            self.b_km.setChecked(False)
            self.b_other.setChecked(False)

            self.day.setEnabled(True)
            self.hour.setEnabled(True)
            self.minute.setEnabled(True)

            self.choice=1
            self.ok_resume.setEnabled(True)

            self.km.setEnabled(False)
            self.other.setEnabled(False)

        elif self.b_km.isChecked():
            self.b_time.setChecked(False)
            self.b_other.setChecked(False)

            self.km.setEnabled(True)

            self.choice=2
            self.ok_resume.setEnabled(True)

            self.day.setEnabled(False)
            self.hour.setEnabled(False)
            self.minute.setEnabled(False)
            self.other.setEnabled(False)

        elif self.b_other.isChecked():
            self.b_time.setChecked(False)
            self.b_km.setChecked(False)

            self.other.setEnabled(True)

            self.choice=3
            self.ok_resume.setEnabled(True)

            self.day.setEnabled(False)
            self.hour.setEnabled(False)
            self.minute.setEnabled(False)
            self.km.setEnabled(False)
        
        self.setMinimumSize(0, 0)
        new_height = self.minimumSizeHint().height()
        self.resize(self.width(), new_height)

        self.day.setValue(0)
        self.hour.setValue(0)
        self.minute.setValue(0)
        self.km.setValue(0)
        self.other.setValue(0)


    def switch(self):
        """
        Choice of the mode for the GPS
        """
        if self.shortestpath.isChecked():
            # self.fastestpath.setChecked(False)
            self.label_15.hide()
            self.timefield.hide()

        elif self.fastestpath.isChecked():
            # self.shortestpath.setChecked(False)
            self.label_15.show()
            self.timefield.show()

            try:
                network = Utilitaires.layer_finder(self.combo_network_GPS)
                self.timefield.setLayer(network)
            except Exception:
                pass

        self.prepa_list()

    
    def resume(self):
        """
        Selection of network edges to be retained according to the value chosen
        """
        message = "Lancement de l'outil de simplification du réseau"
        Utilitaires.progression(self.bar_2, self.message_progres, message, 10, self.color)

        # Preparation of a layer group to put all the layers in the same place
        group = QgsProject.instance().layerTreeRoot().findGroup(self.tr("{}_simplifié").format(self.network.name()))
        if group is None:
            group = QgsProject.instance().layerTreeRoot().insertGroup(0, self.tr("{}_simplifié").format(self.network.name()))
            group.setExpanded(True)

        selected_ids = self.network.selectedFeatureIds()
        self.network.selectAll()
        list_features = []
        new_liste = []

        if self.choice == 1:
            message = self.tr("Tri des arcs en fonction du temps...")
            Utilitaires.progression(self.bar_2, self.message_progres, message, 25, self.color)

            for feature in self.network.selectedFeatures():
                # Using the time sorting function
                new_liste = self.time_selection(feature, self.attribute, list_features)

            name = self.tr("temps_<_")
            if self.day.value() != 0:
                name += str(self.day.value()) + "j"
            if self.hour.value() != 0:
                name += str(self.hour.value()) + "h"
            if self.minute.value() != 0: 
                name += str(self.minute.value()) + "min"
    
        elif self.choice == 2:
            message = self.tr("Tri des arcs en fonction de la distance...")
            percent = 25
            Utilitaires.progression(self.bar_2, self.message_progres, message, percent, self.color)
            
            for feature in self.network.selectedFeatures():
                # Using the distance sorting function
                new_liste = self.distance_selection(feature, self.attribute, list_features)
            
            name = self.tr("distance_<_{}").format(str(self.km.value()))

        elif self.choice == 3:
            message = self.tr("Tri des arcs en fonction du coût...")
            Utilitaires.progression(self.bar_2, self.message_progres, message, 25, self.color)

            for feature in self.network.selectedFeatures():
                # Using the specific function for custom sorting
                new_liste = self.cost_selection(feature, self.attribute, list_features)
            
            name = self.tr("cout_<_{}").format(str(self.other.value()))

        # Creating the layer
        simplifie = QgsVectorLayer("LineString?crs=epsg:2154", self.tr("Reseau_simplifie_{}").format(name), "memory")
        layer_data = simplifie.dataProvider()

        # Check whether entities correspond to the search
        message = self.tr("Ajout des entités sélectionnées dans une nouvelle couche")
        Utilitaires.progression(self.bar_2, self.message_progres, message, 50, self.color)

        if len(new_liste) > 0:
            # Retrieving columns from the attribute table of the reference layer
            attr = self.network.dataProvider().fields().toList()

            # Updating the columns in the new layer
            layer_data.addAttributes(attr)
            simplifie.updateFields()

            # Adding the layer to the group
            QgsProject.instance().addMapLayer(simplifie, False)
            group.insertLayer(0, simplifie)

            style_path = os.path.dirname(os.path.abspath(__file__)).replace('Silanalyses','Styles//Liens.qml')
            if os.path.exists(style_path):
                simplifie.loadNamedStyle(style_path)
            else:
                pass
            
            # Adding selected edges to the new layer
            layer_data.addFeatures(new_liste)

            message = self.tr("Calcule de la centralité du réseau simplifié")
            Utilitaires.progression(self.bar_2, self.message_progres, message, 75, self.color)

            try:
                # Calculating the centrality of the new network
                centralite = Fonctions_QGIS.Centrality(self, simplifie)
                centralite.setName(self.tr("Centralite_noeuds_{}").format(name))
                
                # Adding the layer to the group
                QgsProject.instance().addMapLayer(centralite, False)
                group.insertLayer(0, centralite)

                # Defining the style of the layer
                style_path = os.path.dirname(os.path.abspath(__file__)).replace('Silanalyses','Styles//Noeuds.qml')
                if os.path.exists(style_path):
                    centralite.loadNamedStyle(style_path)
                else:
                    pass

                message = self.tr("Avancement dans l'utilisation des outils")
                iface.messageBar().pushMessage(self.tr("Succès:"), self.tr("Le réseau a été trié avec succès"), level=Qgis.MessageLevel.Success)
                
            except Exception:
                iface.messageBar().pushMessage(self.tr("Attention:"), self.tr("GRASS n'ayant pas été activé, le calcul de centralité n'a pas été réalisé"), level=Qgis.MessageLevel.Warning)
                message = self.tr("Attention: GRASS n'ayant pas été activé, le calcul de centralité n'a pas été réalisé")
                self.message_progres.setText(message)  
                self.message_progres.setStyleSheet("color: red;")
        else:
            message = self.tr("Un problème à eu lieu, aucun élément dans la couche ne correspond à la recherche")
            iface.messageBar().pushMessage(self.tr("Attention:"), self.tr("Aucun élément dans la couche ne correspond à la recherche"), level=Qgis.MessageLevel.Warning)
            self.message_progres.setText(message)  
            self.message_progres.setStyleSheet("color: red;")

        # Reinitialisation of the tool
        self.b_time.setChecked(True)
        self.b_time.setEnabled(False)
        self.day.setValue(0)
        self.hour.setValue(0)
        self.minute.setValue(0)
        self.day.setEnabled(False)
        self.hour.setEnabled(False)
        self.minute.setEnabled(False)
        self.b_km.setEnabled(False)
        self.km.setValue(0)
        self.km.setEnabled(False)
        self.b_other.setEnabled(False)
        self.other.setValue(0)
        self.other.setEnabled(False)

        self.combo_attribute.setLayer(None)
        self.combo_attribute.setEnabled(False)
        self.ok_attribute.setEnabled(False)
        self.ok_resume.setEnabled(False)

        self.network.removeSelection()
        self.network.selectByIds(selected_ids)

        self.message_progres.setText(message)
        self.bar_2.reset()


    def time_selection(self, feature, champ, list):
        """
        Check whether the time linked to the edge is less than the time required to select it

        :param feature: Element of the layer to be checked
        :type feature: QGSfeature

        :param champ: Field containing the value to be compared
        :type champ: str

        :param list: List to fill with the items you want
        :type list: list

        :returns: List of selected edges
        :rtypes: list
        """
        # Link value recovery
        val = feature[champ]
        # print(str(val)) # debugtest
        
        # Retrieving input values
        if self.day.value() != 0:
            j = int(self.day.value())
        else: 
            j = 0

        if self.hour.value() != 0:
            h = int(self.hour.value())
        else: 
            h = 0

        if self.minute.value() != 0: 
            m = int(self.minute.value())
        else: 
            m = 0

        # print("a {},{},{}".format(j,h,m)) # debugtest

        """Sorting the edeges by reference value"""
        # Identifying time values from a character string
        if isinstance(val, str):
            # Format "--j --h --min"
            if "j" in val: 
                day  =  int(val.split("j")[0])
                hour  =  int(val.split("j")[1].split("h")[0])
                min  =  int(val.split("j")[1].split("h")[1].split("min")[0])

                # print("b {},{},{}".format(day,hour,min)) # debugtest
                if day < j:
                    list.append(feature)
                elif day == j:
                    if hour < h:
                        list.append(feature)
                    elif hour == h:
                        if min <= m:
                            list.append(feature)
                        else:
                            pass
                    else:
                        pass
                else:
                    pass
            else:
                # Format "--h --min"
                hour = int(val.split("h")[0])
                min = int(val.split("h")[1].split("min")[0])
                # print("c {},{}".format(hour,min)) # debugtest

                h = h + j*24
                # print(h) # debugtest

                if hour < h:
                    list.append(feature)
                elif hour == h:
                    if min <= m:
                        list.append(feature)
                    else:
                        pass
                else:
                    pass

        # Identify time values from a whole or decimal number
        elif isinstance(val,float):
            hour = floor(val)
            min = val - hour
            h = h + j*24
            # print(h) # debugtest
            # print("d {},{}".format(hour,min)) # debugtest

            if hour < h:
                list.append(feature)
            elif hour == h:
                if min <= m:
                    list.append(feature)
        else:
            iface.messageBar().pushMessage(self.tr("Erreur:"), self.tr("Le champ choisi n'est ni un float, ni un string"), level=Qgis.MessageLevel.Critical)
            self.message_progres.setText(self.tr("Le champ choisi n'est ni un float, ni un string"))  
            self.message_progres.setStyleSheet("color: red;")
        
        # print(str(len(list))) # debugtest
        return list


    def distance_selection(self,feature,champ,list):
        """
        Check whether the distance linked to the edge is less than the distance required to select it

        :param feature: Element of the layer to be checked
        :type feature: QGSfeature

        :param champ: Field containing the value to be compared
        :type champ: str

        :param list: List to fill with the items you want
        :type list: list

        :returns: List of selected edges
        :rtypes: list
        """
        # Link value recovery
        val = float(feature[champ])
        # print(str(val)) # debugtest

        # Recovery of the input value
        ref = float(self.km.value())
        # print(str(ref)) # debugtest

        # Sorting the edges by reference value
        if val < ref:
            list.append(feature)
        else:
            pass

        # print(str(len(list))) # debugtest
        return list


    def cost_selection(self,feature,champ,list):
        """
        Check whether the cost of the link is lower than the one you are looking for to select it
        
        :param feature: Element of the layer to be checked
        :type feature: QGSfeature

        :param champ: Field containing the value to be compared
        :type champ: str

        :param list: List to fill with the items you want
        :type list: list

        :returns: List of selected edges
        :rtypes: list
        """
        # Link value recovery
        val = float(feature["{}".format(champ)])
        # print(str(val)) # debugtest
    
        # Recovery of the input value
        ref = float(self.other.value())
        # print(str(ref)) # debugtest

        # Sorting the edges by reference value
        if val < ref:
            list.append(feature)
        else:
            pass

        # print(str(len(list))) # debugtest
        return list
    

    def itinerary(self):
        """
        Create a route between 2 or more points using the shortest path in a network
        """
        message = self.tr("Préparation du réseau")
        Utilitaires.progression(self.bar_2, self.message_progres, message, 5, "#0049E6")

        # Creation of the loading window
        self.progress_dialog = QProgressDialog(message,
                                        None, 0, 100)
        self.progress_dialog.setWindowModality(Qt.WindowModality.WindowModal)
        self.progress_dialog.setWindowTitle(self.tr("Veuillez patienter"))
        self.progress_dialog.setWindowModality(Qt.WindowModality.ApplicationModal)
        self.progress_dialog.setCancelButton(None)
        self.progress_dialog.setValue(0)
        self.progress_dialog.show()
        QCoreApplication.processEvents()

        self.networkGPS = Utilitaires.layer_finder(self.combo_network_GPS)
        nom_reseau = self.networkGPS.name()
        # print(self.combo_network_GPS.currentText()) # debugtest
        # print(str(self.networkGPS)) # debugtest

        """Recuperation of the points involved in the trip"""
        try:
            # Recuperation of the strating point
            self.start_layer = Utilitaires.layer_finder(self.start)

            # If necessary, recuperation of the intermediary points
            if self.inter.currentText() != "":
                self.inter_layer = Utilitaires.layer_finder(self.inter)
            else:
                self.inter_layer = ""

            # Recuperation of the finish point
            self.end_layer = Utilitaires.layer_finder(self.end)

        except Exception:
            iface.messageBar().pushMessage(self.tr("Attention:"), self.tr("Une des couches chosies n'a pas été trouvée, veuillez vérifier vos entrées"), 2)
            message = self.tr("Problème avec une des couches choisies")
            Utilitaires.progression(self.bar_2, self.message_progres, message, 0, "red;")
            self.progress_dialog.close()
            return

        try:
            # Recovery of network points if the points selected are not directly on the network
            nodes = Fonctions_QGIS.NodesExtraction(self, self.networkGPS)
            # QgsProject.instance().addMapLayer(nodes) # debugtest

            # Checking tool in the event of a problem with the start or finish point
            PB = False
        except Exception:
            iface.messageBar().pushMessage(self.tr("Attention:"), self.tr("GRASS n'ayant pas été activé, l'outil ne peut fonctionner"), level=Qgis.MessageLevel.Critical)
            QgsProject.instance().removeMapLayer(nodes)
            message = self.tr("GRASS n'ayant pas été activé, l'outil ne peut fonctionner")
            Utilitaires.progression(self.bar_2, self.message_progres, message, 0, "red;")
            self.progress_dialog.close()
            return
        
        message = self.tr("Récupération des points du trajet...")
        Utilitaires.progression(self.bar_2, self.message_progres, message, 25, "#0049E6")
        self.progress_dialog.setLabelText(message)
        self.progress_dialog.setValue(5)
        QCoreApplication.processEvents()

        # Search for the network nodes closest to the route points
        try:
            if self.inter.currentText() != "":
                coords_start, coords_end, liste_inter_tri, PB = self.extremities_search(nodes, self.start_layer, self.inter_layer, self.end_layer, PB)
            else:
                coords_start, coords_end, PB = self.extremities_search(nodes, self.start_layer, self.inter_layer, self.end_layer, PB)
                print(coords_start)
                print(coords_end)

        except Exception:
            iface.messageBar().pushMessage(self.tr("Attention:"), self.tr("Une des entités chosies n'a pas été trouvée, veuillez vérifier vos entrées"), level=2)
            QgsProject.instance().removeMapLayer(nodes)
            message = self.tr("Problème avec une des entités choisies")
            Utilitaires.progression(self.bar_2, self.message_progres, message, 0, "red;")
            self.progress_dialog.close()
            return

        if not PB:
            if self.shortestpath.isChecked():
                message = self.tr("Recherche du chemin le plus court entre les points sélectionnés")
            elif self.fastestpath.isChecked():
                message = self.tr("Recherche du chemin le plus rapide entre les points sélectionnés")
            Utilitaires.progression(self.bar_2, self.message_progres, message, 50, "#0049E6")
            self.progress_dialog.setLabelText(message)
            self.progress_dialog.setValue(0)
            QCoreApplication.processEvents()

            # Create  a layer to store the routes created
            SCR = self.networkGPS.crs().authid().replace("EPSG:", "")
            shortest = QgsVectorLayer("{}?crs=epsg:{}".format('LineString',SCR), "Etapes", "memory")
            layer_data = shortest.dataProvider()
            layer_data.addAttributes([QgsField("Etape", QVariant.Int),QgsField("Coords_start", QVariant.String),QgsField("Coords_end", QVariant.String),QgsField("Cost", QVariant.Double),QgsField("Unite", QVariant.String)])

            style_path = os.path.dirname(os.path.abspath(__file__)).replace('Silanalyses','Styles//Etapes.qml')
            if os.path.exists(style_path):
                shortest.loadNamedStyle(style_path)
            else:
                pass

            """Search for the shortest path within the aggregated network between the various points on the route"""
            # Initialisation of specific values
            missing = 0
            order = 1

            # Case 1: No stops during the path
            if self.inter.currentText() == "":
                self.progress_dialog.setLabelText(self.tr("Recherche du chemin entre les points de départ et d'arrivée"))
                self.progress_dialog.setValue(50)
                QCoreApplication.processEvents()

                try:
                    # Version for the shortest path
                    if self.shortestpath.isChecked():
                        # print(coords_start,coords_end) # debugtest
                        path = Fonctions_QGIS.PathExtraction(self.networkGPS, coords_start, coords_end)
                        # print("path OK") # debugtest
                        # QgsProject.instance().addMapLayer(path) # debugtest        
                        
                        path.selectAll()

                        feat = path.selectedFeatures()[0]
                        new_feat = QgsFeature(shortest.fields())
                        new_feat.setGeometry(feat.geometry())

                        attr1 = coords_start.split(" [")[0].split(",")[0]+" "+coords_start.split(" [")[0].split(",")[1]
                        attr2 = coords_end.split(" [")[0].split(",")[0]+" "+coords_end.split(" [")[0].split(",")[1]
                        attr3 = feat.geometry().length()
                        attr4 = QgsUnitTypes.toString(path.crs().mapUnits())

                    # Version for the fastest path
                    elif self.fastestpath.isChecked():
                        field = self.timefield.currentField()
                        path = Fonctions_QGIS.ShortestPath(self.networkGPS, coords_start, coords_end, field)

                        path.selectAll()

                        feat = path.selectedFeatures()[0]
                        new_feat = QgsFeature(shortest.fields())
                        new_feat.setGeometry(feat.geometry())

                        reconstruction = Fonctions_QGIS.PathReconstruction(path, self.networkGPS)
                        total_time = 0
                        for feat in reconstruction.getFeatures():
                            total_time += feat[field]

                        attr1 = str(coords_start[0])+" "+str(coords_start[1])
                        attr2 = str(coords_end[0])+" "+str(coords_end[1])
                        attr3 = total_time
                        attr4 = "heures"

                    # Preparations for the new entity
                    new_feat.setAttributes([1, attr1, attr2, attr3, attr4])

                    shortest.startEditing()
                    shortest.dataProvider().addFeatures([new_feat])
                    shortest.commitChanges()

                except Exception:
                        iface.messageBar().pushMessage(self.tr("Erreur:"), self.tr("Aucun chemin n'a été trouvé"), level=Qgis.MessageLevel.Critical)
                        message = self.tr("Aucun chemin n'a été trouvé")
                        Utilitaires.progression(self.bar_2, self.message_progres, message, 0, "red;")
                        self.progress_dialog.close()
                        return
                
            # Case 2 : Stops during the travel
            else:
                # print("Lancement tri") # debugtest
                # Gathering the points of the route into a list
                points_list = []
                points_list.append(coords_start)

                for feat in liste_inter_tri:
                    points_list.append(feat)
                points_list.append(coords_end)
                # print(str(len(points_list))) # debugtest

                message = self.tr("Recherche du chemin le plus court entre les étapes du trajet...")
                Utilitaires.progression(self.bar_2, self.message_progres, message, 50, "#0049E6")
                self.progress_dialog.setLabelText(message)
                self.progress_dialog.setValue(10)
                QCoreApplication.processEvents()

                for n in range(0, len(points_list) - 1):
                    try:
                        # Version for the shortest path
                        if self.shortestpath.isChecked():
                            # print(str(n)) # debugtest
                            path = Fonctions_QGIS.PathExtraction(self.networkGPS, points_list[n], points_list[n+1])
                            # print("path OK ARR") # debugtest
                            # QgsProject.instance().addMapLayer(path) # debugtest

                            path.selectAll()

                            feat = path.selectedFeatures()[0]
                            new_feat = QgsFeature(shortest.fields())
                            new_feat.setGeometry(feat.geometry())

                            attr1 = points_list[n].split(" [")[0].split(",")[0]+" "+points_list[n].split(" [")[0].split(",")[1]
                            attr2 = points_list[n+1].split(" [")[0].split(" [")[0].split(",")[0]+" "+points_list[n+1].split(" [")[0].split(" [")[0].split(",")[1]
                            attr3 = feat.geometry().length()
                            attr4 = QgsUnitTypes.toString(path.crs().mapUnits())

                        # Version for the fastest path
                        elif self.fastestpath.isChecked():
                            field = self.timefield.currentField()
                            path = Fonctions_QGIS.ShortestPath(self.networkGPS, points_list[n], points_list[n+1], field)

                            path.selectAll()

                            feat = path.selectedFeatures()[0]
                            new_feat = QgsFeature(shortest.fields())
                            new_feat.setGeometry(feat.geometry())

                            reconstruction = Fonctions_QGIS.PathReconstruction(path, self.networkGPS)
                            total_time = 0
                            for feat in reconstruction.getFeatures():
                                # print(feat[field]) # debugtest
                                total_time += feat[field]

                            attr1 = str(points_list[n][0])+" "+str(points_list[n][1])
                            attr2 = str(points_list[n+1][0])+" "+str(points_list[n+1][1])
                            attr3 = total_time
                            attr4 = "heures"

                        # Preparations for the new entity
                        new_feat.setAttributes([order, attr1, attr2, attr3, attr4])
                        order += 1

                        shortest.startEditing()
                        shortest.dataProvider().addFeatures([new_feat])
                        shortest.commitChanges()

                        message = self.tr("{} chemin(s) sur {} créé(s)...").format(str(n),str(len(points_list)-1))
                        self.message_progres.setText(message)  

                        self.progress_dialog.setLabelText(message)
                        self.progress_dialog.setValue(10+round((n*80)/(len(points_list)-1)))
                        QCoreApplication.processEvents()

                    except Exception:
                        missing = missing + 1

                # Verification if a path was found
                try:
                    shortest.featureCount() == 0
                except Exception:
                    iface.messageBar().pushMessage(self.tr("Erreur:"), self.tr("Aucun chemin n'a été trouvé"), level=Qgis.MessageLevel.Critical)
                    message = self.tr("Aucun chemin n'a été trouvé")
                    self.message_progres.setText(message)  
                    self.message_progres.setStyleSheet("color: red;")

            print(self.name_stops)
            if self.name_start != "" or self.name_end != "":
                print(1)
                if self.name_stops not in ["", self.tr("_(avec_arrets)")]:
                    print(11)
                    name = "{}->{}->{}".format(self.name_start, self.name_stops, self.name_end)
                else:
                    print(12)
                    name = "{}->{}{}".format(self.name_start, self.name_end, self.name_stops)
                
            # Preparation of a layer group to put all the layers in the same place
            self.group = QgsProject.instance().layerTreeRoot().findGroup(self.tr("Trajets_dans_{}").format(nom_reseau))
            if self.group is None:
                self.group = QgsProject.instance().layerTreeRoot().insertGroup(0, self.tr("Trajets_dans_{}").format(nom_reseau))
                self.group.setExpanded(True)

            # Fusing the steps in one travel
            try:
                self.fusion_steps(shortest)
            except Exception:
                iface.messageBar().pushMessage(self.tr("Erreur:"), self.tr("Aucun chemin n'a été trouvé"), level=Qgis.MessageLevel.Critical)
                message = self.tr("Aucun chemin n'a été trouvé")
                self.message_progres.setText(message)  
                self.message_progres.setStyleSheet("color: red;")

            if self.inter.currentText() != "":
                # Adding the steps to the group if necessary
                shortest.setName(self.tr("Etapes_{}").format(name))
                QgsProject.instance().addMapLayer(shortest, False)
                self.group.insertLayer(0, shortest)

            message = self.tr("Fusion des étapes en un trajet...")
            Utilitaires.progression(self.bar_2, self.message_progres, message, 90, "#0049E6")

            self.progress_dialog.setLabelText(message)
            self.progress_dialog.setValue(90)
            QCoreApplication.processEvents()

            # Checking for missing links
            if missing > 0:
                if missing >= 2:
                    missing = missing//2 + 1
                else:
                    missing = 1

                iface.messageBar().pushMessage(self.tr("Attention:"), self.tr("Tous les chemins n'ont pu être créés. {} point(s) hors du réseau").format(missing), level=Qgis.MessageLevel.Warning)
                self.message_progres.setText(message)  
                self.message_progres.setStyleSheet("color: red;")
            else:
                iface.messageBar().pushMessage(self.tr("Succès:"), self.tr("L'itinéraire a été créé avec succès"), level=Qgis.MessageLevel.Success)
            
            message = self.tr("Avancement dans l'utilisation des outils")
            self.message_progres.setStyleSheet("color: {self.color}")

            self.inter.setCurrentIndex(0)
            self.shortestpath.setChecked(True)
            # self.fastestpath.setChecked(False)
            self.label_15.hide()
            self.timefield.hide()  

            self.start_point.setEnabled(False)

            self.stops.setEnabled(False)
            self.stops.hide()
            self.indicator_start.hide()
            self.indicator_stops.hide()
            self.indicator_end.hide()

            self.end_point.setEnabled(False)

            self.message_progres.setText(message)        
            self.bar_2.reset()
            
        else:
            message = self.tr("Problème avec le point de départ ou d'arrivée ! Vérifier qu'un seul point est ou peut être sélectionné")
            iface.messageBar().pushMessage(self.tr("Erreur:"), message, level=Qgis.MessageLevel.Critical)
            self.message_progres.setText(message)  
            self.message_progres.setStyleSheet("color: red;")
            

        QgsProject.instance().removeMapLayer(nodes)
        self.networkGPS.removeSelection()
        self.progress_dialog.close()


    def correction_network(self, network, x, y):
        """
        Correction for the network if the points are not on the links
        
        :param network: Network to adapt
        :type network: QgsVectorLayer

        :param x: X coordinates of the point
        :type x: float

        :param y: Y coordinates of the point
        :type y: float

        :returns: Updated network
        :rtypes: QgsVectorLayer
        """
        # Preparation of a memory layer to stock the point used for the correction
        crs = network.crs().authid()
        points_layer = QgsVectorLayer(f"Point?crs={crs}", "points_cibles", "memory")

        prov = points_layer.dataProvider()

        feat = QgsFeature()
        feat.setGeometry(QgsGeometry.fromPointXY(QgsPointXY(x, y)))
        prov.addFeature(feat)
        points = {}

        for feat in points_layer.getFeatures():
            QgsSpatialIndex().insertFeature(feat)
            points[feat.id()] = feat

        # Preparation of the layer for the corrected network
        new_network = QgsVectorLayer(f"LineString?crs={crs}", "reseau_ajuste", "memory")

        new_network.dataProvider().addAttributes(network.fields())
        new_network.updateFields()

        out_feats = []

        for feat in network.getFeatures():
            geom = feat.geometry()

            if geom.isMultipart():
                continue

            line = geom.asPolyline()
            if len(line) < 2:
                continue

            new_line = line[:]

            # Modifying the begining
            start_pt = line[0]
            ids = QgsSpatialIndex().nearestNeighbor(start_pt, 1)
            if ids:
                p = points[ids[0]].geometry().asPoint()
                d = start_pt.distance(p)
                if 1e-6 < d <= 100:
                    new_line[0] = p

            # Modifying the end
            end_pt = line[-1]
            ids = QgsSpatialIndex().nearestNeighbor(end_pt, 1)
            if ids:
                p = points[ids[0]].geometry().asPoint()
                d = end_pt.distance(p)
                if 1e-6 < d <= 100:
                    new_line[-1] = p

            new_feat = QgsFeature(new_network.fields())
            new_feat.setAttributes(feat.attributes())
            new_feat.setGeometry(QgsGeometry.fromPolylineXY(new_line))
            out_feats.append(new_feat)

        new_network.dataProvider().addFeatures(out_feats)
        return new_network


    def extremities_search(self, nodes, start, inter, end, PB):
        """
        Search for the coordinates of the network nodes corresponding to the points on the route if they are not the same

        :param nodes: All the nodes in the network to identify those corresponding to the required points
        :type nodes: QgsVectorLayer

        :param start: Starting point
        :type start: QgsFeature

        :param inter: Stop(s) during the travel
        :type inter: QgsFeature

        :param end: End point
        :type end: QgsFeature

        :param PB: Check that the start and finish points have been found
        :type PB: bool

        :returns coords_start: Coordinates of the starting point
        :returns coords_end: Coordinates of the ending point
        :returns liste_inter_tri: List of coordinates of sorted intermediate points
        :returns PB: Check that the start and finish points have been found
        :rtypes coords_start: str, str, list, bool
        """
        message = self.tr("Localisation du point de départ")
        Utilitaires.progression(self.bar_2, self.message_progres, message, 10, "#0049E6")

        nodes.selectAll()
        nodes = nodes.selectedFeatures()

        # Preparations for the name of the layer
        self.name_start = ""
        self.name_stops = ""
        self.name_end = ""

        """Preparations for the starting point"""
        # Check that there is only one point selected or selectable for the start
        selected_ids = start.selectedFeatureIds()
        if self.start_point.feature().hasGeometry():
            ref_start = self.start_point.feature().id()
            starting_point = next(start.getFeatures(QgsFeatureRequest(ref_start)))

            self.name_start = self.start_point.feature()[self.start_point.displayExpression().strip('"')]
        else:
            if len(start.selectedFeatures()) == 0:
                # print(len(start.selectedFeatures())) # debugtest
                start.selectAll()

            if len(start.selectedFeatures()) == 1:
                starting_point = start.selectedFeatures()[0]
            else:
                PB = True
            self.name_start = self.start_layer.name()
            # print("Départ OK") # debugtest

        if self.networkGPS.crs() != self.start_layer.crs():
            transform = QgsCoordinateTransform(self.start_layer.crs(), self.networkGPS.crs(), QgsProject.instance())
            starting_point = transform.transform(starting_point.geometry().asPoint())

            x = starting_point.x()
            y = starting_point.y()
        else:
            x = starting_point.geometry().asPoint()[0]
            y = starting_point.geometry().asPoint()[1]
        
        # Modification of the network if necessary to reach the point
        self.networkGPS = self.correction_network(self.networkGPS, x, y)

        # Retrieve the coordinates of the network node corresponding to the point
        if self.shortestpath.isChecked():
            coords_start = "{},{} [{}]".format(str(x), str(y), self.networkGPS.crs().authid())
        elif self.fastestpath.isChecked():
            coords_start = (x, y)
        print("Start : ", coords_start) # debugtest

        start.removeSelection()
        start.selectByIds(selected_ids)

        message = self.tr("Localisation du point d'arrivée")
        Utilitaires.progression(self.bar_2, self.message_progres, message, 20, "#0049E6")

        """Preparations for the destination point"""
        # Check that there is only one point selected or selectable for the finish
        selected_ids = end.selectedFeatureIds()
        if self.end_point.feature().hasGeometry():
            ref_end = self.end_point.feature().id()
            ending_point = next(end.getFeatures(QgsFeatureRequest(ref_end)))

            self.name_end = self.end_point.feature()[self.end_point.displayExpression().strip('"')]
        else:
            if len(end.selectedFeatures()) == 0:
                # print(len(start.selectedFeatures())) # debugtest
                end.selectAll()

            if len(end.selectedFeatures()) == 1:
                ending_point = end.selectedFeatures()[0]
            else:
                PB = True
            self.name_end = self.end_layer.name()
            # print("Arrivée OK") # debugtest
        
        if self.networkGPS.crs() != self.end_layer.crs():
            transform = QgsCoordinateTransform(self.end_layer.crs(), self.networkGPS.crs(), QgsProject.instance())
            ending_point = transform.transform(ending_point.geometry().asPoint())

            x = ending_point.x()
            y = ending_point.y()
        else:
            x = ending_point.geometry().asPoint()[0]
            y = ending_point.geometry().asPoint()[1]

        # Modification of the network if necessary to reach the point
        self.networkGPS = self.correction_network(self.networkGPS, x, y)

        # Retrieve the coordinates of the network node corresponding to the point
        if self.shortestpath.isChecked():
            coords_end = "{},{} [{}]".format(str(x), str(y), self.networkGPS.crs().authid())
        elif self.fastestpath.isChecked():
            coords_end = (x, y)
        print("End : ", coords_end) # debugtest

        end.removeSelection()
        end.selectByIds(selected_ids)

        """Preparations if intermetiates points where chosen"""
        # Checking for the presence of intermediate points
        if self.inter.currentText() != "":
            message = self.tr("Localisation et tri des points du trajet")
            Utilitaires.progression(self.bar_2, self.message_progres, message, 30, "#0049E6")

            self.name_stops = self.tr("_(avec_arrets)")

            liste_inter_tri = []
            selected_ids = inter.selectedFeatureIds()
            # Check whether points have already been selected, or whether the entire layer is to be taken into account
            if self.stops.feature().hasGeometry():
                list_inter = []
                list_tempo = []
                ref_stop = self.stops.feature().id()
                stop = next(inter.getFeatures(QgsFeatureRequest(ref_stop)))

                self.name_stops = self.stops.feature()[self.stops.displayExpression().strip('"')]

                list_inter.append(stop)
                list_tempo.append(stop)
            else:
                if len(inter.selectedFeatures()) == 0:
                    # print(len(inter.selectedFeatures())) # debugtest
                    inter.selectAll()
                    list_inter = inter.selectedFeatures()
                else:
                    list_inter = inter.selectedFeatures()
            
            # Vérification if no problems before the sorting of the travel's steps
            if not PB:
                # Defining the first point on the route as a reference
                liste_tri = []

                if self.networkGPS.crs() != self.inter_layer.crs():
                    transform = QgsCoordinateTransform(self.inter_layer.crs(), self.networkGPS.crs(), QgsProject.instance())
                    list_tempo = []
                    for feat in list_inter:
                        new_feat = QgsFeature(feat)
                        geom = new_feat.geometry()
                        geom.transform(transform)
                        new_feat.setGeometry(geom)
                        list_tempo.append(new_feat)

                liste_tri = Utilitaires.order_steps(starting_point, list_inter, ending_point)
                
                # Change of reference point
                for point_I in liste_tri:
                    try:
                        x = point_I.x()
                        y = point_I.y()
                    except Exception:
                        x = point_I.geometry().asPoint()[0]
                        y = point_I.geometry().asPoint()[1]
                    
                    # Modification of the network if necessary to reach the point
                    self.networkGPS = self.correction_network(self.networkGPS, x, y)

                    # Retrieve the coordinates of the network node corresponding to the point
                    if self.shortestpath.isChecked():
                        coords_I = "{},{} [{}]".format(str(x), str(y), self.networkGPS.crs().authid())
                    elif self.fastestpath.isChecked():
                        coords_I = (x, y)
                    liste_inter_tri.append(coords_I)
            # print("Intermédiaire OK") # debugtest

                inter.removeSelection()
                inter.selectByIds(selected_ids)

            return coords_start, coords_end, liste_inter_tri, PB
        else:
            return coords_start, coords_end, PB
    

    def fusion_steps(self, steps):
        """
        Correction for the network if the points are not on the links
        
        :param steps: Different steps of the trip
        :type network: QgsVectorLayer
        """
        # Names of the attributes
        FIELD_1 = "Coords_start"
        FIELD_2 = "Coords_end"
        FIELD_3 = "Cost"
        FIELD_4 = "Unite"

        # Recuperation and fusion of the different steps of the travel
        features = list(steps.getFeatures())
        geoms = [f.geometry() for f in features if f.geometry() and not f.geometry().isEmpty()]
        merged_geom = QgsGeometry.unaryUnion(geoms)

        # Preparation of the fused travel
        new_feat = QgsFeature(steps.fields())
        new_feat.setGeometry(merged_geom)

        attrs = new_feat.attributes()
        attrs[steps.fields().indexOf(FIELD_1)] = features[0][FIELD_1]
        attrs[steps.fields().indexOf(FIELD_2)] = features[-1][FIELD_2]
        attrs[steps.fields().indexOf(FIELD_3)] = sum(float(f[FIELD_3]) for f in features if f[FIELD_3] is not None)
        attrs[steps.fields().indexOf(FIELD_4)] = features[0][FIELD_4]

        new_feat.setAttributes(attrs)

        wkb_str = QgsWkbTypes.displayString(steps.wkbType())
        crs_authid = steps.crs().authid()

        # Creation of the new layer
        result_layer = QgsVectorLayer(f"{wkb_str}?crs={crs_authid}", "Trajet", "memory")
        provider = result_layer.dataProvider()
        provider.addAttributes(steps.fields())
        result_layer.updateFields()
        provider.addFeature(new_feat)
        result_layer.updateExtents()

        # Adding the style to the layer
        style_path = os.path.dirname(os.path.abspath(__file__)).replace('Silanalyses','Styles//Trajet.qml')
        if os.path.exists(style_path):
            result_layer.loadNamedStyle(style_path)
        else:
            pass
        
        # Gestion of the name if more details provided

        # Version for the shortest path
        if self.shortestpath.isChecked():
            name = self.tr("Trajet_+_court")
        # Version for the fastest path
        elif self.fastestpath.isChecked():
            name = self.tr("Trajet_+_rapide")

        if self.name_start != "" or self.name_end != "":
            if self.name_stops not in ["", self.tr("_(avec_arrets)")]:
                result_layer.setName(name + "_{}->{}->{}".format(self.name_start, self.name_stops, self.name_end))
            else:
                result_layer.setName(name + "_{}->{}{}".format(self.name_start, self.name_end, self.name_stops))
        
        # Adding the layer to the group
        QgsProject.instance().addMapLayer(result_layer, False)
        self.group.insertLayer(0, result_layer)
