"""
Fonctions intégrées à QGIS, reprises et appellées pour le fonctionnement du module
"""
import os
import tempfile
import processing
import grassprovider
from datetime import datetime

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


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

class Fonctions_QGIS(QtWidgets.QDialog, FORM_CLASS):
    def __init__(self, parent=None):
        """Constructor."""
        super(Fonctions_QGIS, 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)

    @staticmethod
    def tr(message):
        return QCoreApplication.translate("FonctionsQGIS", message)


    def Selectbylocation_simple(layer, intersect, method=0):
        """Selection by location of the entire layer

        :param layer: Layer to modify
        :type layer: QgsVectorLayer

        :param intersect: Layer used for comparison
        :type intersect: QgsVectorLayer

        :param method: 0 = New selection, 1 = Add to selection, 2 = Select from selection, 3 = Remove from selection
        :type method: int
        """        
        params = {'INPUT':layer,
                  'PREDICATE':[0],
                  'INTERSECT':intersect,
                  'METHOD':method,
                  'INVALID_HANDLING': 2}
        
        processing.run("native:selectbylocation", params)

    
    def Selectbylocation(layer, intersect, selected=True, method=1):
        """Selection by location using selected entities in a layer
        
        :param layer: Layer to modify
        :type layer: QgsVectorLayer

        :param intersect: Layer used for comparison
        :type intersect: QgsVectorLayer

        :param selected: Use only selected features
        :type selected: bool

        :param method: 0 = New selection, 1 = Add to selection, 2 = Select from selection, 3 = Remove from selection
        :type method: int
        """
        params = {'INPUT':layer,
                  'PREDICATE':[0],
                  'INTERSECT':QgsProcessingFeatureSourceDefinition(intersect.source(), 
                                                                 selectedFeaturesOnly=selected, 
                                                                 featureLimit=-1, 
                                                                 geometryCheck=QgsFeatureRequest.InvalidGeometryCheck.GeometryNoCheck),
                  'METHOD':method,
                  'INVALID_HANDLING': 2}
        
        processing.run("native:selectbylocation", params)

    
    def Selectbyattribute(layer, attribute, value, method=0):
        """Function: Selection by attribute in a layer
        
        :param layer: Layer to modify
        :type layer: QgsVectorLayer

        :param attribute: Reference attribute for selection
        :type attribute: str

        :param value: Reference value for selection
        :type value: int, float or str

        :param method: 0 = New selection, 1 = Add to selection, 2 = Remove from selection, 3 = Select from selection
        :type method: int
        """
        params = {'INPUT': layer,
                'FIELD': attribute,
                'OPERATOR':0,
                'VALUE': value,
                'METHOD':method,
                'INVALID_HANDLING': 2}
        
        processing.run("qgis:selectbyattribute", params)

    
    def Buffer(layer, distance, selected=True, dissolve=True):
        """Creating a buffer around a point

        :param layer: Base layer for buffering/erosion
        :type layer: QgsVectorLayer

        :param distance: Distance from buffer (in m)
        :type distance: int

        :param selected: Use only selected features
        :type selected: bool

        :param dissolve: Merge buffers if contact
        :type dissolve: bool

        :returns: Buffer/erosion created
        :rtypes: QgsVectorLayer
        """
        unit = layer.crs().mapUnits()
        if unit != 0:
            layer = processing.run("native:reprojectlayer", {
                'INPUT': layer,
                'TARGET_CRS': QgsCoordinateReferenceSystem('EPSG:2154'),
                'OUTPUT': 'memory:'
            })['OUTPUT']

        params = {'INPUT':QgsProcessingFeatureSourceDefinition(layer.source(), 
                                                              selectedFeaturesOnly=selected, 
                                                              featureLimit=-1, 
                                                              geometryCheck=QgsFeatureRequest.InvalidGeometryCheck.GeometryAbortOnInvalid),
                 'DISTANCE':distance,
                 'SEGMENTS':200,
                 'END_CAP_STYLE':0,
                 'JOIN_STYLE':0,
                 'MITER_LIMIT':2,
                 'DISSOLVE':dissolve,
                 'SEPARATE_DISJOINT':False,
                 'INVALID_HANDLING': 2,
                 'OUTPUT':'TEMPORARY_OUTPUT'}
        
        resulttemp = processing.run("native:buffer", params)

        return resulttemp['OUTPUT']
    

    def Difference(min, max):
        """Create a ring between two distances min and max

        :param min: Buffer with minimum distance
        :type min: (int ou float)

        :param max: Buffer with maximum distance
        :type max: (int ou float)

        :returns: Area resulting from the difference
        :rtypes: QgsVectorLayer
        """
        max = processing.run("native:fixgeometries", {
                'INPUT': max,
                'OUTPUT': 'memory:'
            })['OUTPUT']
        
        min = processing.run("native:fixgeometries", {
                'INPUT': min,
                'OUTPUT': 'memory:'
            })['OUTPUT']
        
        params={'INPUT':max,
                'OVERLAY':min,
                'INVALID_HANDLING': 2,
                'OUTPUT':'TEMPORARY_OUTPUT',
                'GRID_SIZE':None,}
        
        resulttemp = processing.run("native:difference", params)

        return resulttemp['OUTPUT']
    

    def Aggregation(layer):
        """Aggregation of entities in a layer according to a field (the parameters chosen here are linked to the module objectives)

        :param layer: Layer to be aggregated
        :type layer: QgsVectorLayer

        :returns: Layer containing aggregated entities
        :rtypes: QgsVectorLayer
        """
        
        layer = processing.run("native:fixgeometries", {
                'INPUT': layer,
                'OUTPUT': 'memory:'
            })['OUTPUT']

        params = {'INPUT':layer,
                'GROUP_BY':'"ETAGE_FINAL"',
                'AGGREGATES':[{'aggregate': 'concatenate_unique','delimiter': ',','input': '"notation"','length': 4000,'name': 'notation','precision': 0,'sub_type': 0,'type': 10,'type_name': 'text'},
                              {'aggregate': 'concatenate_unique','delimiter': ',','input': '"descr"','length': 4000,'name': 'descr','precision': 0,'sub_type': 0,'type': 10,'type_name': 'text'},
                              {'aggregate': 'concatenate_unique','delimiter': ',','input': '"ere"','length': 4000,'name': 'ere','precision': 0,'sub_type': 0,'type': 10,'type_name': 'text'},
                              {'aggregate': 'concatenate_unique','delimiter': ',','input': '"serie"','length': 4000,'name': 'serie','precision': 0,'sub_type': 0,'type': 10,'type_name': 'text'},
                              {'aggregate': 'concatenate_unique','delimiter': ',','input': '"etage"','length': 4000,'name': 'etage','precision': 0,'sub_type': 0,'type': 10,'type_name': 'text'},
                              {'aggregate': 'concatenate_unique','delimiter': ',','input': '"type_gite"','length': 4000,'name': 'type_gite','precision': 0,'sub_type': 0,'type': 10,'type_name': 'text'},
                              {'aggregate': 'concatenate_unique','delimiter': ',','input': '"nom_num_carte"','length': 4000,'name': 'nom_num_carte','precision': 0,'sub_type': 0,'type': 10,'type_name': 'text'},
                              {'aggregate': 'concatenate_unique','delimiter': ',','input': '"etage_final"','length': 4000,'name': 'etage_final','precision': 0,'sub_type': 0,'type': 10,'type_name': 'text'}],
                'INVALID_HANDLING': 2,
                'OUTPUT':'TEMPORARY_OUTPUT'}
        
        resulttemp = processing.run("native:aggregate", params)

        return resulttemp['OUTPUT']
    

    def Aggregation_simple(layer):
        """Merge the entities of a QgsVectorLayer, without taking into account the fields it contains in its attribute table
        
        :param layer: Layer to be aggregated
        :type layer: QgsVectorLayer

        :returns: Layer where entities have been combined into a single entity
        :rtypes: QgsVectorLayer
        """
        layer = processing.run("native:fixgeometries", {
                'INPUT': layer,
                'OUTPUT': 'memory:'
            })['OUTPUT']
        
        params = {'INPUT':layer,
                'GROUP_BY':'NULL',
                'AGGREGATES':[],
                'INVALID_HANDLING': 2,
                'OUTPUT':'TEMPORARY_OUTPUT'}
        
        resulttemp = processing.run("native:aggregate", params)
        
        return resulttemp['OUTPUT']
    

    def Centroide(layer):
        """Creating centroids within polygons

        :param layer: Layer of polygons used as a basis for centroids
        :type layer: QgsVectorLayer

        :returns: Layer containing centroids
        :rtypes: QgsVectorLayer
        """
        layer = processing.run("native:fixgeometries", {
                'INPUT': QgsProcessingFeatureSourceDefinition(layer.source(), 
                                                              selectedFeaturesOnly=True),
                'OUTPUT': 'memory:'
            })['OUTPUT']

        params={'INPUT':layer,
                'ALL_PARTS':False,
                'INVALID_HANDLING': 2,
                'OUTPUT':'TEMPORARY_OUTPUT'}
        
        resulttemp = processing.run("native:centroids", params)
        
        return resulttemp['OUTPUT']
    
    
    def VerticesExtraction(layer):
        """Extraction of polygon vertices
        
        :param layer: Layer of polygons whose vertices will be extracted
        :type layer: QgsVectorLayer

        :returns: Layer containing extracted vertices
        :rtypes: QgsVectorLayer
        """
        layer = processing.run("native:fixgeometries", {
                'INPUT': layer,
                'OUTPUT': 'memory:'
            })['OUTPUT']
        
        params = {'INPUT':layer,
                'INVALID_HANDLING': 2,
                'OUTPUT':'TEMPORARY_OUTPUT'}
        
        resulttemp = processing.run("native:extractvertices", params)
        return resulttemp['OUTPUT']
    

    def Reprojection(layer, SCR):
        """Vector layer reprojection tool
        
        :param layer: Vector layer to be reprojected
        :type layer: QgsVectorLayer
        
        :param SCR: SCR for reprojection
        :type SCR: int

        :returns: Reprojected layer
        :rtypes: QgsVectorLayer
        """
        layer = processing.run("native:fixgeometries", {
                'INPUT': layer,
                'OUTPUT': 'memory:'
            })['OUTPUT']
        
        params = {'INPUT':layer,
                'TARGET_CRS':QgsCoordinateReferenceSystem('EPSG:{}'.format(SCR)),
                'INVALID_HANDLING': 2,
                'OUTPUT':'TEMPORARY_OUTPUT'}
        
        resulttemps = processing.run("native:reprojectlayer", params)
        return resulttemps['OUTPUT']


    def Fusion_cleaner(layers):
        """Fusion of layers and clean to find duplicates

        :param layers: List of path to the layers to fuse
        :type layers: list

        :returns: Fused and cleaned layer
        :rtypes: QgsVectorLayer
        """        
        params = {'LAYERS':layers,
                  'CRS':None,
                  'INVALID_HANDLING': 2,
                  'OUTPUT':'TEMPORARY_OUTPUT',
                  'ADD_SOURCE_FIELDS':False}
        
        layer = processing.run("native:mergevectorlayers", params)['OUTPUT']

        params = {'INPUT': layer,
                  'INVALID_HANDLING': 2,
                  'OUTPUT':'TEMPORARY_OUTPUT'}
        
        resulttemps = processing.run("native:deleteduplicategeometries", params)
        return resulttemps['OUTPUT']


    def Centrality(self, layer):
        """Network centrality analysis using the v.net.centrality tool
        
        :param layer: Network to be analysed
        :type layer: QgsVectorLayer

        :returns: Layer of points containing centrality information
        :rtypes: QgsVectorLayer
        """
        if QgsApplication.processingRegistry().algorithmById("grass7:v.net.centrality"):
            self.v_GRASS = "grass7"
        else:
            self.v_GRASS = "grass"

        temp_dir = QgsProcessingUtils.tempFolder()
        temp_path = os.path.join(temp_dir, "Centralite_{}.gpkg".format(datetime.now().strftime("%H%M%S")))

        params = {
            'input': layer,
            'degree': 'degree',
            'closeness': 'closeness',
            'betweenness': 'betweenness',
            'eigenvector': 'eigenvector',
            'iterations': 1000,
            'error': 0.1,
            'cats': '',
            'where': '',
            'arc_column': '',
            'arc_backward_column': '',
            'node_column': '',
            '-a': True,
            '-g': False,
            'output': temp_path,
            'GRASS_REGION_PARAMETER': None,
            'GRASS_SNAP_TOLERANCE_PARAMETER': -1,
            'GRASS_MIN_AREA_PARAMETER': 0.0001,
            'GRASS_OUTPUT_TYPE_PARAMETER': 0,
            'GRASS_VECTOR_DSCO': '',
            'GRASS_VECTOR_LCO': '',
            'GRASS_VECTOR_EXPORT_NOCAT': False
        }

        result = processing.run(self.v_GRASS + ":v.net.centrality", params)

        grass_layer = QgsVectorLayer(result['output'], "Centralite_tmp", "ogr")

        if not grass_layer.isValid():
            raise Exception(Fonctions_QGIS.tr("Erreur lors du calcul de la centralité"))
        
        crs = grass_layer.crs().authid()
        final_layer = QgsVectorLayer(
            f"Point?crs={crs}",
            "Noeuds_reseau_centralite",
            "memory"
        )

        final_layer_data = final_layer.dataProvider()
        final_layer_data.addAttributes(grass_layer.fields())
        final_layer.updateFields()

        # Copie des entités
        final_layer_data.addFeatures(grass_layer.getFeatures())
        final_layer.updateExtents()
        QFile.remove(temp_path)
    
        return final_layer
    

    def NodesExtraction(self, layer):
        """Recovering network nodes using the v.net tool
        
        :param layer: Network to be analysed
        :type layer: QgsVectorLayer

        :returns: Layer of points containing the network nodes
        :rtypes: QgsVectorLayer
        """
        if QgsApplication.processingRegistry().algorithmById("grass7:v.net"):
            self.v_GRASS = "grass7"
        else:
            self.v_GRASS = "grass"

        temp_dir = QgsProcessingUtils.tempFolder()
        temp_path = os.path.join(temp_dir, "Noeuds_{}.gpkg".format(datetime.now().strftime("%H%M%S")))

        params = {
            'input': layer,
            'points': None,
            'file': '',
            'operation': 0,
            'threshold': 50,
            'arc_type': [0, 1],
            '-s': False,
            '-c': False,
            'output': temp_path,
            'GRASS_REGION_PARAMETER': None,
            'GRASS_SNAP_TOLERANCE_PARAMETER': -1,
            'GRASS_MIN_AREA_PARAMETER': 0.0001,
            'GRASS_OUTPUT_TYPE_PARAMETER': 0,
            'GRASS_VECTOR_DSCO': '',
            'GRASS_VECTOR_LCO': '',
            'GRASS_VECTOR_EXPORT_NOCAT': False
        }

        result = processing.run(self.v_GRASS + ":v.net", params)

        grass_layer = QgsVectorLayer(result['output'], "Noeuds_tmp", "ogr")

        if not grass_layer.isValid():
            raise Exception(Fonctions_QGIS.tr("Erreur lors de l’extraction des nœuds"))

        crs = grass_layer.crs().authid()
        final_layer = QgsVectorLayer(
            f"Point?crs={crs}",
            "Noeuds",
            "memory"
        )

        final_layer_data = final_layer.dataProvider()
        final_layer_data.addAttributes(grass_layer.fields())
        final_layer.updateFields()

        final_layer_data.addFeatures(grass_layer.getFeatures())
        final_layer.updateExtents()
        QFile.remove(temp_path)
    
        return final_layer


    def PathExtraction(network, start, end):
        """Finding the shortest path in a network between two points

        :param network: Network to analysed
        :type network: QgsVectorLayer

        :param start: Starting point ('X,Y [EPSG:xxxx]')
        :type start: str

        :param end: Arrival point ('X,Y [EPSG:xxxx]')
        :type end: str

        :returns: Shortest route identified (QgsVectorLayer)
        :rtypes: QgsVectorLayer
        """
        params = {'INPUT':network,
                'STRATEGY':1,
                'DEFAULT_DIRECTION':2,
                'SPEED_FIELD':'',
                'DEFAULT_SPEED':6,
                'TOLERANCE':50,
                'START_POINT':start,
                'END_POINT':end,
                'OUTPUT':'TEMPORARY_OUTPUT'}
        
        resulttemps = processing.run("native:shortestpathpointtopoint", params)
        return resulttemps['OUTPUT']


    def ShortestPath(network_layer, start_xy, end_xy, cost_field):
        """
        Shortest path in terms of time in a network using GRASS v.net.path tool

        :param network_layer: Network to analysed
        :type network_layer: QgsVectorLayer

        :param start_xy: Starting point ('X,Y [EPSG:xxxx]')
        :type start: str

        :param end_xy: Arrival point ('X,Y [EPSG:xxxx]')
        :type start: str

        :param cost_field: Name of the field in the layer containing the time to travel
        :type cost_field: str

        :returns: Fastest route identified
        :rtypes: QgsVectorLayer
        """
        if QgsApplication.processingRegistry().algorithmById("grass7:v.net"):
            vpath_id = "grass7"
        else:
            vpath_id = "grass"


        # Couche points (centers)
        crs = network_layer.crs()
        pts = QgsVectorLayer(f"Point?crs={crs.authid()}", "centers", "memory")
        pr = pts.dataProvider()
        pr.addAttributes([QgsField("id", QVariant.Int)])
        pts.updateFields()

        f1 = QgsFeature(pts.fields())
        f1["id"] = 1
        f1.setGeometry(QgsGeometry.fromPointXY(QgsPointXY(*start_xy)))

        f2 = QgsFeature(pts.fields())
        f2["id"] = 2
        f2.setGeometry(QgsGeometry.fromPointXY(QgsPointXY(*end_xy)))

        pr.addFeatures([f1, f2])
        pts.updateExtents()

        tmp_dir = QgsProcessingUtils.tempFolder()
        with tempfile.NamedTemporaryFile("w", delete=False, dir=tmp_dir, suffix=".txt") as f:
            f.write(f"1 {start_xy[0]} {start_xy[1]} {end_xy[0]} {end_xy[1]}\n")
            coords_file = f.name

        e = network_layer.extent()
        region = f"{e.xMinimum()},{e.xMaximum()},{e.yMinimum()},{e.yMaximum()}"

        out_path = QgsProcessingUtils.generateTempFilename("vnet_path.gpkg")

        params = {
            "input": network_layer,
            "points": pts,
            "file": coords_file,
            "threshold": 15000,
            "dmax": 15000,
            "arc_type": 0,
            "arc_layer": 1,
            "node_layer": 2,
            "arc_column": cost_field,
            "arc_backward_column": cost_field,
            "output": out_path,
            "GRASS_REGION_PARAMETER": region,
            "GRASS_SNAP_TOLERANCE_PARAMETER": 0,
            "GRASS_MIN_AREA_PARAMETER": 0.0001,
            "GRASS_OUTPUT_TYPE_PARAMETER": 2
        }

        res = processing.run(vpath_id+":v.net.path", params)

        disk_layer = QgsVectorLayer(res["output"], "vnet_path_tmp", "ogr")

        resulttemps = QgsVectorLayer(f"LineString?crs={crs.authid()}", "vnet_path", "memory")
        prov = resulttemps.dataProvider()
        prov.addAttributes(disk_layer.fields())
        resulttemps.updateFields()
        prov.addFeatures(disk_layer.getFeatures())
        resulttemps.updateExtents()

        try:
            os.remove(coords_file)
            os.remove(out_path)
        except Exception:
            pass

        return resulttemps
    

    def PathReconstruction(layer, network):
        """Selection by location in a network of the links used to create the path
        
        :param layer: Layer with the path extracted
        :type layer: QgsVectorLayer

        :param intersect: Layer with the network
        :type intersect: QgsVectorLayer

        :returns: Links composing the path (QgsVectorLayer)
        :rtypes: QgsVectorLayer
        """
        params = {'INPUT':layer,
                  'DISTANCE':5,
                  'SEGMENTS':5,
                  'END_CAP_STYLE':0,
                  'JOIN_STYLE':0,
                  'MITER_LIMIT':2,
                  'DISSOLVE':False,
                  'SEPARATE_DISJOINT':False,
                  'OUTPUT':'TEMPORARY_OUTPUT'}
        resulttemps = processing.run("native:buffer", params)['OUTPUT']

        params = {'INPUT':network,
                  'PREDICATE':[6],
                  'INTERSECT':resulttemps,
                  'METHOD':0,
                  'OUTPUT':'TEMPORARY_OUTPUT'}
        resulttemps = processing.run("native:extractbylocation", params)['OUTPUT']


        return resulttemps

    def SelectEqual(layer, intersect, method):
        """Selection by location using selected entities in a layer to obtain entities with identical geometry
        
        :param layer: Layer to modify
        :type layer: QgsVectorLayer

        :param intersect: Layer used for comparison
        :type intersect: QgsVectorLayer

        :param method: 0 = New selection, 1 = Add to selection, 2 = Select from selection, 3 = Remove from selection
        :type method: int
        """
        params = {'INPUT':layer,
                'PREDICATE':[3],
                'INTERSECT':intersect,
                'METHOD':method}
        processing.run("native:selectbylocation", params)


    def Extremities(layer):
        """Recovering the first and last points of lines in a layer

        :param layer: Layer from which the ends of entities must be selected
        :type layer: QgsVectorLayer

        :returns first: First point
        :returns last: Last point
        :rtypes coords_start: QgsVectorLayer, QgsVectorLayer
        """
        params = {'INPUT':layer,
                 'VERTICES':'0',
                 'OUTPUT':'TEMPORARY_OUTPUT'}
        
        resulttemps = processing.run("native:extractspecificvertices", params)
        first = resulttemps['OUTPUT']

        params = {'INPUT':layer,
                 'VERTICES':'-1',
                 'OUTPUT':'TEMPORARY_OUTPUT'}
        resulttemps = processing.run("native:extractspecificvertices", params)
        last = resulttemps['OUTPUT']

        return first, last
    
    
    def Extraction(layer):
        """Extracting selected feature in layer

        :param layer: Layer from which the ends of entities must be extracted
        :type layer: QgsVectorLayer

        :returns layer: Last point
        :rtypes layer: QgsVectorLayer
        """
        params = {'INPUT':layer,
                  'OUTPUT':'TEMPORARY_OUTPUT'}
        resulttemp = processing.run("native:saveselectedfeatures", params)

        return resulttemp['OUTPUT']

    def ClosestFurthestPoints(polygons_layer, point_layer, make_closest=False, make_furthest=False):
        """
            Research of the closest or furthest point of polygon(s) from a reference point

            :param polygons_layer: Layer containing the polygon(s) to simplify
            :type polygons_layer: QgsVectorLayer

            :param polygons_layer: Layer containing the polygon(s) to simplify
            :type polygons_layer: QgsVectorLayer

            :param c: Creation of the layer with the closest points
            :param c: bool

            :param f: Creation of the layer with the furthest points
            :param f: bool

            :returns: Laer with all the closest or furthest points
            :rtypes: QgsVectorLayer
            """
        
        closest = None
        furthest = None

        # Fixing the geometries 
        polygons_layer = processing.run("native:fixgeometries", {
                'INPUT': QgsProcessingFeatureSourceDefinition(polygons_layer.source(), 
                                                            selectedFeaturesOnly=True),
                'OUTPUT': 'memory:'})['OUTPUT']

        # Reprojection if necessary
        if polygons_layer.crs() != point_layer.crs():        
            polygons_layer = processing.run(
                "native:reprojectlayer", 
                {'INPUT':polygons_layer,
                'TARGET_CRS':point_layer.crs(),
                'INVALID_HANDLING': 2,
                'OUTPUT':'TEMPORARY_OUTPUT'}
            )['OUTPUT']

        # Creation of a layer for the clostest/furthest points
        if make_closest:
            name = Fonctions_QGIS.tr("Points_+_Proche_de_{}").format(point_layer.name())
            closest = QgsVectorLayer(f"Point?crs={point_layer.crs().authid()}", name, "memory")
            prc = closest.dataProvider()
            prc.addAttributes([QgsField("id", QVariant.Int), 
                            QgsField("id_origine", QVariant.String), 
                            QgsField("distance", QVariant.Double)])
            closest.updateFields()

        if make_furthest:
            name = Fonctions_QGIS.tr("Points_+_Eloigne_de_{}").format(point_layer.name())
            furthest = QgsVectorLayer(f"Point?crs={point_layer.crs().authid()}", name, "memory")
            prf = furthest.dataProvider()
            prf.addAttributes([QgsField("id", QVariant.Int), 
                            QgsField("id_origine", QVariant.String), 
                            QgsField("distance", QVariant.Double)])
            furthest.updateFields()

        # Creation of a temporary layer to perform the analysis
        tempo = QgsVectorLayer(f"Polygon?crs={point_layer.crs().authid()}", 'Tempo', "memory")
        tempo_provider = tempo.dataProvider()
        attr = polygons_layer.dataProvider().fields().toList()
        tempo_provider.addAttributes(attr)
        tempo.updateFields()

        id = 0
        polygons = polygons_layer.getFeatures()
        # Looping on all the polygons to transform
        for polygon in polygons:
            tempo_provider.addFeature(polygon)

            vertices = processing.run(
                "native:extractvertices",
                {"INPUT": tempo, "OUTPUT": "memory:"}
            )["OUTPUT"]

            # Creating a value to initialise the search
            dist_min = 0
            dist_max = 0

            xa = point_layer.selectedFeatures()[0].geometry().asPoint()[0]
            ya = point_layer.selectedFeatures()[0].geometry().asPoint()[1]

            """Search all the vertices of the transformed polygon"""
            for vertex in vertices.getFeatures():
                # Retrieving vertex coordinates
                xb = vertex.geometry().asPoint()[0]
                yb = vertex.geometry().asPoint()[1]

                # Calculation of the distance separating the vertex from the origin of the LCP
                dist=(((xa - xb)**2) + ((ya - yb)**2))**0.5

                # Checking whether it is furthest or closest to the origin of the LCP
                if (dist < dist_min or dist_min == 0) and make_closest:
                    feat_min = vertex
                    dist_min = dist
                if (dist > dist_max or dist_max == 0) and make_furthest:
                    feat_max = vertex
                    dist_max = dist
            
            id_origin = polygon.attributes()[0]
            distance_value = dist_min

            if make_closest:
                new_feat = QgsFeature()
                new_feat.setGeometry(feat_min.geometry())
                new_feat.setAttributes([id, str(id_origin), distance_value])
                prc.addFeatures([new_feat])
                closest.updateExtents()

            if make_furthest:
                new_feat = QgsFeature()
                new_feat.setGeometry(feat_max.geometry())
                new_feat.setAttributes([id, str(id_origin), distance_value])
                prf.addFeatures([new_feat])
                furthest.updateExtents()

            id += 1
            tempo_provider.truncate()

        return closest, furthest
    