"""This file contains basic interface for plugins within Plaso.

This library serves a basis for all plugins in Plaso, whether that are Windows
Registry plugins, SQLite plugins or any other parsing plugins.

This is provided as a separate file to make it easier to inherit in other
projects that may want to use the Plaso plugin system.
"""


class BasePlugin:
  """A plugin is a lightweight parser that makes use of a common data structure.

  When a data structure is common among several artifacts or files a plugin
  infrastructure can be written to make writing parsers simpler. The goal of a
  parser plugin is to have only a single parser that understands the data
  structure that can call plugins that have specialized knowledge of certain
  structures.

  An example of this is a SQLite database. A plugin can be written that has
  knowledge of certain database, such as Chrome history, or Skype history, etc.
  This can be done without needing to write a fully-fledged parser that needs to
  re-implement the data structure knowledge. A single parser can be created that
  calls the plugins to see if it knows that particular database.

  Another example is Windows Registry, there a single parser that can parse the
  Registry can be made and the job of a single plugin is to parse a particular
  Registry key. The parser can then read a Registry key and compare it to a list
  of available plugins to see if it can be parsed.
  """

  # The name of the plugin. This is the name that is used in the registration
  # and used for parser/plugin selection, so this needs to be concise and unique
  # for all plugins/parsers, such as 'Chrome', 'Safari' or 'UserAssist'.
  NAME = 'base_plugin'

  # Data format supported by the parser plugin. This information is used by
  # the parser manager to generate parser and plugin information.
  DATA_FORMAT = ''

  # pylint: disable=unused-argument
  def Process(self, parser_mediator, **kwargs):
    """Extracts events using a parser plugin.

    Args:
      parser_mediator (ParserMediator): mediates interactions between parsers
          and other components, such as storage and dfVFS.
      kwargs (dict[str, object]): Depending on the plugin they may require
          different sets of arguments to be able to evaluate whether or not
          this is the correct plugin.

    Raises:
      ValueError: when there are unused keyword arguments.
    """
    if kwargs:
      names = ', '.join(kwargs.keys())
      raise ValueError(f'Unused keyword arguments: {names:s}')

  def UpdateChainAndProcess(self, parser_mediator, **kwargs):
    """Extracts events using a parser plugin and synchronizes the parser chain.

    This method updates the parser chain object held by the mediator, transfers
    control to the plugin-specific Process() method, and updates the chain again
    once the processing is complete.

    Args:
      parser_mediator (ParserMediator): mediates interactions between parsers
          and other components, such as storage and dfVFS.
    """
    parser_mediator.AppendToParserChain(self.NAME)

    parser_chain = parser_mediator.GetParserChain()
    parser_mediator.SampleStartTiming(parser_chain)

    try:
      self.Process(parser_mediator, **kwargs)

    finally:
      parser_mediator.SampleStopTiming(parser_chain)

      parser_mediator.PopFromParserChain()


class BasePluginCache:
  """A generic cache for parser plugins."""

  def GetResults(self, attribute_name, default_value=None):
    """Retrieves a cached attribute.

    Args:
      attribute_name (str): name of the cached attribute.
      default_value (Optional[object]): default value.

    Returns:
      object: value of the cached attribute or default value if the cache
          does not contain the attribute.
    """
    return getattr(self, attribute_name, default_value)

  def SetResults(self, attribute_name, value):
    """Sets a cached attribute.

    Args:
      attribute_name (str): name of the cached attribute.
      value (object): value of the attribute.
    """
    setattr(self, attribute_name, value)
