"""This file contains a class for managing digest analyzers for Plaso."""


class AnalyzersManager:
  """Class that implements the analyzers manager."""

  _analyzer_classes = {}

  @classmethod
  def DeregisterAnalyzer(cls, analyzer_class):
    """Deregisters a analyzer class.

    The analyzer classes are identified based on their lower case name.

    Args:
      analyzer_class (type): class object of the analyzer.

    Raises:
      KeyError: if analyzer class is not set for the corresponding name.
    """
    analyzer_name = analyzer_class.NAME.lower()
    if analyzer_name not in cls._analyzer_classes:
      raise KeyError(
          f'analyzer class not set for name: {analyzer_class.NAME:s}')

    del cls._analyzer_classes[analyzer_name]

  @classmethod
  def GetAnalyzersInformation(cls):
    """Retrieves the analyzers information.

    Returns:
      list[tuple]: containing:

        str: analyzer name.
        str: analyzer description.
    """
    analyzer_information = []
    for _, analyzer_class in cls.GetAnalyzers():
      description = getattr(analyzer_class, 'DESCRIPTION', '')
      analyzer_information.append((analyzer_class.NAME, description))

    return analyzer_information

  @classmethod
  def GetAnalyzerInstance(cls, analyzer_name):
    """Retrieves an instance of a specific analyzer.

    Args:
      analyzer_name (str): name of the analyzer to retrieve.

    Returns:
      BaseAnalyzer: analyzer instance.

    Raises:
      KeyError: if analyzer class is not set for the corresponding name.
    """
    analyzer_name = analyzer_name.lower()
    if analyzer_name not in cls._analyzer_classes:
      raise KeyError(f'analyzer class not set for name: {analyzer_name:s}.')

    analyzer_class = cls._analyzer_classes[analyzer_name]
    return analyzer_class()

  @classmethod
  def GetAnalyzerInstances(cls, analyzer_names):
    """Retrieves instances for all the specified analyzers.

    Args:
      analyzer_names (list[str]): names of the analyzers to retrieve.

    Returns:
      list[BaseAnalyzer]: analyzer instances.
    """
    analyzer_instances = []
    for analyzer_name, analyzer_class in cls.GetAnalyzers():
      if analyzer_name in analyzer_names:
        analyzer_instances.append(analyzer_class())

    return analyzer_instances

  @classmethod
  def GetAnalyzerNames(cls):
    """Retrieves the names of all loaded analyzers.

    Returns:
      list[str]: of analyzer names.
    """
    return cls._analyzer_classes.keys()

  @classmethod
  def GetAnalyzers(cls):
    """Retrieves the registered analyzers.

    Yields:
      tuple: containing:

        str: the uniquely identifying name of the analyzer
        type: the analyzer class.
    """
    for analyzer_name, analyzer_class in cls._analyzer_classes.items():
      yield analyzer_name, analyzer_class

  @classmethod
  def RegisterAnalyzer(cls, analyzer_class):
    """Registers a analyzer class.

    The analyzer classes are identified by their lower case name.

    Args:
      analyzer_class (type): the analyzer class to register.

    Raises:
      KeyError: if analyzer class is already set for the corresponding name.
    """
    analyzer_name = analyzer_class.NAME.lower()
    if analyzer_name in cls._analyzer_classes:
      raise KeyError(
          f'analyzer class already set for name: {analyzer_class.NAME:s}.')

    cls._analyzer_classes[analyzer_name] = analyzer_class
