# -*- coding: utf-8 -*-
"""
Module Flux Editor pour le plugin CenRA_FLUX
Permet de gérer et charger des couches depuis les bases de données PostGIS (SIG et REF)
"""

from __future__ import absolute_import
# Import des bibliothèques PyQt et QGIS
from builtins import str

from qgis.PyQt import QtCore, QtGui
from qgis.PyQt.QtCore import QSettings
from qgis.PyQt import QtWidgets
from qgis.PyQt.QtGui import QIcon
import os

from qgis.core import (
    QgsDataSourceUri,
    QgsCoordinateReferenceSystem,
    QgsCoordinateTransform,
    QgsProject,
    QgsSettings,
    QgsApplication,
    QgsVectorLayer,
    QgsRasterLayer,
    QgsWkbTypes
)
from qgis.PyQt.QtWidgets import (
    QDialog,
    QPushButton,
    QInputDialog,
    QTableWidgetItem,
    QMessageBox,
    QVBoxLayout,
)
from .tools.SQLRequet import schemaname_list, schemaname_list_ref, schemaname_distinct
from .tools.resources import (
    load_ui,
    resources_path,
)
try:
    if os.path.exists('N:'):
        from .tools.PythonSQL import login_base
except NameError:
    print('Pas de fichier PythonSQL')

from qgis.utils import iface
import psycopg2
import psycopg2.extras

# Variable globale pour le mode debug
global DeBUG
DeBUG = 0

# Création des icônes pour les couches raster et vecteur
itemIconRaster = QTableWidgetItem()
icon = QIcon()
icon.addPixmap(QtGui.QPixmap(resources_path('icons', 'mIconRaster.svg')), QIcon.Mode(0), QIcon.State(1))
itemIconRaster.setIcon(icon)

itemIconVecteur = QTableWidgetItem()
icon = QIcon()
icon.addPixmap(QtGui.QPixmap(resources_path('icons', 'mIconVecteur.svg')), QIcon.Mode(0), QIcon.State(1))
itemIconVecteur.setIcon(icon)

# Récupération des informations de connexion à la base de données
try:
    account = login_base('account')
    user = account[0]       # Nom d'utilisateur
    user_save = account[0]  # Nom d'utilisateur sauvegarde
    mdp = account[1]        # Mot de passe
    mdp_save = account[1]   # Mot de passe sauvegard
    host = account[2]       # Hôte de la base de données
    port = account[3]       # Port de connexion
    dbname = account[4]     # Nom de la base de données
    sigdb = account[5]      # Base de données SIG
    refdb = account[6]      # Base de données REF


except NameError:
    print('Fails to login DB for account')

# Chargement de l'interface utilisateur depuis le fichier .ui
EDITOR_CLASS = load_ui('CenRa_Flux_base.ui')

# Configuration des systèmes de coordonnées de référence (CRS)
targetCrs = QgsCoordinateReferenceSystem('EPSG:4326')  # WGS84 (coordonnées géographiques)
layerCrs = QgsCoordinateReferenceSystem('EPSG:2154')   # Lambert 93 (projection française)
TranformCRS = QgsCoordinateTransform(layerCrs, targetCrs, QgsProject.instance())


