# Copyright 2016, Chris PeBenito <pebenito@ieee.org>
#
# SPDX-License-Identifier: LGPL-2.1-only
#
#
from typing import Dict, NamedTuple
from enum import Enum

import sip
from PyQt5.QtWidgets import QDialogButtonBox, QScrollArea

from ..widget import SEToolsWidget


class AnalysisSection(Enum):

    """Groupings of analysis tabs"""

    Analysis = 1
    Components = 2
    General = 3
    Labeling = 4
    Other = 5
    Rules = 6


TAB_REGISTRY: Dict[str, type] = {}


class TabRegistry(sip.wrappertype):

    """
    Analysis tab registry metaclass.  This registers tabs to be used both for
    populating the content of the "choose analysis" dialog and also for
    saving tab/workspace info.
    """

    def __new__(cls, *args, **kwargs):
        classdef = super().__new__(cls, *args, **kwargs)

        clsname = args[0]
        attributedict = args[2]
        if clsname != "AnalysisTab":
            assert "section" in attributedict, "Class {} is missing the section value, " \
                "this is an setools bug".format(clsname)

            assert "tab_title" in attributedict, "Class {} is missing the tab_title value, " \
                "this is an setools bug".format(clsname)

            assert "mlsonly" in attributedict, "Class {} is missing the mlsonly value, " \
                "this is an setools bug".format(clsname)

            # ensure there is no duplication of class name or title
            for existing_tabname, existing_class in TAB_REGISTRY.items():
                if existing_tabname == clsname:
                    raise TypeError("Analysis tab {} conflicts with registered tab {}, "
                                    "this is an setools bug".format(clsname, existing_tabname))

                if existing_class.tab_title == attributedict["tab_title"]:
                    raise TypeError("Analysis tab {}'s title \"{}\" conflicts with registered tab "
                                    "{}, this is an setools bug.".
                                    format(clsname, attributedict["tab_title"], existing_tabname))

            TAB_REGISTRY[clsname] = classdef

        return classdef


# pylint: disable=invalid-metaclass
class AnalysisTab(SEToolsWidget, QScrollArea, metaclass=TabRegistry):

    """Base class for Apol analysis tabs."""

    # A QButtonBox which has an Apply button
    # for running the analysis.
    buttonBox = None

    # The set of tab fields that are in error
    errors = None

    # Normal and error palettes to use
    orig_palette = None
    error_palette = None

    #
    # Tab error state
    #
    def set_criteria_error(self, field, error):
        """Set the specified widget to an error state."""
        field.setToolTip("Error: {0}".format(error))
        field.setPalette(self.error_palette)
        self.errors.add(field)
        self._check_query()

    def clear_criteria_error(self, field, tooltip):
        """Clear the specified widget's error state."""
        field.setToolTip(tooltip)
        field.setPalette(self.orig_palette)
        self.errors.discard(field)
        self._check_query()

    def _check_query(self):
        button = self.buttonBox.button(QDialogButtonBox.StandardButton.Apply)
        enabled = not self.errors
        button.setEnabled(enabled)
        button.setToolTip("Run the analysis." if enabled else "There are errors in the tab.")

    #
    # Save/Load tab
    #
    def save(self):
        raise NotImplementedError

    def load(self, settings):
        raise NotImplementedError

    #
    # Results runner
    #
    def run(self, button):
        raise NotImplementedError

    def update_complete(self, count):
        raise NotImplementedError
