# -*- coding: utf-8 -*-
"""
/***************************************************************************
 sentinel2analyzer
                                 A QGIS plugin
 The plugin allows for managing Sentinel-2 data; computing multispectral indices; and making some statistical analysis.
 Generated by Plugin Builder: http://g-sherman.github.io/Qgis-Plugin-Builder/
                              -------------------
        begin                : 2025-04-03
        git sha              : $Format:%H$
        copyright            : (C) 2025 by Chiara Bottaro, Thomas Martinoli
        email                : chiara.bottaro@polimi.it ; thomas.martinoli@polimi.it
 ***************************************************************************/

/***************************************************************************
 *                                                                         *
 *   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.                                   *
 *                                                                         *
 ***************************************************************************/
"""
from qgis.PyQt.QtCore import QSettings, QTranslator, QCoreApplication
from qgis.PyQt.QtGui import QIcon
from qgis.PyQt.QtWidgets import QAction, QFileDialog, QMessageBox
from qgis.core import QgsProject
from PyQt5 import QtWidgets
from qgis.core import QgsExpression


# Initialize Qt resources from file resources.py
from .resources import *
#it is necessary to insert this line in order to make possible the import of data
from qgis.core import QgsProject
# Import the code for the dialog
from .sentinel2analyzer_dialog import sentinel2analyzerDialog
import os.path
import numpy as np
from qgis.utils import iface
import time


# Import the functionality of the plugin
from .Indices import *
from .Stack import *
from .Analysis import *




def check_band_list(band_list):
            
            if len(band_list) ==0:
                return None, 1 
                
    
        # if the position in the band_list is not unique, and the number is not from 1 to the number of bands selected, raise an error
            band_list.sort(key=lambda x: x[1])
        
            unique_positions = set()
        
            for _, position, _,_ in band_list:
                if position in unique_positions or position < 1 or position > len(band_list):
                    return None, 2
                
            unique_positions.add(position)
            
            return band_list, None

def define_band_list(self):
            
            band_list=[]
                        
            layer_path=None
            name=None
            text = self.dlg.comboBox_multinput_2.currentText()
            
            if text == "":
                        return None, None, None, 3
            else:
                text_string = str(text)
                info_path = QgsProject.instance().mapLayersByName(text_string)
                input_path = info_path[0].dataProvider().dataSourceUri()
            
            scale_factor = self.dlg.doubleSpinBox_2.value()
            
            
            for i in range(1, 14):
                if getattr(self.dlg, f"checkBox_B{i}_3").isChecked():
                    index=i
                    position=getattr(self.dlg,f"spinBox_B{i}_3").value()
                    
                    band_list.append((index,position,name,layer_path))
                    
            # check if the band_list is valid
            band_list, message = check_band_list(band_list)
            
            return band_list, input_path, scale_factor, message
        
        



class sentinel2analyzer:
    """QGIS Plugin Implementation."""

    def __init__(self, iface):
        """Constructor.

        :param iface: An interface instance that will be passed to this class
            which provides the hook by which you can manipulate the QGIS
            application at run time.
        :type iface: QgsInterface
        """
        # Save reference to the QGIS interface
        self.iface = iface
        # initialize plugin directory
        self.plugin_dir = os.path.dirname(__file__)
        # initialize locale
        locale = QSettings().value('locale/userLocale')[0:2]
        locale_path = os.path.join(
            self.plugin_dir,
            'i18n',
            'sentinel2analyzer_{}.qm'.format(locale))

        if os.path.exists(locale_path):
            self.translator = QTranslator()
            self.translator.load(locale_path)
            QCoreApplication.installTranslator(self.translator)

        # Declare instance attributes
        self.actions = []
        self.menu = self.tr(u'&Sentinel-2 Analyzer')

        # Check if plugin was started the first time in current QGIS session
        # Must be set in initGui() to survive plugin reloads
        self.first_start = None

    # noinspection PyMethodMayBeStatic
    def tr(self, message):
        """Get the translation for a string using Qt translation API.

        We implement this ourselves since we do not inherit QObject.

        :param message: String for translation.
        :type message: str, QString

        :returns: Translated version of message.
        :rtype: QString
        """
        # noinspection PyTypeChecker,PyArgumentList,PyCallByClass
        return QCoreApplication.translate('sentinel2analyzer', message)


    def add_action(
        self,
        icon_path,
        text,
        callback,
        enabled_flag=True,
        add_to_menu=True,
        add_to_toolbar=True,
        status_tip=None,
        whats_this=None,
        parent=None):
        """Add a toolbar icon to the toolbar.

        :param icon_path: Path to the icon for this action. Can be a resource
            path (e.g. ':/plugins/foo/bar.png') or a normal file system path.
        :type icon_path: str

        :param text: Text that should be shown in menu items for this action.
        :type text: str

        :param callback: Function to be called when the action is triggered.
        :type callback: function

        :param enabled_flag: A flag indicating if the action should be enabled
            by default. Defaults to True.
        :type enabled_flag: bool

        :param add_to_menu: Flag indicating whether the action should also
            be added to the menu. Defaults to True.
        :type add_to_menu: bool

        :param add_to_toolbar: Flag indicating whether the action should also
            be added to the toolbar. Defaults to True.
        :type add_to_toolbar: bool

        :param status_tip: Optional text to show in a popup when mouse pointer
            hovers over the action.
        :type status_tip: str

        :param parent: Parent widget for the new action. Defaults None.
        :type parent: QWidget

        :param whats_this: Optional text to show in the status bar when the
            mouse pointer hovers over the action.

        :returns: The action that was created. Note that the action is also
            added to self.actions list.
        :rtype: QAction
        """

        icon = QIcon(icon_path)
        action = QAction(icon, text, parent)
        action.triggered.connect(callback)
        action.setEnabled(enabled_flag)

        if status_tip is not None:
            action.setStatusTip(status_tip)

        if whats_this is not None:
            action.setWhatsThis(whats_this)

        if add_to_toolbar:
            # Adds plugin icon to Plugins toolbar
            self.iface.addToolBarIcon(action)

        if add_to_menu:
            self.iface.addPluginToMenu(
                self.menu,
                action)

        self.actions.append(action)

        return action

    def initGui(self):
        """Create the menu entries and toolbar icons inside the QGIS GUI."""

        icon_path = ':/plugins/sentinel2analyzer/icon.png'
        self.add_action(
            icon_path,
            text=self.tr(u'sentinel2analyzer'),
            callback=self.run,
            parent=self.iface.mainWindow())

        # will be set False in run()
        self.first_start = True

    def unload(self):
        """Removes the plugin menu item and icon from QGIS GUI."""
        for action in self.actions:
            self.iface.removePluginMenu(
                self.tr(u'&Sentinel-2 Analyzer'),
                action)
            self.iface.removeToolBarIcon(action)


