# -*- coding: utf-8 -*-
"""
/***************************************************************************
 Difference
                                 A QGIS plugin
 wide are mapping
 Generated by Plugin Builder: http://g-sherman.github.io/Qgis-Plugin-Builder/
                             -------------------
        begin                : 2020-11-13
        git sha              : $Format:%H$
        copyright            : (C) 2020 by forschung@ciss.de
        email                : forschung@ciss.de
 ***************************************************************************/

/***************************************************************************
 *                                                                         *
 *   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 abc import abstractmethod

from weissflaechenkartierung.src.qgis import QGisInterface
from weissflaechenkartierung.src.xml.owner import Owner
from weissflaechenkartierung.src.logger import Logger

import weissflaechenkartierung.src.xml.xml_config_ctrl as xml


class Difference:
    def __init__(self, xml_section, module):
        """
        :param xml_section: section of an xml dom
        :param module: an module instance
        """
        self._xml_section = xml_section
        self._module = module
        self._parameters = xml.XMLConfigCtrl.get_parameter_from_xml(xml=self._xml_section)
        self._diff_layer = None

    @property
    def parameters(self):
        """
        returns the parameters
        """
        return self._parameters

    @property
    def diff_layer(self):
        """
        returns the diff layer
        """
        return self._diff_layer

    @property
    def xml_section(self):
        """
        returns the xml section
        """
        return self._xml_section

    @abstractmethod
    def run(self, diff_layer):
        """
        runs the difference function from QGisTool
        """
        if self._diff_layer is not None and diff_layer is not None:
            return QGisInterface.diff_from_layer(base_layer=diff_layer,
                                                 input_layer=self._diff_layer)
        else:
            return diff_layer


class BufferDifference(Difference):
    def run(self, diff_layer):
        buff = None
        if "default_buffer" in self._module.config.parameters:
            buff = self._module.config.parameters["default_buffer"]
        if "buffer" in self._parameters:
            buff = self._parameters["buffer"]

        if buff is None:
            self._diff_layer = self._module.layer.layer
        else:
            self._diff_layer = QGisInterface.buffer_layer(input_layer=self._module.layer.layer,
                                                          distance=buff,
                                                          name_layer="tmp")

        return super().run(diff_layer)


class SelectiveBufferDifference(Difference):
    def run(self, diff_layer):

        selector = "id"
        if "selector" in self._parameters:
            selector = self._parameters["selector"]

        if "buffer_list" in self._parameters and "type_list" in self._parameters:
            if len(self._parameters["type_list"]) == len(self._parameters["buffer_list"]):
                self._diff_layer = QGisInterface.selective_buffer(input_layer=self._module.layer.layer,
                                                                  crs=self._module.layer.crs,
                                                                  type_list=self._parameters["type_list"],
                                                                  buffer_list=self._parameters["buffer_list"],
                                                                  attribute=selector,
                                                                  name="tmp")
                Logger.debug("Created SelectiveBufferDifference", )
            else:
                Logger.error("The type list has not the same length as the buffer list", )
        else:
            Logger.error("he buffer list or/and the type is not inside the parameters", )

        return super().run(diff_layer)


class BlacklistingDifference(Difference):
    def __init__(self, xml_section, module):
        super().__init__(xml_section, module)
        self.save_blacklisted_layer = False

    def run(self, diff_layer):

        # get path parameter
        csv_file_path = ""
        if "path" in self._parameters:
            csv_file_path: str = self._parameters["path"]

        # get the layer position selector
        selector = ""
        if "position_selector" in self._parameters:
            selector: str = self._parameters["position_selector"]

        # get csv-column selector
        csv_column_selector = ""
        if "csv_selector" in self.parameters:
            csv_column_selector = self.parameters["csv_selector"]

        # get csv-column selector
        if "save_blacklisted_layer" in self.parameters:
            self.save_blacklisted_layer = xml.XMLConfigCtrl.get_bool_value(
                value=self._parameters["save_blacklisted_layer"],
                default=False)

        # get csv_blacklist selector
        csv_black_list_selector = ""
        if "csv_black_list_selector" in self.parameters:
            csv_black_list_selector = self.parameters["csv_black_list_selector"]

        # get owner objects
        owner_dict: dict = Owner.from_csv_to_dict(file_name=csv_file_path,
                                                  column_name=csv_column_selector)

        # get attribute
        def get_attribute(o: Owner, a_n: str):
            try:
                a = getattr(o, a_n)
                return a
            except AttributeError:
                Logger.error("AttributeError while blacklisting")
                return None

        # iterate over owner
        count = 0
        expression = ""
        for key, owner_list in owner_dict.items():
            # iterate over owner
            for owner in owner_list:
                attr_value = get_attribute(o=owner, a_n=csv_black_list_selector)
                # check if blacklist attribute is one or zero
                if attr_value == "1":
                    if count == 0:
                        expression += """\"""" + selector + """\" = '""" + key + """' """
                        count += 1
                    else:
                        expression += """or \"""" + selector + """\" = '""" + key + """' """

        Logger.debug("Blacklisting expression: " + expression)

        if expression != "":

            # run qgis function
            Logger.debug("Start extract_by_expression")
            self._diff_layer = QGisInterface.extract_by_expression(layer=self._module.layer.layer,
                                                                   expression=expression)
            self._diff_layer.setName("Blacklisted")

            # get names which will not be deleted
            not_del_attributes = []
            for field_cat in diff_layer.dataProvider().fields():
                not_del_attributes.append(field_cat.name())

            # delete attributes except selector
            del_attributes_pos = []
            count = 0
            for field in self._diff_layer.dataProvider().fields():
                f_n = field.name()
                if f_n not in not_del_attributes and \
                        f_n != selector and \
                        f_n != csv_column_selector and \
                        f_n != csv_black_list_selector:
                    del_attributes_pos.append(count)
                count += 1
            self._diff_layer.dataProvider().deleteAttributes(del_attributes_pos)
            self._diff_layer.updateFields()

            Logger.debug("finished extract_by_expression ")
        else:
            self.save_blacklisted_layer = False

        return super().run(diff_layer=diff_layer)
