# Except.py -- Pamhyr model exceptions
# Copyright (C) 2023-2026  INRAE
#
# 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 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program.  If not, see <https://www.gnu.org/licenses/>.

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

from PyQt5.QtCore import (
    QCoreApplication,
)

from PyQt5.QtWidgets import (
    QApplication, QMessageBox, QLabel,
)

_translate = QCoreApplication.translate


####################################
# Message Box for python exception #
####################################

def exception_message_box(exception):
    msg = QMessageBox()
    msg.setIcon(QMessageBox.Critical)
    msg.findChild(QLabel, "qt_msgbox_label").setFixedWidth(384)

    msg.setText("Exception :")
    msg.setInformativeText(f"{exception}")
    msg.setWindowTitle("Exception")

    msg.exec_()

################
# Custom error #
################


class ExeceptionWithMessageBox(Exception):
    def __init__(self, title="Exeception"):
        self.title = title

    def header(self):
        return _translate("Exception", "Generic error message")

    def short_message(self):
        return _translate("Exception", "Undefined error message")

    def message(self):
        return _translate("Exception", "Undefined error message")

    def alert(self):
        msg = QMessageBox()
        msg.setIcon(QMessageBox.Critical)

        msg.setText(f"{self.header()} : {self.short_message()}")
        msg.setInformativeText(f"{self.message()}")
        msg.setWindowTitle(f"{self.title}")

        msg.exec_()


class NotImplementedMethodeError(ExeceptionWithMessageBox):
    def __init__(self, obj, func):
        super(NotImplementedMethodeError, self).__init__(
            title=_translate("Exception", "Method not implemented")
        )

        self.obj = obj
        self.func = func

        self.alert()

    def __str__(self):
        class_type = self.obj
        if self.obj.__class__ != type:
            class_type = self.obj.__class__

        return (
            _translate("Exception", "Method") +
            f" '{self.func.__name__}' " +
            _translate("Exception", "not implemented") +
            _translate("Exception", "for class") +
            f" '{class_type}'"
        )

    def header(self):
        return _translate("Exception", "Not implemented method")

    def short_message(self):
        return _translate("Exception", "Not implemented method")

    def message(self):
        return (
            _translate("Exception", "Method") +
            f" '{self.func.__name__}' " +
            _translate("Exception", "not implemented") +
            _translate("Exception", "for class") +
            f" '{self.obj.__class__}'"
        )


class FileFormatError(ExeceptionWithMessageBox):
    def __init__(self, filename, reason):
        super(FileFormatError, self).__init__(
            title=_translate("Exception", "FileFormatError")
        )

        self.reason = reason
        self.filename = filename

    def __str__(self):
        return (
            _translate("Exception", "Invalid file format:") +
            f" '{self.filename}'\n{self.message()}"
        )

    def header(self):
        return _translate("Exception", "File format error")

    def short_message(self):
        return _translate("Exception", "Invalid file format")

    def message(self):
        return (
            _translate("Exception", "Invalid file") +
            f" '{self.filename}' " +
            _translate("Exception", "format because of") +
            f" '{self.reason}'"
        )


class ClipboardFormatError(ExeceptionWithMessageBox):
    def __init__(self, mime=None, header=None, data=None):
        super(ClipboardFormatError, self).__init__(
            title=_translate("Exception", "Clipboard format error")
        )

        self._mime = mime
        self._header = header
        self._data = data

        if self._mime is not None:
            self.msg = f"Impossible to decode data to mime code '{self._mime}'"
        else:
            if len(self._header) == 0:
                msg = _translate("Exception", "without header")
            else:
                msg = (
                    _translate("Exception", "with header") +
                    f": {self._header}"
                )

            self.msg = (
                _translate("Exception", "Invalid clipboard data format:") +
                f" '{self._data}' {msg}"
            )

        self.alert()

    def __str__(self):
        return self.msg

    def header(self):
        return _translate("Exception", "Clipboard format error")

    def short_message(self):
        return _translate("Exception", "Clipboard format unknown")

    def message(self):
        return self.msg


class ExternFileMissingError(ExeceptionWithMessageBox):
    def __init__(self, module="mage", filename="libbief", path="??/libbief.so",
                 src_except=None):
        super(ExternFileMissingError, self).__init__(
            title=_translate(
                "Exception", "External file dependence is missing"
            )
        )

        self.msg = _translate(
            "Exception",
            "'@file' is missing for module @module:\n'@path'"
        )
        self.msg = self.msg.replace("@file", filename)
        self.msg = self.msg.replace("@module", module)
        self.msg = self.msg.replace("@path", path)

        if src_except is not None:
            self.msg = self.msg + "\n\n" + f"Exception: {src_except}"

        self.alert()

    def __str__(self):
        return self.msg

    def header(self):
        return _translate("Exception", "External file dependence is missing")

    def short_message(self):
        return _translate("Exception", "External file dependence is missing")

    def message(self):
        return self.msg
