# -*- coding: utf-8 -*-

def get_frames_differences(initial_frames, frames):
    differences = {'matching_frames': [],
                   'part_matching_frames': [],
                   'missing_frames': []}
    matching_frames = []
    for ini_frame in initial_frames:
        matching_frame = get_matching_frame(frames, ini_frame)
        if matching_frame:
            differences['matching_frames'].append(ini_frame)
            matching_frames.append(matching_frame)
        else:
            differences['missing_frames'].append(ini_frame)
    not_matched_frames = list(set(frames) - set(matching_frames))
    for miss_frame in differences['missing_frames']:
        part_matching_frames = get_partially_matching_frames(not_matched_frames, miss_frame)
        if part_matching_frames:
            not_matched_frames.remove(part_matching_frames[0])
            differences['part_matching_frames'].append(miss_frame)
    differences['missing_frames'] = list(set(differences['missing_frames']) - set(differences['part_matching_frames']))
    return differences

def get_matching_frame(frames, frame_to_find):
    for frame in frames.all():
        if lexical_units_match(frame, frame_to_find) and frames_match(frame, frame_to_find):
            return frame
    return None

def lexical_units_match(frame1, frame2):
    if set(frame1.lexical_units.all()) == set(frame2.lexical_units.all()):
        return True
    return False
        
def frames_match(frame1, frame2):
    complements1 = frame1.complements
    complements2 = frame2.complements
    if complements1.count() == complements2.count():
        for compl in complements1.all():
            if not matching_complement_exists(complements2.all(), compl):
                return False
    else:
        return False
    return True
        
def matching_complement_exists(complements, compl_to_find):
    for compl in complements:
        if complements_match(compl, compl_to_find):
            return True
    return False
        
def complements_match(compl1, compl2):
    if (roles_match(compl1.roles, compl2.roles) and 
        preference_match(compl1.selective_preference, compl2.selective_preference)):
        return True
    return False
        
def roles_match(roles1, roles2):
    if set(roles1.all()) == set(roles2.all()):
        return True
    return False 

def preference_match(sel_preference1, sel_preference2):
    if sel_preference1 is None and sel_preference2 is None:
        return True
    elif((sel_preference1 is None and sel_preference2 is not None) or
         (sel_preference1 is not None and sel_preference2 is None)):
        return False
    elif(general_sel_prefs_match(sel_preference1, sel_preference2) and
         synset_sel_prefs_match(sel_preference1, sel_preference2) and
         relation_sel_prefs_match(sel_preference1, sel_preference2) and
         synset_rel_sel_prefs_match(sel_preference1, sel_preference2)):
        return True
    return False
    
def general_sel_prefs_match(sel_preference1, sel_preference2):
    if set(sel_preference1.generals.all()) == set(sel_preference2.generals.all()):
        return True
    return False

def synset_sel_prefs_match(sel_preference1, sel_preference2):
    if set(sel_preference1.synsets.all()) == set(sel_preference2.synsets.all()):
        return True
    return False

def relation_sel_prefs_match(sel_preference1, sel_preference2):
    relations1 = sel_preference1.relations
    relations2 = sel_preference2.relations
    if relations1.count() == relations2.count():
        for rel in relations1.all():
            if not matching_relation_exists(rel, relations2):
                return False
    else:
        return False
    return True

def matching_relation_exists(rel_to_find, relations):
    for rel in relations.filter(relation=rel_to_find.relation):
        if complements_match(rel_to_find.to, rel.to):
            return True
    return False

def synset_rel_sel_prefs_match(sel_preference1, sel_preference2):
    relations1 = sel_preference1.synset_relations
    relations2 = sel_preference2.synset_relations
    if relations1.count() == relations2.count():
        for rel in relations1.all():
            if not matching_synset_relation_exists(rel, relations2):
                return False
    else:
        return False
    return True

def matching_synset_relation_exists(rel_to_find, relations):
    for rel in relations.filter(relation=rel_to_find.relation):
        if rel_to_find.to == rel.to:
            return True
    return False

def get_partially_matching_frames(frames, frame_to_find):
    matching_frames = []
    for frame in frames:
        if lexical_units_match(frame, frame_to_find) and frames_partially_match(frame, frame_to_find):
            matching_frames.append(frame)
    return matching_frames

def frames_partially_match(frame1, frame2):
    complements1 = frame1.complements
    complements2 = frame2.complements
    if complements1.count() == complements2.count():
        for compl in complements1.all():
            if not partially_matching_complement_exists(complements2.all(), compl):
                return False
    else:
        return False
    return True

def partially_matching_complement_exists(complements, compl_to_find):
    for compl in complements:
        if complements_partially_match(compl, compl_to_find):
            return True
    return False
        
def complements_partially_match(compl1, compl2):
    if roles_match(compl1.roles, compl2.roles):
        return True
    return False

def get_structural_matching_frame(frames, frame_to_find):
    for frame in frames.all():
        if frames_match(frame, frame_to_find):
            return frame
    return None
