import os.path as opath
from sys import path as spath
spath.append(opath.join(opath.dirname(__file__), '../lib'))
from mitie import *


class Sentence():
    """A class for sentence metadata.

    Attributes:
        text: A string of the sentence text.
        lower_text: A string of the lowercased sentence text.
        offset_list: A list storing the offset of each character in the
            sentence.
        tokens: A list of tokens generated by the MITIE tokenizer.
        token_ranges: A list of tuples containing the begin and end index of
            each token.
        entities: A dictionary of the form {mention_range: mention_type} storing
            the range and type of the entities.
    """

    def __init__(self, text, offset_list):
        self.text = text
        self.lower_text = text.lower()
        self.offset_list = offset_list
        self.tokens = tokenize(self.lower_text)  # using MITIE tokenizer
        self.entities = {}
        self._mention_id_dict = {}

        self.token_ranges = []
        curr_pos = 0
        for token in self.tokens:
            begin = self.lower_text.find(token, curr_pos)
            end = begin + len(token) - 1
            curr_pos = end + 1
            self.token_ranges.append((begin, end))

    def get_begin(self):
        return self.offset_list[0]

    def get_end(self):
        return self.offset_list[-1]

    def get_entity_range(self, mention_id):
        return self.mention_id_dict[mention_id]

    def offset_to_index(self, offset):
        return self.offset_list.index(offset)

    def has_entity(self):
        return len(self.entities) > 0

    def has_this_entity(self, mention_id):
        return (mention_id in self.mention_id_dict)

    def add_mention(self, mention, entity_type):
        """Adds an entity to the Sentence object.

        Args:
            mention: An Element object containing the entity mention.
            entity_type: A string containing the type of the entity mention.
        """
        begin_idx = self.offset_to_index(int(mention.attrib['offset']))
        end_idx = self.offset_to_index(int(mention.attrib['offset']) +
                                       int(mention.attrib['length']) - 1)
        started = False
        for idx, (token_begin, token_end) in enumerate(self.token_ranges):
            if token_begin >= begin_idx and token_end <= end_idx:
                if started:
                    continue
                else:
                    first_token = idx
                    started = True
            else:
                if started:
                    last_token = idx
                    break
                else:
                    continue
        if started:
            self.entities[(first_token, last_token)] = entity_type
            self._mention_id_dict[mention.attrib['id']] = \
                xrange(first_token, last_token)
