"""This file contains the analysis plugin manager class."""

from plaso.analysis import definitions


class AnalysisPluginManager:
    """Analysis plugin manager."""

    _plugin_classes = {}

    _PLUGIN_TYPE_STRINGS = {
        definitions.PLUGIN_TYPE_ANNOTATION: ("Annotation/Tagging plugin"),
        definitions.PLUGIN_TYPE_ANOMALY: ("Anomaly plugin"),
        definitions.PLUGIN_TYPE_REPORT: ("Summary/Report plugin"),
        definitions.PLUGIN_TYPE_STATISTICS: ("Statistics plugin"),
    }
    _PLUGIN_TYPE_STRINGS.setdefault("Unknown type")

    @classmethod
    def DeregisterPlugin(cls, plugin_class):
        """Deregisters an analysis plugin class.

        The analysis plugin classes are identified by their lower case name.

        Args:
          plugin_class (type): class of the analysis plugin.

        Raises:
          KeyError: if an analysis plugin class is not set for the corresponding
              name.
        """
        plugin_name = plugin_class.NAME.lower()
        if plugin_name not in cls._plugin_classes:
            raise KeyError(f"Plugin class not set for name: {plugin_class.NAME:s}.")

        del cls._plugin_classes[plugin_name]

    # TODO: refactor to match parsers manager.
    @classmethod
    def GetAllPluginInformation(cls):
        """Retrieves a list of the registered analysis plugins.

        Returns:
          list[tuple[str, str, str]]: the name, docstring and type string of each
              analysis plugin in alphabetical order.
        """
        results = []
        for plugin_class in cls._plugin_classes.values():
            if not plugin_class.TEST_PLUGIN:
                plugin_object = plugin_class()
                # TODO: Use a specific description variable, not the docstring.
                doc_string, _, _ = plugin_class.__doc__.partition("\n")
                type_string = cls._PLUGIN_TYPE_STRINGS.get(plugin_object.plugin_type)
                information_tuple = (plugin_object.NAME, doc_string, type_string)
                results.append(information_tuple)

        return sorted(results)

    @classmethod
    def GetPluginNames(cls):
        """Retrieves the analysis  plugin names.

        Returns:
          list[str]: analysis plugin names.
        """
        return sorted(cls._plugin_classes.keys())

    @classmethod
    def GetPluginObjects(cls, plugin_names):
        """Retrieves the plugin objects.

        Args:
          plugin_names (list[str]): names of plugins that should be retrieved.

        Returns:
          dict[str, AnalysisPlugin]: analysis plugins per name.
        """
        plugin_objects = {}
        for plugin_name, plugin_class in cls._plugin_classes.items():
            if plugin_name not in plugin_names:
                continue

            plugin_objects[plugin_name] = plugin_class()

        return plugin_objects

    @classmethod
    def GetPlugins(cls):
        """Retrieves the registered analysis plugin classes.

        Yields:
          tuple: containing:

            str: name of the plugin
            type: plugin class
        """
        for plugin_name, plugin_class in cls._plugin_classes.items():
            yield plugin_name, plugin_class

    @classmethod
    def RegisterPlugin(cls, plugin_class):
        """Registers an analysis plugin class.

        Then analysis plugin classes are identified based on their lower case name.

        Args:
          plugin_class (type): class of the analysis plugin.

        Raises:
          KeyError: if an analysis plugin class is already set for the corresponding
              name.
        """
        plugin_name = plugin_class.NAME.lower()
        if plugin_name in cls._plugin_classes:
            raise KeyError(f"Plugin class already set for name: {plugin_class.NAME:s}.")

        cls._plugin_classes[plugin_name] = plugin_class

    @classmethod
    def RegisterPlugins(cls, plugin_classes):
        """Registers analysis plugin classes.

        The analysis plugin classes are identified based on their lower case name.

        Args:
          plugin_classes (list[type]): classes of the analysis plugin.

        Raises:
          KeyError: if an analysis plugin class is already set for the corresponding
              name.
        """
        for plugin_class in plugin_classes:
            cls.RegisterPlugin(plugin_class)
