import re


class Signature(object):
    """Signature is an indicator of a problem in web page's contents

    For example, signature of a problem is "PHP Fatal error"
    string in page contents. Each signature has function 'find(page_contents)'
    which returns True if signature was found in the page, False otherwise,
    and two properties:
    - problem_found_on_source: problem ID in case signature was found on
    source server. That usually means that site on the source server
    may work incorrectly.
    - problem_found_on_target_only: problem ID in case signature was found
    on target server only, but not on source server. That usually means
    that problem was introduced during domain transfer or system upgrade.
    """
    def __init__(self, problem_found_on_source, problem_found_on_target_only):
        self.problem_found_on_source = problem_found_on_source
        self.problem_found_on_target_only = problem_found_on_target_only

    def find(self, page_contents):
        """Check if signature exists in provided page. 
        
        Return string - signature text found on the page,
        None - signature was not found on the page
        
        Override in child classes.
        """
        raise NotImplementedError()


class TextSignature(Signature):
    """Simple text signature, which looks for an exact match of a string"""
    def __init__(self, signature_text, problem_found_on_source, problem_found_on_target_only):
        super(TextSignature, self).__init__(problem_found_on_source, problem_found_on_target_only)
        self.signature_text = signature_text

    def find(self, page_contents):
        """Check if signature exists in provided page."""
        if self.signature_text in page_contents:
            return self.signature_text
        else:
            return None


class RegexSignature(Signature):
    """Regular expression based signature, which looks for regexp match"""
    def __init__(self, regex, problem_found_on_source, problem_found_on_target_only, limit_match_length=1024):
        """Class constructor

        When 'limit_match_length' parameter is specified (which is default),
        all matches like ".*" or ".+" will be limited to maximum specified number of symbols.
        That is necessary to avoid performance issues (which look like hanged migration) when working with long lines.

        :type regex: str | unicode
        :type problem_found_on_source: str | unicode
        :type problem_found_on_target_only: str | unicode
        :type limit_match_length: int | None
        """
        super(RegexSignature, self).__init__(problem_found_on_source, problem_found_on_target_only)
        self.regex = regex
        if limit_match_length is not None:
            self.regex = self.regex.replace('*', '{0,%s}' % str(limit_match_length))
            self.regex = self.regex.replace('+', '{1,%s}' % str(limit_match_length))

    def find(self, page_contents):
        """Check if signature exists in provided page."""
        m = re.search(self.regex, page_contents)
        if m is None:
            return None
        else:
            return m.group(0)
