# -*- coding: utf-8 -*-
"""
This tool is a direct copy (except some flake8 changes) from:
https://github.com/threedi/beta-plugins/tree/master/threedi_custom_stats

/***************************************************************************
 ThreeDiCustomStats
                                 A QGIS plugin
 This plugin calculates statistics of Rana simulation results. The user chooses the variable, aggregation method and spatiotemperal filtering.
 Generated by Plugin Builder: http://g-sherman.github.io/Qgis-Plugin-Builder/
                              -------------------
        begin                : 2019-11-27
        git sha              : $Format:%H$
        copyright            : (C) 2019 by Leendert van Wolfswinkel | Nelen en Schuurmans
        email                : leendert.vanwolfswinkel@nelen-schuurmans.nl
 ***************************************************************************/

/***************************************************************************
 *                                                                         *
 *   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.                                   *
 *                                                                         *
 ***************************************************************************/
"""
# Import the code for the dialog
from .threedi_custom_stats_dialog import ThreeDiCustomStatsDialog
from threedi_results_analysis.threedi_plugin_tool import ThreeDiPluginTool
from threedi_results_analysis.threedi_plugin_model import ThreeDiResultItem, ThreeDiGridItem
from qgis.PyQt.QtCore import pyqtSlot

import os
import os.path
import logging

logger = logging.getLogger(__name__)


# TODO: cfl strictness factors instelbaar maken
# TODO: berekening van max timestep ook op basis van volume vs. debiet

class StatisticsTool(ThreeDiPluginTool):

    group_name = "Result aggregation outputs"

    def __init__(self, iface, model):
        super().__init__()

        self.iface = iface
        self.model = model
        self.icon_path = os.path.join(
            os.path.dirname(os.path.dirname(__file__)),
            "icons",
            "icon_result_aggregation.svg"
        )
        self.menu_text = u"Result aggregation tool"
        self.dlg = None

        # Keeps track of the layer groups already generated
        self.layer_groups = {}

        # Check if plugin was started the first time in current QGIS session
        self.first_start = True

    def read(self, _) -> bool:
        """A new project is loaded, see if we can fetch some precreated groups"""
        return self._collect_result_groups()

    def _collect_result_groups(self):
        # Go through the results and check whether corresponding output layer groups already exist
        self.layer_groups = {}

        results = self.model.get_results(False)
        for result in results:
            grid_item = result.parent()
            assert grid_item
            tool_group = grid_item.layer_group.findGroup(self.group_name)
            if tool_group:
                tool_group.willRemoveChildren.connect(lambda n, i1, i2: self._group_removed(n, i1, i2))
                result_group = tool_group.findGroup(result.text())
                if result_group:
                    self.layer_groups[result.id] = result_group
                    result_group.nameChanged.connect(lambda _, txt, result_item=result: result_item.setText(txt))
        return True

    def _group_removed(self, n, idxFrom, idxTo):
        for result_id in list(self.layer_groups):
            group = self.layer_groups[result_id]
            for i in range(idxFrom, idxTo+1):
                if n.children()[i] is group:
                    del self.layer_groups[result_id]

    def run(self):

        # Create the dialog with elements (after translation) and keep reference
        # Only create GUI ONCE in callback, so that it will only load when the plugin is started
        if self.first_start:
            self._collect_result_groups()
            self.first_start = False
            self.dlg = ThreeDiCustomStatsDialog(
                iface=self.iface,
                model=self.model,
                owner=self,
            )

        # show the dialog
        self.dlg.show()

    @pyqtSlot(ThreeDiResultItem)
    def result_added(self, result_item: ThreeDiResultItem) -> None:
        self.action_icon.setEnabled(self.model.number_of_results() > 0)
        if not self.dlg:
            return

        self.dlg.add_result(result_item)

    @pyqtSlot(ThreeDiResultItem)
    def result_removed(self, result_item: ThreeDiResultItem) -> None:
        self.action_icon.setEnabled(self.model.number_of_results() > 0)
        if not self.dlg:
            return

        # Remove from combobox etc
        self.dlg.remove_result(result_item)

        # Remove group in layer manager
        if result_item.id in self.layer_groups:
            result_group = self.layer_groups[result_item.id]
            tool_group = result_group.parent()
            tool_group.removeChildNode(result_group)

            # In case the tool ("statistics") group is now empty, we'll remove that too
            tool_group = result_item.parent().layer_group.findGroup(self.group_name)
            if len(tool_group.children()) == 0:
                tool_group.parent().removeChildNode(tool_group)

            # Via a callback (willRemoveChildren), the deleted group should already have removed itself from the list
            assert result_item.id not in self.layer_groups

    @pyqtSlot(ThreeDiResultItem)
    def result_changed(self, result_item: ThreeDiResultItem) -> None:
        if result_item.id in self.layer_groups:
            self.layer_groups[result_item.id].setName(result_item.text())

        if not self.dlg:
            return
        self.dlg.change_result(result_item)

    @pyqtSlot(ThreeDiGridItem)
    def grid_changed(self, grid_item: ThreeDiGridItem) -> None:
        if not self.dlg:
            return

        results = []
        self.model.get_results_from_item(grid_item, False, results)
        for result in results:
            self.dlg.change_result(result)

    def on_unload(self):
        if self.dlg:
            self.dlg.close()
            self.dlg = None
            self.first_start = True
        self.layer_groups = {}
