"""Output plugin manager."""


class OutputManager:
    """Output module manager."""

    _disabled_output_classes = {}
    _output_classes = {}

    @classmethod
    def DeregisterOutput(cls, output_class):
        """Deregisters an output class.

        The output classes are identified based on their NAME attribute.

        Args:
          output_class (type): output module class.

        Raises:
          KeyError: if output class is not set for the corresponding data type.
        """
        output_class_name = output_class.NAME.lower()

        if output_class_name in cls._disabled_output_classes:
            class_dict = cls._disabled_output_classes
        else:
            class_dict = cls._output_classes

        if output_class_name not in class_dict:
            raise KeyError(f"Output class not set for name: {output_class.NAME!s}")

        del class_dict[output_class_name]

    @classmethod
    def GetDisabledOutputClasses(cls):
        """Retrieves the disabled output classes and its associated name.

        Yields:
          tuple[str, type]: output module name and class.
        """
        for output_class in cls._disabled_output_classes.values():
            yield output_class.NAME, output_class

    @classmethod
    def GetOutputClass(cls, name):
        """Retrieves the output class for a specific name.

        Args:
          name (str): name of the output module.

        Returns:
          type: output module class.

        Raises:
          KeyError: if there is no output class found with the supplied name.
          ValueError: if name is not a string.
        """
        if not isinstance(name, str):
            raise ValueError("Name attribute is not a string.")

        name = name.lower()
        if name not in cls._output_classes:
            raise KeyError(f"Name: [{name:s}] not registered as an output module.")

        return cls._output_classes[name]

    @classmethod
    def GetOutputClasses(cls):
        """Retrieves the available output classes its associated name.

        Yields:
          tuple[str, type]: output class name and type object.
        """
        for output_class in cls._output_classes.values():
            yield output_class.NAME, output_class

    @classmethod
    def HasOutputClass(cls, name):
        """Determines if a specific output class is registered with the manager.

        Args:
          name (str): name of the output module.

        Returns:
          bool: True if the output class is registered.
        """
        if not isinstance(name, str):
            return False

        return name.lower() in cls._output_classes

    @classmethod
    def NewOutputModule(cls, name):
        """Creates a new output module object for the specified output format.

        Args:
          name (str): name of the output module.

        Returns:
          OutputModule: output module.

        Raises:
          KeyError: if there is no output class found with the supplied name.
          ValueError: if name is not a string.
        """
        output_class = cls.GetOutputClass(name)
        return output_class()

    @classmethod
    def RegisterOutput(cls, output_class, disabled=False):
        """Registers an output class.

        The output classes are identified based on their NAME attribute.

        Args:
          output_class (type): output module class.
          disabled (Optional[bool]): True if the output module is disabled due to
              the module not loading correctly or not.

        Raises:
          KeyError: if output class is already set for the corresponding name.
        """
        output_name = output_class.NAME.lower()

        if disabled:
            class_dict = cls._disabled_output_classes
        else:
            class_dict = cls._output_classes

        if output_name in class_dict:
            raise KeyError(
                (f"Output class already set for name: {output_class.NAME:s}.")
            )

        class_dict[output_name] = output_class

    @classmethod
    def RegisterOutputs(cls, output_classes, disabled=False):
        """Registers output classes.

        The output classes are identified based on their NAME attribute.

        Args:
          output_classes (list[type]): output module classes.
          disabled (Optional[bool]): True if the output module is disabled due to
              the module not loading correctly or not.

        Raises:
          KeyError: if output class is already set for the corresponding name.
        """
        for output_class in output_classes:
            cls.RegisterOutput(output_class, disabled)