class Flux_Editor(QDialog, EDITOR_CLASS):
    """
    Classe principale de l'éditeur de flux
    Gère l'interface de sélection et de chargement des couches depuis les bases de données
    """

    def __init__(self, parent=None):
        """Initialisation de l'interface et des composants"""
        _ = parent
        super().__init__()
        self.setupUi(self)
        self.settings = QgsSettings()
        self.s = QSettings()
        self.setWindowIcon(QtGui.QIcon(resources_path('icons', 'icon.png')))
        self.first_start = None
        self.iface = iface
        # Configuration des éléments visuels de l'interface
        self.label_3.setPixmap(QtGui.QPixmap(resources_path('ui', 'logo.png')))
        self.commandLinkButton.setIcon(QtGui.QIcon(resources_path('ui', 'arrow-bottom.png')))
        self.commandLinkButton_2.setIcon(QtGui.QIcon(resources_path('ui', 'arrow-up.png')))

        # Configuration du tableau des couches disponibles
        self.tableWidget.setEditTriggers(QtWidgets.QAbstractItemView.EditTrigger(0))
        self.toolButton.setIcon(QtGui.QIcon(resources_path('ui', 'find.png')))
        self.toolButton_2.setIcon(QtGui.QIcon(resources_path('ui', 'star.png')))
        # Ajout des options de base de données (SIG ou REF)
        self.comboBox_2.addItem("SIG")
        self.comboBox_2.addItem('REF')

        # Connexion des signaux aux slots (événements de l'interface)
        self.commandLinkButton.clicked.connect(self.selection_flux)           # Bouton de sélection de flux
        self.tableWidget.itemDoubleClicked.connect(self.selection_flux)       # Double-clic sur une couche
        self.pushButton_2.clicked.connect(self.limite_flux)                   # Bouton de chargement
        self.commandLinkButton_2.clicked.connect(self.suppression_flux)       # Bouton de suppression
        self.tableWidget_2.itemDoubleClicked.connect(self.suppression_flux)   # Double-clic pour supprimer
        self.comboBox_2.currentIndexChanged.connect(self.bd_source)           # Changement de base de données
        self.checkBox.hide()
        self.toolButton.clicked.connect(self.getCanevas)                      # Filtrer par emprise du canevas
        self.toolButton.setToolTip('Filtrer uniquement les couche Contour/Habitat/Travaux \nqui ce trouve dans le canvas de la carte.')
        self.toolButton_2.clicked.connect(self.filtre_favorit)                # Filtrer par favoris
        self.toolButton_2.setToolTip('Afficher uniquement les favoris.')
        layout = QVBoxLayout()
        self.lineEdit.textChanged.connect(self.filtre_dynamique)              # Recherche dynamique
        layout.addWidget(self.lineEdit)
        self.viewer.hide()
        # Configuration du menu de debug (caché par défaut)
        self.DeBUG.addItem('')
        self.DeBUG.addItem('Dev')
        self.DeBUG.addItem('01')
        self.DeBUG.addItem('0726')
        self.DeBUG.addItem('4269')
        self.comboBox.currentIndexChanged.connect(self.initialisation_flux)

        self.DeBUG.currentIndexChanged.connect(self.SwitchDEBUG)
        self.DeBUG.hide()  # Menu debug caché par défaut

    def raise_(self):
        """Run method that performs all the real work"""
        self.bd_source()

    def SwitchDEBUG(self):
        """Change les paramètres de connexion selon le mode debug sélectionné"""
        try:
            global user, mdp, host, port, dbname, sigdb, refdb
            account = login_base(self.DeBUG.currentText())
            user = account[0]
            mdp = account[1]
            host = account[2]
            port = account[3]
            dbname = account[4]
            sigdb = account[5]
            refdb = account[6]
            self.bd_source()

        except NameError:
            print('Fails to switch DB for account')

    def ModeDeBUG(self):
        self.DeBUG.show()

    def mousePressEvent(self, event):
        """Détecte les clics sur le logo pour activer le mode debug (3 clics consécutifs)"""
        global DeBUG
        # Zone du logo (coordonnées x: 330-560, y: 5-75)
        if 330 <= event.pos().x() <= 560 and 5 <= event.pos().y() <= 75:
            DeBUG = DeBUG + 1
            if DeBUG == 3:  # Activation après 3 clics
                DeBUG = 0
                self.ModeDeBUG()
        else:
            DeBUG = 0
            self.DeBUG.hide()

    def bd_source(self):
        global user, mdp
        if user != user_save or mdp != mdp_save:
            user = user_save
            mdp = mdp_save
        """Sélectionne la base de données source (SIG ou REF)"""
        self.activateWindow()
        bd_origine = self.comboBox_2.currentText()
        if bd_origine == 'REF':
            self.run_ref()  # Connexion à la base REF
        if bd_origine == 'SIG':
            self.run_sig()  # Connexion à la base SIG

    def run_ref(self):
        """Initialise la connexion à la base de données REF"""
        # Vider le tableau des flux sélectionnés
        while self.tableWidget_2.rowCount() > 0:
            self.tableWidget_2.removeRow(self.tableWidget_2.rowCount() - 1)

        global cur, con, dbtype
        dbtype = refdb
        # Connexion à la base de données REF
        con = psycopg2.connect("host=" + host + " port=" + port + " dbname=" + dbtype + " user=" + user + " password=" + mdp)
        cur = con.cursor(cursor_factory=psycopg2.extras.DictCursor)
        self.combobox_custom()
        self.initialisation_flux()
        # Create the dialog with elements (after translation) and keep reference
        # Only create GUI ONCE in callback, so that it will only load when the plugin is started
        if self.first_start is True:
            self.first_start = False
        # show the dialog
        self.show()
        # Run the dialog event loop
        result = self.exec()
        if result:
            pass

    def run_sig(self):
        """Initialise la connexion à la base de données SIG"""
        # Vider le tableau des flux sélectionnés
        while self.tableWidget_2.rowCount() > 0:
            self.tableWidget_2.removeRow(self.tableWidget_2.rowCount() - 1)
        global cur, con, dbtype
        dbtype = sigdb
        # Connexion à la base de données SIG
        con = psycopg2.connect("host=" + host + " port=" + port + " dbname=" + dbtype + " user=" + user + " password=" + mdp)
        cur = con.cursor(cursor_factory=psycopg2.extras.DictCursor)
        self.combobox_custom()
        self.initialisation_flux()

        if self.first_start is True:
            self.first_start = False

    def suppression_flux(self):
        self.tableWidget_2.removeRow(self.tableWidget_2.currentRow())

    def AddOrDelToUserFav(self):
        """Ajoute ou supprime une couche des favoris de l'utilisateur"""
        selected_items = self.tableWidget.selectedItems()
        favorit_statut = selected_items[4].text()  # 0 = non favori, 1 = favori

        selected_items[4].tableWidget().removeCellWidget(selected_items[4].row(), 4)

        schema_name = selected_items[2].text()
        table_name = selected_items[3].text()

        # Ajout aux favoris
        if favorit_statut == "0":
            FAV = "mStarIconDel.png"  # Icône étoile pleine
            selected_items[4].setText("1")
            # Requête SQL pour ajouter aux favoris
            SQLAddFav = """INSERT INTO admin_sig.favtable (utilisateur, schema_name, table_name) VALUES ('""" + user + "','" + schema_name + "','" + table_name + """');"""
            if dbtype == sigdb:
                cur.execute(SQLAddFav)
                con.commit()
            else:
                conSIG = psycopg2.connect("host=" + host + " port=" + port + " dbname=" + sigdb + " user=" + user + " password=" + mdp)
                curSIG = conSIG.cursor(cursor_factory=psycopg2.extras.DictCursor)
                curSIG.execute(SQLAddFav)
                conSIG.commit()
                conSIG.close()

        # Suppression des favoris
        else:
            FAV = "mStarIconAdd.png"  # Icône étoile vide
            selected_items[4].setText("0")
            # Requête SQL pour supprimer des favoris
            SQLDelFav = """DELETE FROM admin_sig.favtable WHERE utilisateur LIKE '""" + user + """' AND schema_name LIKE '""" + schema_name + """' AND table_name LIKE '""" + table_name + """';"""
            if dbtype == sigdb:
                cur.execute(SQLDelFav)
                con.commit()
            else:
                conSIG = psycopg2.connect("host=" + host + " port=" + port + " dbname=" + sigdb + " user=" + user + " password=" + mdp)
                curSIG = conSIG.cursor(cursor_factory=psycopg2.extras.DictCursor)
                curSIG.execute(SQLDelFav)
                conSIG.commit()
                conSIG.close()

        iconFav = QIcon()
        iconFav.addPixmap(QtGui.QPixmap(resources_path('icons', FAV)), QIcon.Mode(0), QIcon.State(1))
        self.FavButton = QPushButton(iconFav, "")
        selected_items[4].tableWidget().setCellWidget(selected_items[4].row(), 4, self.FavButton)
        self.FavButton.clicked.connect(self.AddOrDelToUserFav)

    def initialisation_flux(self):
        """Initialise et remplit le tableau des couches disponibles"""
        if self.toolButton_2.text() == "1":
            self.filtre_favorit(None)
        self.tableWidget.clear()
        if NoSignals == 0:  # Éviter les boucles infinies lors des mises à jour
            if dbtype == sigdb:
                if self.comboBox.currentText() == 'toutes les catégories':
                    custom_list = schemaname_list
                elif self.comboBox.currentText() == 'travaux':
                    custom_list = schemaname_list[:-2] + """
                    WHERE schemaname LIKE '""" + str(self.comboBox.currentText()) + """%';
                    """
                else:
                    custom_list = schemaname_list[:-2] + """
                    WHERE schemaname LIKE '_""" + str(self.comboBox.currentText()) + """%';
                    """
            else:
                if self.comboBox.currentText() == 'toutes les catégories':
                    custom_list = schemaname_list_ref
                else:
                    custom_list = schemaname_list_ref[:-2] + """
                    WHERE schemaname LIKE '""" + str(self.comboBox.currentText()) + """%' AND tablename NOT LIKE 'qgis_projects';
                    """
            cur.execute(custom_list)
            list_schema = cur.fetchall()

            # Vérification de la présence de couches raster dans la base
            SQLcountRaster = """SELECT schemaname,viewname FROM pg_catalog.pg_views
            WHERE schemaname LIKE 'public' AND viewname LIKE 'raster_columns';"""
            cur.execute(SQLcountRaster)
            RasterIF = len(cur.fetchall())

            # Récupération de la liste des couches raster si disponibles
            if RasterIF == 1:
                SQLloadRaster = """SELECT concat(r_table_schema,'.',r_table_name) from public.raster_columns; """
                cur.execute(SQLloadRaster)
                list_raster = cur.fetchall()
                RasterList = []
                for rasterFind in list_raster:
                    RasterList.append(rasterFind[0])
            else:
                RasterList = []

            # Récupération des projets QGIS stockés dans la base de données
            SQLprojects = """SELECT schemaname, tablename FROM pg_catalog.pg_tables WHERE tablename LIKE 'qgis_projects'"""
            cur.execute(SQLprojects)
            list_projects = cur.fetchall()
            list_projects_qgis = []
            if len(list_projects) <= 1:
                for ProjectName in list_projects:
                    SQLProjectsQgis = """SELECT name, metadata, content FROM """ + '"' + ProjectName[0] + '"."' + ProjectName[1] + '"'
                    cur.execute(SQLProjectsQgis)
                    list_projects_qgis.append(cur.fetchall())

            # Récupération des droits d'accès de l'utilisateur sur les tables
            SQLGrands = """
                WITH t as (SELECT
                    n.nspname AS table_schema,
                    c.relname AS table_name,
                    r.rolname AS grantee,
                    CASE
                        WHEN acl_text LIKE '%r%' THEN 'SELECT'
                        WHEN acl_text LIKE '%w%' THEN 'UPDATE'
                        WHEN acl_text LIKE '%a%' THEN 'INSERT'
                        WHEN acl_text LIKE '%d%' THEN 'DELETE'
                        WHEN acl_text LIKE '%x%' THEN 'REFERENCES'
                        ELSE 'OTHER'
                    END AS privilege_type
                FROM pg_class c
                JOIN pg_namespace n ON n.oid = c.relnamespace
                LEFT JOIN LATERAL unnest(c.relacl) AS acl_item(acl) ON TRUE
                LEFT JOIN LATERAL (
                    SELECT acl::text AS acl_text,
                        split_part(acl::text, '=', 1) AS grantee_name
                ) priv ON TRUE
                LEFT JOIN pg_roles r ON r.rolname = priv.grantee_name
                WHERE c.relkind IN ('r', 'v','m'))
                """
            if self.comboBox.currentText() == 'toutes les catégories':
                SQLGrands = SQLGrands + """SELECT concat(table_schema,'.',table_name) FROM t WHERE grantee in(SELECT rolname FROM pg_catalog.pg_roles WHERE oid in(SELECT roleid FROM pg_auth_members WHERE member = (SELECT usesysid FROM pg_catalog.pg_user WHERE usename = '""" + user + """'))) and privilege_type = 'SELECT';"""
            else:
                if dbtype == sigdb:
                    SQLGrands = SQLGrands + """SELECT concat(table_schema,'.',table_name) FROM t WHERE grantee in(SELECT rolname FROM pg_catalog.pg_roles WHERE oid in(SELECT roleid FROM pg_auth_members WHERE member = (SELECT usesysid FROM pg_catalog.pg_user WHERE usename = '""" + user + """'))) and privilege_type = 'SELECT' AND table_schema LIKE '_""" + str(self.comboBox.currentText()) + """_%';"""
                elif dbtype == refdb:
                    SQLGrands = SQLGrands + """SELECT concat(table_schema,'.',table_name) FROM t WHERE grantee in(SELECT rolname FROM pg_catalog.pg_roles WHERE oid in(SELECT roleid FROM pg_auth_members WHERE member = (SELECT usesysid FROM pg_catalog.pg_user WHERE usename = '""" + user + """'))) and privilege_type = 'SELECT' AND table_schema LIKE '""" + str(self.comboBox.currentText()) + """%';"""
            cur.execute(SQLGrands)
            list_grands = cur.fetchall()
            GrandUser = []
            for grandsFind in list_grands:
                GrandUser.append(grandsFind[0])

            # Récupération de la liste des favoris de l'utilisateur
            SQLFavTable = "SELECT concat(schema_name, '.', table_name) FROM admin_sig.favtable WHERE utilisateur LIKE '" + user + "';"
            if dbtype == refdb:
                conSIG = psycopg2.connect("host=" + host + " port=" + port + " dbname=" + sigdb + " user=" + user + " password=" + mdp)
                curSIG = conSIG.cursor(cursor_factory=psycopg2.extras.DictCursor)
                curSIG.execute(SQLFavTable)
                list_fav = curSIG.fetchall()
                conSIG.close()
                print('SIG')
            else:
                cur.execute(SQLFavTable)
                list_fav = cur.fetchall()
            FavList = []
            for favFind in list_fav:
                FavList.append(favFind[0])

            # Remplissage du tableau avec les couches disponibles
            self.tableWidget.setRowCount(len(list_schema))
            self.tableWidget.setColumnCount(5)
            i = 0
            for value in list_schema:
                MetadataXML = value[2]
                if dbtype == sigdb:
                    type_val = str(value[0])[1:3]
                    schema_name = str(value[0])[4:]
                    table_name = str(value[1][len(value[0]) + 1:])
                    if value[0] == value[1][:len(value[0])]:
                        table_name = str(value[1][len(value[0]) + 1:])
                    else:
                        table_name = str(value[1])
                    if type_val == "00":
                        table_name = value[1]
                else:
                    type_val = ''
                    schema_name = str(value[0])
                    table_name = str(value[1])
                if type_val == 'fo':
                    type_val = str(value[0])[1:5]
                    schema_name = str(value[0])[6:]
                    if value[0] == value[1][:len(value[0])]:
                        table_name = str(value[1][len(value[0]) + 1:])
                    else:
                        table_name = str(value[1])
                elif type_val == 'ra':
                    type_val = 'travaux'
                    schema_name = str(value[0])
                    table_name = str(value[1])
                elif type_val != '00' and type_val != '01' and type_val != '07' and type_val != '26' and type_val != '42' and type_val != '69' and type_val != 'ra':
                    type_val = 'agregation'
                    schema_name = str(value[0])
                    table_name = str(value[1])

                FavStatut = 0
                if (schema_name + '.' + table_name) not in FavList:
                    FAV = "mStarIconAdd.png"
                    FavStatut = 0
                else:
                    FAV = "mStarIconDel.png"
                    FavStatut = 1
                iconFav = QIcon()
                iconFav.addPixmap(QtGui.QPixmap(resources_path('icons', FAV)), QIcon.Mode(0), QIcon.State(1))
                self.FavButton = QPushButton(iconFav, "")
                self.FavButton.clicked.connect(self.AddOrDelToUserFav)

                if (str(value[0]) + '.' + str(value[1])) in RasterList:
                    SVG = 'mIconRaster.svg'
                else:
                    SVG = 'mIconVecteur.svg'

                itemIcon = QTableWidgetItem()
                icon = QIcon()
                icon.addPixmap(QtGui.QPixmap(resources_path('icons', SVG)), QIcon.Mode(0), QIcon.State(1))
                itemIcon.setIcon(icon)

                self.tableWidget.setItem(i, 0, itemIcon)
                item = QTableWidgetItem(type_val)
                self.tableWidget.setItem(i, 1, item)
                item = QTableWidgetItem(schema_name)
                self.tableWidget.setItem(i, 2, item)
                item = QTableWidgetItem(table_name)
                self.tableWidget.setItem(i, 3, item)
                item = QTableWidgetItem(str(FavStatut))
                self.tableWidget.setItem(i, 4, item)
                self.tableWidget.setCellWidget(i, 4, self.FavButton)

                # Coloration des lignes selon les droits d'accès
                if (str(value[0]) + '.' + str(value[1])) in GrandUser:  # L'utilisateur a les droits
                    for j in range(self.tableWidget.columnCount()):
                        self.tableWidget.item(i, j).setToolTip(MetadataXML)
                else:
                    # Coloration en violet si droits insuffisants
                    for j in range(self.tableWidget.columnCount()):
                        self.tableWidget.item(i, j).setBackground(QtGui.QColor(187, 134, 192, 50))
                        self.tableWidget.item(i, j).setToolTip('Droit insuffisant pour ouvrire la couche !')

                i = i + 1

            if self.comboBox.currentText() == 'toutes les catégories':
                SQLprojects = """SELECT schemaname, tablename FROM pg_catalog.pg_tables WHERE tablename LIKE 'qgis_projects'"""
            else:
                SQLprojects = """SELECT schemaname, tablename FROM pg_catalog.pg_tables WHERE tablename LIKE 'qgis_projects' AND schemaname LIKE '""" + str(self.comboBox.currentText()) + """';"""
            cur.execute(SQLprojects)
            list_projects = cur.fetchall()

            list_projects_qgis = []
            if len(list_projects) >= 1:
                for ProjectName in list_projects:
                    SQLProjectsQgis = """SELECT name, metadata, content FROM """ + '"' + ProjectName[0] + '"."' + ProjectName[1] + '"'
                    cur.execute(SQLProjectsQgis)
                    list_projects_qgis = cur.fetchall()
                    for Project in list_projects_qgis:
                        FavStatut = 0
                        if (ProjectName[0] + '.' + Project[0]) not in FavList:
                            FAV = "mStarIconAdd.png"
                            FavStatut = 0
                        else:
                            FAV = "mStarIconDel.png"
                            FavStatut = 1
                        iconFav = QIcon()
                        iconFav.addPixmap(QtGui.QPixmap(resources_path('icons', FAV)), QIcon.Mode(0), QIcon.State(1))
                        self.FavButton = QPushButton(iconFav, "")
                        self.FavButton.clicked.connect(self.AddOrDelToUserFav)
                        if dbtype == refdb:
                            self.FavButton.setEnabled(False)

                        self.tableWidget.setRowCount(i + 1)
                        itemIcon = QTableWidgetItem()
                        icon = QIcon()
                        icon.addPixmap(QtGui.QPixmap(resources_path('icons', 'mIconQgis.svg')), QIcon.Mode(0), QIcon.State(1))
                        itemIcon.setIcon(icon)
                        self.tableWidget.setItem(i, 0, itemIcon)

                        item = QTableWidgetItem('qgis')
                        self.tableWidget.setItem(i, 1, item)

                        item = QTableWidgetItem(ProjectName[0])
                        self.tableWidget.setItem(i, 2, item)

                        item = QTableWidgetItem(Project[0])
                        self.tableWidget.setItem(i, 3, item)

                        item = QTableWidgetItem(str(FavStatut))
                        self.tableWidget.setItem(i, 4, item)
                        self.tableWidget.setCellWidget(i, 4, self.FavButton)

                        i = i + 1

            self.tableWidget.setColumnWidth(0, 20)
            self.tableWidget.setColumnWidth(1, 70)
            self.tableWidget.setColumnWidth(2, 300)
            self.tableWidget.setColumnWidth(3, 300)
            self.tableWidget.setColumnWidth(4, 20)
            self.tableWidget.setHorizontalHeaderLabels(["Type", "Code", "Schema", "Table", "Favorit"])

            if self.lineEdit.text() != 'Recherche par mots-clés':
                self.filtre_dynamique(self.lineEdit.text())

    def selection_flux(self):
        """Ajoute une couche sélectionnée à la liste des flux à charger"""
        selected_row = 0
        selected_items = self.tableWidget.selectedItems()

        new_item_text = selected_items[3].text()

        if not self.item_already_exists(new_item_text):
            self.tableWidget_2.insertRow(selected_row)

            for column in range(self.tableWidget.columnCount()):
                cloned_item = selected_items[column].clone()
                self.tableWidget_2.setHorizontalHeaderLabels(["Type", "Code", "Schema", "Table", "Favorit"])
                self.tableWidget_2.setColumnCount(5)
                self.tableWidget_2.setItem(selected_row, column, cloned_item)

            self.tableWidget_2.setColumnWidth(0, 20)
            self.tableWidget_2.setColumnWidth(1, 70)
            self.tableWidget_2.setColumnWidth(2, 300)
            self.tableWidget_2.setColumnWidth(3, 300)
            self.tableWidget_2.setColumnWidth(4, 20)
            self.tableWidget_2.setColumnHidden(4, True)

    def item_already_exists(self, new_item_text):
        # Assuming you want to compare items in the first column for uniqueness
        existing_items = self.tableWidget_2.findItems(new_item_text, QtCore.Qt.MatchFlag(0))
        # Check if there are any existing items with the same text in the first column
        return len(existing_items) > 0

    def limite_flux(self):
        """Vérifie le nombre de flux à charger et affiche un avertissement si > 5"""
        # Avertissement si plus de 5 couches sélectionnées (risque de performance)
        if self.tableWidget_2.rowCount() > 5:
            self.QMBquestion = QMessageBox.question(iface.mainWindow(), u"Attention !",
                                                    "Le nombre de flux à charger en une seule fois est limité à 5 pour des questions de performances. Souhaitez vous tout de même charger les " + str(
                                                        self.tableWidget_2.rowCount()) + " flux sélectionnés ? (risque de plantage de QGIS)",
                                                    QMessageBox.StandardButton(0x00004000) | QMessageBox.StandardButton(0x00010000))
            if self.QMBquestion == QMessageBox.StandardButton(0x00004000):
                self.chargement_flux()

            if self.QMBquestion == QMessageBox.StandardButton(0x00001000):
                print("Annulation du chargement des couches")

        if self.tableWidget_2.rowCount() <= 5:
            self.chargement_flux()

    def chargement_flux(self):
        global cur, con, dbtype
        """Charge les couches sélectionnées dans QGIS"""
        managerAU = QgsApplication.authManager()
        managerAU.availableAuthMethodConfigs().keys()

        def REQUEST(type):
            switcher = {
                'WFS': "GetFeature",
                'WMS': "GetMap",
                'WMS+Vecteur': "GetMap",
                'WMS+Raster': "GetMap",
                'WMTS': "GetMap"
            }
            return switcher.get(type, "nothing")

        # Vérification de la présence de l'extension PostGIS Raster
        SQLloadRaster = """SELECT concat(r_table_schema,'.',r_table_name) from public.raster_columns; """
        SQLextension = """SELECT count(extname) FROM pg_catalog.pg_extension WHERE extname LIKE 'postgis_raster';"""

        cur.execute(SQLextension)
        count_extension = cur.fetchall()[0][0]

        if count_extension == 1:
            cur.execute(SQLloadRaster)
            list_raster = cur.fetchall()
        else:
            list_raster = []

        RasterList = []
        for rasterFind in list_raster:
            RasterList.append(rasterFind[0])

        # Chargement de chaque couche sélectionnée
        for row in range(0, self.tableWidget_2.rowCount()):
            color_rgba_db = 855030089      # Code couleur pour couche dans autre BD
            color_rgba_droit = 851150528   # Code couleur pour droits insuffisants
            self.QMBquestionNoLogin = QMessageBox()
            if self.tableWidget_2.item(row, 1).background().color().rgba() == color_rgba_droit:
                self.QMBquestionNoLogin.setWindowTitle(u"Attention !")
                self.QMBquestionNoLogin.setIcon(QMessageBox.Icon.Warning)
                self.QMBquestionNoLogin.setText("Vous ne disposez pas des droit pour la couche «" + str(self.tableWidget_2.item(row, 1).text()) + ' ' + str(self.tableWidget_2.item(row, 2).text()) + "» !")
                self.QMBquestionNoLogin.setStandardButtons(QMessageBox.StandardButton(0x00004000) | QMessageBox.StandardButton(0x00080000))
                self.QMBquestionNoLogin = self.QMBquestionNoLogin.exec()
                # self.QMBquestionNoLogin = QMessageBox.question(iface.mainWindow(), u"Attention !", "Vous ne disposez pas des droit pour la couche «" + str(self.tableWidget_2.item(row, 1).text()) + ' ' + str(self.tableWidget_2.item(row, 2).text()) + "» !", QMessageBox.StandardButton(0x00004000), QMessageBox.StandardButton(0x00080000))
                if self.QMBquestionNoLogin != QMessageBox.StandardButton(0x00004000):
                    self.InputDialog = QInputDialog()
                    user_bypass = (self.InputDialog.getText(None, 'Foncier', 'Identifiant:'))[0]
                    mdp_bypass = (self.InputDialog.getText(None, 'Foncier', 'Mot de pass:'))[0]

                    global user, mdp
                    user = user_bypass
                    mdp = mdp_bypass
                    try:
                        con = psycopg2.connect("host=" + host + " port=" + port + " dbname=" + dbtype + " user=" + user + " password=" + mdp)
                        cur = con.cursor(cursor_factory=psycopg2.extras.DictCursor)
                    except psycopg2.OperationalError:
                        print('password authentication failed')
                        user = user_save
                        mdp = mdp_save

            else:
                if user != user_save or mdp != mdp_save:
                    user = user_save
                    mdp = mdp_save

            if (self.tableWidget_2.item(row, 1).background().color().rgba() != color_rgba_db) and (self.QMBquestionNoLogin != QMessageBox.StandardButton(0x00004000)):
                # supression de la partie de l'url après le point d'interrogation
                if dbtype == sigdb:
                    code = self.tableWidget_2.item(row, 1).text()
                    schema = '_' + code + '_' + self.tableWidget_2.item(row, 2).text()
                    if code == 'travaux' or code == 'agregation':
                        schema = self.tableWidget_2.item(row, 2).text()
                        table = self.tableWidget_2.item(row, 3).text()
                    elif code == '00':
                        table = self.tableWidget_2.item(row, 3).text()
                    else:
                        table = self.tableWidget_2.item(row, 3).text()
                        table = schema + '_' + table
                elif dbtype == refdb:
                    code = self.tableWidget_2.item(row, 1).text()
                    schema = self.tableWidget_2.item(row, 2).text()
                    table = self.tableWidget_2.item(row, 3).text()
                # Configuration de l'URI de connexion PostGIS
                uri = QgsDataSourceUri()
                uri.setConnection(host, port, dbtype, user, mdp)

                # Chargement selon le type de couche (raster, vecteur ou projet QGIS)
                if (schema + '.' + table) in RasterList:
                    # Chargement d'une couche raster
                    uri.setDataSource(schema, table, "rast")
                    uri.setKeyColumn('rid')  # Clé primaire pour les rasters
                    uri.setSrid('2154')      # Lambert 93
                    layer = QgsRasterLayer(uri.uri(), table, "postgresraster")
                    QgsProject.instance().addMapLayer(layer)
                elif code == 'qgis':
                    # Chargement d'un projet QGIS stocké dans la base de données
                    schema = self.tableWidget_2.item(row, 2).text()
                    table = self.tableWidget_2.item(row, 3).text()
                    uri_project = 'postgresql://' + user + ':' + mdp + '@' + host + ':' + port + '?sslmode=disable&dbname=' + dbtype + "&schema=" + schema + '&project=' + table
                    QgsProject.instance().read(uri_project)
                else:
                    # Chargement d'une couche vecteur
                    uri.setDataSource(schema, table, "geom")  # Colonne géométrie
                    uri.setKeyColumn('gid')  # Clé primaire

                    # Détection du type de géométrie
                    geom_type = 'SELECT right(st_geometrytype(geom),-3) as a FROM ' + schema + '.' + table + ' GROUP BY a'
                    try:
                        cur.execute(geom_type)
                        list_typegeom = cur.fetchall()
                        if len(list_typegeom) > 1:
                            for typegeom in list_typegeom:
                                if typegeom[0] == 'MultiPolygon':
                                    uri.setWkbType(QgsWkbTypes.MultiPolygon)
                                elif typegeom[0] == 'MultiLineString':
                                    uri.setWkbType(QgsWkbTypes.MultiLineString)
                                elif typegeom[0] == 'Point':
                                    uri.setWkbType(QgsWkbTypes.Point)
                                if typegeom[0] == 'Polygon':
                                    uri.setWkbType(QgsWkbTypes.Polygon)
                                elif typegeom[0] == 'LineString':
                                    uri.setWkbType(QgsWkbTypes.LineString)
                                elif typegeom[0] == 'MultiPoint':
                                    uri.setWkbType(QgsWkbTypes.MultiPoint)
                                if (typegeom[0] is not None and typegeom[0] != 'Polygon'):
                                    uri.setSrid('2154')
                                    layer = QgsVectorLayer(uri.uri(), table, "postgres")
                                    # Ajout de la couche au canevas QGIS
                                    QgsProject.instance().addMapLayer(layer)
                        else:
                            layer = QgsVectorLayer(uri.uri(), table, "postgres")
                            # Ajout de la couche au canevas QGIS
                            QgsProject.instance().addMapLayer(layer)
                    except psycopg2.errors.UndefinedTable:
                        print('Table not exist... RollBack !')
                        con.rollback()
                    except psycopg2.errors.InsufficientPrivilege:
                        print('Insufficient Privilege... RollBack !')
                        con.rollback()
                    except psycopg2.errors.UndefinedColumn:
                        print('Column "geom" does not exist... RollBack !')
                        con.rollback()

            else:
                if self.QMBquestionNoLogin != QMessageBox.StandardButton(0x00004000):
                    self.QMBquestion = QMessageBox.question(iface.mainWindow(), u"Attention !", "La couche «" + str(self.tableWidget_2.item(row, 1).text()) + ' ' + str(self.tableWidget_2.item(row, 2).text()) + "» ne ce trouve pas dans cette BD !", QMessageBox.StandardButton(0x00004000))

    def combobox_custom(self):
        """Remplit la liste déroulante des catégories selon la base de données sélectionnée"""
        global NoSignals
        NoSignals = 1  # Désactive temporairement les signaux pour éviter les boucles
        if dbtype == sigdb:
            self.toolButton.setEnabled(1)
            self.comboBox.clear()
            self.comboBox.addItem("toutes les catégories")
            self.comboBox.addItem('00')
            self.comboBox.addItem('01')
            self.comboBox.addItem('07')
            self.comboBox.addItem('26')
            self.comboBox.addItem('42')
            self.comboBox.addItem('69')
            self.comboBox.addItem('agregation')
            self.comboBox.addItem('travaux')
            self.comboBox.addItem('qgis')
            self.comboBox.addItem('form')
        if dbtype == refdb:
            self.toolButton.setEnabled(0)
            custom_list = schemaname_distinct
            cur.execute(custom_list)
            list_schema = cur.fetchall()
            self.comboBox.clear()
            self.comboBox.addItem("toutes les catégories")
            for baxval in list_schema:
                self.comboBox.addItem(baxval[0])
        NoSignals = 0

    def filtre_favorit(self, filter_fav):
        """Active ou désactive le filtre des favoris"""
        if self.toolButton_2.text() == "0":  # Activation du filtre
            self.toolButton_2.setText("1")
            self.toolButton_2.setDown(True)
            if self.lineEdit.text() != 'Recherche par mots-clés':
                self.filtre_dynamique(self.lineEdit.text())
            else:
                for i in range(self.tableWidget.rowCount()):
                    item = self.tableWidget.item(i, 4)
                    match = self.toolButton_2.text() not in item.text().lower()
                    self.tableWidget.setRowHidden(i, match)
        elif self.toolButton_2.text() == "1":
            self.toolButton_2.setText("0")
            self.toolButton_2.setDown(False)
            if self.lineEdit.text() != 'Recherche par mots-clés':
                self.filtre_dynamique(self.lineEdit.text())
            else:
                for i in range(self.tableWidget.rowCount()):
                    self.tableWidget.setRowHidden(i, False)

    def filtre_dynamique(self, filter_text):
        """Filtre dynamique des couches selon le texte saisi"""
        # Remplacement des espaces par des underscores pour la recherche
        if filter_text.find(' ') >= 0:
            filter_text = filter_text.replace(" ", "_")
        for i in range(self.tableWidget.rowCount()):
            for j in range(self.tableWidget.columnCount()):
                item = self.tableWidget.item(i, j)
                match = filter_text.lower() not in item.text().lower()
                if match is False:
                    if self.toolButton_2.text() == "1":
                        item = self.tableWidget.item(i, 4)
                        match = self.toolButton_2.text() not in item.text().lower()
                self.tableWidget.setRowHidden(i, match)
                if not match:
                    break

    def getCanevas(self):
        """Filtre les couches selon l'emprise du canevas QGIS actuel"""

        # Récupération de la liste des favoris de l'utilisateur
        SQLFavTable = "SELECT concat(schema_name, '.', table_name) FROM admin_sig.favtable WHERE utilisateur LIKE '" + user + "';"
        if dbtype == refdb:
            conSIG = psycopg2.connect("host=" + host + " port=" + port + " dbname=" + sigdb + " user=" + user + " password=" + mdp)
            curSIG = conSIG.cursor(cursor_factory=psycopg2.extras.DictCursor)
            curSIG.execute(SQLFavTable)
            list_fav = curSIG.fetchall()
            conSIG.close()
        else:
            cur.execute(SQLFavTable)
            list_fav = cur.fetchall()
        FavList = []
        for favFind in list_fav:
            FavList.append(favFind[0])

        # Récupération de l'emprise du canevas
        poly = iface.mapCanvas().extent()
        geom = (str(poly.xMinimum()) + ',' + str(poly.yMinimum()) + ',' + str(poly.xMaximum()) + ',' + str(poly.yMaximum()))

        SQL_GEOM_CONTOUR = """SELECT DISTINCT tschema,tname FROM "_agregation_ra"."_agreg_contour" WHERE st_intersects(geom,ST_MakeEnvelope(""" + geom + ",2154)) ORDER BY tname"
        SQL_GEOM_HABITAT = """SELECT DISTINCT tschema,tname FROM "_agregation_ra"."_agreg_habitat" WHERE st_intersects(geom,ST_MakeEnvelope(""" + geom + ",2154)) ORDER BY tname"
        SQL_GEOM_EU_HABITAT = """SELECT DISTINCT tschema,tname FROM "_agregation_ra"."_agreg_eu_habitat" WHERE st_intersects(geom,ST_MakeEnvelope(""" + geom + ",2154)) ORDER BY tname"
        SQL_GEOM_TRAVAUX_PREVUS_LIGNE = """SELECT DISTINCT tschema,tname FROM "_agregation_ra"."_agreg_travaux_prevus_ligne" WHERE st_intersects(geom,ST_MakeEnvelope(""" + geom + ",2154)) ORDER BY tname"
        SQL_GEOM_TRAVAUX_PREVUS_POINT = """SELECT DISTINCT tschema,tname FROM "_agregation_ra"."_agreg_travaux_prevus_point" WHERE st_intersects(geom,ST_MakeEnvelope(""" + geom + ",2154)) ORDER BY tname"
        SQL_GEOM_TRAVAUX_PREVUS_POLY = """SELECT DISTINCT tschema,tname FROM "_agregation_ra"."_agreg_travaux_prevus_poly" WHERE st_intersects(geom,ST_MakeEnvelope(""" + geom + ",2154)) ORDER BY tname"

        cur.execute(SQL_GEOM_CONTOUR)
        TableContour = cur.fetchall()
        cur.execute(SQL_GEOM_HABITAT)
        TableHabitat = cur.fetchall()
        cur.execute(SQL_GEOM_EU_HABITAT)
        TableEuHabitat = cur.fetchall()
        cur.execute(SQL_GEOM_TRAVAUX_PREVUS_LIGNE)
        TableTravauxLigne = cur.fetchall()
        cur.execute(SQL_GEOM_TRAVAUX_PREVUS_POINT)
        TableTravauxPoint = cur.fetchall()
        cur.execute(SQL_GEOM_TRAVAUX_PREVUS_POLY)
        TableTravauxPoly = cur.fetchall()

        TableHaveGeom = sorted(TableContour + TableHabitat + TableEuHabitat + TableTravauxLigne + TableTravauxPoint + TableTravauxPoly)
        row_count = 0
        self.tableWidget.setRowCount(0)
        for e in TableHaveGeom:
            cur.execute("""SELECT DISTINCT count(*) FROM pg_catalog.pg_tables WHERE schemaname LIKE '""" + e[0] + """' AND tablename LIKE '""" + e[1] + """';""")
            TableSomme = cur.fetchall()[0][0]

            if e[0][1:3] != 'fo':
                schema_name = e[0][4:]
                DepName = QTableWidgetItem(e[0][1:3])
                SchemaName = QTableWidgetItem(schema_name)
            else:
                schema_name = e[0][6:]
                DepName = QTableWidgetItem('form')
                SchemaName = QTableWidgetItem(schema_name)
            table_name = e[1][len(e[0]) + 1:]
            TableName = QTableWidgetItem(table_name)

            FavStatut = 0
            if (schema_name + '.' + table_name) not in FavList:
                FAV = "mStarIconAdd.png"
                FavStatut = 0
            else:
                FAV = "mStarIconDel.png"
                FavStatut = 1
            iconFav = QIcon()
            iconFav.addPixmap(QtGui.QPixmap(resources_path('icons', FAV)), QIcon.Mode(0), QIcon.State(1))
            self.FavButton = QPushButton(iconFav, "")
            self.FavButton.clicked.connect(self.AddOrDelToUserFav)

            self.tableWidget.insertRow(row_count)

            itemIcon = QTableWidgetItem()
            icon = QIcon()
            icon.addPixmap(QtGui.QPixmap(resources_path('icons', 'mIconVecteur.svg')), QIcon.Mode(0), QIcon.State(1))
            itemIcon.setIcon(icon)

            self.tableWidget.setItem(row_count, 0, itemIcon)
            self.tableWidget.setItem(row_count, 1, DepName)
            self.tableWidget.setItem(row_count, 2, SchemaName)
            self.tableWidget.setItem(row_count, 3, TableName)
            item = QTableWidgetItem(str(FavStatut))
            self.tableWidget.setItem(row_count, 4, item)
            self.tableWidget.setCellWidget(row_count, 4, self.FavButton)
            if TableSomme == 0:
                for j in range(self.tableWidget.columnCount()):
                    self.tableWidget.item(row_count, j).setBackground(QtGui.QColor(246, 185, 73, 50))
                    self.tableWidget.item(row_count, j).setToolTip('Couche dans une autre BD !')
            row_count = row_count + 1
        if self.lineEdit.text() != 'Recherche par mots-clés':
            self.filtre_dynamique(self.lineEdit.text())

    def SwitchGeom(self, vargeom):
        new_object = '['
        obj = vargeom['coordinates'][0][0]
        for obj_X in obj:
            new_object = new_object + '[' + str(obj_X[1]) + ',' + str(obj_X[0]) + '],'
        new_object = new_object[:-1] + ']'
        return (new_object)
