"""Shared functionality for delimiter separated values output modules."""

import collections

from plaso.output import formatting_helper
from plaso.output import text_file


class DSVEventFormattingHelper(formatting_helper.EventFormattingHelper):
  """Delimiter separated values output module event formatting helper.

  Attributes:
    field_delimiter (str): field delimiter.
  """

  def __init__(self, field_formatting_helper, field_names, field_delimiter=','):
    """Initializes a delimiter separated values event formatting helper.

    Args:
      field_formatting_helper (FieldFormattingHelper): field formatting helper.
      field_names (list[str]): names of the fields to output.
      field_delimiter (Optional[str]): field delimiter.
    """
    super().__init__()
    self._custom_fields = {}
    self._field_names = field_names
    self._field_formatting_helper = field_formatting_helper

    self.field_delimiter = field_delimiter

  def _SanitizeField(self, field):
    """Sanitizes a field for output.

    This method replaces any field delimiters with a space.

    Args:
      field (str): value of the field to sanitize.

    Returns:
      str: sanitized value of the field.
    """
    if self.field_delimiter and isinstance(field, str):
      return field.replace(self.field_delimiter, ' ')
    return field

  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.
    """
    field_values = collections.OrderedDict()
    for field_name in self._field_names:
      field_value = self._field_formatting_helper.GetFormattedField(
          output_mediator, field_name, event, event_data, event_data_stream,
          event_tag)

      if field_value is None and field_name in self._custom_fields:
        field_value = self._custom_fields.get(field_name)

      if field_value is None:
        field_value = '-'

      field_value = self._SanitizeField(field_value)
      field_values[field_name] = field_value

    return field_values

  def GetFormattedFieldNames(self):
    """Retrieves a string representation of the field names.

    Returns:
      str: string representation of the field names.
    """
    return self.field_delimiter.join(self._field_names)

  def SetAdditionalFields(self, field_names):
    """Sets the names of additional fields to output.

    Args:
      field_names (list[str]): names of additional fields to output.
    """
    self._field_names.extend(field_names)

  def SetCustomFields(self, field_names_and_values):
    """Sets the names and values of custom fields to output.

    Args:
      field_names_and_values (list[tuple[str, str]]): names and values of
          custom fields to output.
    """
    self._custom_fields = dict(field_names_and_values)
    self._field_names.extend(self._custom_fields.keys())

  def SetFieldDelimiter(self, field_delimiter):
    """Sets the field delimiter.

    Args:
      field_delimiter (str): field delimiter.
    """
    self.field_delimiter = field_delimiter

  def SetFields(self, field_names):
    """Sets the names of the fields to output.

    Args:
      field_names (list[str]): names of the fields to output.
    """
    self._field_names = field_names


class DSVOutputModule(text_file.SortedTextFileOutputModule):
  """Shared functionality for delimiter separated values output modules."""

  def __init__(
      self, field_formatting_helper, names, delimiter=',', header=None):
    """Initializes a delimiter separated values output module.

    Args:
      field_formatting_helper (FieldFormattingHelper): field formatting helper.
      names (list[str]): names of the fields to output.
      delimiter (Optional[str]): field delimiter.
      header (Optional[str]): header, where None will have WriteHeader
          generate a header from the field names.
    """
    event_formatting_helper = DSVEventFormattingHelper(
        field_formatting_helper, names, field_delimiter=delimiter)
    super().__init__(event_formatting_helper)
    self._header = header

  def _GetString(self, output_mediator, field_values):
    """Retrieves an output string.

    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.

    Returns:
      str: output string.
    """
    output_text = self._event_formatting_helper.field_delimiter.join(
        field_values.values())
    return ''.join([output_text, '\n'])

  def SetAdditionalFields(self, field_names):
    """Sets the names of additional fields to output.

    Args:
      field_names (list[str]): names of additional fields to output.
    """
    self._event_formatting_helper.SetAdditionalFields(field_names)

  def SetCustomFields(self, field_names_and_values):
    """Sets the names and values of custom fields to output.

    Args:
      field_names_and_values (list[tuple[str, str]]): names and values of
          custom fields to output.
    """
    self._event_formatting_helper.SetCustomFields(field_names_and_values)

  def SetFieldDelimiter(self, field_delimiter):
    """Sets the field delimiter.

    Args:
      field_delimiter (str): field delimiter.
    """
    self._event_formatting_helper.SetFieldDelimiter(field_delimiter)

  def SetFields(self, field_names):
    """Sets the names of the fields to output.

    Args:
      field_names (list[str]): names of the fields to output.
    """
    self._event_formatting_helper.SetFields(field_names)

  def WriteHeader(self, output_mediator):
    """Writes the header to the output.

    Args:
      output_mediator (OutputMediator): mediates interactions between output
          modules and other components, such as storage and dfVFS.
    """
    if self._header:
      output_text = self._header
    else:
      output_text = self._event_formatting_helper.GetFormattedFieldNames()

    self.WriteLine(output_text)