###################################################################################################  
    """
    Behavior of the Indices - Custom TAB
    Calculator buttons
    """  
        
    def plus(self):
        current_text = self.dlg.textEdit.toPlainText()  # Ottieni il testo attuale nel QTextEdit
        new_text = current_text + "+"  # Aggiungi il simbolo "+"
        self.dlg.textEdit.setPlainText(new_text)  # Imposta il nuovo testo
    def minus(self):
        current_text = self.dlg.textEdit.toPlainText()  # Ottieni il testo attuale nel QTextEdit
        new_text = current_text + "-"  # Aggiungi il simbolo "-"
        self.dlg.textEdit.setPlainText(new_text)  # Imposta il nuovo testo
    def mult(self):
        current_text = self.dlg.textEdit.toPlainText()
        new_text = current_text + "*"
        self.dlg.textEdit.setPlainText(new_text)
    def div(self):
        current_text = self.dlg.textEdit.toPlainText()
        new_text = current_text + "/"
        self.dlg.textEdit.setPlainText(new_text)
    def open(self):
        current_text = self.dlg.textEdit.toPlainText()
        new_text = current_text + "("
        self.dlg.textEdit.setPlainText(new_text)
    def close(self):
        current_text = self.dlg.textEdit.toPlainText()
        new_text = current_text + ")"
        self.dlg.textEdit.setPlainText(new_text)
    def power(self):
        current_text = self.dlg.textEdit.toPlainText()
        new_text = current_text + "^"
        self.dlg.textEdit.setPlainText(new_text)
        
    def add_B1(self):
        current_text = self.dlg.textEdit.toPlainText()
        new_text = current_text + "B1"
        self.dlg.textEdit.setPlainText(new_text)
    def add_B2(self):
        current_text = self.dlg.textEdit.toPlainText()
        new_text = current_text + "B2"
        self.dlg.textEdit.setPlainText(new_text)
    def add_B3(self):
        current_text = self.dlg.textEdit.toPlainText()
        new_text = current_text + "B3"
        self.dlg.textEdit.setPlainText(new_text)
    def add_B4(self):
        current_text = self.dlg.textEdit.toPlainText()
        new_text = current_text + "B4"
        self.dlg.textEdit.setPlainText(new_text)
    def add_B5(self):
        current_text = self.dlg.textEdit.toPlainText()
        new_text = current_text + "B5"
        self.dlg.textEdit.setPlainText(new_text)
    def add_B6(self):
        current_text = self.dlg.textEdit.toPlainText()
        new_text = current_text + "B6"
        self.dlg.textEdit.setPlainText(new_text)
    def add_B7(self):
        current_text = self.dlg.textEdit.toPlainText()
        new_text = current_text + "B7"
        self.dlg.textEdit.setPlainText(new_text)
    def add_B8(self):
        current_text = self.dlg.textEdit.toPlainText()
        new_text = current_text + "B8"
        self.dlg.textEdit.setPlainText(new_text)
    def add_B9(self):
        current_text = self.dlg.textEdit.toPlainText()
        new_text = current_text + "B9"
        self.dlg.textEdit.setPlainText(new_text)
    def add_B10(self):
        current_text = self.dlg.textEdit.toPlainText()
        new_text = current_text + "B10"
        self.dlg.textEdit.setPlainText(new_text)
    def add_B11(self):
        current_text = self.dlg.textEdit.toPlainText()
        new_text = current_text + "B11"
        self.dlg.textEdit.setPlainText(new_text)
    def add_B12(self):
        current_text = self.dlg.textEdit.toPlainText()
        new_text = current_text + "B12"
        self.dlg.textEdit.setPlainText(new_text)         
    def add_B13(self):
        current_text = self.dlg.textEdit.toPlainText()
        new_text = current_text + "B13"
        self.dlg.textEdit.setPlainText(new_text)
  
    
    def toggle_b1_button(self):
        if  self.dlg.checkBox_B1_3.isChecked():
            self.dlg.B1_button.setEnabled(True)
        else:
            self.dlg.B1_button.setEnabled(False)
            #rimuovi da textEdit il B1
            current_text = self.dlg.textEdit.toPlainText()
            new_text = current_text.replace("B1", "")
            self.dlg.textEdit.setPlainText(new_text) 
    def toggle_b2_button(self):
        if  self.dlg.checkBox_B2_3.isChecked():
            self.dlg.B2_button.setEnabled(True)
        else:
            self.dlg.B2_button.setEnabled(False)
            #rimuovi da textEdit il B2
            current_text = self.dlg.textEdit.toPlainText()
            new_text = current_text.replace("B2", "")
            self.dlg.textEdit.setPlainText(new_text)         
    def toggle_b3_button(self):
        if  self.dlg.checkBox_B3_3.isChecked():
            self.dlg.B3_button.setEnabled(True)
        else:
            self.dlg.B3_button.setEnabled(False)
            #rimuovi da textEdit il B3
            current_text = self.dlg.textEdit.toPlainText()
            new_text = current_text.replace("B3", "")
            self.dlg.textEdit.setPlainText(new_text)
    def toggle_b4_button(self):
        if  self.dlg.checkBox_B4_3.isChecked():
            self.dlg.B4_button.setEnabled(True)
        else:
            self.dlg.B4_button.setEnabled(False)
            #rimuovi da textEdit il B4
            current_text = self.dlg.textEdit.toPlainText()
            new_text = current_text.replace("B4", "")
            self.dlg.textEdit.setPlainText(new_text)
    def toggle_b5_button(self):
        if  self.dlg.checkBox_B5_3.isChecked():
            self.dlg.B5_button.setEnabled(True)
        else:
            self.dlg.B5_button.setEnabled(False)
            #rimuovi da textEdit il B5
            current_text = self.dlg.textEdit.toPlainText()
            new_text = current_text.replace("B5", "")
            self.dlg.textEdit.setPlainText(new_text)
    def toggle_b6_button(self):
        if  self.dlg.checkBox_B6_3.isChecked():
            self.dlg.B6_button.setEnabled(True)
        else:
            self.dlg.B6_button.setEnabled(False)
            #rimuovi da textEdit il B6
            current_text = self.dlg.textEdit.toPlainText()
            new_text = current_text.replace("B6", "")
            self.dlg.textEdit.setPlainText(new_text)
    def toggle_b7_button(self):
        if  self.dlg.checkBox_B7_3.isChecked():
            self.dlg.B7_button.setEnabled(True)
        else:
            self.dlg.B7_button.setEnabled(False)
            #rimuovi da textEdit il B7
            current_text = self.dlg.textEdit.toPlainText()
            new_text = current_text.replace("B7", "")
            self.dlg.textEdit.setPlainText(new_text)
    def toggle_b8_button(self):
        if  self.dlg.checkBox_B8_3.isChecked():
            self.dlg.B8_button.setEnabled(True)
        else:
            self.dlg.B8_button.setEnabled(False)
            #rimuovi da textEdit il B8
            current_text = self.dlg.textEdit.toPlainText()
            new_text = current_text.replace("B8", "")
            self.dlg.textEdit.setPlainText(new_text)
    def toggle_b9_button(self):
        if  self.dlg.checkBox_B9_3.isChecked():
            self.dlg.B9_button.setEnabled(True)
        else:
            self.dlg.B9_button.setEnabled(False)
            #rimuovi da textEdit il B9
            current_text = self.dlg.textEdit.toPlainText()
            new_text = current_text.replace("B9", "")
            self.dlg.textEdit.setPlainText(new_text)
    def toggle_b10_button(self):
        if  self.dlg.checkBox_B10_3.isChecked():
            self.dlg.B10_button.setEnabled(True)
        else:
            self.dlg.B10_button.setEnabled(False)
            #rimuovi da textEdit il B10
            current_text = self.dlg.textEdit.toPlainText()
            new_text = current_text.replace("B10", "")
            self.dlg.textEdit.setPlainText(new_text)
    def toggle_b11_button(self):
        if  self.dlg.checkBox_B11_3.isChecked():
            self.dlg.B11_button.setEnabled(True)
        else:
            self.dlg.B11_button.setEnabled(False)
            #rimuovi da textEdit il B11
            current_text = self.dlg.textEdit.toPlainText()
            new_text = current_text.replace("B11", "")
            self.dlg.textEdit.setPlainText(new_text)
    def toggle_b12_button(self):
        if  self.dlg.checkBox_B12_3.isChecked():
            self.dlg.B12_button.setEnabled(True)
        else:
            self.dlg.B12_button.setEnabled(False)
            #rimuovi da textEdit il B12
            current_text = self.dlg.textEdit.toPlainText()
            new_text = current_text.replace("B12", "")
            self.dlg.textEdit.setPlainText(new_text)                   
    def toggle_b13_button(self):
        if  self.dlg.checkBox_B13_3.isChecked():
            self.dlg.B13_button.setEnabled(True)
        else:
            self.dlg.B13_button.setEnabled(False)
            #rimuovi da textEdit il B13
            current_text = self.dlg.textEdit.toPlainText()
            new_text = current_text.replace("B13", "")
            self.dlg.textEdit.setPlainText(new_text)

    # Validate the expression in the textEdit
    
    def validate_expression(self):
        expression_text = self.dlg.textEdit.toPlainText()
        expr = QgsExpression(expression_text)

        if (expr.hasParserError() or 
            has_invalid_operators(expression_text) or
            has_adjacent_band_names(expression_text) or
            has_invalid_characters(expression_text) or
            has_invalid_band_names(expression_text)):
            
            self.dlg.textEdit.setStyleSheet("color: red;")
            self.dlg.compute_custom_button.setEnabled(False)
        else:
            self.dlg.textEdit.setStyleSheet("color: green;")
            self.dlg.compute_custom_button.setEnabled(True)

