# -*- coding: utf-8 -*-

"""
/***************************************************************************
 Geohazard
                                 A QGIS plugin
 Plugin with various tools for landslide analysis and management
 Generated by Plugin Builder: http://g-sherman.github.io/Qgis-Plugin-Builder/
                              -------------------
        begin                : 2024-11-29
        copyright            : (C) 2024 by Campus S., Castelli M., Fasciano C., Filipello A.
        email                : andrea[dot]filipello[at]arpa[dot]piemonte[dot]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.                                   *
 *                                                                         *
 ***************************************************************************/
"""

__author__ = 'Campus S., Castelli M., Fasciano C., Filipello A.'
__date__ = '2024-11-29'
__copyright__ = '(C) 2024 by Campus S., Castelli M., Fasciano C., Filipello A.'

# This will get replaced with a git SHA1 when you do a git archive

__revision__ = '$Format:%H$'

import os
# Importa QIcon da PyQt5 per le icone
from PyQt5.QtGui import QIcon 

from qgis.core import QgsProcessing
from qgis.core import QgsProcessingAlgorithm
from qgis.core import QgsProcessingMultiStepFeedback
from qgis.core import QgsProcessingParameterRasterLayer
from qgis.core import QgsProcessingParameterNumber
from qgis.core import QgsProcessingParameterVectorLayer
from qgis.core import QgsProcessingParameterFeatureSink
from qgis.core import QgsProcessingParameterDefinition
from qgis.core import QgsProcessingContext
import processing
# Aggiungo per nome output
from qgis.core import QgsProcessingContext

class RockfallDrokaBasic(QgsProcessingAlgorithm):

