"""
***************************************************************************
    LinesToPolygons.py
    ---------------------
    Date                 : August 2012
    Copyright            : (C) 2012 by Victor Olaya
    Email                : volayaf at gmail dot com
***************************************************************************
*                                                                         *
*   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__ = "Victor Olaya"
__date__ = "August 2012"
__copyright__ = "(C) 2012, Victor Olaya"

import os

from qgis.core import (
    QgsApplication,
    QgsFeature,
    QgsFeatureSink,
    QgsGeometry,
    QgsGeometryCollection,
    QgsMultiPolygon,
    QgsMultiSurface,
    QgsPolygon,
    QgsProcessing,
    QgsProcessingParameterFeatureSink,
    QgsProcessingParameterFeatureSource,
    QgsProcessingUtils,
    QgsWkbTypes,
)
from qgis.PyQt.QtGui import QIcon

from processing.algs.qgis.QgisAlgorithm import QgisFeatureBasedAlgorithm
from processing.tools import dataobjects, vector

pluginPath = os.path.split(os.path.split(os.path.dirname(__file__))[0])[0]


class LinesToPolygons(QgisFeatureBasedAlgorithm):
    def icon(self):
        return QgsApplication.getThemeIcon("/algorithms/mAlgorithmLineToPolygon.svg")

    def svgIconPath(self):
        return QgsApplication.iconPath("/algorithms/mAlgorithmLineToPolygon.svg")

    def tags(self):
        return self.tr("line,polygon,convert").split(",")

    def group(self):
        return self.tr("Vector geometry")

    def groupId(self):
        return "vectorgeometry"

    def __init__(self):
        super().__init__()

    def name(self):
        return "linestopolygons"

    def displayName(self):
        return self.tr("Lines to polygons")

    def shortDescription(self):
        return self.tr("Generates polygons using the lines from an input line layer.")

    def shortHelpString(self):
        return self.tr(
            "This algorithm generates a polygon layer using as polygon rings the lines from an input line layer.\n"
            "All attributes from the input line layer will be copied to the output layer."
        )

    def outputName(self):
        return self.tr("Polygons")

    def outputType(self):
        return QgsProcessing.SourceType.TypeVectorPolygon

    def inputLayerTypes(self):
        return [QgsProcessing.SourceType.TypeVectorLine]

    def outputWkbType(self, input_wkb_type):
        return self.convertWkbToPolygons(input_wkb_type)

    def processFeature(self, feature, context, feedback):
        if feature.hasGeometry():
            feature.setGeometry(QgsGeometry(self.convertToPolygons(feature.geometry())))
            if feature.geometry().isEmpty():
                feedback.reportError(
                    self.tr(
                        "One or more line ignored due to geometry not having a minimum of three vertices."
                    )
                )
        return [feature]

    def supportInPlaceEdit(self, layer):
        return False

    def convertWkbToPolygons(self, wkb):
        multi_wkb = QgsWkbTypes.Type.NoGeometry
        if (
            QgsWkbTypes.singleType(QgsWkbTypes.flatType(wkb))
            == QgsWkbTypes.Type.LineString
        ):
            multi_wkb = QgsWkbTypes.Type.MultiPolygon
        elif (
            QgsWkbTypes.singleType(QgsWkbTypes.flatType(wkb))
            == QgsWkbTypes.Type.CompoundCurve
        ):
            multi_wkb = QgsWkbTypes.Type.MultiSurface
        if QgsWkbTypes.hasM(wkb):
            multi_wkb = QgsWkbTypes.addM(multi_wkb)
        if QgsWkbTypes.hasZ(wkb):
            multi_wkb = QgsWkbTypes.addZ(multi_wkb)

        return multi_wkb

    def convertToPolygons(self, geometry):
        surfaces = self.getSurfaces(geometry.constGet())
        output_wkb = self.convertWkbToPolygons(geometry.wkbType())
        out_geom = None
        if QgsWkbTypes.flatType(output_wkb) == QgsWkbTypes.Type.MultiPolygon:
            out_geom = QgsMultiPolygon()
        else:
            out_geom = QgsMultiSurface()

        for surface in surfaces:
            out_geom.addGeometry(surface)

        return out_geom

    def getSurfaces(self, geometry):
        surfaces = []
        if isinstance(geometry, QgsGeometryCollection):
            # collection
            for i in range(geometry.numGeometries()):
                surfaces.extend(self.getSurfaces(geometry.geometryN(i)))
        else:
            # not collection
            if geometry.vertexCount() > 2:
                surface = QgsPolygon()
                surface.setExteriorRing(geometry.clone())
                surfaces.append(surface)

        return surfaces
