"""
Fonctions qualifiables comme utilitaires, utilisables par les différents outils du module
"""
import os

from qgis import *
from qgis.PyQt import *
from qgis.core import *
from qgis.utils import *
from PyQt5.QtGui import *
from PyQt5.QtCore import *
from PyQt5.QtWidgets import *
from PyQt5.QtCore import *
from processing.tools import dataobjects
from distutils.dir_util import copy_tree
from processing.tools.system import mkdir, userFolder
import processing

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


    def progression(bar, label, message, percent):
        """
        Input:  bar (QgsProgessBar) = bar to update
                label (str) = text to modify in order to give informations
                message (str) = message to display 
                percent (int) = advancement's percent
        Function: Updating a loading bar according to stages
        """
        # Reset the bar to 0 to make it easier to go back and forth through the stages
        bar.setValue(0)
        # Changing the progress bar message
        label.setText(message)
        # Function to move the loading bar forward
        completed = 0
        while completed < percent:
            completed += 1
            bar.setValue(completed)


    def add_layers():
        """
        Function: Automatic addition of vector layers when using the module
        """
        n=1
        names_list = ["Communes", "Departements", "Regions_Naturelles"]
        for nom in names_list :
            # Check that one of the layers is not already loaded
            if not QgsProject.instance().mapLayersByName(str(n)+" - "+ nom):
                # Access to the layer in the module folder
                path = os.path.dirname(os.path.abspath(__file__))
                path = path.replace('Fonctions', 'Couches//{}.shp'.format(nom))
                layer = QgsVectorLayer(path,str(n)+" - "+ nom, "ogr")
                # Layer style definition
                style_path = os.path.dirname(os.path.abspath(__file__))
                style_path = style_path.replace('Fonctions', 'Styles//{}.qml'.format(nom))
                layer.loadNamedStyle(style_path)
                # Adding the layer to the map
                QgsProject.instance().addMapLayer(layer)
            n = n + 1


    def layer_finder(ComboBox):
        """
        Input: ComboBox (QgsComboBox) = Drop-down list of the layer to be retrieved from
        Function: Select a layer from the name selected in a drop-down list
        """
        name = ComboBox.currentText()
        # Select the layer by name
        layer = QgsProject.instance().mapLayersByName(name)[0]
        return layer
    

    def prepare_wfs(self, name):
        """
        Input: name (str) = Name of the department used to load the corresponding WFS feed from the GDR SILEX
        Function: Loading WFS flows from the GDR SILEX based on a department name
        """
        # print("Task") # debugtest
        # Correction and standardisation of department names for use in a url
        nom_corr = name.replace("-","_").replace(" ","_").replace("è","%C3%A8").replace("é","%C3%A9").replace("ô","%C3%B4")
        # print(nom_corr) # debudtest
        # Preparing the loading parameters for the WFS stream
        uri = QgsDataSourceUri()
        url = 'https://services3.arcgis.com/zy1UGXGNCAGm516O/arcgis/rest/services/Formations_{}/FeatureServer/0'.format(nom_corr)
        # print(url) # debudtest
        uri.setParam('url', url)
        uri.setSrid('EPSG:3857')
        layer = QgsVectorLayer(uri.uri(), "{}".format(name) , 'arcgisfeatureserver')
        if layer.isValid():
            QgsSettings().setValue("/qgis/wfs/useCachedFeatureDownload", True)
            iface.setRenderFlag(False)
            # Ajout de la couche à la carte
            QgsProject.instance().addMapLayer(layer)
            # Création d'un index spatial pour faciliter les recherches par localisation
            layer.dataProvider().createSpatialIndex()
            # Ne pas afficher les entités de la couche pour limiter les calcules
            QgsProject.instance().layerTreeRoot().findLayer(layer.id()).setItemVisibilityChecked(False)
            # Définition du style de la couche
            style_path = os.path.dirname(os.path.abspath(__file__))
            style_path = style_path.replace('Fonctions','Styles//Legende_CODE_HEXA_ETAGE_FINAL_vEV.qml')
            if os.path.exists(style_path):
                layer.loadNamedStyle(style_path)
            else:
                pass
            iface.setRenderFlag(True)
        else:
            print('Invalid layer: failed to add layer') # debudtest

    
    def layer_creation(self, type, EPSG, name, reference):
        """
        Input:  type (str) = Vector type (Point, LineString, Polygon)
                EPSG (int) = Layer projection system
                name (str) = Name of the output layer
                reference (str) = Layer used as a model for attribute table columns
        Function: Creating a layer from a reference model
        Output: New layer created (QgsVectorLayer)
        """
        # Layer creation
        new_layer=QgsVectorLayer("{}?crs=epsg:{}".format(type,EPSG), name, "memory")
        Layer_data = new_layer.dataProvider()
        # Retrieving columns from the attribute table of the reference layer
        attr = reference.dataProvider().fields().toList()
        # Updating the columns in the new layer
        Layer_data.addAttributes(attr)
        new_layer.updateFields()
        # Adding the layer to the map
        QgsProject.instance().addMapLayer(new_layer)
        return new_layer
    

    def closest_point(self, reference, nodes):
        """
        Input:  reference (QgsFeature) = Reference point
                nodes (list of QgsFeature) = Set of points to compare
        Function: Find the closest node in a network to a reference point
        Output: Closest point to the reference point (QgsFeature)
        """
        xa = reference.geometry().asPoint()[0]
        ya = reference.geometry().asPoint()[1]
        # Creating a value to initialise the search
        dist_min = 0
        # Search all the vertices of the transformed polygon
        if isinstance(nodes, list):
            for vertice in nodes:
                # Retrieving vertex coordinates
                xb = vertice.geometry().asPoint()[0]
                yb = vertice.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:
                    feat_min = vertice
                    dist_min = dist
        else:
            for vertice in nodes.getFeatures():
                # Retrieving vertex coordinates
                xb = vertice.geometry().asPoint()[0]
                yb = vertice.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:
                    feat_min = vertice
                    dist_min = dist
        return feat_min
    

    def furthest_point(self,reference,nodes):
        """
        Input:  reference (QgsFeature) = Reference point
                nodes (list of QgsFeature) = Set of points to compare
        Function: Find the furthest node in a network to a reference point
        Output: Furthest point from the reference (QgsFeature)
        """
        xa = reference.geometry().asPoint()[0]
        ya = reference.geometry().asPoint()[1]
        # Creating a value to initialise the search
        dist_max = 0
        # Search all the vertices of the transformed polygon
        if isinstance(nodes, list):
            for vertice in nodes:
                # Retrieving vertex coordinates
                xb = vertice.geometry().asPoint()[0]
                yb = vertice.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_max or dist_max == 0 :
                    feat_max = vertice
                    dist_max = dist
        else:
            for vertice in nodes.getFeatures() :
                # Retrieving vertex coordinates
                xb = vertice.geometry().asPoint()[0]
                yb = vertice.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_max or dist_max == 0 :
                    feat_max = vertice
                    dist_max = dist
        return feat_max