"""This file contains the output module interface class."""

import abc

from plaso.output import logger


class OutputModule:
  """Output module interface."""

  NAME = ''
  DESCRIPTION = ''

  # Value to indicate the output module supports outputting additional fields.
  SUPPORTS_ADDITIONAL_FIELDS = False

  # Value to indicate the output module supports outputting custom fields.
  SUPPORTS_CUSTOM_FIELDS = False

  # Value to indicate the output module writes to an output file.
  WRITES_OUTPUT_FILE = False

  def _ReportEventError(self, event, event_data, error_message):
    """Reports an event related error.

    Args:
      event (EventObject): event.
      event_data (EventData): event data.
      error_message (str): error message.
    """
    event_identifier = event.GetIdentifier()
    event_identifier_string = event_identifier.CopyToString()
    display_name = getattr(event_data, 'display_name', None) or 'N/A'
    parser_chain = getattr(event_data, '_parser_chain', None) or 'N/A'

    error_message = (
        f'Event: {event_identifier_string!s} data type: '
        f'{event_data.data_type:s} display name: {display_name:s} parser '
        f'chain: {parser_chain:s} with error: {error_message:s}')
    logger.error(error_message)

  def Close(self):
    """Closes the output."""
    return

  @abc.abstractmethod
  def GetFieldValues(
      self, output_mediator, event, event_data, event_data_stream, event_tag):
    """Retrieves the output field values.

    Args:
      output_mediator (OutputMediator): mediates interactions between output
          modules and other components, such as storage and dfVFS.
      event (EventObject): event.
      event_data (EventData): event data.
      event_data_stream (EventDataStream): event data stream.
      event_tag (EventTag): event tag.

    Returns:
      dict[str, str]: output field values per name.
    """

  def GetMissingArguments(self):
    """Retrieves arguments required by the module that have not been specified.

    Returns:
      list[str]: names of argument that are required by the module and have
          not been specified.
    """
    return []

  def Open(self, **kwargs):  # pylint: disable=unused-argument
    """Opens the output."""
    return

  @abc.abstractmethod
  def WriteFieldValues(self, output_mediator, field_values):
    """Writes field values to the output.

    Args:
      output_mediator (OutputMediator): mediates interactions between output
          modules and other components, such as storage and dfVFS.
      field_values (dict[str, str]): output field values per name.
    """

  def WriteFieldValuesOfMACBGroup(self, output_mediator, macb_group):
    """Writes field values of a MACB group to the output.

    Args:
      output_mediator (OutputMediator): mediates interactions between output
          modules and other components, such as storage and dfVFS.
      macb_group (list[tuple[event, event_data, event_data_stream, event_tag]]):
          group of event, event_data, event_data_stream and event_tag objects
          with identical timestamps, attributes and values.
    """
    for event, event_data, event_data_stream, event_tag in macb_group:
      field_values = self.GetFieldValues(
          output_mediator, event, event_data, event_data_stream, event_tag)
      self.WriteFieldValues(output_mediator, field_values)

  def WriteFooter(self):
    """Writes the footer to the output.

    Can be used for post-processing or output after the last event is written,
    such as writing a file footer.
    """
    return

  def WriteHeader(self, output_mediator):  # pylint: disable=unused-argument
    """Writes the header to the output.

    Can be used for pre-processing or output before the first event
    is written, such as writing a file header.

    Args:
      output_mediator (OutputMediator): mediates interactions between output
          modules and other components, such as storage and dfVFS.
    """
    return