###################################################################################################        
    """
    Behavior of the group boxes whitin the Stack TAB
    if the folder group box is checked, the file group box and the combo boxes are disabled
    if the file group box is checked, the folder group box and the combo boxes are disabled
    """      
    def deactivatefile(self):
        # Check if the folder group box is checked
        folder_checked = self.dlg.groupBox_folder.isChecked()

        # Enable/Disable file group box and combo boxes based on the folder checkbox state
        self.dlg.groupBox_file.setEnabled(not folder_checked)
        for i in range(1, 16):
            getattr(self.dlg, f"ComboBox_{i}").setEnabled(not folder_checked)            
    def deactivatefolder(self):
        # Check if the folder group box is checked
        file_checked = self.dlg.groupBox_file.isChecked()

        # Enable/Disable file group box and combo boxes based on the folder checkbox state
        self.dlg.groupBox_folder.setEnabled(not file_checked)
        for i in range(1, 16):
            getattr(self.dlg, f"ComboBox_{i}").setEnabled(not file_checked)
            
            
    """
    Behavior of the group boxes whitin the Analysis - Masking TAB
    if the DISCRETE group box is checked, the CONTINUOS group box is disabled
    if the CONTINUOS group box is checked, the DOISCRETE group box is disabled
    """         
    def deactivatecontinuos(self):
        # Get the state of the checkbox
        if self.dlg.groupBox_discrete.isChecked():
        # Enable or disable the file input field based on the checkbox state
            self.dlg.groupBox_continuos.setEnabled(False)
        else:
            self.dlg.groupBox_continuos.setEnabled(True)
    def deactivatediscrete(self):
        # Get the state of the checkbox
        if self.dlg.groupBox_continuos.isChecked():
        # Enable or disable the file input field based on the checkbox state
            self.dlg.groupBox_discrete.setEnabled(False)
        else:
            self.dlg.groupBox_discrete.setEnabled(True)


    """
    Behavior of the checkbox of bands whitin the stack - TAB
    if the BANDS is not checked, all relative widgets are disabled
    """ 
    def band1_activation(self):
        if self.dlg.checkBox_B1.isChecked():
            self.dlg.spinBox_B1.setEnabled(True)
            self.dlg.Name_B1.setEnabled(True)
            self.dlg.ComboBox_1.setEnabled(True)
        else:
            self.dlg.spinBox_B1.setEnabled(False)
            self.dlg.Name_B1.setEnabled(False)
            self.dlg.ComboBox_1.setEnabled(False)
        
    def band2_activation(self):
        if self.dlg.checkBox_B2.isChecked():
            self.dlg.spinBox_B2.setEnabled(True)
            self.dlg.Name_B2.setEnabled(True)
            self.dlg.ComboBox_2.setEnabled(True)
        else:
            self.dlg.spinBox_B2.setEnabled(False)
            self.dlg.Name_B2.setEnabled(False)
            self.dlg.ComboBox_2.setEnabled(False)
            
    def band3_activation(self):
        if self.dlg.checkBox_B3.isChecked():
            self.dlg.spinBox_B3.setEnabled(True)
            self.dlg.Name_B3.setEnabled(True)
            self.dlg.ComboBox_3.setEnabled(True)
        else:
            self.dlg.spinBox_B3.setEnabled(False)
            self.dlg.Name_B3.setEnabled(False)
            self.dlg.ComboBox_3.setEnabled(False)
            
    def band4_activation(self):
        if self.dlg.checkBox_B4.isChecked():
            self.dlg.spinBox_B4.setEnabled(True)
            self.dlg.Name_B4.setEnabled(True)
            self.dlg.ComboBox_4.setEnabled(True)
        else:
            self.dlg.spinBox_B4.setEnabled(False)
            self.dlg.Name_B4.setEnabled(False)
            self.dlg.ComboBox_4.setEnabled(False)
            
    def band5_activation(self):
        if self.dlg.checkBox_B5.isChecked():
            self.dlg.spinBox_B5.setEnabled(True)
            self.dlg.Name_B5.setEnabled(True)
            self.dlg.ComboBox_5.setEnabled(True)
        else:
            self.dlg.spinBox_B5.setEnabled(False)
            self.dlg.Name_B5.setEnabled(False)
            self.dlg.ComboBox_5.setEnabled(False)

    def band6_activation(self):
        if self.dlg.checkBox_B6.isChecked():
            self.dlg.spinBox_B6.setEnabled(True)
            self.dlg.Name_B6.setEnabled(True)
            self.dlg.ComboBox_6.setEnabled(True)
        else:
            self.dlg.spinBox_B6.setEnabled(False)
            self.dlg.Name_B6.setEnabled(False)
            self.dlg.ComboBox_6.setEnabled(False)
            
    def band7_activation(self):
        if self.dlg.checkBox_B7.isChecked():
            self.dlg.spinBox_B7.setEnabled(True)
            self.dlg.Name_B7.setEnabled(True)
            self.dlg.ComboBox_7.setEnabled(True)
        else:
            self.dlg.spinBox_B7.setEnabled(False)
            self.dlg.Name_B7.setEnabled(False)
            self.dlg.ComboBox_7.setEnabled(False)
            
    def band8_activation(self):
        if self.dlg.checkBox_B8.isChecked():
            self.dlg.spinBox_B8.setEnabled(True)
            self.dlg.Name_B8.setEnabled(True)
            self.dlg.ComboBox_8.setEnabled(True)
        else:
            self.dlg.spinBox_B8.setEnabled(False)
            self.dlg.Name_B8.setEnabled(False)
            self.dlg.ComboBox_8.setEnabled(False)
    
    def band9_activation(self):
        if self.dlg.checkBox_B9.isChecked():
            self.dlg.spinBox_B9.setEnabled(True)
            self.dlg.Name_B9.setEnabled(True)
            self.dlg.ComboBox_9.setEnabled(True)
        else:
            self.dlg.spinBox_B9.setEnabled(False)
            self.dlg.Name_B9.setEnabled(False)
            self.dlg.ComboBox_9.setEnabled(False)
            
    def band10_activation(self):
        if self.dlg.checkBox_B10.isChecked():
            self.dlg.spinBox_B10.setEnabled(True)
            self.dlg.Name_B10.setEnabled(True)
            self.dlg.ComboBox_10.setEnabled(True)
        else:
            self.dlg.spinBox_B10.setEnabled(False)
            self.dlg.Name_B10.setEnabled(False)
            self.dlg.ComboBox_10.setEnabled(False)
            
    def band11_activation(self):
        if self.dlg.checkBox_B11.isChecked():
            self.dlg.spinBox_B11.setEnabled(True)
            self.dlg.Name_B11.setEnabled(True)
            self.dlg.ComboBox_11.setEnabled(True)
        else:
            self.dlg.spinBox_B11.setEnabled(False)
            self.dlg.Name_B11.setEnabled(False)
            self.dlg.ComboBox_11.setEnabled(False)
            
    def band12_activation(self):
        if self.dlg.checkBox_B12.isChecked():
            self.dlg.spinBox_B12.setEnabled(True)
            self.dlg.Name_B12.setEnabled(True)
            self.dlg.ComboBox_12.setEnabled(True)
        else:
            self.dlg.spinBox_B12.setEnabled(False)
            self.dlg.Name_B12.setEnabled(False)
            self.dlg.ComboBox_12.setEnabled(False)
            
    def band13_activation(self):
        if self.dlg.checkBox_B13.isChecked():
            self.dlg.spinBox_B13.setEnabled(True)
            self.dlg.Name_B13.setEnabled(True)
            self.dlg.ComboBox_13.setEnabled(True)
        else:
            self.dlg.spinBox_B13.setEnabled(False)
            self.dlg.Name_B13.setEnabled(False)
            self.dlg.ComboBox_13.setEnabled(False)
    
    def band14_activation(self):
        if self.dlg.checkBox_B14.isChecked():
            self.dlg.spinBox_B14.setEnabled(True)
            self.dlg.Name_B14.setEnabled(True)
            self.dlg.ComboBox_14.setEnabled(True)
        else:
            self.dlg.spinBox_B14.setEnabled(False)
            self.dlg.Name_B14.setEnabled(False)
            self.dlg.ComboBox_14.setEnabled(False)
            
    def band15_activation(self):
        if self.dlg.checkBox_B15.isChecked():
            self.dlg.spinBox_B15.setEnabled(True)
            self.dlg.Name_B15.setEnabled(True)
            self.dlg.ComboBox_15.setEnabled(True)
        else:
            self.dlg.spinBox_B15.setEnabled(False)
            self.dlg.Name_B15.setEnabled(False)
            self.dlg.ComboBox_15.setEnabled(False)
    
    """
    Behavior of the checkbox of bands whitin the Indeces - Input - TAB
    if the BANDS is not checked, all relative widgets are disabled
    """ 
    def band1_Indeces_activation(self):
        if self.dlg.checkBox_B1_3.isChecked():
            self.dlg.spinBox_B1_3.setEnabled(True)
        else:
            self.dlg.spinBox_B1_3.setEnabled(False)
    def band2_Indeces_activation(self):
        if self.dlg.checkBox_B2_3.isChecked():
            self.dlg.spinBox_B2_3.setEnabled(True)
        else:
            self.dlg.spinBox_B2_3.setEnabled(False)
    def band3_Indeces_activation(self):
        if self.dlg.checkBox_B3_3.isChecked():
            self.dlg.spinBox_B3_3.setEnabled(True)
        else:
            self.dlg.spinBox_B3_3.setEnabled(False)
    def band4_Indeces_activation(self):
        if self.dlg.checkBox_B4_3.isChecked():
            self.dlg.spinBox_B4_3.setEnabled(True)
        else:
            self.dlg.spinBox_B4_3.setEnabled(False)
    def band5_Indeces_activation(self):
        if self.dlg.checkBox_B5_3.isChecked():
            self.dlg.spinBox_B5_3.setEnabled(True)
        else:
            self.dlg.spinBox_B5_3.setEnabled(False)
    def band6_Indeces_activation(self):
        if self.dlg.checkBox_B6_3.isChecked():
            self.dlg.spinBox_B6_3.setEnabled(True)
        else:
            self.dlg.spinBox_B6_3.setEnabled(False)
    def band7_Indeces_activation(self):
        if self.dlg.checkBox_B7_3.isChecked():
            self.dlg.spinBox_B7_3.setEnabled(True)
        else:
            self.dlg.spinBox_B7_3.setEnabled(False)
    def band8_Indeces_activation(self):
        if self.dlg.checkBox_B8_3.isChecked():
            self.dlg.spinBox_B8_3.setEnabled(True)
        else:
            self.dlg.spinBox_B8_3.setEnabled(False)
    def band9_Indeces_activation(self):
        if self.dlg.checkBox_B9_3.isChecked():
            self.dlg.spinBox_B9_3.setEnabled(True)
        else:
            self.dlg.spinBox_B9_3.setEnabled(False)
    def band10_Indeces_activation(self):
        if self.dlg.checkBox_B10_3.isChecked():
            self.dlg.spinBox_B10_3.setEnabled(True)
        else:
            self.dlg.spinBox_B10_3.setEnabled(False)
    def band11_Indeces_activation(self):
        if self.dlg.checkBox_B11_3.isChecked():
            self.dlg.spinBox_B11_3.setEnabled(True)
        else:
            self.dlg.spinBox_B11_3.setEnabled(False)
    def band12_Indeces_activation(self):
        if self.dlg.checkBox_B12_3.isChecked():
            self.dlg.spinBox_B12_3.setEnabled(True)
        else:
            self.dlg.spinBox_B12_3.setEnabled(False)
    def band13_Indeces_activation(self):
        if self.dlg.checkBox_B13_3.isChecked():
            self.dlg.spinBox_B13_3.setEnabled(True)
        else:
            self.dlg.spinBox_B13_3.setEnabled(False)


