# -*- coding: utf-8 -*-
import cPickle as pickle
import collections

from core.runtime.relations import RelationCollection
from networks.context.processing.relations.position import ExtractedRelationPosition
from networks.context.processing.relations.relation import ExtractedRelation
from networks.context.processing.terms.news_terms import NewsTerms


class ExtractedRelationsCollection:
    """
    Describes text relations with a position precision and forward connection, so
    for each relation we store it's continuation if it originally has.

    Usage:
    It is possible to add relations from news via add_news_relations

    Limitations:
    Not it represents IN-MEMORY implementation.
    Therefore it is supposed not so large amount of relations.
    """

    NO_NEXT_RELATION = None

    def __init__(self):
        # list ExtractedRelations
        self.__relations = []
        # list describes that has i'th relation continuation in text.
        self.__next_relation_id = []
        # provides original label by relation_id
        self.__opinion_labels = []
        # labels defined
        self.__labels_defined = []

    def add_extracted_relations(self,
                                relations,
                                check_relation_is_correct):
        assert(isinstance(relations, collections.Iterable))
        assert(callable(check_relation_is_correct))

        missed = 0
        for index, relation in enumerate(relations):
            assert(isinstance(relation, ExtractedRelation))
            assert(relation.RelationID is None)

            if not check_relation_is_correct(relation):
                missed += 1
                continue

            relation.set_relation_id(len(self.__relations))

            self.__register_relation(relation)

        self.__next_relation_id[-1] = self.NO_NEXT_RELATION
        return missed

    def add_news_relations(self,
                           relations,
                           label,
                           news_terms,
                           news_index,
                           check_relation_is_correct):
        assert(isinstance(relations, RelationCollection))
        assert(isinstance(news_terms, NewsTerms))
        assert(isinstance(news_index, int))
        assert(callable(check_relation_is_correct))

        missed = 0
        for index, relation in enumerate(relations):

            pos_subj = news_terms.get_entity_position(relation.LeftEntityID)
            pos_obj = news_terms.get_entity_position(relation.RightEntityID)
            relation_id = len(self.__relations)

            extracted_relation = ExtractedRelation(
                ExtractedRelationPosition(news_index, pos_subj, pos_obj),
                relation_id,
                relation.LeftEntityValue,
                relation.RightEntityValue,
                label)

            if not check_relation_is_correct(extracted_relation):
                missed += 1
                continue

            self.__register_relation(extracted_relation)

        self.__next_relation_id[-1] = self.NO_NEXT_RELATION
        return missed

    def __register_relation(self, relation):
        assert(isinstance(relation, ExtractedRelation))
        self.__relations.append(relation)
        self.__next_relation_id.append(relation.RelationID + 1)
        self.__opinion_labels.append(relation.Label)
        self.__labels_defined.append(True)

    def check_all_relations_has_labels(self):
        return not (False in self.__labels_defined)

    def check_all_relations_without_labels(self):
        return not (True in self.__labels_defined)

    def apply_label(self, label, relation_id):
        assert(isinstance(relation_id, int))

        if self.__labels_defined[relation_id] is not False:
            assert(self.__relations[relation_id].Label == label)
            return

        self.__relations[relation_id].set_label(label)
        self.__labels_defined[relation_id] = True

    def get_original_label(self, relation_id):
        assert(isinstance(relation_id, int))
        return self.__opinion_labels[relation_id]

    def reset_labels(self):
        for relation in self.__relations:
            relation.set_label(self.__opinion_labels[relation.RelationID])
        self.__labels_defined = [False] * len(self.__labels_defined)

    def save(self, pickle_filepath):
        pickle.dump(self, open(pickle_filepath, 'wb'))

    @classmethod
    def load(cls, pickle_filepath):
        return pickle.load(open(pickle_filepath, 'rb'))

    def __iter__(self):
        for relation in self.__relations:
            yield relation

    def __len__(self):
        return len(self.__relations)

    def __iter_by_linked_relations(self):
        lst = []
        for index, relation in enumerate(self.__relations):
            lst.append(relation)
            if self.__next_relation_id[index] == self.NO_NEXT_RELATION:
                yield lst
                lst = []

    def iter_by_linked_relations(self):
        return self.__iter_by_linked_relations()

    def iter_by_linked_relations_groups(self, group_size):
        assert(isinstance(group_size, int))
        group = []
        for index, linked_relations in enumerate(self.__iter_by_linked_relations()):
            group.append(linked_relations)
            if len(group) == group_size:
                yield group
                group = []

# -*- coding: utf-8 -*-
import cPickle as pickle
import collections

from core.runtime.relations import RelationCollection
from networks.context.processing.relations.position import ExtractedRelationPosition
from networks.context.processing.relations.relation import ExtractedRelation
from networks.context.processing.terms.news_terms import NewsTerms


