from spacy.matcher import Matcher


class SentenceSegmenter(object):
    """Adds custom sentence boundaries to spaCy Doc.
    @param vocab: the language vocabulary from the spaCy nlp object
    @param boundary_protection_rules: an optional list of labelled
    matching patterns that will explicitly prevent sentence boundaries.
    """

    name = "sentence_segmenter"

    def __init__(self, vocab, boundary_protection_rules=[]):
        self.matcher = Matcher(vocab)
        for rule in boundary_protection_rules:
            self.matcher.add(rule["label"], None, rule["pattern"])

    def __call__(self, doc):
        matches = self.matcher(doc)
        for i, token in enumerate(doc[:-2]):
            if token_in_match_range(token, matches):
                token.is_sent_start = False
            if token.text == "Sch" and doc[i + 1].is_punct:
                doc[i + 2].is_sent_start = False
            if str(doc[i]) == "]" and doc[i + 1].is_digit:
                doc[i + 2].is_sent_start = False
            if str(doc[i + 1]) == ")":
                doc[i + 2].is_sent_start = False
            if str(doc[i + 1]) == "(":
                doc[i + 2].is_sent_start = False
            if str(doc[i + 1]) == "]":
                doc[i + 2].is_sent_start = False
            if str(doc[i + 1]) == "[":
                doc[i + 2].is_sent_start = False
            if doc[i + 1].is_digit:
                doc[i + 2].is_sent_start = False
            if str(doc[i + 1]) == ";":
                doc[i + 2].is_sent_start = False
            if str(doc[i + 1]) == ":":
                doc[i + 2].is_sent_start = True
            if str(doc[i + 1]) == "\n\n":
                doc[i + 2].is_sent_start = True
            if str(doc[i + 1]) == "\n":
                doc[i + 2].is_sent_start = True
            if str(doc[i + 1]) == "-":
                doc[i + 2].is_sent_start = False
            if str(doc[i + 2]) == "[":
                doc[i + 2].is_sent_start = False
            if doc[i].is_digit and str(doc[i + 1]) == "]":
                doc[i + 1].is_sent_start = False
            if doc[i].is_digit:
                doc[i + 1].is_sent_start = False
            if token.text == "?" and doc[i + 1].is_quote:
                doc[i + 1].is_sent_start = False
            if token.text == "ex":
                doc[i].is_sent_start = False
            if token.text == "ex" and str(doc[i + 1]) == "parte":
                doc[i + 2].is_sent_start = False
            if token.text == "\n" and str(doc[i + 1]) == "\n":
                doc[i + 2].is_sent_start = True
            if token.text == "cf" and str(doc[i + 1]) == ".":
                doc[i + 2].is_sent_start = False
            if token.text == "unreported" and str(doc[i + 1]) == ":":
                doc[i + 2].is_sent_start = False
            if token.text == "Hon" and str(doc[i + 1]) == ".":
                doc[i + 2].is_sent_start = False
            if token.text == "." and doc[i + 1].is_quote:
                doc[i + 1].is_sent_start = False
            if token.text == "?" and str(doc[i + 1]) == "!":
                doc[i + 1].is_sent_start = False
            if token.text == "!" and str(doc[i + 1]) == "?":
                doc[i + 1].is_sent_start = False
            if str(doc[i + 2]) == "(":
                doc[i + 2].is_sent_start = False
            if token.text == "reg" and doc[i + 1].is_punct:
                doc[i + 2].is_sent_start = False
            if token.text == "’s":
                doc[i].is_sent_start = False
            if doc[i].is_quote:
                doc[i + 1].is_sent_start = False
            if token.text == ")" and doc[i + 1].is_punct is False:
                doc[i + 2].is_sent_start = False
            if token.text == "Eu" and doc[i + 1].is_punct:
                doc[i + 2].is_sent_start = False
        return doc


def token_in_match_range(token, matches):
    for _, start, end in matches:
        if token.i >= start and token.i <= end:
            return True
    return False