###################################################################################################
    """
    ALL BROWSE BUTTONS' FUNCTION  
    when a browse button is clicked, a function is called.
    The function opens a file dialog to select a file/folder.
    The selected file/folder path is then set in the corresponding line edit.
    """
    
    def select_file(self):
        file_path, _ = QFileDialog.getOpenFileName(self.dlg, "Select File Raster", "", "Raster Files (*.tif *.jp2);;GeoTIFF Files (*.tif);;JPEG 2000 Files (*.jp2)")
        if file_path:
            self.pre_fire_path = file_path
            self.dlg.lineEdit_file.setText(file_path) 
    def select_safefolder(self):
        folder_path = QFileDialog.getExistingDirectory(self.dlg, "Select Safe Folder", "")
        if folder_path:
            self.pre_fire_path = folder_path
            self.dlg.lineEdit_safefolder.setText(folder_path)
    
###################################################################################################     
    """
    ALL TOOL BUTTONS' FUNCTION  
    when a tool button is clicked, a function is called.
    The function opens a file dialog to specify the path where to save the output.
    The selected path is then set in the corresponding line edit.
    """
            
    def save_output_stack(self):
                filename_stack, _filter = QFileDialog.getSaveFileName(self.dlg, "Select output file","",'GeoTIFF (*.tif);;JPEG 2000 (*.jp2)')
                self.dlg.lineEdit_StackLayer.setText(filename_stack)

    def save_output_NDVI(self):
                filename_NDVI, _filter = QFileDialog.getSaveFileName(self.dlg, "Select output file","",'GeoTIFF (*.tif);;JPEG 2000 (*.jp2)')
                self.dlg.lineEdit_NDVI.setText(filename_NDVI)
                
    def save_output_EVI(self):
                filename_EVI, _filter = QFileDialog.getSaveFileName(self.dlg, "Select output file","",'GeoTIFF (*.tif);;JPEG 2000 (*.jp2)')
                self.dlg.lineEdit_EVI.setText(filename_EVI)
                
    def save_output_SAVI(self):
                filename_SAVI, _filter = QFileDialog.getSaveFileName(self.dlg, "Select output file","",'GeoTIFF (*.tif);;JPEG 2000 (*.jp2)')
                self.dlg.lineEdit_SAVI.setText(filename_SAVI)
                
    def save_output_NDRE(self):
                filename_NDRE, _filter = QFileDialog.getSaveFileName(self.dlg, "Select output file","",'GeoTIFF (*.tif);;JPEG 2000 (*.jp2)')
                self.dlg.lineEdit_NDRE.setText(filename_NDRE)
                
    def save_output_custom(self):
                filename_custom, _filter = QFileDialog.getSaveFileName(self.dlg, "Select output file","",'GeoTIFF (*.tif);;JPEG 2000 (*.jp2)')
                self.dlg.lineEdit_custom.setText(filename_custom)
    
    def save_output_mask(self):
                filename_mask, _filter = QFileDialog.getSaveFileName(self.dlg, "Select output file","",'GeoTIFF (*.tif);;JPEG 2000 (*.jp2)')
                self.dlg.lineEdit_mask.setText(filename_mask)
                
    def save_masked_raster(self):
                filename_masked, _filter = QFileDialog.getSaveFileName(self.dlg, "Select output file","",'GeoTIFF (*.tif);;JPEG 2000 (*.jp2)')
                self.dlg.lineEdit_maskedlayer.setText(filename_masked)
                
    def save_report(self):
                filename_report, _filter = QFileDialog.getSaveFileName(self.dlg, "Select output file","",'*.pdf')
                self.dlg.lineEdit_report.setText(filename_report)

    def save_combined_report(self):
                filename_combined_report, _filter = QFileDialog.getSaveFileName(self.dlg, "Select output file","",'*.pdf')
                self.dlg.lineEdit_combined_report.setText(filename_combined_report)
    
    def save_output_difference(self):
                filename_difference, _filter = QFileDialog.getSaveFileName(self.dlg, "Select output file","",'GeoTIFF (*.tif);;JPEG 2000 (*.jp2)')
                self.dlg.lineEdit_difference.setText(filename_difference)
    
    def save_output_euclidean_distance(self):
                filename_euclidean_distance, _filter = QFileDialog.getSaveFileName(self.dlg, "Select output file","",'GeoTIFF (*.tif);;JPEG 2000 (*.jp2)')
                self.dlg.lineEdit_euclidean.setText(filename_euclidean_distance)
    
    def save_output_hamming_distance(self):
                filename_hamming_distance, _filter = QFileDialog.getSaveFileName(self.dlg, "Select output file","",'GeoTIFF (*.tif);;JPEG 2000 (*.jp2)')
                self.dlg.lineEdit_hamming.setText(filename_hamming_distance)
    
    def save_report_hamming(self):
                filename_report_change, _filter = QFileDialog.getSaveFileName(self.dlg, "Select output file","",'*.pdf')
                self.dlg.lineEdit_report_change.setText(filename_report_change)
    
    def save_output_NDWI(self):
                filename_NDWI, _filter = QFileDialog.getSaveFileName(self.dlg, "Select output file","",'GeoTIFF (*.tif);;JPEG 2000 (*.jp2)')
                self.dlg.lineEdit_NDWI.setText(filename_NDWI)
        
    def save_output_MNDWI(self):
                filename_MNDWI, _filter = QFileDialog.getSaveFileName(self.dlg, "Select output file","",'GeoTIFF (*.tif);;JPEG 2000 (*.jp2)')
                self.dlg.lineEdit_MNDWI.setText(filename_MNDWI)
    
    def save_output_NDMI(self):
                filename_NDMI, _filter = QFileDialog.getSaveFileName(self.dlg, "Select output file","",'GeoTIFF (*.tif);;JPEG 2000 (*.jp2)')
                self.dlg.lineEdit_NDMI.setText(filename_NDMI)

    def save_output_NBR(self):
                filename_NBR, _filter = QFileDialog.getSaveFileName(self.dlg, "Select output file","",'GeoTIFF (*.tif);;JPEG 2000 (*.jp2)')
                self.dlg.lineEdit_NBR.setText(filename_NBR)
    
    def save_output_NBR2(self):
                filename_NBR2, _filter = QFileDialog.getSaveFileName(self.dlg, "Select output file","",'GeoTIFF (*.tif);;JPEG 2000 (*.jp2)')
                self.dlg.lineEdit_NBR2.setText(filename_NBR2)
                
    def save_output_MIRBI(self):
                filename_MIRBI, _filter = QFileDialog.getSaveFileName(self.dlg, "Select output file","",'GeoTIFF (*.tif);;JPEG 2000 (*.jp2)')
                self.dlg.lineEdit_MIRBI.setText(filename_MIRBI)
    
    def save_output_NDBI(self):
                filename_NDBI, _filter = QFileDialog.getSaveFileName(self.dlg, "Select output file","",'GeoTIFF (*.tif);;JPEG 2000 (*.jp2)')
                self.dlg.lineEdit_NDBI.setText(filename_NDBI)
        
    def save_output_NBI(self):
                filename_NBI, _filter = QFileDialog.getSaveFileName(self.dlg, "Select output file","",'GeoTIFF (*.tif);;JPEG 2000 (*.jp2)')
                self.dlg.lineEdit_NBI.setText(filename_NBI)   
    
    def save_output_NBAI(self):
                filename_NBAI, _filter = QFileDialog.getSaveFileName(self.dlg, "Select output file","",'GeoTIFF (*.tif);;JPEG 2000 (*.jp2)')
                self.dlg.lineEdit_NBAI.setText(filename_NBAI)
    
    def save_output_BAEI(self):
                filename_BAEI, _filter = QFileDialog.getSaveFileName(self.dlg, "Select output file","",'GeoTIFF (*.tif);;JPEG 2000 (*.jp2)')
                self.dlg.lineEdit_BAEI.setText(filename_BAEI)
   
    def save_output_discretization(self):
                filename_discretization, _filter = QFileDialog.getSaveFileName(self.dlg, "Select output file","",'GeoTIFF (*.tif);;JPEG 2000 (*.jp2)')
                self.dlg.lineEdit_discretization.setText(filename_discretization)
    
    
