"""
 wfk_ctrl

 wide are mapping
 Generated by Plugin Builder: http://g-sherman.github.io/Qgis-Plugin-Builder/
                             -------------------
        begin                : 2022-01-01
        git sha              : $Format:%H$
        copyright            : (C) 2022 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.                                   *
 *                                                                         *
 ***************************************************************************/
"""
import os

from qgis.core import QgsApplication
from weissflaechenkartierung.src.wfk.wfk_task import WfkTask, WfkTaskRunInfo, WfkResult
from PyQt5.QtCore import *
from weissflaechenkartierung.src.logger import Logger
import time


class WfkSignals(QObject):
    finished = pyqtSignal(WfkResult)        # signal to connect to
    progressChanged = pyqtSignal(float)     # signal to connect to

    """
    emitted before finished gets emitted
    """
    error = pyqtSignal(str)              # signal to connect to


class WfkCtrl:
    def __init__(self):
        self._is_running: bool = False
        self.signals = WfkSignals()
        self.task: WfkTask = None
        self._wfk_last_result = WfkResult()
        self._wfk_current_result = WfkResult()
        self._task_run_info: WfkTaskRunInfo = None

    @property
    def last_run_info(self) -> WfkResult():
        """
        returns last run information
        """
        return self._task_run_info

    @property
    def last_result_info(self) -> WfkResult():
        """
        returns last result information
        """
        return self._wfk_last_result

    @property
    def running(self) -> bool:
        """
        returns the current running state
        """
        return self._is_running

    def _update(self):
        """
        sends updates about the task process
        """
        Logger.debug("wfk ctrl update", )
        if self.task is not None:
            self.signals.progressChanged.emit(self.task.progress())

    def _finished(self):
        """
        called if the wfk task has finished
        """
        Logger.info("wfk ctrl finished called", )
        self.task = None
        self._wfk_current_result.time_elapsed = time.time() - self._wfk_current_result.time_started
        self._wfk_last_result = self._wfk_current_result        # set the last data
        self.signals.finished.emit(self._wfk_current_result)    # then emit, if u set the data before emit finish....
        self._is_running = False

    def _result(self, result: WfkResult):
        """
        called if the wfk task has results to show
        """
        Logger.info("wfk ctrl result called")
        self._wfk_current_result.result = result.result
        self._wfk_current_result.result_txt = result.result_txt
        self._wfk_current_result.layer_to_protocol = result.layer_to_protocol
        self._wfk_current_result.layer_for_analysis = result.layer_for_analysis

    def stop(self) -> None:
        """
        called if to stop the wfk process
        """
        if self.task is not None:
            try:
                self.task.cancel()
            except Exception as e:
                self.signals.error.emit("Can not cancel wfk task")
            self._is_running = False
            self.task = None
            self.signals.finished.emit(self._wfk_current_result)        # emit the watcher, the task finished

    def start(self, wfk_data: WfkTaskRunInfo):
        """
        starts the wfk process and checks the task run info
        The controller checks the given data before he starts the task.
        """
        Logger.debug("Check given wfk-task data", )
        if not os.path.exists(wfk_data.xml_config_path):
            self.signals.error.emit("The given XML-Config path does not exist!")
            self.signals.finished.emit(self._wfk_current_result)  # emit the watcher, the task finished
            return

        if wfk_data.interface is None:
            self.signals.error.emit("The qgis interface is not initialized!")
            self.signals.finished.emit(self._wfk_current_result)  # emit the watcher, the task finished
            return

        if not wfk_data.description:
            self.signals.error.emit("The given Task has no description!")
            self.signals.finished.emit(self._wfk_current_result)  # emit the watcher, the task finished
            return

        if not wfk_data.config_name:
            self.signals.error.emit("There is no configuration selected or there is no configuration!\nPlease select "
                                    "a configuration. If there is no configuration to select, please load one")
            self.signals.finished.emit(self._wfk_current_result)  # emit the watcher, the task finished
            return

        if not wfk_data.qgis_layer:
            self.signals.error.emit("There is no layer selected!\nPlease select a layer!")
            self.signals.finished.emit(self._wfk_current_result)  # emit the watcher, the task finished
            return

        Logger.debug("RunWithError: " + str(wfk_data.run_with_errors), )
        Logger.info("Start wfk task", )
        self._start(wfk_data)

    def _start(self,  wfk_data: WfkTaskRunInfo):
        """
        starts the wfk process
        """
        self._task_run_info = wfk_data
        self.task = WfkTask(run_config=wfk_data)
        self.task.signals.finished.connect(self._finished)
        self.task.signals.result.connect(self._result)
        self.task.progressChanged.connect(lambda: self._update())
        QgsApplication.taskManager().addTask(self.task)  # start wfk task
        self._wfk_current_result.time_started = time.time()  # track start time
        self._is_running = True
