# -*- 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-02-13'
__copyright__ = '(C) 2022 by Tiago Prudencio e Leandro França'

from qgis.PyQt.QtCore import QCoreApplication, QMetaType
from qgis.core import (QgsProject,
                       QgsFeatureRequest,
                       QgsVectorLayer,
                       QgsField,
                       QgsCoordinateTransform,
                       QgsProcessingParameterExtent,
                       QgsEditorWidgetSetup,
                       QgsCoordinateReferenceSystem,
                       QgsProcessingUtils,
                       QgsProcessingParameterEnum,
                       QgsProcessingParameterBoolean,
                       QgsProcessingLayerPostProcessorInterface,
                       QgsProcessingException,
                       QgsFeatureSink,
                       QgsProcessingAlgorithm,
                       QgsProcessingParameterFeatureSink)

import os
from qgis.PyQt.QtGui import QIcon


class ConnectBase(QgsProcessingAlgorithm):

    INPUT = 'INPUT'
    OUTPUT = 'OUTPUT'
    EXTENT = 'EXTENT'
    GEOONE = 'GEOONE'
    WFS = 'WFS'

    mapping ={ 0: 'SIGEF - Certificados - Particular',
               1: 'SIGEF - Certificados - Público',
               2: 'SNCI - 1ª/2ª Norma - Privado',
               3: 'SNCI - 1ª/2ª Norma - Público',
               4: 'Assentamentos',
               5: 'Quilombolas',
               6: 'Imóveis Pendentes de Titulação',
            }

    layer_name ={    0: 'ms:certificada_sigef_particular_xx',
                     1: 'ms:certificada_sigef_publico_xx',
                     2: 'ms:imoveiscertificados_privado_xx',
                     3: 'ms:imoveiscertificados_publico_xx',
                     4: 'ms:assentamentos_xx',
                     5: 'ms:quilombolas_xx',
                     6: 'ms:parcelageo_xx',
            }

    links = {     mapping[0]: 'http://acervofundiario.incra.gov.br/i3geo/ogc.php?tema=certificada_sigef_particular_xx',
                  mapping[1]: 'http://acervofundiario.incra.gov.br/i3geo/ogc.php?tema=certificada_sigef_publico_xx',
                  mapping[2]: 'http://acervofundiario.incra.gov.br/i3geo/ogc.php?tema=imoveiscertificados_privado_xx',
                  mapping[3]: 'http://acervofundiario.incra.gov.br/i3geo/ogc.php?tema=imoveiscertificados_publico_xx',
                  mapping[4]:'http://acervofundiario.incra.gov.br/i3geo/ogc.php?tema=assentamentos_xx',
                  mapping[5]:'http://acervofundiario.incra.gov.br/i3geo/ogc.php?tema=quilombolas_xx',
                  mapping[6]:'http://acervofundiario.incra.gov.br/i3geo/ogc.php?tema=parcelageo_xx'
            }

    def initAlgorithm(self, config):

        self.addParameter(
            QgsProcessingParameterExtent(
                self.EXTENT,
                self.tr('Retângulo de Extensão')
            )
        )

        self.addParameter(
            QgsProcessingParameterEnum(
                self.WFS,
                self.tr('Camada do acervo fundiário'),
                options = self.links.keys(),
                defaultValue= 0
            )
        )

        self.addParameter(
            QgsProcessingParameterBoolean(
                self.GEOONE,
                self.tr('Consultar base da GeoOne (caso o acervo fundiário esteja Offline)'),
                defaultValue= False
            )
        )

        self.addParameter(
            QgsProcessingParameterFeatureSink(
                self.OUTPUT,
                self.tr('Resultado da consulta ao INCRA')
            )
        )

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

        extensao = self.parameterAsExtent(
        parameters,
        self.EXTENT,
        context
        )
        if not extensao:
            raise QgsProcessingException(self.invalidSourceError(parameters, self.EXTENT))

        geoone = self.parameterAsBool(
            parameters,
            self.GEOONE,
            context
        )

        crsSrc = QgsCoordinateReferenceSystem(QgsProject().instance().crs())
        crsDest = QgsCoordinateReferenceSystem('EPSG:4326')
        proj2geo = QgsCoordinateTransform(crsSrc, crsDest, QgsProject.instance())
        extensao = proj2geo.transform(extensao)
        request = QgsFeatureRequest().setFilterRect(extensao)

        option = self.parameterAsEnum(parameters, self.WFS, context)
        layer = self.mapping[option]
        name = self.layer_name[option]
        link = self.links[layer]

        if not geoone:
            path = os.path.dirname(__file__) + "/shp" + "/BR_UF_2020.shp"
            estado = QgsVectorLayer(path, "BR_UF_2020", "ogr")

            uris = list()
            for feat in estado.getFeatures(request):
                if feat.geometry().intersects(extensao):

                    uri_default="""pagingEnabled='true' preferCoordinatesForWfsT11='false' restrictToRequestBBOX='1'  srsname='EPSG:4326' typename='name_' url='link' version='auto'"""
                    uri_default = uri_default.replace('name_',name)
                    uri_default = uri_default.replace('link',link)
                    uri_default = uri_default.replace('xx',feat['SIGLA_UF'])
                    uris.append(uri_default)

            source = QgsVectorLayer(uris[0], "my wfs layer", "WFS")
            (sink, dest_id) = self.parameterAsSink(
                parameters,
                self.OUTPUT,
                context,
                source.fields(),
                source.wkbType(),
                source.sourceCrs()
            )
            if sink is None:
                raise QgsProcessingException(self.invalidSinkError(parameters, self.OUTPUT))

            for uri in uris:
                vlayer = QgsVectorLayer(uri, "wfs_layer", "WFS")
                for feature in vlayer.getFeatures(request):
                    if feedback.isCanceled():
                        break
                    sink.addFeature(feature, QgsFeatureSink.FastInsert)
        else:

            # Verificar tamanho da extensão
            y_min = extensao.yMinimum()
            y_max = extensao.yMaximum()
            x_min = extensao.xMinimum()
            x_max = extensao.xMaximum()

            if (x_max - x_min) > 1 or (y_max - y_min) > 1:
                raise QgsProcessingException('Faça a consulta para um retângulo de MENOR extensão!')

            layer_uri ={    0: "pagingEnabled='true' preferCoordinatesForWfsT11='false' restrictToRequestBBOX='1' srsname='EPSG:4674' typename='GeoINCRA:certificado_sigef_privado' url='http://geoonecloud.com/geoserver/GeoINCRA/wfs' version='auto'",
                            1: "pagingEnabled='true' preferCoordinatesForWfsT11='false' restrictToRequestBBOX='1' srsname='EPSG:4674' typename='GeoINCRA:certificado_sigef_publico' url='http://geoonecloud.com/geoserver/GeoINCRA/wfs' version='auto'",
                            2: "pagingEnabled='true' preferCoordinatesForWfsT11='false' restrictToRequestBBOX='1' srsname='EPSG:4674' typename='GeoINCRA:certificados_SNCI_privado' url='http://geoonecloud.com/geoserver/GeoINCRA/wfs' version='auto'",
                            3: "pagingEnabled='true' preferCoordinatesForWfsT11='false' restrictToRequestBBOX='1' srsname='EPSG:4674' typename='GeoINCRA:certificados_SNCI_publico' url='http://geoonecloud.com/geoserver/GeoINCRA/wfs' version='auto'",
                            4: "pagingEnabled='true' preferCoordinatesForWfsT11='false' restrictToRequestBBOX='1' srsname='EPSG:4674' typename='GeoINCRA:assentamentos' url='http://geoonecloud.com/geoserver/GeoINCRA/wfs' version='auto'",
                            5: "pagingEnabled='default' preferCoordinatesForWfsT11='false' restrictToRequestBBOX='1' srsname='EPSG:4674' typename='GeoINCRA:quilombolas' url='http://geoonecloud.com/geoserver/ows' version='auto'",
                            6: "pagingEnabled='true' preferCoordinatesForWfsT11='false' restrictToRequestBBOX='1' srsname='EPSG:4326' typename='GeoINCRA:parcelageo' url='http://geoonecloud.com/geoserver/GeoINCRA/wfs' version='auto'",
            }

            vlayer = QgsVectorLayer(layer_uri[option], "wfs_layer", "WFS")
            (sink, dest_id) = self.parameterAsSink(
                parameters,
                self.OUTPUT,
                context,
                vlayer.fields(),
                vlayer.wkbType(),
                vlayer.sourceCrs()
            )
            if sink is None:
                raise QgsProcessingException(self.invalidSinkError(parameters, self.OUTPUT))
            for feature in vlayer.getFeatures(request): 
                if feedback.isCanceled():
                    break
                sink.addFeature(feature, QgsFeatureSink.FastInsert)

        global renamer
        suffix = ' - GeoOne' if geoone else ' - INCRA'
        renamer = Renamer(layer + suffix)
        context.layerToLoadOnCompletionDetails(dest_id).setPostProcessor(renamer)

        layer = QgsProcessingUtils.mapLayerFromString(dest_id, context)
        self.addField(layer)

        return {self.OUTPUT: self.addField(layer)}


    def addField(self, layer):
        config = {'IsMultiline': True, 'UseHtml': True}
        field_type = 'TextEdit'
        widget_setup = QgsEditorWidgetSetup(field_type,config)
        layer.setEditorWidgetSetup(layer.fields().indexOf('base_INCRA'), widget_setup)
        field= QgsField( 'base_INCRA', QMetaType.Type.QString)
        layer.addExpressionField(
'''replace('<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
			<html>
			<head>
				<meta content="text/html; charset=ISO-8859-1"
				http-equiv="content-type">
				<title>base_INCRA</title>
			</head>
			<body>
			<a
			 href="https://sigef.incra.gov.br/geo/exportar/vertice/csv/[ID]/">Clique
			aqui para baixar CSV v&eacute;rtices (pontos)</a><br>
			<a
			 href="https://sigef.incra.gov.br/geo/exportar/limite/shp/[ID]/">Clique
			aqui para baixar Shapefile dos limites (linhas)</a><br>
			<a
			 href="https://sigef.incra.gov.br/geo/exportar/parcela/shp/[ID]/">Clique
			aqui para baixar Shapefile da parcela (&aacute;rea)</a><br><br>
            <a
			 href="https://sigef.incra.gov.br/geo/parcela/detalhe/[ID]/">Clique
			aqui para saber mais detalhes sobre a parcela (&aacute;rea)</a>
			</body>
			</html>','[ID]',  "parcela_codigo" )''', field
			)

        return layer

    def name(self):
        return 'connectbase'

    def displayName(self):
        return self.tr('a. Consultar base do INCRA')

    def group(self):
        return self.tr('1. 🔍 Consultas a bases de Referência')

    def groupId(self):
        return 'consultas_referencias'

    def tr(self, string):
        return QCoreApplication.translate('Processing', string)

    def createInstance(self):
        return ConnectBase()

    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,consultar,base do incra,wfs,certificados,quilombolas,SNCI,assentamentos,titulação,regularização,fundiária'.split(',')

    
    def shortHelpString(self):
        txt = "Conecta a base de dados do INCRA e carrega camada de imóveis a partir de um retângulo selecionado pelo usuário. Também é possível baixar dados dos imóveis certificados nos formatos CSV e SHP, obtendo-se mais informações complementares."

        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://sigef.incra.gov.br/consultar/parcelas/"><span style="font-weight: bold;">Clique aqui para consultar parcelas do SIGEF</span></a><br>
                      </p>
                      <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=2232"><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

class Renamer (QgsProcessingLayerPostProcessorInterface):
    def __init__(self, layer_name):
        self.name = layer_name
        super().__init__()

    def postProcessLayer(self, layer, context, feedback):
        layer.setName(self.name)