###################################################################################################   
    """
    ALL PUSH BUTTONS' FUNCTION  
    when a push button is clicked, a function is called.
    """
    # STACK TAB: "Generate stack"
    def generate_stack(self):
        
        band_list=[]
        path = None    
        
        output_path = self.dlg.lineEdit_StackLayer.text()
        
        if output_path == "":
            QMessageBox.warning(self.dlg, "Warning", "Please specify Output")
            return
        
          
        # input path (raster or folder or each single band)
        # raster
        if self.dlg.groupBox_file.isChecked():
            scenario=1
            path= self.dlg.lineEdit_file.text()
            resolution=None
            # print('path is ', path)
            
            if path is None:
                return QMessageBox.warning(self.dlg, "Warning", "Please specify an Input")
        
        # folder
        elif self.dlg.groupBox_folder.isChecked():
            scenario=2
            path= self.dlg.lineEdit_safefolder.text()
            if self.dlg.radioButton_10m.isChecked():
                resolution=10
            elif self.dlg.radioButton_20m.isChecked():
                resolution=20
            elif self.dlg.radioButton_60m.isChecked():
                resolution=60
            # print('path is ', path, 'res=',resolution)
            if path is None:
                return QMessageBox.warning(self.dlg, "Warning", "Please specify an Input")
        
        # if the scenario is not 1 or 2, go on scenario 3
        elif self.dlg.groupBox_file.isChecked()==False and self.dlg.groupBox_folder.isChecked()==False:
            scenario=3
            resolution=None
        
        # read the bands selected and their position for the new stack and the path if a layer is selected by the user
        for i in range(1, 16):
            if getattr(self.dlg, f"checkBox_B{i}").isChecked():
                index=i
                position=getattr(self.dlg,f"spinBox_B{i}").value()
                
                name= getattr(self.dlg, f"Name_B{i}").text()
                
                text = getattr(self.dlg, f"ComboBox_{i}").currentText()
                # print(text)
                
                if text is None or text == "":
                    if self.dlg.groupBox_file.isChecked()==False and self.dlg.groupBox_folder.isChecked()==False:
                        return QMessageBox.warning(self.dlg, "Warning", "Please select a layer")
                    layer_path = None
                    
                else:
                    text_string = str(text)
                    info_path = QgsProject.instance().mapLayersByName(text_string)
                    layer_path = info_path[0].dataProvider().dataSourceUri()
                
                band_list.append((index,position,name,layer_path))
                
                
        # check if the band_list is valid
        
        band_list, message = check_band_list(band_list)
        
        
        if message==1:
            return QMessageBox.warning(self.dlg, "Warning", "Please select at least one band")
        if message==2:
            return QMessageBox.warning(self.dlg, "Warning", "Please select a unique and valid position for each selected band")

        # print('band_list is ', band_list)
        
        message_sg = stack_generator(input_path = path,
                        output_path = output_path,
                        scenario = scenario,
                        resolution = resolution,
                        band_list = band_list)
        
        # print('message_sg is ', message_sg)
        if message_sg==2:
            return QMessageBox.warning(self.dlg, "Warning", "Number of bands in the input file is less than the number of slected bands")
        if message_sg==3:
            return QMessageBox.warning(self.dlg, "Warning","Some selected bands are not founded in the input file.")
        if message_sg==4:
            return  QMessageBox.warning(self.dlg, "Warning", "Shape or geotransform does not match for the selected layers")
        if message_sg==False:
            return QMessageBox.warning(self.dlg, "Warning", "An error occurred during the stack generation. Please check the input parameters and try again. Control the log for more details.")
        if message_sg==True:
            if self.dlg.checkBox_StackLayer.isChecked():
                    iface.addRasterLayer(output_path, "Stacked Raster")
            
            return QMessageBox.information(self.dlg, "Success", "Stack generated successfully")

    # INDICES TAB VEGETATION: "Compute"       
    def compute_vegetation(self):
        
        band_list, input_path, scale_factor, message = define_band_list(self)
        
        if message==1:
            return QMessageBox.warning(self.dlg, "Warning", "Please select at least one band")
        if message==2:
            return QMessageBox.warning(self.dlg, "Warning", "Please select a unique and valid position for each selected band")
        if message==3:
            return QMessageBox.warning(self.dlg, "Warning", "Please select an Input")
        
        indices_list=[]
        
        # check which indices are selected
        if self.dlg.checkBox_NDVI.isChecked():  
            output_path = self.dlg.lineEdit_NDVI.text()
            if output_path == "":
                return QMessageBox.warning(self.dlg, "Warning", "Please specify NDVI Output")
            indices_list.append(('NDVI',output_path))
        
        if self.dlg.checkBox_EVI.isChecked():  
            output_path = self.dlg.lineEdit_EVI.text()
            if output_path == "":
                return QMessageBox.warning(self.dlg, "Warning", "Please specify EVI Output")
            indices_list.append(('EVI',output_path))
            
        if self.dlg.checkBox_SAVI.isChecked():
            output_path = self.dlg.lineEdit_SAVI.text()
            if output_path == "":
                return QMessageBox.warning(self.dlg, "Warning", "Please specify SAVI Output")
            indices_list.append(('SAVI',output_path))
            
        if self.dlg.checkBox_NDRE.isChecked():
            output_path = self.dlg.lineEdit_NDRE.text()
            if output_path == "":
                return QMessageBox.warning(self.dlg, "Warning", "Please specify NDRE Output")
            indices_list.append(('NDRE',output_path))
  
        L=self.dlg.doubleSpinBox_SAVI.value()
        
        if len(indices_list)==0:
            return QMessageBox.warning(self.dlg, "Warning", "Please select at least a index")
        
        
        compute_vegetation_indices(input_path = input_path,
                                    band_list = band_list,
                                    indices_list = indices_list,
                                    scale_factor = scale_factor,
                                    L_SAVI=L)
            
        if self.dlg.checkBox_vegetation_display.isChecked():
            for index in indices_list:
                iface.addRasterLayer(index[1], index[0])
        
        return QMessageBox.information(self.dlg, "Success", "Vegetation Indices generated successfully")

    # INDICES TAB WATER: "Compute" 
    def compute_water(self):

        band_list, input_path, scale_factor, message = define_band_list(self)
        if message==1:
            return QMessageBox.warning(self.dlg, "Warning", "Please select at least one band")
        if message==2:
            return QMessageBox.warning(self.dlg, "Warning", "Please select a unique and valid position for each selected band")
        if message==3:
            return QMessageBox.warning(self.dlg, "Warning", "Please select an Input")
        
        
        indices_list=[]
        
        # check which indices are selected
        if self.dlg.checkBox_NDWI.isChecked():  
            output_path = self.dlg.lineEdit_NDWI.text()
            if output_path == "":
                return QMessageBox.warning(self.dlg, "Warning", "Please specify NDWI Output")
            indices_list.append(('NDWI',output_path))
        
        if self.dlg.checkBox_MNDWI.isChecked():  
            output_path = self.dlg.lineEdit_MNDWI.text()
            if output_path == "":
                return QMessageBox.warning(self.dlg, "Warning", "Please specify MNDWI Output")
            indices_list.append(('MNDWI',output_path))
            
        if self.dlg.checkBox_NDMI.isChecked():
            output_path = self.dlg.lineEdit_NDMI.text()
            if output_path == "":
                return QMessageBox.warning(self.dlg, "Warning", "Please specify NDMI Output")
            indices_list.append(('NDMI',output_path))
        
        if len(indices_list)==0:
            return QMessageBox.warning(self.dlg, "Warning", "Please select at least a index")
        
        compute_water_indices(input_path = input_path,
                                    band_list = band_list,
                                    indices_list = indices_list,
                                    scale_factor = scale_factor
                                    )
            
        if self.dlg.checkBox_water.isChecked():
            for index in indices_list:
                iface.addRasterLayer(index[1], index[0])
        
        return QMessageBox.information(self.dlg, "Success", "Water Indices generated successfully")
  
    # INDICES TAB FIRE: "Compute"   
    def compute_fire(self):
        
        band_list, input_path, scale_factor, message = define_band_list(self)
        if message==1:
            return QMessageBox.warning(self.dlg, "Warning", "Please select at least one band")
        if message==2:
            return QMessageBox.warning(self.dlg, "Warning", "Please select a unique and valid position for each selected band")
        if message==3:
            return QMessageBox.warning(self.dlg, "Warning", "Please select an Input")
        
        indices_list=[]
        
        # check which indices are selected
        if self.dlg.checkBox_NBR.isChecked():  
            output_path = self.dlg.lineEdit_NBR.text()
            if output_path == "":
                return QMessageBox.warning(self.dlg, "Warning", "Please specify NBR Output")
            indices_list.append(('NBR',output_path))
        
        if self.dlg.checkBox_NBR2.isChecked():  
            output_path = self.dlg.lineEdit_NBR2.text()
            if output_path == "":
                return QMessageBox.warning(self.dlg, "Warning", "Please specify NBR2 Output")
            indices_list.append(('NBR2',output_path))
            
        if self.dlg.checkBox_MIRBI.isChecked():
            output_path = self.dlg.lineEdit_MIRBI.text()
            if output_path == "":
                return QMessageBox.warning(self.dlg, "Warning", "Please specify MIRBI Output")
            indices_list.append(('MIRBI',output_path))
        
        if len(indices_list)==0:
            return QMessageBox.warning(self.dlg, "Warning", "Please select at least a index")
        
        compute_fire_indices(input_path = input_path,
                                    band_list = band_list,
                                    indices_list = indices_list,
                                    scale_factor = scale_factor
                                    )
            
        if self.dlg.checkBox_fire.isChecked():
            for index in indices_list:
                iface.addRasterLayer(index[1], index[0])
        
        return QMessageBox.information(self.dlg, "Success", "Fire Indices generated successfully")

    # INDICES TAB BUILDING: "Compute"   
    def compute_building(self):
        
        band_list, input_path, scale_factor, message = define_band_list(self)
        if message==1:
            return QMessageBox.warning(self.dlg, "Warning", "Please select at least one band")
        if message==2:
            return QMessageBox.warning(self.dlg, "Warning", "Please select a unique and valid position for each selected band")
        if message==3:
            return QMessageBox.warning(self.dlg, "Warning", "Please select an Input")
                
        
        indices_list=[]
        
        # check which indices are selected
        if self.dlg.checkBox_NDBI.isChecked():  
            output_path = self.dlg.lineEdit_NDBI.text()
            if output_path == "":
                return QMessageBox.warning(self.dlg, "Warning", "Please specify NDBI Output")
            indices_list.append(('NDBI',output_path))
        
        if self.dlg.checkBox_NBI.isChecked():  
            output_path = self.dlg.lineEdit_NBI.text()
            if output_path == "":
                return QMessageBox.warning(self.dlg, "Warning", "Please specify NBI Output")
            indices_list.append(('NBI',output_path))
            
        if self.dlg.checkBox_NBAI.isChecked():
            output_path = self.dlg.lineEdit_NBAI.text()
            if output_path == "":
                return QMessageBox.warning(self.dlg, "Warning", "Please specify NBAI Output")
            indices_list.append(('NBAI',output_path))
            
        
        if self.dlg.checkBox_BAEI.isChecked():
            output_path = self.dlg.lineEdit_BAEI.text()
            if output_path == "":
                return QMessageBox.warning(self.dlg, "Warning", "Please specify BAEI Output")
            indices_list.append(('BAEI',output_path))
  
        if len(indices_list)==0:
            return QMessageBox.warning(self.dlg, "Warning", "Please select at least a index")
        
        compute_building_indices(input_path = input_path,
                                    band_list = band_list,
                                    indices_list = indices_list,
                                    scale_factor = scale_factor
                                    )
            
        if self.dlg.checkBox_building.isChecked():
            for index in indices_list:
                iface.addRasterLayer(index[1], index[0])
        
        return QMessageBox.information(self.dlg, "Success", "Building Indices generated successfully")

    # INDICES TAB CUSTOM: "Compute"
    def compute_custom(self):
        
        band_list, input_path, scale_factor, message = define_band_list(self)
        if message==1:
            return QMessageBox.warning(self.dlg, "Warning", "Please select at least one band")
        if message==2:
            return QMessageBox.warning(self.dlg, "Warning", "Please select a unique and valid position for each selected band")
        
        
        output_path = self.dlg.lineEdit_custom.text()
        
        expression_text = self.dlg.textEdit.toPlainText()
        
        # print('expression', expression_text)
        
        compute_expression( input_path = input_path,
                            band_list = band_list,
                            expression = expression_text,
                            scale_factor = scale_factor,
                            output_path = output_path)
        
        if self.dlg.checkBox_custom_display.isChecked():
            iface.addRasterLayer(output_path, "Custom Index")
        
        return QMessageBox.information(self.dlg, "Success", "Custom Index generated successfully")
        
    # ANALISYS TAB MASKING: "Compute Mask"
    def compute_mask(self):
        
        output_path = self.dlg.lineEdit_mask.text()  
        
        if output_path == "":
            QMessageBox.warning(self.dlg, "Warning", "Please specify Output")
            return     
        
        text = self.dlg.mMapLayerComboBox_maskgenaration.currentText()
        
        if text == "":
            return QMessageBox.warning(self.dlg, "Warning", "Please select an Input")
        else:
            text_string = str(text)
            info_path = QgsProject.instance().mapLayersByName(text_string)
            input_path = info_path[0].dataProvider().dataSourceUri()
        
        
        if self.dlg.groupBox_discrete.isChecked():
            value = []
            for i in range(0,12):
                if getattr(self.dlg, f"Classe_{i}").isChecked():
                    value.append(i)
            mask_type = 'discrete'
            
        elif self.dlg.groupBox_continuos.isChecked():
            value = self.dlg.doubleSpinBox_mask.value()
            mask_type = 'continuous'
        
        elif self.dlg.groupBox_discrete.isChecked()==False and self.dlg.groupBox_continuos.isChecked()==False:
            return QMessageBox.warning(self.dlg, "Warning", "Please select a Masking Type")
        
        generate_mask(input_path = input_path,
                        mask_type = mask_type,
                        masking_value = value,
                        output_path = output_path)
        
        if self.dlg.checkBox_mask.isChecked():
            iface.addRasterLayer(output_path, "Mask Raster")
        
        return QMessageBox.information(self.dlg, "Success", "Mask generated successfully")
    
    # ANALISYS TAB MASKING: "Masking Input Layer"
    def masking_raster(self):
        
        output_path = self.dlg.lineEdit_maskedlayer.text()
        
        if output_path == "":
            QMessageBox.warning(self.dlg, "Warning", "Please specify Output")
            return
        
        mask_text = self.dlg.mMapLayerComboBox_mask.currentText()
        
        if mask_text == "":
            return QMessageBox.warning(self.dlg, "Warning", "Please select a Mask")
        else:
            text_string = str(mask_text)
            info_path = QgsProject.instance().mapLayersByName(text_string)
            mask_path = info_path[0].dataProvider().dataSourceUri()
        
        input_text = self.dlg.mMapLayerComboBox_layer2mask.currentText()
        if input_text == "":
            return QMessageBox.warning(self.dlg, "Warning", "Please select an Input")
        else:
            text_string = str(input_text)
            info_path = QgsProject.instance().mapLayersByName(text_string)
            input_path = info_path[0].dataProvider().dataSourceUri()
        
        
        message = apply_mask(input_path = input_path,
                    mask_path = mask_path,
                    output_path = output_path)
        
        if message==False:
            return QMessageBox.warning(self.dlg,"Warning","Shape or geotransform does not match for the selected layers")
            
        if self.dlg.checkBox_maskedlayer.isChecked():
            iface.addRasterLayer(output_path, "Masked Raster")
        

        return QMessageBox.information(self.dlg, "Success", "Masked Raster generated successfully")   
    
    # ANALISYS STATISTIC: "Save report"    
    def generate_report(self):
        
        report_indices = []
        
        if self.dlg.checkBox_histogram.isChecked():
            report_indices.append(1)
        if self.dlg.checkBox_boxplot.isChecked():
            report_indices.append(2)
        if self.dlg.checkBox_statistic.isChecked():
            report_indices.append(3)
        
        layer_report_text = self.dlg.comboBox_report.currentText()
        
        if layer_report_text == "":
            return QMessageBox.warning(self.dlg, "Warning", "Please select a Layer")
        else:
            text_string = str(layer_report_text)
            info_path = QgsProject.instance().mapLayersByName(text_string)
            layer_path = info_path[0].dataProvider().dataSourceUri()
        
        output_path = self.dlg.lineEdit_report.text()
        if output_path == "":
            return QMessageBox.warning(self.dlg, "Warning", "Please specify Output")
        
        generate_report(input_path = layer_path,
                        output_path = output_path,
                        report_indices = report_indices)

        return QMessageBox.information(self.dlg, "Success", "Report generated successfully")
     
    # ANALISYS STATISTIC: "Save combined report"   
    def generate_combined_report(self):
        
        report_indices = []
        
        if self.dlg.checkBox_histo_combined_report.isChecked():
            report_indices.append(1)
        if self.dlg.checkBox_boxplot_combined_report.isChecked():
            report_indices.append(2)
        if self.dlg.checkBox_stat_combined_report.isChecked():
            report_indices.append(3)
            
        layer_report_text = self.dlg.comboBox_report_continuos.currentText()
        if layer_report_text == "":
            return QMessageBox.warning(self.dlg, "Warning", "Please select a Layer")
        else:
            text_string = str(layer_report_text)
            info_path = QgsProject.instance().mapLayersByName(text_string)
            layer_path_continuos = info_path[0].dataProvider().dataSourceUri()
        
            
        layer_report_text2 = self.dlg.comboBox_report_discrete.currentText()
        if layer_report_text2 == "":
            return QMessageBox.warning(self.dlg, "Warning", "Please select a Layer")
        else:
            text_string = str(layer_report_text2)
            info_path = QgsProject.instance().mapLayersByName(text_string)
            layer_path_discrete = info_path[0].dataProvider().dataSourceUri()
        
        output_path = self.dlg.lineEdit_combined_report.text()
        if output_path == "":
            return QMessageBox.warning(self.dlg, "Warning", "Please specify Output")
        
        message=generate_comb_report(layer_continous = layer_path_continuos,
                                layer_discrete = layer_path_discrete,
                                output_path = output_path,
                                report_indices = report_indices)
        
        if message==False:
            return QMessageBox.warning(self.dlg, "Warning", "Shape or geotransform does not match for the selected layers")


        
        return QMessageBox.information(self.dlg, "Success", "Report generated successfully")
    
    # CHANGE DETECTION TAB: "Save output difference"
    def change_detection(self):
        layer_t0 = self.dlg.comboBox_layer_t0.currentText()
        
        if layer_t0 == "":
            return QMessageBox.warning(self.dlg, "Warning", "Please select Layer t0")
        else:
            text_t0 = str(layer_t0)
            info_path_t0 = QgsProject.instance().mapLayersByName(text_t0)
            layer_t0_path = info_path_t0[0].dataProvider().dataSourceUri()
        
        
        layer_t1 = self.dlg.comboBox_layer_t1.currentText()
        if layer_t1 == "":
            return QMessageBox.warning(self.dlg, "Warning", "Please select Layer t1")
        else:
            text_t1 = str(layer_t1)
            info_path_t1 = QgsProject.instance().mapLayersByName(text_t1)
            layer_t1_path = info_path_t1[0].dataProvider().dataSourceUri()
                       
        output_path = []

        
        if self.dlg.checkBox_difference.isChecked():
            path= self.dlg.lineEdit_difference.text()
            if path == "":
                return QMessageBox.warning(self.dlg, "Warning", "Please specify Output")
            else:
                output_path.append((path,'difference'))
            
        if self.dlg.checkBox_euclidean_distance.isChecked():
            path= self.dlg.lineEdit_euclidean.text()
            if path == "":
                return QMessageBox.warning(self.dlg, "Warning", "Please specify Output")
            else:
                output_path.append((path,'euclidean'))
    
        
        if self.dlg.checkBox_hamming.isChecked():
            path= self.dlg.lineEdit_hamming.text()
            if path == "":
                return QMessageBox.warning(self.dlg, "Warning", "Please specify Output")
            else:
                output_path.append((path,'hamming'))
            path= self.dlg.lineEdit_report_change.text()
            if path != "":
                output_path.append((path,'Hamm_report'))
        
        
        if self.dlg.checkBox_hamming.isChecked()==False and self.dlg.checkBox_difference.isChecked()==False and self.dlg.checkBox_euclidean_distance.isChecked()==False:
            return QMessageBox.warning(self.dlg, "Warning", "Please select a Distance")
                

        message=compute_change_detection(input_path_t0 = layer_t0_path,
                                  input_path_t1 = layer_t1_path,
                                  output_path = output_path
                                  )

        if message==False:
            return QMessageBox.warning(self.dlg, "Warning", "Shape or geotransform does not match for the selected layers")
        
        if self.dlg.checkBox_change.isChecked():
            for elem in output_path:
                if elem[1] != 'Hamm_report':
                    iface.addRasterLayer(elem[0], elem[1])
          
            
        return QMessageBox.information(self.dlg, "Success", "Change Detection generated successfully")
    
    # ANALISYS DISCRETIZATION: ""
    def insertRow(self):
        row_count = self.dlg.tableWidget.rowCount()
        self.dlg.tableWidget.insertRow(row_count)  # Aggiunge alla fine
        return
        
    def removeRow(self):
        row_count = self.dlg.tableWidget.rowCount()
        if row_count > 0:
            self.dlg.tableWidget.removeRow(row_count - 1)  # Rimuove l’ultima
        return
    
    def discretization(self):
        
        #leggere input layer
        layer_input = self.dlg.mMapLayerComboBox_LayerToDiscretize.currentText()
        
        if layer_input == "":
            return QMessageBox.warning(self.dlg, "Warning", "Please select Input")
        else:
            text = str(layer_input)
            info_path = QgsProject.instance().mapLayersByName(text)
            layer_path = info_path[0].dataProvider().dataSourceUri()
        
        
        output_path = self.dlg.lineEdit_discretization.text()
        
        if output_path == "":
            QMessageBox.warning(self.dlg, "Warning", "Please specify Output")
            return
        
        
        #leggere i valori da discretizzare
        #values are in the tableWidget 
        table = self.dlg.tableWidget
        rows = table.rowCount()
        cols = table.columnCount()

        table_values = []

        for i in range(rows):
            row_data = []
            for j in range(cols):
                item = table.item(i, j)
                value = item.text() if item else ""
                value = value.replace(',', '.')  # replace comma with dot
                row_data.append(float(value))
            table_values.append(tuple(row_data))  # convert row to tuple

        # print('data is ', table_values)
        
        # check the validity of the values
        message=validate_discretization(table_values)
        if message==1:
            return QMessageBox.warning(self.dlg, "Warning", "Classes must be unique")
        if message==2:
            return QMessageBox.warning(self.dlg, "Warning", "Intervals are overlapping")
        
        
        #applica funzione di discretizzazione
        
        message = classify(input_path=layer_path,
                           table_values=table_values,
                           output_path=output_path,
                           )
        
        if message ==3:
            return QMessageBox.critical(None, "Error", "Could not open input raster")
        if message ==4:
            return QMessageBox.critical(None, "Error", "Input raster has more than one band")
        
        if self.dlg.checkBox_discretization.isChecked():
            iface.addRasterLayer(output_path, "Discretized Raster")
        
        return QMessageBox.information(self.dlg, "Success", "Discretization generated successfully")

