# -*- coding: utf-8 -*-
"""
\\***************************************************************************
 Connector
                                 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.                                   *
 *                                                                         *
 ***************************************************************************\\
"""
import os
import zipfile
import shutil
from abc import ABC, abstractmethod

from weissflaechenkartierung.src.exceptions import InternetConnectionError, RemoteFileDownloadError, ExtractZipError
from weissflaechenkartierung.src.logger import Logger
from weissflaechenkartierung.src.tools import download_over_qt, get_base_root_dir, check_internet_qgis, get_plugin_dir
import weissflaechenkartierung.src.xml.xml_config_ctrl as xml


class Connector(ABC):
    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._connection = None
        self._parameters = xml.XMLConfigCtrl.get_parameter_from_xml(xml=self._xml_section)
        self._temp_zip_file = "temp.zip"

    @property
    def temp_zip_file(self):
        """
        returns the path of the temp zip file
        """
        return self._temp_zip_file

    @temp_zip_file.setter
    def temp_zip_file(self, value):
        """
        sets the path of the temp zip file
        """
        self._temp_zip_file = value

    @property
    def connection(self) -> str:
        """
        returns the connection of the connector
        """
        return self._connection

    @connection.setter
    def connection(self, value):
        """
        sets the connection string
        """
        self._connection = value

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

    @abstractmethod
    def retrieve_data(self):
        """
        abstract method for inheritance
        """
        pass

    def get_root_dir(self) -> str:
        """
        returns the given root_dir
        """
        if "root_dir" in self._module.config.parameters:
            return self._module.config.parameters["root_dir"]
        Logger.warning("The root_dir is not given")
        Logger.info("The program created the root_dir inside documents of the user")
        return get_base_root_dir()


class LocalFileConnector(Connector):
    """
    """
    def __init__(self, xml_section, module):
        Connector.__init__(self, xml_section=xml_section, module=module)

    def retrieve_data(self):
        Logger.debug("Process the local file connector")
        root_dir = self.get_root_dir()
        # check if the root dir is absolut
        if not os.path.exists(root_dir):
            root_dir = os.path.join(get_plugin_dir(), root_dir)
            if not os.path.isdir(root_dir):
                raise FileNotFoundError("The given root directory does not exist: " + root_dir)

        # check given local file
        if "path" not in self._parameters:
            raise FileNotFoundError("The given local file path from the xml file is none!")
        file_path = self._parameters["path"]
        if not os.path.isabs(file_path):
            Logger.debug("The given file path is not absolut")
            file_path = os.path.join(root_dir, file_path)
        else:
            Logger.debug("The given file path is absolut")

        if not os.path.isfile(file_path):
            raise FileNotFoundError("The given file does not exist: " + file_path)

        if "sub_path" in self._parameters:
            if os.path.isabs(self._parameters["sub_path"]):
                root_dir = self._parameters["sub_path"]
            else:
                root_dir = os.path.join(root_dir, self._parameters["sub_path"])
            Logger.debug("Root dir:" + root_dir)
        self._retrieve_data(file_path=file_path, root_dir=root_dir)

    def _retrieve_data(self, file_path: str, root_dir: str):
        self._connection = file_path
        zipped = False
        if "zipped" in self._parameters:
            zipped: bool = xml.XMLConfigCtrl.get_bool_value(self._parameters["zipped"], False)
        Logger.debug("Is file zipped: " + str(zipped))
        if zipped:
            zip_file_name = ""
            if "zip_file_name" in self._parameters:
                zip_file_name = self._parameters["zip_file_name"]
            else:
                Logger.warning("The 'zip_file_name' is not given")
            # extract zip file
            Logger.debug("Extract data out of zip file")
            try:
                with zipfile.ZipFile(file_path, 'r') as zip_ref:
                    zip_ref.extractall(root_dir)
                    Logger.debug("Extracted: " + file_path)
            except Exception:
                raise ExtractZipError("The given zip: " + file_path + " can not be extracted")
            self._connection = os.path.join(root_dir, zip_file_name)
            Logger.debug("Extracted file path: " + self._connection)


class RemoteFileConnector(LocalFileConnector):
    """
    """
    def __init__(self, xml_section, module):
        Connector.__init__(self, xml_section=xml_section, module=module)

    def retrieve_data(self):
        Logger.debug("Process the remote file connector")
        root_dir = self.get_root_dir()

        if not os.path.exists(root_dir):
            root_dir = os.path.join(get_plugin_dir(), root_dir)
            Logger.debug("The given root dir is not a dir, get plugin dir")
            if not os.path.isdir(root_dir):
                raise FileNotFoundError("The given root directory does not exist: " + root_dir)

        # check given remote file
        if "path" not in self._parameters:
            raise FileNotFoundError("The given remote path from the xml file is none!")
        remote_path = self._parameters["path"]
        
        # check the given file
        if "file" in self._parameters:
            self._temp_zip_file = self._parameters["file"]
            Logger.debug("Given file: " + self._temp_zip_file)
        
        if "sub_path" in self._parameters:
            if os.path.isabs(self._parameters["sub_path"]):
                root_dir = self._parameters["sub_path"]
            else:
                root_dir = os.path.join(root_dir, self._parameters["sub_path"])
            Logger.debug("Root dir: " + root_dir)

        # check if the fle is on the plate
        local_path = os.path.join(root_dir, self._temp_zip_file)
        if os.path.isfile(local_path):
            Logger.debug(local_path + " ist im cache")
        else:
            Logger.debug("Create directory: " + str(root_dir))
            os.makedirs(root_dir, exist_ok=True)
            try:
                Logger.debug("Check internet connection...")
                if not check_internet_qgis():
                    raise InternetConnectionError("There is no internet connection!")
                Logger.info("There is an internet connection")
                Logger.debug("Download file: " + remote_path)
                size, attr = download_over_qt(dlURL=remote_path, LokFileName=local_path)
                if size is not None and size > 0:
                    Logger.debug("File downloaded successful. Size: " + str(size))
                else:
                    Logger.debug("Can not download the file: " + remote_path)
                    raise RemoteFileDownloadError("Can not download the file: " + remote_path)
            except Exception:
                if not check_internet_qgis():
                    raise InternetConnectionError("There is no internet connection!")
                raise Exception(Logger.get_current_system_exception())
        super()._retrieve_data(local_path, root_dir)