class ExtractedRelationsCollection:
    """
    Describes text relations with a position precision and forward connection, so
    for each relation we store it's continuation if it originally has.

    Usage:
    It is possible to add relations from news via add_news_relations

    Limitations:
    Not it represents IN-MEMORY implementation.
    Therefore it is supposed not so large amount of relations.
    """

    NO_NEXT_RELATION = None

    def __init__(self):
        # list ExtractedRelations
        self.__relations = []
        # list describes that has i'th relation continuation in text.
        self.__next_relation_id = []
        # provides original label by relation_id
        self.__opinion_labels = []
        # labels defined
        self.__labels_defined = []

    def add_extracted_relations(self,
                                relations,
                                check_relation_is_correct):
        assert(isinstance(relations, collections.Iterable))
        assert(callable(check_relation_is_correct))

        missed = 0
        for index, relation in enumerate(relations):
            assert(isinstance(relation, ExtractedRelation))
            assert(relation.RelationID is None)

            if not check_relation_is_correct(relation):
                missed += 1
                continue

            relation.set_relation_id(len(self.__relations))

            self.__register_relation(relation)

        self.__next_relation_id[-1] = self.NO_NEXT_RELATION
        return missed

    def add_news_relations(self,
                           relations,
                           label,
                           news_terms,
                           news_index,
                           check_relation_is_correct):
        assert(isinstance(relations, RelationCollection))
        assert(isinstance(news_terms, NewsTerms))
        assert(isinstance(news_index, int))
        assert(callable(check_relation_is_correct))

        missed = 0
        for index, relation in enumerate(relations):

            pos_subj = news_terms.get_entity_position(relation.LeftEntityID)
            pos_obj = news_terms.get_entity_position(relation.RightEntityID)
            relation_id = len(self.__relations)

            extracted_relation = ExtractedRelation(
                ExtractedRelationPosition(news_index, pos_subj, pos_obj),
                relation_id,
                relation.LeftEntityValue,
                relation.RightEntityValue,
                label)

            if not check_relation_is_correct(extracted_relation):
                missed += 1
                continue

            self.__register_relation(extracted_relation)

        self.__next_relation_id[-1] = self.NO_NEXT_RELATION
        return missed

    def __register_relation(self, relation):
        assert(isinstance(relation, ExtractedRelation))
        self.__relations.append(relation)
        self.__next_relation_id.append(relation.RelationID + 1)
        self.__opinion_labels.append(relation.Label)
        self.__labels_defined.append(True)

    def check_all_relations_has_labels(self):
        return not (False in self.__labels_defined)

    def check_all_relations_without_labels(self):
        return not (True in self.__labels_defined)

    def apply_label(self, label, relation_id):
        assert(isinstance(relation_id, int))

        if self.__labels_defined[relation_id] is not False:
            assert(self.__relations[relation_id].Label == label)
            return

        self.__relations[relation_id].set_label(label)
        self.__labels_defined[relation_id] = True

    def get_original_label(self, relation_id):
        assert(isinstance(relation_id, int))
        return self.__opinion_labels[relation_id]

    def reset_labels(self):
        for relation in self.__relations:
            relation.set_label(self.__opinion_labels[relation.RelationID])
        self.__labels_defined = [False] * len(self.__labels_defined)

    def save(self, pickle_filepath):
        pickle.dump(self, open(pickle_filepath, 'wb'))

    @classmethod
    def load(cls, pickle_filepath):
        return pickle.load(open(pickle_filepath, 'rb'))

    def __iter__(self):
        for relation in self.__relations:
            yield relation

    def __len__(self):
        return len(self.__relations)

    def __iter_by_linked_relations(self):
        lst = []
        for index, relation in enumerate(self.__relations):
            lst.append(relation)
            if self.__next_relation_id[index] == self.NO_NEXT_RELATION:
                yield lst
                lst = []

    def iter_by_linked_relations(self):
        return self.__iter_by_linked_relations()

    def iter_by_linked_relations_groups(self, group_size):
        assert(isinstance(group_size, int))
        group = []
        for index, linked_relations in enumerate(self.__iter_by_linked_relations()):
            group.append(linked_relations)
            if len(group) == group_size:
                yield group
                group = []

# -*- coding: utf-8 -*- Describes text relations with a position precision and forward connection, so     for each relation we store it's continuation if it originally has.      Usage:     It is possible to add relations from news via add_news_relations      Limitations:     Not it represents IN-MEMORY implementation.     Therefore it is supposed not so large amount of relations. # list ExtractedRelations # list describes that has i'th relation continuation in text. # provides original label by relation_id # labels defined