"""Operating system independent (generic) preprocessor plugins."""

from dfvfs.helpers import file_system_searcher

from plaso.lib import definitions
from plaso.preprocessors import interface
from plaso.preprocessors import manager


class DetermineOperatingSystemPlugin(
    interface.FileSystemArtifactPreprocessorPlugin):
  """Plugin to determine the operating system."""

  # pylint: disable=abstract-method
  # This plugin does not use an artifact definition and therefore does not
  # use _ParsePathSpecification.

  # We need to check for both forward and backward slashes since the path
  # specification will be dfVFS back-end dependent.
  _WINDOWS_LOCATIONS = set([
      '/windows/system32', '\\windows\\system32', '/winnt/system32',
      '\\winnt\\system32', '/winnt35/system32', '\\winnt35\\system32',
      '\\wtsrv\\system32', '/wtsrv/system32'])

  def __init__(self):
    """Initializes a plugin to determine the operating system."""
    super().__init__()
    self._find_specs = [
        file_system_searcher.FindSpec(
            case_sensitive=False, location='/etc',
            location_separator='/'),
        file_system_searcher.FindSpec(
            case_sensitive=False, location='/System/Library',
            location_separator='/'),
        file_system_searcher.FindSpec(
            case_sensitive=False, location='\\Windows\\System32',
            location_separator='\\'),
        file_system_searcher.FindSpec(
            case_sensitive=False, location='\\WINNT\\System32',
            location_separator='\\'),
        file_system_searcher.FindSpec(
            case_sensitive=False, location='\\WINNT35\\System32',
            location_separator='\\'),
        file_system_searcher.FindSpec(
            case_sensitive=False, location='\\WTSRV\\System32',
            location_separator='\\')]

  # pylint: disable=unused-argument
  def Collect(self, mediator, artifact_definition, searcher, file_system):
    """Collects values using a file artifact definition.

    Args:
      mediator (PreprocessMediator): mediates interactions between preprocess
          plugins and other components, such as storage and knowledge base.
      artifact_definition (artifacts.ArtifactDefinition): artifact definition.
      searcher (dfvfs.FileSystemSearcher): file system searcher to preprocess
          the file system.
      file_system (dfvfs.FileSystem): file system to be preprocessed.

    Raises:
      PreProcessFail: if the preprocessing fails.
    """
    locations = []
    for path_spec in searcher.Find(find_specs=self._find_specs):
      relative_path = searcher.GetRelativePath(path_spec)
      if relative_path:
        locations.append(relative_path.lower())

    operating_system = definitions.OPERATING_SYSTEM_FAMILY_UNKNOWN
    if self._WINDOWS_LOCATIONS.intersection(set(locations)):
      operating_system = definitions.OPERATING_SYSTEM_FAMILY_WINDOWS_NT

    elif '/system/library' in locations:
      operating_system = definitions.OPERATING_SYSTEM_FAMILY_MACOS

    elif '/etc' in locations:
      operating_system = definitions.OPERATING_SYSTEM_FAMILY_LINUX

    if operating_system != definitions.OPERATING_SYSTEM_FAMILY_UNKNOWN:
      mediator.SetValue('operating_system', operating_system)


manager.PreprocessPluginsManager.RegisterPlugins([
    DetermineOperatingSystemPlugin])
