# -*- coding: utf-8 -*-

"""
/***************************************************************************
                              -------------------
        begin                : 2016
        copyright            : (C) 2016 by OPENGIS.ch
        email                : info@opengis.ch
 ***************************************************************************/

/***************************************************************************
 *                                                                         *
 *   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 fnmatch
import os
import stat
import sys
from functools import partial

from qgis.PyQt.QtCore import (QCoreApplication,
                              QObject,
                              QSettings,
                              Qt)
from qgis.PyQt.QtPrintSupport import QPrinter
from qgis.PyQt.QtGui import QValidator
from qgis.PyQt.QtWidgets import (QFileDialog,
                                 QApplication,
                                 QWizard,
                                 QTextEdit)
from qgis.core import Qgis

from asistente_ladm_col.lib.logger import Logger


def selectFileName(line_edit_widget, title, file_filter, parent):
    filename, matched_filter = QFileDialog.getOpenFileName(parent, title, line_edit_widget.text(), file_filter)
    line_edit_widget.setText(filename)


def make_file_selector(widget, title=QCoreApplication.translate("Asistente-LADM-COL", "Open File"),
                       file_filter=QCoreApplication.translate("Asistente-LADM-COL", "Any file(*)"), parent=None):
    return partial(selectFileName, line_edit_widget=widget, title=title, file_filter=file_filter, parent=parent)

def selectFileNameToSave(line_edit_widget, title, file_filter, parent, extension, extensions):
    filename, matched_filter = QFileDialog.getSaveFileName(parent, title, line_edit_widget.text(), file_filter)
    extension_valid = False

    if not extensions:
        extensions = [extension]

    if extensions:
        extension_valid = any(filename.endswith(ext) for ext in extensions)

    if not extension_valid and filename:
        filename = filename + extension

    line_edit_widget.setText(filename)

def make_save_file_selector(widget, title=QCoreApplication.translate("QgisModelBaker", "Open File"),
                            file_filter=QCoreApplication.translate("QgisModelBaker", "Any file(*)"), parent=None,
                            extension='', extensions=None):
    return partial(selectFileNameToSave, line_edit_widget=widget, title=title, file_filter=file_filter, parent=parent,
                   extension=extension, extensions=extensions)

def selectFolder(line_edit_widget, title, parent):
    foldername = QFileDialog.getExistingDirectory(parent, title, line_edit_widget.text())
    line_edit_widget.setText(foldername)


def make_folder_selector(widget, title=QCoreApplication.translate("Asistente-LADM-COL", "Open Folder"), parent=None):
    return partial(selectFolder, line_edit_widget=widget, title=title, parent=parent)


def disable_next_wizard(wizard, with_back=True):
    button_list = [QWizard.HelpButton, QWizard.Stretch, QWizard.FinishButton, QWizard.CancelButton]
    if with_back: button_list.insert(2, QWizard.BackButton)
    wizard.setButtonLayout(button_list)


def enable_next_wizard(wizard, with_back=True):
    button_list = [QWizard.HelpButton, QWizard.Stretch, QWizard.NextButton, QWizard.FinishButton, QWizard.CancelButton]
    if with_back: button_list.insert(2, QWizard.BackButton)
    wizard.setButtonLayout(button_list)


def get_plugin_metadata(plugin_name, key):
    plugin_dir = os.path.dirname(sys.modules[plugin_name].__file__)
    file_path = os.path.join(plugin_dir, 'metadata.txt')
    if os.path.isfile(file_path):
        with open(file_path) as metadata:
            for line in metadata:
                line_array = line.strip().split("=")
                if line_array[0] == key:
                    return line_array[1].strip()

                # Some plugins use : instead of =...
                line_array = line.strip().split(":")
                if line_array[0] == key:
                    return line_array[1].strip()
    return None


def remove_readonly(func, path, _):
    """Clear the readonly bit and reattempt the removal"""
    try:
        os.chmod(path, stat.S_IWRITE)
        func(path)
    except (TypeError, PermissionError, OSError) as e:
        pass


def normalize_local_url(url):
    return url[1:] if url.startswith("/") else url



class NetworkError(RuntimeError):
    def __init__(self, error_code, msg):
        self.msg = msg
        self.error_code = error_code

def save_pdf_format(settings_path, title, text):
    settings = QSettings()
    new_filename, filter = QFileDialog.getSaveFileName(None,
                                                       QCoreApplication.translate("Asistente-LADM-COL", "Export to PDF"),
                                                       settings.value(settings_path, '.'),
                                                       filter="PDF (*.pdf)")

    if new_filename:
        settings.setValue(settings_path, os.path.dirname(new_filename))
        new_filename = new_filename if new_filename.lower().endswith(".pdf") else "{}.pdf".format(new_filename)

        txt_log = QTextEdit()
        txt_log.setHtml("{}<br>{}".format(title, text))

        printer = QPrinter()
        printer.setPageSize(QPrinter.Letter)
        printer.setOutputFormat(QPrinter.PdfFormat)
        printer.setOutputFileName(new_filename)
        txt_log.print(printer)

        msg = QCoreApplication.translate("Asistente-LADM-COL",
            "Report successfully generated in folder <a href='file:///{normalized_path}'>{path}</a>!").format(
            normalized_path=normalize_local_url(new_filename),
            path=new_filename)
        Logger().success_msg(__name__, msg)

class Validators(QObject):
    def validate_line_edits(self, *args, **kwargs):
        """
        Validate line edits and set their color to indicate validation state.
        """
        senderObj = self.sender()
        validator = senderObj.validator()
        if validator is None:
            color = '#fff'  # White
        else:
            state = validator.validate(senderObj.text().strip(), 0)[0]
            if state == QValidator.Acceptable:
                color = '#fff'  # White
            elif state == QValidator.Intermediate:
                color = '#ffd356'  # Light orange
            else:
                color = '#ffd356'  # Light orange
        senderObj.setStyleSheet('QLineEdit {{ background-color: {} }}'.format(color))

    def validate_line_edits_lower_case(self, *args, **kwargs):
        """
        Validate line edits and set their color to indicate validation state.
        """
        senderObj = self.sender()
        validator = senderObj.validator()
        if validator is None:
            color = '#fff'  # White
        else:
            state = validator.validate(senderObj.text().strip(), 0)[0]
            if state == QValidator.Acceptable:
                color = '#fff'  # White
            elif state == QValidator.Intermediate:
                color = '#ffd356'  # Light orange
            else:
                color = '#ffd356'  # Light orange
        senderObj.setStyleSheet('QLineEdit {{ background-color: {} }}'.format(color))
        senderObj.setText(senderObj.text().strip().lower())


class FileValidator(QValidator):
    def __init__(self, pattern='*', is_executable=False, parent=None, allow_empty=False, allow_non_existing=False):
        QValidator.__init__(self, parent)
        self.pattern = pattern
        self.is_executable = is_executable
        self.allow_empty = allow_empty
        self.allow_non_existing = allow_non_existing

    """
    Validator for file line edits
    """

    def validate(self, text, pos):
        if self.allow_empty and not text.strip():
            return QValidator.Acceptable, text, pos

        pattern_matches = False
        if type(self.pattern) is str:
            pattern_matches = fnmatch.fnmatch(text, self.pattern)
        elif type(self.pattern) is list:
            pattern_matches = True in (fnmatch.fnmatch(text, pattern) for pattern in self.pattern)
        else:
            raise TypeError('pattern must be str or list, not {}'.format(type(self.pattern)))

        if not text \
                or (not self.allow_non_existing and not os.path.isfile(text)) \
                or not pattern_matches \
                or (self.is_executable and not os.access(text, os.X_OK)):
            return QValidator.Intermediate, text, pos
        else:
            return QValidator.Acceptable, text, pos

class DirValidator(QValidator):
    def __init__(self, pattern=None, parent=None, allow_empty=False, allow_non_existing=False, allow_empty_dir=False):
        QValidator.__init__(self, parent)
        self.pattern = pattern
        self.allow_empty = allow_empty
        self.allow_non_existing = allow_non_existing
        self.allow_empty_dir = allow_empty_dir

    """
    Validator for line edits that hold a dir path
    """
    def validate(self, text, pos):
        if self.allow_empty and not text.strip():
            return QValidator.Acceptable, text, pos

        if self.pattern is not None:
            pattern_matches = False
            if type(self.pattern) is str:
                pattern_matches = fnmatch.fnmatch(text, self.pattern)
            elif type(self.pattern) is list:
                pattern_matches = True in (fnmatch.fnmatch(text, pattern) for pattern in self.pattern)
            else:
                raise TypeError('pattern must be str or list, not {}'.format(type(self.pattern)))
        else:
            pattern_matches = True

        if not text \
                or (not self.allow_non_existing and not os.path.isdir(text)) \
                or not pattern_matches:
            return QValidator.Intermediate, text, pos
        else:
            if not self.allow_empty_dir and not os.listdir(text):
                return QValidator.Intermediate, text, pos
            else:
                return QValidator.Acceptable, text, pos

class NonEmptyStringValidator(QValidator):
    def __init__(self, parent=None):
        QValidator.__init__(self, parent)

    def validate(self, text, pos):
        if not text.strip():
            return QValidator.Intermediate, text, pos

        return QValidator.Acceptable, text, pos


class OverrideCursor():
    def __init__(self, cursor):
        self.cursor = cursor

    def __enter__(self):
        QApplication.setOverrideCursor(self.cursor)

    def __exit__(self, exc_type, exc_val, exc_tb):
        QApplication.restoreOverrideCursor()


class ProcessWithStatus():
    def __init__(self, msg):
        self.msg = msg

    def __enter__(self):
        QApplication.setOverrideCursor(Qt.WaitCursor)
        Logger().status(self.msg)

    def __exit__(self, exc_type, exc_val, exc_tb):
        QApplication.restoreOverrideCursor()
        Logger().clear_status()