# -*- coding: utf-8 -*-
"""
/***************************************************************************
 Prisma
                                 A QGIS plugin
 Plugin para fazer caracterização de imóveis
 Generated by Plugin Builder: http://g-sherman.github.io/Qgis-Plugin-Builder/
                              -------------------
        begin                : 2021-09-29
        git sha              : $Format:%H$
        copyright            : (C) 2021 by Zago
        email                : guilherme.nascimento@economia.gov.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.                                   *
 *                                                                         *
 ***************************************************************************/
"""
from ..utils.utils import Utils

import geopandas as gpd

class OverlayAnalisys():
    """
    Classe utilizada para verificar quais áreas possuem sobreposição entre input de entrada e camadas de comparação.

    @ivar operation_config: Dicionário que armazena configurações de operação, como por exemplo: dado de input, bases de dados selecionadas para comparação, busca por ponto, shapefile, etc...
    @ivar shp_handle: Armazena classe para leitura de arquivos shapefile.
    @ivar utils: Armazena classe contendo algumas funções úteis para o código.
    """
    def __init__(self):
        """Método construtor da classe."""
        self.utils = Utils()

    def overlay_analysis(self, input, input_standard, gdf_selected_shp, gdf_selected_wfs, gdf_selected_db, operation_config):
        """
        Função que conta quantas sobreposições aconteceram entre a camada de input e as todas as camadas de comparação selecionadas.
        Esta função é feita através da projeção geográfica.

        @keyword operation_config: Dicionário que armazena configurações de operação, como por exemplo: dado de input, bases de dados selecionadas para comparação, busca por ponto, shapefile, etc...
        @return result: Dicionário que retorna, no formato de geodataframe, todas camadas passadas para comparação e também as camadas que tiveram sobreposição.
        """
        self.operation_config = operation_config

        # gdf_buffered_shp, gdf_buffered_pg = self.handle_approximation_layers()

        # input['Área Homologada_area'] = 0
        # Comparação de sobreposição entre input e Shapefiles
        input = self.analisys_shp(input, gdf_selected_shp)

        # Comparação de sobreposição entre input e Shapefiles
        input = self.analisys_wfs(input, gdf_selected_wfs)

        # Comparação de sobreposição entre input e bases de dados de banco de dados
        input = self.analysis_db(input, gdf_selected_db)

        result = {'input': input, 'input_standard': input_standard, 'gdf_selected_shp': gdf_selected_shp,
                  'gdf_selected_wfs': gdf_selected_wfs, 'gdf_selected_db': gdf_selected_db}

        return result

    def analisys_shp(self, input, gdf_selected_shp):
        """Verifica sobreposição entre camada de input e camadas shapefiles selecionadas.

        @keyword input: Camada de input.
        @keyword gdf_selected_shp: Camadas shapefiles selecionadas para comparação.
        @return overlay_shp: Retorna camada contendo um campo True para feições de comparação que se sobrepuseram a camada de input.
        """
        index = 0
        overlay_shp = input.copy()
        for area in gdf_selected_shp:
            overlay_shp[self.operation_config['shp'][index]['nomeFantasiaCamada']] = False
            area = area.to_crs(4326)
            for indexArea, rowArea in area.iterrows():
                for indexInput, rowInput in input.iterrows():
                    if (rowArea['geometry'].intersection(rowInput['geometry'])):
                        overlay_shp.loc[indexInput, self.operation_config['shp'][index]['nomeFantasiaCamada']] = True
                        # if str(input.geom_type) == str(area.geom_type):
                        #     overlay_shp.loc[indexInput, str(self.operation_config['shp'][index]['nomeFantasiaCamada'] + "_area")] += (rowArea['geometry'].intersection(rowInput['geometry'])).area

            index += 1
        return overlay_shp

    def analisys_wfs(self, input, gdf_selected_wfs):
        """Verifica sobreposição entre camada de input e camadas shapefiles selecionadas.

        @keyword input: Camada de input.
        @keyword gdf_selected_shp: Camadas shapefiles selecionadas para comparação.
        @return overlay_shp: Retorna camada contendo um campo True para feições de comparação que se sobrepuseram a camada de input.
        """
        index = 0
        overlay_wfs = input.copy()
        for area in gdf_selected_wfs:
            overlay_wfs[self.operation_config['wfs'][index]['nomeFantasiaTabelasCamadas']] = False
            area = area.to_crs(4326)
            for indexArea, rowArea in area.iterrows():
                for indexInput, rowInput in input.iterrows():
                    if (rowArea['geometry'].intersection(rowInput['geometry'])):
                        overlay_wfs.loc[indexInput, self.operation_config['wfs'][index]['nomeFantasiaTabelasCamadas']] = True
                        # if str(input.geom_type) == str(area.geom_type):
                        #     overlay_shp.loc[indexInput, str(self.operation_config['shp'][index]['nomeFantasiaCamada'] + "_area")] += (rowArea['geometry'].intersection(rowInput['geometry'])).area

            index += 1
        return overlay_wfs

    def analysis_db(self, input, gdf_selected_db):
        """Verifica sobreposição entre camada de input e camadas de banco de dados selecionadas.

        @keyword input: Camada de input.
        @keyword gdf_selected_shp: Camadas de banco de dados selecionadas para comparação.
        @return overlay_db: Retorna camada contendo um campo True para feições de comparação que se sobrepuseram a camada de input.
        """
        index_db = 0
        overlay_db = input.copy()
        # overlay_db['sobreposicao'] = False
        for db in gdf_selected_db:
            index_layer = 0
            for layer_db in db:
                overlay_db[self.operation_config['pg'][index_db]['nomeFantasiaTabelasCamadas'][index_layer]] = False
                # layer_db.geometry = gpd.GeoSeries.from_wkt(layer_db['geometry'])
                layer_db = layer_db.to_crs(4326)
                for indexArea, rowArea in layer_db.iterrows():
                    for indexInput, rowInput in input.iterrows():
                        if (rowArea['geometry'].intersection(rowInput['geometry'])):
                            overlay_db.loc[indexInput, self.operation_config['pg'][index_db]['nomeFantasiaTabelasCamadas'][
                                    index_layer]] = True
                            # if str(input.geom_type) == str(layer_db.geom_type):
                            #     overlay_db.loc[
                            #         indexInput, str(self.operation_config['pg'][index_db]['nomeFantasiaTabelasCamadas'][
                            #             index_layer] + "_area")] += (rowArea['geometry'].intersection(rowInput['geometry'])).area

                index_layer += 1

            index_db += 1
        return overlay_db

    def handle_approximation_layers(self, gdf_buffered_shp, gdf_buffered_pg):
        for index, value in enumerate(self.operation_config['shp']):
            if 'aproximacao' in self.operation_config['shp'][index]:
                gdf_buffered_shp[index] = self.utils.add_input_approximation_geographic(gdf_buffered_shp, self.operation_config['shp'][index][0])

        for index, value in enumerate(self.operation_config['pg']):
            if 'aproximacao' in self.operation_config['pg'][index]:
                gdf_buffered_pg[index] = self.utils.add_input_approximation_geographic(gdf_buffered_pg[index], self.operation_config['pg'][index])

    def get_utm_crs(self, input, epsg_shp_dir):
        """Para cada feição da camada de input, através da análise de sobreposição, verifica em qual zona UTM a mesma se encontra.

        @keyword input: Camada de input.
        @keyword epsg_shp_dir: Armazena o caminho do diretório, dentro do Prisma, em que se encontra o shapefile contendo a camada de Zonas UTM.
        @return input: Retorna coluna contendo a zona UTM em que se encontra cada feiçõa de input.
        """
        input['crs_feature'] = None
        epsg_shp = gpd.read_file(epsg_shp_dir)

        # Caso input seja polígonos
        if input.iloc[0]['geometry'].type in ['Polygon', 'MultiPolygon']:
            for indexInput, rowInput in input.iterrows():
                areamaior = 0
                for indexEpsg, rowEpsg in epsg_shp.iterrows():
                    area = rowInput['geometry'].intersection(rowEpsg['geometry']).area
                    if area > 0:
                        if area > areamaior:
                            input.loc[indexInput, 'crs_feature'] = rowEpsg['EPSG_S2000']
                            areamaior = area

        # Caso input seja linhas
        elif input.iloc[0]['geometry'].type in ['LineString', 'MultiLineString']:
            for indexInput, rowInput in input.iterrows():
                areamaior = 0
                for indexEpsg, rowEpsg in epsg_shp.iterrows():
                    area = rowInput['geometry'].intersection(rowEpsg['geometry']).length
                    if area > 0:
                        if area > areamaior:
                            input.loc[indexInput, 'crs_feature'] = rowEpsg['EPSG_S2000']
                            areamaior = area

        return input['crs_feature']