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

"""
/***************************************************************************
 GeoINCRA
                                 A QGIS plugin
 Georreferenciamento de Imóveis Rurais
 Generated by Plugin Builder: http://g-sherman.github.io/Qgis-Plugin-Builder/
                              -------------------
        begin                : 2022-02-13
        copyright            : (C) 2022 by Tiago Prudencio e Leandro França
        email                : contato@geoone.com.br
 ***************************************************************************/

/***************************************************************************
 *                                                                         *
 *   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__ = 'Tiago Prudencio e Leandro França'
__date__ = '2022-07-25'
__copyright__ = '(C) 2022 by Tiago Prudencio e Leandro França'

from qgis.PyQt.QtCore import QCoreApplication
from qgis.core import (QgsProcessing,
                       QgsProcessingException,
                       QgsProcessingAlgorithm,
                       QgsProcessingParameterEnum,
                       QgsProcessingParameterBoolean,
                       QgsGeometry,
                       QgsPoint,
                       QgsProcessingParameterVectorLayer,
                       QgsProcessingParameterVectorLayer)

from qgis.PyQt.QtGui import QIcon
import os


class InterpolarVerticeV(QgsProcessingAlgorithm):

    def tr(self, string):

        return QCoreApplication.translate('Processing', string)

    def createInstance(self):
        return InterpolarVerticeV()

    def name(self):
        return 'interpolarverticev'

    def displayName(self):
        return self.tr('e. Interpolar vértice V')

    def group(self):
        return self.tr('2. ⚙️ Fluxo de processamento')

    def groupId(self):
        return 'fluxo_processamento'

    def icon(self):
        return QIcon(os.path.join(os.path.dirname(os.path.dirname(__file__)), 'images/geoincra_pb.png'))
    
    def tags(self):
        return 'GeoOne,GeoRural,INCRA,Sigef,cota Z,virtual,PA1,PA2,PA3,sigmas,interpolação,interpolar,virtuais,IDW,paralela,parelelo,interseção de retas,regularização,fundiária'.split(',')  

    def shortHelpString(self):
        txt = '''Esta ferramenta calcula e preenche automaticamente o valor da cota Z e os sigmas de vértices do tipo V (virtual) obtidos dos métodos de posicionamento "PA1:Paralela", "PA2: interseção de retas" e "PA3: Projeção Técnica". O cálculo da interpolação é dado a partir dos dois vértices mais próximos utilizando a média ponderada pelo inverso da distância.'''

        footer = '''<div>
                      <div align="center">
                      <a target="_blank" rel="noopener noreferrer" href="https://geoone.com.br/pvgeoincra/"><img title="Inscreva-se no curso de GeoINCRA" style="width: 100%; height: auto;" src="'''+ os.path.join(os.path.dirname(os.path.dirname(__file__)), 'images/INCRA_GeoOne.jpg') +'''"></a>
                      </div>
                      <div align="right">
                      <p align="right">
                      <a href="https://geoone.com.br/pvgeoincra/"><span style="font-weight: bold;">Conheça o curso de GeoINCRA no QGIS</span></a>
                      </p>
                      <p align="right">
                      <a href="https://portal.geoone.com.br/m/lessons/geoincra?classId=2237"><span style="font-weight: bold;">Acesse a aula sobre esta ferramenta no curso de GeoINCRA no GeoOne</span></a>
                      </p>
                      <a target="_blank" rel="noopener noreferrer" href="https://geoone.com.br/"><img title="GeoOne" width="280"  src="'''+ os.path.join(os.path.dirname(os.path.dirname(__file__)), 'images/GeoOne.png') +'''"></a>
                      <p><i>"Mapeamento automatizado, fácil e direto ao ponto é na GeoOne!"</i></p>
                      </div>
                    </div>'''
        return txt + footer
    

    VERTICES = 'VERTICES'
    SELEC = 'SELEC'
    TIPO = 'TIPO'
    SALVAR = 'SALVAR'

    def initAlgorithm(self, config=None):

        self.addParameter(
            QgsProcessingParameterVectorLayer(
                self.VERTICES,
                self.tr('Camada Vértice'),
                [QgsProcessing.TypeVectorPoint])
        )

        self.addParameter(
            QgsProcessingParameterBoolean(
                self.SELEC,
                self.tr('Apenas pontos selecionados'),
                defaultValue= False
            )
        )

        self.addParameter(
            QgsProcessingParameterEnum(
                self.TIPO,
                self.tr('Interpolar'),
				options = ['Precisões e cota', 'Apenas precisões', 'Apenas cota'],
                defaultValue= 0
            )
        )

        self.addParameter(
            QgsProcessingParameterBoolean(
                self.SALVAR,
                self.tr('Salvar Edições'),
                defaultValue = False
            )
        )

    def processAlgorithm(self, parameters, context, feedback):

        vertice = self.parameterAsVectorLayer(
            parameters,
            self.VERTICES,
            context
        )
        if vertice is None:
            raise QgsProcessingException(self.invalidSourceError(parameters, self.VERTICES))

        selecionados = self.parameterAsBool(
            parameters,
            self.SELEC,
            context
        )

        Interp = self.parameterAsEnum(
            parameters,
            self.TIPO,
            context
        )

        vertice.startEditing()
        campos = vertice.fields()

        # Verificar se existe ponto virtual com método de posicionamento PA1, PA2 ou PA3
        existe = False
        for feat in vertice.getSelectedFeatures() if selecionados else vertice.getFeatures():
            if feat['tipo_verti'] == 'V' and feat['metodo_pos'] in ('PA1','PA2','PA3'):
                existe = True
                break
        if not existe:
            raise QgsProcessingException('Não existe vértice do tipo V obtida pelo método PA1 (paralela), PA2 (interseção) ou PA3 (Projeção Técnica)!')

        # Verificar se as precisões dos pontos foram preenchidas
        for feat in vertice.getSelectedFeatures() if selecionados else vertice.getFeatures():
            if feat['tipo_verti'] != 'V':
                if feat['sigma_x'] < 0 or feat['sigma_x'] > 10 or feat['sigma_x'] == None:
                    raise QgsProcessingException ('Verifique os valores do atrituto "sigma_x"!')
                if feat['sigma_y'] < 0 or feat['sigma_y'] > 10  or feat['sigma_y'] == None:
                    raise QgsProcessingException ('Verifique os valores do atrituto "sigma_y"!')
                if feat['sigma_z'] < 0 or feat['sigma_z'] > 10  or feat['sigma_z'] == None:
                    raise QgsProcessingException ('Verifique os valores do atrituto "sigma_z"!')
                if feat['metodo_pos'] not in ('PG1', 'PG2', 'PG3', 'PG4', 'PG5', 'PG6', 'PG7', 'PG8', 'PG9', 'PT1', 'PT2', 'PT3', 'PT4', 'PT5', 'PT6', 'PT7', 'PT8', 'PT9','PA1', 'PA2', 'PA3', 'PS1', 'PS2', 'PS3', 'PS4', 'PB1', 'PB2'):
                    raise QgsProcessingException ('Verifique os valores do atrituto "metodo_pos"!')
                if feat['tipo_verti'] not in ('M', 'P', 'V'):
                    raise QgsProcessingException ('Verifique os valores do atrituto "tipo_vertice"!')

        # Verificar se as cotas dos pontos do tipo não Virtual foram preenchidas
        for feat in vertice.getSelectedFeatures() if selecionados else vertice.getFeatures():
            pnt = feat.geometry().constGet()
            if feat['tipo_verti'] != 'V' and str(pnt.z()) == 'nan':
                raise QgsProcessingException('Coordenada Z do vértice de ID = {} deve ser preenchida!'.format(feat.id()))
            elif feat['tipo_verti'] != 'V' and pnt.z() == 0:
                feedback.pushInfo('Coordenada Z do vértice de ID = {} é igual a Zero.'.format(feat.id()))

        def norma2(p1, p2):
            return (p1.x() - p2.x())**2 + (p1.y() - p2.y())**2

        def MediaInvDist(v1, dist1, v2, dist2):
            return (v1/dist1 + v2/dist2)/(1/dist1 + 1/dist2)

        for feat1 in vertice.getSelectedFeatures() if selecionados else vertice.getFeatures():
            if feat1['tipo_verti'] == 'V' and feat1['metodo_pos'] in ('PA1','PA2', 'PA3'):
                pnt1 = feat1.geometry().constGet()
                prox1 = {'dist':1e9, 'z': None, 'stdx': None, 'stdy': None, 'stdz': None, 'id': None}
                prox2 = {'dist':1e9, 'z': None, 'stdx': None, 'stdy': None, 'stdz': None, 'id': None}
                # Pegar os dois pontos mais próximos
                for feat2 in vertice.getSelectedFeatures() if selecionados else vertice.getFeatures():
                    if not feat2['tipo_verti'] == 'V':
                        pnt2 = feat2.geometry().constGet()
                        dist = norma2(pnt1, pnt2)*1e5
                        if dist < prox1['dist'] and dist != 0:
                            prox2 = prox1
                            prox1 = {'dist':dist, 'z': pnt2.z(), 'stdx': feat2['sigma_x'], 'stdy': feat2['sigma_y'], 'stdz': feat2['sigma_z'], 'id': feat2.id()}
                        elif dist < prox2['dist'] and dist != 0:
                            prox2 = {'dist':dist, 'z': pnt2.z(), 'stdx': feat2['sigma_x'], 'stdy': feat2['sigma_y'], 'stdz': feat2['sigma_z'], 'id': feat2.id()}
                # Interpolar valores
                Z_interp = MediaInvDist(prox1['z'], prox1['dist'], prox2['z'], prox2['dist'])
                if feat1['metodo_pos'] == 'PA3':
                        Std_x_interp, Std_y_interp, Std_z_interp = 0, 0, 0  # Para projeção técnica PA3, as precisões deverão ser fixadas em Zero.
                else:
                    Std_x_interp = MediaInvDist(prox1['stdx'], prox1['dist'], prox2['stdx'], prox2['dist'])
                    Std_y_interp = MediaInvDist(prox1['stdy'], prox1['dist'], prox2['stdy'], prox2['dist'])
                    Std_z_interp = MediaInvDist(prox1['stdz'], prox1['dist'], prox2['stdz'], prox2['dist'])
                newPoint = QgsGeometry(QgsPoint(pnt1.x(), pnt1.y(), float(Z_interp)))
                if Interp in (0,2):
                    vertice.changeGeometry(feat1.id(), newPoint)
                if Interp in (0,1):
                    vertice.changeAttributeValue(feat1.id(), campos.indexFromName('sigma_x'), float(Std_x_interp))
                    vertice.changeAttributeValue(feat1.id(), campos.indexFromName('sigma_y'), float(Std_y_interp))
                    vertice.changeAttributeValue(feat1.id(), campos.indexFromName('sigma_z'), float(Std_z_interp))

        salvar = self.parameterAsBool(
           parameters,
           self.SALVAR,
           context
        )
        if salvar is None:
           raise QgsProcessingException(self.invalidSourceError(parameters, self.SAVE))

        if salvar:
           vertice.commitChanges() # salva as edições

        return {}