###################################################################################################
###################################################################################################
 
    def run(self):
        """Run method that performs all the real work"""

        # The GUI is reseted each time the pluign is closed and S2A gui starts from the begging
        # to take trace of what was done it is necessary to revome  self.first_start == False
        if self.first_start == True or self.first_start == False:
            self.first_start = False
            self.dlg = sentinel2analyzerDialog()

            
            """ STACK TAB """
            # group boxes       
            self.dlg.groupBox_folder.toggled.connect(self.deactivatefile)
            self.dlg.groupBox_file.toggled.connect(self.deactivatefolder)
            # browse buttons           
            self.dlg.pushButton_file.clicked.connect(self.select_file)
            self.dlg.pushButton_safefolder.clicked.connect(self.select_safefolder)
            # tool buttons
            self.dlg.toolButton_StackLayer.clicked.connect(self.save_output_stack)                           
            # push button
            self.dlg.pushButton_stack.clicked.connect(self.generate_stack)
            
            # checkboxes behavior
            self.dlg.checkBox_B1.toggled.connect(self.band1_activation)
            self.dlg.checkBox_B2.toggled.connect(self.band2_activation)
            self.dlg.checkBox_B3.toggled.connect(self.band3_activation)
            self.dlg.checkBox_B4.toggled.connect(self.band4_activation)
            self.dlg.checkBox_B5.toggled.connect(self.band5_activation)
            self.dlg.checkBox_B6.toggled.connect(self.band6_activation)
            self.dlg.checkBox_B7.toggled.connect(self.band7_activation)
            self.dlg.checkBox_B8.toggled.connect(self.band8_activation)
            self.dlg.checkBox_B9.toggled.connect(self.band9_activation)
            self.dlg.checkBox_B10.toggled.connect(self.band10_activation)
            self.dlg.checkBox_B11.toggled.connect(self.band11_activation)
            self.dlg.checkBox_B12.toggled.connect(self.band12_activation)
            self.dlg.checkBox_B13.toggled.connect(self.band13_activation)
            self.dlg.checkBox_B14.toggled.connect(self.band14_activation)
            self.dlg.checkBox_B15.toggled.connect(self.band15_activation)
            
            
            ########################################################################
            """ INDICES TAB """
            """ input """
            # checkboxes behavior
            self.dlg.checkBox_B1_3.toggled.connect(self.band1_Indeces_activation)
            self.dlg.checkBox_B2_3.toggled.connect(self.band2_Indeces_activation)
            self.dlg.checkBox_B3_3.toggled.connect(self.band3_Indeces_activation)
            self.dlg.checkBox_B4_3.toggled.connect(self.band4_Indeces_activation)
            self.dlg.checkBox_B5_3.toggled.connect(self.band5_Indeces_activation)
            self.dlg.checkBox_B6_3.toggled.connect(self.band6_Indeces_activation)
            self.dlg.checkBox_B7_3.toggled.connect(self.band7_Indeces_activation)
            self.dlg.checkBox_B8_3.toggled.connect(self.band8_Indeces_activation)
            self.dlg.checkBox_B9_3.toggled.connect(self.band9_Indeces_activation)
            self.dlg.checkBox_B10_3.toggled.connect(self.band10_Indeces_activation)
            self.dlg.checkBox_B11_3.toggled.connect(self.band11_Indeces_activation)
            self.dlg.checkBox_B12_3.toggled.connect(self.band12_Indeces_activation)
            self.dlg.checkBox_B13_3.toggled.connect(self.band13_Indeces_activation)
            
            """ vegeatation """
            
            # tool buttons
            self.dlg.toolButton_NDVI.clicked.connect(self.save_output_NDVI)
            self.dlg.toolButton_EVI.clicked.connect(self.save_output_EVI)
            self.dlg.toolButton_SAVI.clicked.connect(self.save_output_SAVI)
            self.dlg.toolButton_NDRE.clicked.connect(self.save_output_NDRE)
            # push button
            self.dlg.pushButton_computeVegetation.clicked.connect(self.compute_vegetation)
            
            """ water """
            # tool buttons
            self.dlg.toolButton_NDWI.clicked.connect(self.save_output_NDWI)
            self.dlg.toolButton_MNDWI.clicked.connect(self.save_output_MNDWI)
            self.dlg.toolButton_NDMI.clicked.connect(self.save_output_NDMI)
            # push button
            self.dlg.pushButton_water.clicked.connect(self.compute_water)
            
            """ fire """
            # tool buttons
            self.dlg.toolButton_NBR.clicked.connect(self.save_output_NBR)
            self.dlg.toolButton_NBR2.clicked.connect(self.save_output_NBR2)
            self.dlg.toolButton_MIRBI.clicked.connect(self.save_output_MIRBI)
            
            # push button
            self.dlg.pushButton_fire.clicked.connect(self.compute_fire)
            
            """ bulding """
            # tool buttons
            self.dlg.toolButton_NDBI.clicked.connect(self.save_output_NDBI)
            self.dlg.toolButton_NBI.clicked.connect(self.save_output_NBI)
            self.dlg.toolButton_NBAI.clicked.connect(self.save_output_NBAI)
            self.dlg.toolButton_BAEI.clicked.connect(self.save_output_BAEI)
             # push button
            self.dlg.pushButton_building.clicked.connect(self.compute_building)
                       
            
            """ custom """
            # tool buttons
            self.dlg.toolButton_custom.clicked.connect(self.save_output_custom)
            
            # Behavior of the Custom TAB
            # buttons of the calculator
            self.dlg.plus_button.clicked.connect(self.plus)
            self.dlg.minus_button.clicked.connect(self.minus)
            self.dlg.mult_button.clicked.connect(self.mult)
            self.dlg.div_button.clicked.connect(self.div)
            self.dlg.open_button.clicked.connect(self.open)
            self.dlg.close_button.clicked.connect(self.close)
            self.dlg.power_button.clicked.connect(self.power)
            
            self.dlg.B1_button.clicked.connect(self.add_B1)
            self.dlg.B2_button.clicked.connect(self.add_B2)
            self.dlg.B3_button.clicked.connect(self.add_B3)
            self.dlg.B4_button.clicked.connect(self.add_B4)
            self.dlg.B5_button.clicked.connect(self.add_B5)
            self.dlg.B6_button.clicked.connect(self.add_B6)
            self.dlg.B7_button.clicked.connect(self.add_B7)
            self.dlg.B8_button.clicked.connect(self.add_B8)
            self.dlg.B9_button.clicked.connect(self.add_B9)
            self.dlg.B10_button.clicked.connect(self.add_B10)
            self.dlg.B11_button.clicked.connect(self.add_B11)
            self.dlg.B12_button.clicked.connect(self.add_B12)
            self.dlg.B13_button.clicked.connect(self.add_B13)
                         
            # verify the status of the checkboxes in the Indices - Input tab
            self.dlg.checkBox_B1_3.stateChanged.connect(self.toggle_b1_button)
            self.dlg.checkBox_B2_3.stateChanged.connect(self.toggle_b2_button)
            self.dlg.checkBox_B3_3.stateChanged.connect(self.toggle_b3_button)
            self.dlg.checkBox_B4_3.stateChanged.connect(self.toggle_b4_button)
            self.dlg.checkBox_B5_3.stateChanged.connect(self.toggle_b5_button)
            self.dlg.checkBox_B6_3.stateChanged.connect(self.toggle_b6_button)
            self.dlg.checkBox_B7_3.stateChanged.connect(self.toggle_b7_button)
            self.dlg.checkBox_B8_3.stateChanged.connect(self.toggle_b8_button)
            self.dlg.checkBox_B9_3.stateChanged.connect(self.toggle_b9_button)
            self.dlg.checkBox_B10_3.stateChanged.connect(self.toggle_b10_button)
            self.dlg.checkBox_B11_3.stateChanged.connect(self.toggle_b11_button)
            self.dlg.checkBox_B12_3.stateChanged.connect(self.toggle_b12_button)
            self.dlg.checkBox_B13_3.stateChanged.connect(self.toggle_b13_button)
            
            # verify the validity of the expression in the textEdit of the calculator 
            self.dlg.textEdit.textChanged.connect(self.validate_expression)
            
            # push button
            self.dlg.compute_custom_button.clicked.connect(self.compute_custom)
            
            
            ########################################################################
            """ ANALYSIS TAB """
            
            # group boxes 
            self.dlg.groupBox_discrete.toggled.connect(self.deactivatecontinuos)
            self.dlg.groupBox_continuos.toggled.connect(self.deactivatediscrete)
            
            #push button
            self.dlg.pushButton_computemask.clicked.connect(self.compute_mask)
            self.dlg.pushButton_maskinglayer.clicked.connect(self.masking_raster)
            self.dlg.pushButton_report.clicked.connect(self.generate_report)
            self.dlg.pushButton_combined_report.clicked.connect(self.generate_combined_report)
            
            # tool button
            self.dlg.toolButton_savemask.clicked.connect(self.save_output_mask)
            self.dlg.toolButton_savemaskedlayer.clicked.connect(self.save_masked_raster)
            self.dlg.toolButton_report.clicked.connect(self.save_report)
            self.dlg.toolButton_combined_report.clicked.connect(self.save_combined_report)
        
            ########################################################################
            """ CHANGE DETECTION TAB """
            # tool button
            self.dlg.toolButton_difference.clicked.connect(self.save_output_difference)
            self.dlg.toolButton_euclidean_distance.clicked.connect(self.save_output_euclidean_distance)
            self.dlg.toolButton_hamming.clicked.connect(self.save_output_hamming_distance)
            self.dlg.toolButton_report_hamming.clicked.connect(self.save_report_hamming)
            
            # push button
            self.dlg.pushButton_change_detection.clicked.connect(self.change_detection)
            
            ########################################################################
            
            
            self.dlg.pushButton_insertRow.clicked.connect(self.insertRow)
            self.dlg.pushButton_removeRow.clicked.connect(self.removeRow)
            self.dlg.pushButton_discretize.clicked.connect(self.discretization)
            
            self.dlg.toolButton_discretization.clicked.connect(self.save_output_discretization)
            
            ########################################################################
        
        # show the dialog
        # self.dlg.setFixedSize(self.dlg.sizeHint()) 
        self.dlg.resize(50, 60)
        self.dlg.show()
        # Run the dialog event loop
        result = self.dlg.exec_()
        # See if OK was pressed
        if result:
            pass
