"""Analyzer that matches Yara rules."""

import yara

try:
    from yara import Error as YaraError
except ImportError:
    from yara import YaraError

try:
    from yara import TimeoutError as YaraTimeoutError
except ImportError:
    from yara import YaraTimeoutError

from plaso.analyzers import interface
from plaso.analyzers import logger
from plaso.analyzers import manager
from plaso.containers import analyzer_result
from plaso.lib import definitions


class YaraAnalyzer(interface.BaseAnalyzer):
    """Analyzer that matches Yara rules."""

    # pylint: disable=no-member

    NAME = "yara"
    DESCRIPTION = "Matches Yara rules over input data."

    PROCESSING_STATUS_HINT = definitions.STATUS_INDICATOR_YARA_SCAN

    INCREMENTAL_ANALYZER = False

    _ATTRIBUTE_NAME = "yara_match"
    _MATCH_TIMEOUT = 60

    def __init__(self):
        """Initializes the Yara analyzer."""
        super().__init__()
        self._matches = []
        self._rules = None

    def Analyze(self, data):
        """Analyzes a block of data, attempting to match Yara rules to it.

        Args:
          data(bytes): a block of data.
        """
        if not self._rules:
            return

        try:
            self._matches = self._rules.match(data=data, timeout=self._MATCH_TIMEOUT)

        except YaraTimeoutError:
            logger.error(
                f"Could not process file within timeout: {self._MATCH_TIMEOUT:d}"
            )

        except YaraError as exception:
            logger.error(f"Error processing file with Yara: {exception!s}.")

    def GetResults(self):
        """Retrieves results of the most recent analysis.

        Returns:
          list[AnalyzerResult]: results.
        """
        result = analyzer_result.AnalyzerResult()
        result.analyzer_name = self.NAME
        result.attribute_name = self._ATTRIBUTE_NAME
        result.attribute_value = [match.rule for match in self._matches]
        return [result]

    def Reset(self):
        """Resets the internal state of the analyzer."""
        self._matches = []

    def SetRules(self, rules_string):
        """Sets the rules that the Yara analyzer will use.

        Args:
          rules_string(str): Yara rule definitions
        """
        self._rules = yara.compile(source=rules_string)


manager.AnalyzersManager.RegisterAnalyzer(YaraAnalyzer)
