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

"""
/***************************************************************************
 LightPollutionToolbox
                                 A QGIS plugin
 Light pollution indicators (focus on public lighting)
 Generated by Plugin Builder: http://g-sherman.github.io/Qgis-Plugin-Builder/
                              -------------------
        begin                : 2020-04-20
        copyright            : (C) 2020 by Mathieu Chailloux
        email                : mathieu@chailloux.org
 ***************************************************************************/

/***************************************************************************
 *                                                                         *
 *   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__ = 'Mathieu Chailloux'
__date__ = '2020-04-20'
__copyright__ = '(C) 2020 by Mathieu Chailloux'

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

__revision__ = '$Format:%H$'

from PyQt5.QtCore import QCoreApplication, QVariant
from qgis.core import (QgsProcessing,
                       QgsProcessingAlgorithm,
                       QgsProcessingUtils,
                       QgsProcessingException,
                       QgsProcessingParameterMultipleLayers,
                       QgsProcessingParameterCrs,
                       QgsProcessingParameterFeatureSource,
                       QgsProcessingParameterFeatureSink,
                       QgsProcessingParameterVectorDestination,
                       QgsProcessingParameterVectorDestination,
                       QgsProcessingMultiStepFeedback,
                       QgsCoordinateReferenceSystem,
                       QgsCoordinateTransform,
                       QgsCoordinateTransformContext,
                       QgsGeometry,
                       QgsFields,
                       QgsFeature,
                       QgsFeatureSink,
                       QgsWkbTypes)

from ..qgis_lib_mc import utils, qgsUtils, qgsTreatments


class MergeGeomAlg(QgsProcessingAlgorithm):
    
    OUTPUT = 'OUTPUT'
    LAYER_A = 'LAYER_A'
    LAYER_B = 'LAYER_B'
    LAYERS = 'LAYERS'
    CRS = 'CRS'
    
    DEFAULT_CRS = QgsCoordinateReferenceSystem("epsg:2154")
    
    def initAlg(self):
        self.addParameter(
            QgsProcessingParameterMultipleLayers(
                self.LAYERS,
                self.tr('Layers')))
        self.addParameter(
            QgsProcessingParameterCrs(
                self.CRS,
                description=self.tr("Output CRS"),
                defaultValue=self.DEFAULT_CRS))
        self.addParameter(
            QgsProcessingParameterVectorDestination(
                self.OUTPUT,
                self.tr('Output layer')))

    def tr(self, string):
        return QCoreApplication.translate('Processing', string)
        
    def group(self):
        return self.tr('Utils')
        
    def groupId(self):
        return self.tr('utils')

    

class MergeGeometryAlgorithm(MergeGeomAlg):

    NAME = 'mergeGeom'
    
    def initAlgorithm(self, config=None):
        self.initAlg()

    def processAlgorithm(self, parameters, context, feedback):
        layers = self.parameterAsLayerList(parameters,self.LAYERS,context)
        dest_crs = self.parameterAsCrs(parameters,self.CRS,context)
        
        out_fields = QgsFields()
        (sink, dest_id) = self.parameterAsSink(parameters, self.OUTPUT,
                context, out_fields, QgsWkbTypes.MultiPolygon, dest_crs)
                
        nb_feats = 0
        for layer in layers:
            nb_feats += layer.featureCount()
        total = 100.0 / nb_feats if nb_feats else 0
        curr = 0
                
        for layer in layers:
            layer_crs = layer.sourceCrs()
            if layer_crs == dest_crs:
                transformator = None
            else:
                trContext = QgsCoordinateTransformContext()
                transformator = QgsCoordinateTransform(layer_crs,dest_crs,trContext)
            for feat in layer.getFeatures():
                feat_geom = QgsGeometry(feat.geometry())
                if feat_geom.isEmpty():
                    continue
                feat_geom.convertToMultiType()
                if transformator:
                    feat_geom.transform(transformator)
                new_feat = QgsFeature(out_fields)
                new_feat.setGeometry(feat_geom)
                sink.addFeature(new_feat, QgsFeatureSink.FastInsert)
                curr += 1
                feedback.setProgress(int(curr * total))
                
        return {self.OUTPUT: dest_id}
        
    def name(self):
        return self.NAME

    def displayName(self):
        return self.tr('Merge geometries')

    def createInstance(self):
        return MergeGeometryAlgorithm()
  

class MergeGeometryDissolveAlgorithm(MergeGeomAlg):

    NAME = 'mergeGeomDissolve'
    
    def initAlgorithm(self, config=None):
        self.initAlg()

    def processAlgorithm(self, parameters, context, feedback):
        layers = self.parameterAsLayerList(parameters,self.LAYERS,context)
        parameters[self.LAYERS] = layers
        
        mfeed = QgsProcessingMultiStepFeedback(3,feedback)
        out_merged = QgsProcessingUtils.generateTempFilename('out_merged.gpkg')
        init_out = self.parameterAsOutputLayer(parameters,self.OUTPUT,context)
        parameters[self.OUTPUT] = out_merged
        
        qgsTreatments.applyProcessingAlg("LPT",MergeGeometryAlgorithm.NAME,parameters,
            context=context,feedback=mfeed)
        mfeed.setCurrentStep(1)
            
        out_fixed = QgsProcessingUtils.generateTempFilename('out_fixed.gpkg')
        qgsTreatments.fixGeometries(out_merged,out_fixed,context=context,feedback=mfeed)
        mfeed.setCurrentStep(2)
        qgsTreatments.dissolveLayer(out_fixed,init_out,context=context,feedback=mfeed)
        mfeed.setCurrentStep(3)
        return {self.OUTPUT: init_out}
        
    def name(self):
        return self.NAME

    def displayName(self):
        return self.tr('Merge geometries (dissolve)')

    def createInstance(self):
        return MergeGeometryDissolveAlgorithm()
        
        
class MergeGeometryNoOverlapAlgorithm(MergeGeomAlg):
    
    def initAlgorithm(self, config=None):
        self.addParameter(
            QgsProcessingParameterFeatureSource(
                self.LAYER_A,
                self.tr('Layer A')))
        self.addParameter(
            QgsProcessingParameterFeatureSource(
                self.LAYER_B,
                self.tr('Layer B')))
        # self.addParameter(
            # QgsProcessingParameterCrs(
                # self.CRS,
                # description=self.tr("Output CRS"),
                # defaultValue=self.DEFAULT_CRS))
        self.addParameter(
            QgsProcessingParameterVectorDestination(
                self.OUTPUT,
                self.tr('Output layer')))

    def processAlgorithm(self, parameters, context, feedback):
        layer_a = self.parameterAsVectorLayer(parameters,self.LAYER_A,context)
        if not layer_a:
            raise QgsProcessingException("No Layer A")
        layer_b = self.parameterAsVectorLayer(parameters,self.LAYER_B,context)
        if not layer_b:
            raise QgsProcessingException("No Layer B")
        output = self.parameterAsOutputLayer(parameters,self.OUTPUT,context)
        # dest_crs = self.parameterAsCrs(parameters,self.CRS,context)
        
        out_fields = QgsFields()
        out_crs = layer_a.sourceCrs()
        (sink, dest_id) = self.parameterAsSink(parameters, self.OUTPUT,
                context, out_fields, QgsWkbTypes.MultiPolygon, out_crs)
                
        feedback = QgsProcessingMultiStepFeedback(2,feedback)
               
        diff = QgsProcessingUtils.generateTempFilename('diff.gpkg')
        qgsTreatments.applyDifference(layer_a,layer_b,diff,context=context,feedback=feedback)
        diff_layer = qgsUtils.loadVectorLayer(diff)
        
        feedback.setCurrentStep(1)
        
        layers = [ layer_a, diff_layer ]
        params = { MergeGeometryAlgorithm.LAYERS : layers,
            MergeGeometryAlgorithm.CRS : out_crs,
            MergeGeometryAlgorithm.OUTPUT : output }
        qgsTreatments.applyProcessingAlg("LPT",MergeGeometryAlgorithm.name(),parameters,
            context=context,feedback=feedback)
                
        feedback.setCurrentStep(2)
        
        return {self.OUTPUT: output}
        
    def name(self):
        return 'mergeGeomNoOverlap'

    def displayName(self):
        return self.tr('Merge geometries (no overlap)')

    def createInstance(self):
        return MergeGeometryNoOverlapAlgorithm()
        