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

from common.js_to_obj import jsPosToObj
from dictionary.models import Argument
from semantics.models import Complement, LexicalUnitExamples
from semantics.saving import modify_frames, update_meanings
from wordnet.models import LexicalUnit 

def get_semantic_operations(lemma, schemata_conversions):
    connections = []
    operations = []

    frames = lemma.entry_obj.visible_frames()

    for conv in schemata_conversions:
        schema_operations = get_reconnect_operations_and_extend_connections(frames,
                                                                            connections,
                                                                            conv['obj'], 
                                                                            conv['js'])
        operations.extend(schema_operations)
    operations.extend(get_disconnect_operations(lemma, frames, connections))
    
    return operations
    
def get_reconnect_operations_and_extend_connections(frames, connections, schema, js_schema):
    operations = []
    used_poss_ids = [] 
    for js_position in js_schema['positions']:
        if len(js_position['arguments']) > 0:
            position = get_position(schema, js_position, used_poss_ids)
            for js_phrase_type in js_position['arguments']:
                phrase_type = Argument.objects.get(text_rep=js_phrase_type['text_rep'])
                new_connection_target = {'schema': schema,
                                         'position': position,
                                         'phrase_type': phrase_type}
                for conn in js_phrase_type['connections']:
                    operations.extend(reconnect_operations(frames, conn, new_connection_target))
                    conn_dict = next((conn_dict 
                                      for conn_dict in connections if conn_dict['compl'] == conn['compl']), None)
                    if conn_dict:
                        conn_dict['realizations'].extend(conn['realizations'])
                    else:
                        connections.append({'compl': conn['compl'],
                                            'realizations': conn['realizations']})
    return operations

def get_position(schema, js_position, used_poss_ids):
    position = jsPosToObj(js_position)
    same_poss = schema.positions.filter(text_rep=position.text_rep)
    unused_same_poss = same_poss.exclude(id__in=used_poss_ids).order_by('id')
    position = unused_same_poss[0]
    used_poss_ids.append(position.id)
    return position

def reconnect_operations(frames, connection, new_target):
    operations = []
    compl = Complement.objects.get(id=connection['compl'])
    frame = frames.get(complements=compl)
    arg_ref = create_argument_ref(frame, compl)
    for real_id in connection['realizations']:
        realization = compl.realizations.get(id=real_id)
        old_phrase_type_ref = create_phrase_type_ref(realization.frame, realization.position,
                                                     realization.argument, realization.alternation)
        new_phrase_type_ref = create_phrase_type_ref(new_target['schema'], new_target['position'],
                                                     new_target['phrase_type'], realization.alternation)
        if new_phrase_type_ref != old_phrase_type_ref:
            operations.append(create_operation('disconnect', arg_ref, old_phrase_type_ref))
            operations.append(create_operation('connect', arg_ref, new_phrase_type_ref))
    return operations
        
def create_argument_ref(frame, complement):
    return 'frame_%d_comp_%d_' % (frame.id, complement.id)
        
def create_phrase_type_ref(schema, position, phrase_type, alternation):
    return 'schema_%d_pos_%d_arg_%d_alt_%d_' % (schema.id, position.id,
                                                phrase_type.id, alternation)

def create_operation(operation, arg_ref, phrase_type_ref):
    return {'operation': operation, 'arg': arg_ref, 'connect': phrase_type_ref}

def get_disconnect_operations(lemma, frames, connections):
    operations = []
    shared_schemata_ids = get_shared_schemata_ids(lemma)
    for frame in frames:
        for compl in frame.complements.all():
            conn_dict = next((conn_dict 
                              for conn_dict in connections if conn_dict['compl'] == compl.id), None)
            for real in compl.realizations.all():
                if real.frame.id not in shared_schemata_ids:
                    if not conn_dict or not real.id in conn_dict['realizations']:
                        phrase_type_ref = create_phrase_type_ref(real.frame, real.position,
                                                                 real.argument, real.alternation)
                        arg_ref = create_argument_ref(frame, compl)
                        operations.append(create_operation('disconnect', arg_ref, phrase_type_ref))
    return operations

def get_shared_schemata_ids(lemma):
    ids = [f.id for f in lemma.frames.all()]
    for connected in lemma.entry_obj.rel_entries.all():
        if connected.defined():
            ids += [f.id for f in connected.actual_lemma().frames.all()]
    return ids

def update_connections(lemma_id, reconnect_operations, user):
    modify_frames(lemma_id, reconnect_operations, user)

def disconnect_all_examples_operations(lemma):
    operations = []
    lex_units = lemma.entry_obj.meanings.all()
    for lu in lex_units:
        lu_examples = LexicalUnitExamples.objects.filter(lexical_unit=lu)
        for lu_ex in lu_examples:
            example = lu_ex.example
            operations.append({'operation': 'remove_example', 
                               'unit': lu.id, 
                               'example': example.id})
    return operations

def connect_example_operation(example_dict, example_obj):
    lu = LexicalUnit.objects.get(id=example_dict['lexical_unit'])
    return {'operation': 'add_example', 'unit': lu.id, 'example': example_obj.id}

def disconnect_example_operation(example_dict, example_obj):
    lu = LexicalUnit.objects.get(id=example_dict['lexical_unit'])
    return {'operation': 'remove_example', 'unit': lu.id, 'example': example_obj.id}

def reconnect_examples(lemma, operations):
    update_meanings(lemma.id, operations)
