# Filename: generate_vector
# Description: Takes a triple generated by OpenIE as argument and outputs a
#              vector representation of that triple. The first 10 features will
#              indicate the label of the subject, the last 10 features will
#              indicate the label of the object, and the remaining features in
#              the middle will be generated based on word2vec.

from constants import * ;
import numpy as np ;
import re;
import gensim;

#constants 
DISTANCE_WEIGHT = 0.5
LENGTH_WEIGHT = 0.5
FIRST = 1
THIRD = 3

# to hold mapping of descriptors to labels and descriptors ordered by length
descriptors_to_labels, descriptors_ordered = get_dictionary_desc_to_labels() ;
VECTOR_SIZE = 100;

all_text = ''
with open(ALL_TEXT_FILE, 'r') as file:
    all_text = str(file.read());
all_text = all_text.replace('\n', '');
all_text_sentences = all_text.split('.');

# remove empty sentences
all_text_sentences = [ sentence.split() for sentence in \
    all_text_sentences if len(sentence) > 0];

model = gensim.models.Word2Vec(all_text_sentences, size=VECTOR_SIZE, \
        window=5, min_count=5, workers=4)

# finds the descriptor (if one exists) in the phrase and returns its label
def assign_label (desc_phrase, direction):
    descriptor_arr = []
    # iterate through ordered descriptors
    for descriptor in descriptors_ordered:
        r = re.compile(r'\b%s\b' % re.escape(descriptor))
        temp_desc_arr = []
        for match in r.finditer(desc_phrase):
            position = match.span()
            distance = None
            if direction == FIRST:
                distance = len(desc_phrase) - 1 - position[1]
            else:
                distance = position[0]
            desc_tuple = (descriptor, distance)
            temp_desc_arr.append(desc_tuple)
        desc_arr_sorted = sorted(temp_desc_arr, key=lambda x: x[1])
        if (len(desc_arr_sorted) > 0):
            closest_desc = desc_arr_sorted[0];
            distance_value = (closest_desc[1] * (-1) * DISTANCE_WEIGHT) + \
                (len(closest_desc[0]) * LENGTH_WEIGHT)

            descriptor_arr.append((descriptor, distance_value));
        # no matches found
        else:
            continue;
    sorted_desc = sorted(descriptor_arr, key=lambda x: x[1])
    if (len(sorted_desc) != 0):
        return descriptors_to_labels[sorted_desc[len(sorted_desc) - 1][0]];
        
    # no descriptor was found in the phrase
    return None ;

# returns a list/vector of 10 binary features corresponding to the given label
def create_label_vector (label):
    label_vector = [(1 if (label == x) else 0) for x in \
        descriptor_labels_alpha] ;

    return np.array(label_vector) ;
    # for label_type in descriptor_labels_alpha:

# returns the normalized sum of the word vectors generated by word2vec for each
# word in the segment
def vectorize_action (action):
    action_words = action.split(' ');

    # initialize zero-filled sum array
    vector_sum = np.zeros((VECTOR_SIZE,));

    for word in action_words:
        if word in model.wv: 
            vector_sum += model.wv[word];

    # - perform normalization -
    magnitude = np.sqrt(np.sum(vector_sum ** 2)); 
    vector_sum_norm = vector_sum;

    if magnitude > 0:
        vector_sum_norm = vector_sum / magnitude;
    # -

    return vector_sum;

def generate_triple_vector (triple):
    # parse the triple into its constituents
    triple_segments = triple.split('\t') ;

    subj = triple_segments[1] ;
    action = triple_segments[2] ;
    obj = triple_segments[3] ;

    # label the subject and object from the triple
    subj_label = assign_label(subj, FIRST) ;
    obj_label = assign_label(obj, THIRD) ;

    # turn those labels into 10-feature vectors
    subj_vector = create_label_vector(subj_label) ;
    obj_vector = create_label_vector(obj_label) ;

    # process the action segment of the triple with word2vec or similar
    action_vector = vectorize_action(action) ;

    # concatenate vectors together to produce output
    output_vector = np.concatenate((subj_vector, action_vector, \
        obj_vector), axis=0) ;

    return output_vector ;