## Aggiunta Icona
    def icon(self):
        """
        Should return a QIcon which is used for your provider inside
        the Processing toolbox.
        """
        # Individua la cartella del plugin in cui risiede questo file script
        cmd_folder = os.path.dirname(__file__)
        # Costruisce il percorso relativo verso la sottocartella icons
        icon_path = os.path.join(cmd_folder, 'icons', 'droka.png')
        
        return QIcon(icon_path)

    def initAlgorithm(self, config=None):
        self.addParameter(QgsProcessingParameterRasterLayer('dtm', 'DTM', defaultValue=None))
        self.addParameter(QgsProcessingParameterNumber('cell_size', 'Cell size', type=QgsProcessingParameterNumber.Double, defaultValue=10))
        self.addParameter(QgsProcessingParameterVectorLayer('source_points', 'Source Points', types=[QgsProcessing.TypeVectorPoint], defaultValue=None))
        param = QgsProcessingParameterNumber('lateral_spreading_angle_', 'Lateral spreading angle (°)', type=QgsProcessingParameterNumber.Double, minValue=1, maxValue=179, defaultValue=15)
        param.setFlags(param.flags() | QgsProcessingParameterDefinition.FlagAdvanced)
        self.addParameter(param)
        self.addParameter(QgsProcessingParameterNumber('energy_angle_', 'Energy angle (°)', type=QgsProcessingParameterNumber.Double, minValue=10, maxValue=90, defaultValue=40))
        self.addParameter(QgsProcessingParameterNumber('mass_kg', 'Mass (kg)', type=QgsProcessingParameterNumber.Integer, defaultValue=2600))
        self.addParameter(QgsProcessingParameterFeatureSink('Results_drokaBasic', 'Results_Droka basic', type=QgsProcessing.TypeVectorAnyGeometry, createByDefault=True, supportsAppend=True, defaultValue=None))

    def processAlgorithm(self, parameters, context, model_feedback):
        # Use a multi-step feedback, so that individual child algorithm progress reports are adjusted for the
        # overall progress through the model
        feedback = QgsProcessingMultiStepFeedback(31, model_feedback)
        results = {}
        outputs = {}

        # start_elev
        # Estraggo (campionando) la quota dei source point
        alg_params = {
            'COLUMN_PREFIX': 'start_elev',
            'INPUT': parameters['source_points'],
            'RASTERCOPY': parameters['dtm'],
            'OUTPUT': QgsProcessing.TEMPORARY_OUTPUT
        }
        outputs['Start_elev'] = processing.run('native:rastersampling', alg_params, context=context, feedback=feedback, is_child_algorithm=True)

        feedback.setCurrentStep(1)
        if feedback.isCanceled():
            return {}

        # Aspect
        alg_params = {
            'INPUT': parameters['dtm'],
            'Z_FACTOR': 1,
            'OUTPUT': QgsProcessing.TEMPORARY_OUTPUT
        }
        outputs['Aspect'] = processing.run('native:aspect', alg_params, context=context, feedback=feedback, is_child_algorithm=True)

        feedback.setCurrentStep(2)
        if feedback.isCanceled():
            return {}

        # Campiona aspect
        # Unisce gli attributi Aspect e start_elev
        alg_params = {
            'COLUMN_PREFIX': 'aspect',
            'INPUT': outputs['Start_elev']['OUTPUT'],
            'RASTERCOPY': outputs['Aspect']['OUTPUT'],
            'OUTPUT': QgsProcessing.TEMPORARY_OUTPUT
        }
        outputs['CampionaAspect'] = processing.run('native:rastersampling', alg_params, context=context, feedback=feedback, is_child_algorithm=True)

        feedback.setCurrentStep(3)
        if feedback.isCanceled():
            return {}

        # Calculate x
        alg_params = {
            'FIELD_LENGTH': 50,
            'FIELD_NAME': 'x',
            'FIELD_PRECISION': 2,
            'FIELD_TYPE': 0,  # Decimale (doppia precisione)
            'FORMULA': '$x',
            'INPUT': outputs['CampionaAspect']['OUTPUT'],
            'OUTPUT': QgsProcessing.TEMPORARY_OUTPUT
        }
        outputs['CalculateX'] = processing.run('native:fieldcalculator', alg_params, context=context, feedback=feedback, is_child_algorithm=True)

        feedback.setCurrentStep(4)
        if feedback.isCanceled():
            return {}

        # Calculate y
        # Calcolo x e y
        alg_params = {
            'FIELD_LENGTH': 50,
            'FIELD_NAME': 'y',
            'FIELD_PRECISION': 2,
            'FIELD_TYPE': 0,  # Decimale (doppia precisione)
            'FORMULA': '$y',
            'INPUT': outputs['CalculateX']['OUTPUT'],
            'OUTPUT': QgsProcessing.TEMPORARY_OUTPUT
        }
        outputs['CalculateY'] = processing.run('native:fieldcalculator', alg_params, context=context, feedback=feedback, is_child_algorithm=True)

        feedback.setCurrentStep(5)
        if feedback.isCanceled():
            return {}

        # Field lateral
        alg_params = {
            'FIELD_LENGTH': 10,
            'FIELD_NAME': 'lateral',
            'FIELD_PRECISION': 2,
            'FIELD_TYPE': 0,  # Decimale (doppia precisione)
            'FORMULA': parameters['lateral_spreading_angle_'],
            'INPUT': outputs['CalculateY']['OUTPUT'],
            'OUTPUT': QgsProcessing.TEMPORARY_OUTPUT
        }
        outputs['FieldLateral'] = processing.run('native:fieldcalculator', alg_params, context=context, feedback=feedback, is_child_algorithm=True)

        feedback.setCurrentStep(6)
        if feedback.isCanceled():
            return {}

        # Triangle
        # A partire dai source point creo i triangoli generando i vertici con la formula:   
        # x + 1000 * sin (aspect - 15°)
        # 
        # Impostata una divergenza di +15 e -15 ed una distanza di 1000 metri
        alg_params = {
            'EXPRESSION': 'make_triangle(make_point ($x,$y),\r\nmake_point ($x+2000*sin( radians( "aspect1"- "lateral" )),$y+2000*cos(radians("aspect1"- "lateral"))), make_point ($x+2000*sin( radians( "aspect1"+ "lateral" )),$y+2000*cos(radians("aspect1"+ "lateral" ))))',
            'INPUT': outputs['FieldLateral']['OUTPUT'],
            'OUTPUT_GEOMETRY': 0,  # Poligono
            'WITH_M': False,
            'WITH_Z': False,
            'OUTPUT': QgsProcessing.TEMPORARY_OUTPUT
        }
        outputs['Triangle'] = processing.run('native:geometrybyexpression', alg_params, context=context, feedback=feedback, is_child_algorithm=True)

        feedback.setCurrentStep(7)
        if feedback.isCanceled():
            return {}

        # Envolope triangle
        # Unisco tutti i trangoli in uno solo
        alg_params = {
            'FIELD': [''],
            'INPUT': outputs['Triangle']['OUTPUT'],
            'SEPARATE_DISJOINT': False,
            'OUTPUT': QgsProcessing.TEMPORARY_OUTPUT
        }
        outputs['EnvolopeTriangle'] = processing.run('native:dissolve', alg_params, context=context, feedback=feedback, is_child_algorithm=True)

        feedback.setCurrentStep(8)
        if feedback.isCanceled():
            return {}

        # Triangle point
        # Genero i punti nel triangolo
        alg_params = {
            'INPUT_RASTER': parameters['dtm'],
            'INPUT_VECTOR': outputs['EnvolopeTriangle']['OUTPUT'],
            'OUTPUT': QgsProcessing.TEMPORARY_OUTPUT
        }
        outputs['TrianglePoint'] = processing.run('native:generatepointspixelcentroidsinsidepolygons', alg_params, context=context, feedback=feedback, is_child_algorithm=True)

        feedback.setCurrentStep(9)
        if feedback.isCanceled():
            return {}

        # Merge attributes
        # Unisco gli attributi dei triangoli precedenti nei punti creati del triangolo grande
        alg_params = {
            'DISCARD_NONMATCHING': True,
            'INPUT': outputs['TrianglePoint']['OUTPUT'],
            'JOIN': outputs['Triangle']['OUTPUT'],
            'JOIN_FIELDS': [''],
            'METHOD': 0,  # Crea elementi separati per ciascun elemento corrispondente (uno-a-molti)
            'PREDICATE': [0],  # interseca
            'PREFIX': '',
            'OUTPUT': QgsProcessing.TEMPORARY_OUTPUT
        }
        outputs['MergeAttributes'] = processing.run('native:joinattributesbylocation', alg_params, context=context, feedback=feedback, is_child_algorithm=True)

        feedback.setCurrentStep(10)
        if feedback.isCanceled():
            return {}

        # Calculate distance
        # Calcola la distanza di ogni punto tramite le cordinate x-y dei punti dalla sorgente tramite la formula:
        # sqrt [ (x-xo)^2 + (y-yo)^2 ]
        alg_params = {
            'FIELD_LENGTH': 10,
            'FIELD_NAME': 'distance',
            'FIELD_PRECISION': 2,
            'FIELD_TYPE': 0,  # Decimale (doppia precisione)
            'FORMULA': '(($x - "x" )^2 +($y - "y" )^2 )^0.5',
            'INPUT': outputs['MergeAttributes']['OUTPUT'],
            'OUTPUT': QgsProcessing.TEMPORARY_OUTPUT
        }
        outputs['CalculateDistance'] = processing.run('native:fieldcalculator', alg_params, context=context, feedback=feedback, is_child_algorithm=True)

        feedback.setCurrentStep(11)
        if feedback.isCanceled():
            return {}

        # final_elev
        # Estraggo (campionando) le quote finali di accumulo
        # 
        # I punti che escono da qui hanno tutte le info: 
        # - quota iniziale
        # - aspect
        # - shadow angle
        # - distanza
        # - quota finale
        alg_params = {
            'COLUMN_PREFIX': 'final_elev',
            'INPUT': outputs['CalculateDistance']['OUTPUT'],
            'RASTERCOPY': parameters['dtm'],
            'OUTPUT': QgsProcessing.TEMPORARY_OUTPUT
        }
        outputs['Final_elev'] = processing.run('native:rastersampling', alg_params, context=context, feedback=feedback, is_child_algorithm=True)

        feedback.setCurrentStep(12)
        if feedback.isCanceled():
            return {}

        # Field shadow angle
        alg_params = {
            'FIELD_LENGTH': 10,
            'FIELD_NAME': 'shadow',
            'FIELD_PRECISION': 2,
            'FIELD_TYPE': 0,  # Decimale (doppia precisione)
            'FORMULA': parameters['energy_angle_'],
            'INPUT': outputs['Final_elev']['OUTPUT'],
            'OUTPUT': QgsProcessing.TEMPORARY_OUTPUT
        }
        outputs['FieldShadowAngle'] = processing.run('native:fieldcalculator', alg_params, context=context, feedback=feedback, is_child_algorithm=True)

        feedback.setCurrentStep(13)
        if feedback.isCanceled():
            return {}

        # Calculation delta
        # Calcolo "arrivo" tramite la formula:
        # (quota_iniziale - distanza * tan(shadow_angle)) - quota_finale
        # 
        # Questi parametri vanno presi dagli attributi uscenti dai punti di "Quote_accumulo". Quindi mettendo la formula sul calcolatore di Qgis (fuori da processing) selezionando il layer "quote_accumulo" e poi copiando la formula qui.
        # 
        # ARRIVO = Il delta della energy line: distanza dalla energy line al terreno
        alg_params = {
            'FIELD_LENGTH': 10,
            'FIELD_NAME': 'delta',
            'FIELD_PRECISION': 3,
            'FIELD_TYPE': 0,  # Decimale (doppia precisione)
            'FORMULA': '( "start_elev1"  -  "distance"  *tan(radians("shadow" )))-  "final_elev1"  ',
            'INPUT': outputs['FieldShadowAngle']['OUTPUT'],
            'OUTPUT': QgsProcessing.TEMPORARY_OUTPUT
        }
        outputs['CalculationDelta'] = processing.run('native:fieldcalculator', alg_params, context=context, feedback=feedback, is_child_algorithm=True)

        feedback.setCurrentStep(14)
        if feedback.isCanceled():
            return {}

        # Exclude points that don't arrive
        # Di "arrivo" bisogna prendere solo i valori positivi, perchè quelli negativi vanno sotto la quota del terreno quindi li escludo
        alg_params = {
            'EXPRESSION': 'delta > 0',
            'INPUT': outputs['CalculationDelta']['OUTPUT'],
            'OUTPUT': QgsProcessing.TEMPORARY_OUTPUT
        }
        outputs['ExcludePointsThatDontArrive'] = processing.run('native:extractbyexpression', alg_params, context=context, feedback=feedback, is_child_algorithm=True)

        feedback.setCurrentStep(15)
        if feedback.isCanceled():
            return {}

        # Number of boulders arriving
        # <<conta>> l'attributo "arrivo"
        # 
        # Calcola il numero di massi che arrivano in quel punto
        alg_params = {
            'DISCARD_NONMATCHING': False,
            'INPUT': outputs['ExcludePointsThatDontArrive']['OUTPUT'],
            'JOIN': outputs['ExcludePointsThatDontArrive']['OUTPUT'],
            'JOIN_FIELDS': ['delta'],
            'PREDICATE': [2],  # è uguale
            'SUMMARIES': [0],  # conta
            'OUTPUT': QgsProcessing.TEMPORARY_OUTPUT
        }
        outputs['NumberOfBouldersArriving'] = processing.run('native:joinbylocationsummary', alg_params, context=context, feedback=feedback, is_child_algorithm=True)

        feedback.setCurrentStep(16)
        if feedback.isCanceled():
            return {}

        # Velocity [m/s]
        alg_params = {
            'FIELD_LENGTH': 10,
            'FIELD_NAME': 'velocity',
            'FIELD_PRECISION': 2,
            'FIELD_TYPE': 0,  # Decimale (doppia precisione)
            'FORMULA': 'sqrt(2*9.81* "delta")',
            'INPUT': outputs['NumberOfBouldersArriving']['OUTPUT'],
            'OUTPUT': QgsProcessing.TEMPORARY_OUTPUT
        }
        outputs['VelocityMs'] = processing.run('native:fieldcalculator', alg_params, context=context, feedback=feedback, is_child_algorithm=True)

        feedback.setCurrentStep(17)
        if feedback.isCanceled():
            return {}

        # Field weight
        alg_params = {
            'FIELD_LENGTH': 10000,
            'FIELD_NAME': 'peso',
            'FIELD_PRECISION': 2,
            'FIELD_TYPE': 0,  # Decimale (doppia precisione)
            'FORMULA': parameters['mass_kg'],
            'INPUT': outputs['VelocityMs']['OUTPUT'],
            'OUTPUT': QgsProcessing.TEMPORARY_OUTPUT
        }
        outputs['FieldWeight'] = processing.run('native:fieldcalculator', alg_params, context=context, feedback=feedback, is_child_algorithm=True)

        feedback.setCurrentStep(18)
        if feedback.isCanceled():
            return {}

        # Energy [kJ]
        alg_params = {
            'FIELD_LENGTH': 10,
            'FIELD_NAME': 'energy',
            'FIELD_PRECISION': 2,
            'FIELD_TYPE': 0,  # Decimale (doppia precisione)
            'FORMULA': '"delta" *9.81* "peso" /1000',
            'INPUT': outputs['FieldWeight']['OUTPUT'],
            'OUTPUT': QgsProcessing.TEMPORARY_OUTPUT
        }
        outputs['EnergyKj'] = processing.run('native:fieldcalculator', alg_params, context=context, feedback=feedback, is_child_algorithm=True)

        feedback.setCurrentStep(19)
        if feedback.isCanceled():
            return {}

        # Grid
        alg_params = {
            'CRS': parameters['dtm'],
            'EXTENT': outputs['EnergyKj']['OUTPUT'],
            'HOVERLAY': 0,
            'HSPACING': parameters['cell_size'],
            'TYPE': 0,  # Punto
            'VOVERLAY': 0,
            'VSPACING': parameters['cell_size'],
            'OUTPUT': QgsProcessing.TEMPORARY_OUTPUT
        }
        outputs['Grid'] = processing.run('native:creategrid', alg_params, context=context, feedback=feedback, is_child_algorithm=True)

        feedback.setCurrentStep(20)
        if feedback.isCanceled():
            return {}

        # Grid_spatial
        alg_params = {
            'INPUT': outputs['Grid']['OUTPUT']
        }
        outputs['Grid_spatial'] = processing.run('native:createspatialindex', alg_params, context=context, feedback=feedback, is_child_algorithm=True)

        feedback.setCurrentStep(21)
        if feedback.isCanceled():
            return {}

        # Recap_energy
        alg_params = {
            'DISCARD_NONMATCHING': True,
            'INPUT': outputs['Grid_spatial']['OUTPUT'],
            'JOIN': outputs['EnergyKj']['OUTPUT'],
            'JOIN_FIELDS': ['energy'],
            'PREDICATE': [2],  # è uguale
            'SUMMARIES': [0,2,3,6],  # conta,min,max,media
            'OUTPUT': QgsProcessing.TEMPORARY_OUTPUT
        }
        outputs['Recap_energy'] = processing.run('native:joinbylocationsummary', alg_params, context=context, feedback=feedback, is_child_algorithm=True)

        feedback.setCurrentStep(22)
        if feedback.isCanceled():
            return {}

        # Recap_velocity
        alg_params = {
            'DISCARD_NONMATCHING': True,
            'INPUT': outputs['Recap_energy']['OUTPUT'],
            'JOIN': outputs['EnergyKj']['OUTPUT'],
            'JOIN_FIELDS': ['velocity'],
            'PREDICATE': [0],  # interseca
            'SUMMARIES': [2,3,6],  # min,max,media
            'OUTPUT': QgsProcessing.TEMPORARY_OUTPUT
        }
        outputs['Recap_velocity'] = processing.run('native:joinbylocationsummary', alg_params, context=context, feedback=feedback, is_child_algorithm=True)

        feedback.setCurrentStep(23)
        if feedback.isCanceled():
            return {}

        # Percentage boulders
        alg_params = {
            'FIELD_LENGTH': 10,
            'FIELD_NAME': 'percent',
            'FIELD_PRECISION': 2,
            'FIELD_TYPE': 1,  # Intero (32 bit)
            'FORMULA': '"energy_count" * 100 / maximum("energy_count")',
            'INPUT': outputs['Recap_velocity']['OUTPUT'],
            'OUTPUT': QgsProcessing.TEMPORARY_OUTPUT
        }
        outputs['PercentageBoulders'] = processing.run('native:fieldcalculator', alg_params, context=context, feedback=feedback, is_child_algorithm=True)

        feedback.setCurrentStep(24)
        if feedback.isCanceled():
            return {}

        # Rename field count
        alg_params = {
            'FIELD': 'energy_count',
            'INPUT': outputs['PercentageBoulders']['OUTPUT'],
            'NEW_NAME': 'count',
            'OUTPUT': QgsProcessing.TEMPORARY_OUTPUT
        }
        outputs['RenameFieldCount'] = processing.run('native:renametablefield', alg_params, context=context, feedback=feedback, is_child_algorithm=True)

        feedback.setCurrentStep(25)
        if feedback.isCanceled():
            return {}
        
        # Delete fields
        alg_params = {
            'COLUMN': ['left','top','right','bottom','row_index','col_index'],
            'INPUT': outputs['RenameFieldCount']['OUTPUT'],
            'OUTPUT': QgsProcessing.TEMPORARY_OUTPUT
        }
        outputs['DeleteFields'] = processing.run('native:deletecolumn', alg_params, context=context, feedback=feedback, is_child_algorithm=True)
        
        feedback.setCurrentStep(26)
        if feedback.isCanceled():
            return {}

        # --- INTEGRAZIONE PULIZIA PER TOGLIERE I PUNTI CHE NON SONO CONNESSI ALLA ZONA DI DISTACCO---
        # 1. Buffer (Ipotizzo 3 volte la dimensione delle celle --> cell_size * 3)
        alg_params = {
            'DISSOLVE': False,
            'DISTANCE': parameters['cell_size'] * 3,
            'END_CAP_STYLE': 0,  # Arrotondato
            'INPUT': outputs['DeleteFields']['OUTPUT'],
            'JOIN_STYLE': 0,  # Arrotondato
            'MITER_LIMIT': 2,
            'SEGMENTS': 1,
            'SEPARATE_DISJOINT': False,
            'OUTPUT': QgsProcessing.TEMPORARY_OUTPUT
        }
        outputs['Buffer_pulizia'] = processing.run('native:buffer', alg_params, context=context, feedback=feedback, is_child_algorithm=True)

        feedback.setCurrentStep(27)
        if feedback.isCanceled():
            return {}

        # 2. Dissolvi
        alg_params = {
            'FIELD': [''],
            'INPUT': outputs['Buffer_pulizia']['OUTPUT'],
            'SEPARATE_DISJOINT': False,
            'OUTPUT': QgsProcessing.TEMPORARY_OUTPUT
        }
        outputs['Dissolvi_pulizia'] = processing.run('native:dissolve', alg_params, context=context, feedback=feedback, is_child_algorithm=True)

        feedback.setCurrentStep(28)
        if feedback.isCanceled():
            return {}

        # 3. Da multi parte a parti singole
        alg_params = {
            'INPUT': outputs['Dissolvi_pulizia']['OUTPUT'],
            'OUTPUT': QgsProcessing.TEMPORARY_OUTPUT
        }
        outputs['PartiSingole_pulizia'] = processing.run('native:multiparttosingleparts', alg_params, context=context, feedback=feedback, is_child_algorithm=True)

        feedback.setCurrentStep(29)
        if feedback.isCanceled():
            return {}

        # 4. Estrai 1 (Intersezione con source_points)
        alg_params = {
            'INPUT': outputs['PartiSingole_pulizia']['OUTPUT'],
            'INTERSECT': parameters['source_points'],
            'PREDICATE': [0],  # interseca
            'OUTPUT': QgsProcessing.TEMPORARY_OUTPUT
        }
        outputs['EstraiPoligonoValido'] = processing.run('native:extractbylocation', alg_params, context=context, feedback=feedback, is_child_algorithm=True)

        feedback.setCurrentStep(30)
        if feedback.isCanceled():
            return {}

        # 5. Estrai 2 (Filtro finale sui punti connessi)
        alg_params = {
            'INPUT': outputs['DeleteFields']['OUTPUT'],
            'INTERSECT': outputs['EstraiPoligonoValido']['OUTPUT'],
            'PREDICATE': [4,6],  # tocca, sono contenuti
            'OUTPUT': parameters['Results_drokaBasic']
        }
        outputs['Pulito_Finale'] = processing.run('native:extractbylocation', alg_params, context=context, feedback=feedback, is_child_algorithm=True)
        # ----------------------------

        # --- COSTRUZIONE DEL NOME DINAMICO SUL LAYER PULITO ---
        energy_angle_val = parameters.get('energy_angle_', '')
        lateral_angle_val = parameters.get('lateral_spreading_angle_', '')
        
        output_name = f"droka_basic_output_E{energy_angle_val}_L{lateral_angle_val}"
        output_layer = outputs['Pulito_Finale']['OUTPUT']
        
        context.addLayerToLoadOnCompletion(
            output_layer,
            QgsProcessingContext.LayerDetails(output_name, context.project(), 'Results_drokaBasic')
        )
        # ------------------------------------------------------------

        results['Results_drokaBasic'] = output_layer
        return results


    def name(self):
        return 'Rockfall - Droka basic'

    def displayName(self):
        return 'Rockfall - Droka basic'

    def group(self):
        return 'Landslide'

    def groupId(self):
        return 'Landslide'

    def shortHelpString(self):
        return """<html><body><p><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd">
<html><head><meta name="qrichtext" content="1" /><style type="text/css">
</style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;">
<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:14pt; font-weight:600;">DROKA BASIC</span></p>
<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Droka_basic is based on the Cone method which enables the definition of the area affected by rockfall events on a slope. This is achieved through a cone representing the envelope of all possible rockfall paths. The apex of the cone is located at the source point and its geometry is defined by three angles: the dip direction angle θ of the slope at the source point defines the orientation of the cone; the energy angle ϕp outlines its vertical extension and the lateral spreading angle α delineates the extension of the cone in the horizontal plane.</p>
<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">This module enables the creation of a frequency map, where areas with higher frequencies are the most prone to be reached by fallen blocks, identifying them as the most susceptible to this type of danger.</p>
<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Using the concept of the energy line, the module enables the calculation of the velocity and kinetic energy of the block at any position within the affected area. The results are filtered eliminating the points that arrive below the ground.</p>
<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">The attributes of source points are obtained from the DTM while the cone parameters are constant across all source points and are specific to each case study. Calibrating these parameters is essential to achieve reliable and conservative results. It should be based on information from past events in the area, rockfall inventories, territorial databases, and quick field observations of the slope.</p>
<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p>
<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">The output is a vector layer of points located at the center of the DTM cells within the affected area, containing:</p>
<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">- Id</p>
<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">- Energy min, max, mean (kJ)</p>
<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">- Velocity min, max, mean (m/s)</p>
<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">- Count: number of overlapping cones</p>
<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">- Percent: mumber of overlapping cones at the point as a proportion of the total number of cones generated</p></body></html></p>
<h2>Parametri in ingresso
</h2>
<h3>DTM</h3>
<p>Raster layer of the DTM</p>
<h3>Cell size</h3>
<p>Dimension of the DTM cell (m)</p>
<h3>Source Points</h3>
<p>Vector layer of the source points</p>
<h3>Lateral spreading angle (°)</h3>
<p>Lateral spreading angle α = cost (°)</p>
<h3>Energy angle (°)</h3>
<p>Energy angle ϕp = cost  (°)</p>
<h3>Mass (kg)</h3>
<p>Mass of the block (kg)</p>
<h2></h2>
<p><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd">
<html><head><meta name="qrichtext" content="1" /><style type="text/css">
</style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;">
<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p></body></html></p><br><p align="right">Autore della guida: Claudio Fasciano</p></body></html>"""

    def createInstance(self):
        return RockfallDrokaBasic()
