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

from django.db.models import Q

from dictionary.models import Lemma
from semantics.models import Complement, RelationalSelectivePreference, \
                             SelectivePreference, SemanticFrame
from wordnet.models import LexicalUnit

# creating log of changes
def store_old_versions(lemma_id, operations, author):
    backup_preference = set()
    backup_complement = set()
    backup_frame = set()
    for operation in operations:
        if operation['operation'] == "create_frame":
            pass
        elif operation['operation'] == "remove_frame":
            backup_frame.add(int(operation['id']))
        elif operation['operation'] == "add_argument": 
            backup_frame.add(int(operation['frame_id']))
        elif operation['operation'] == "remove_argument":
            backup_frame.add(int(operation['frame_id']))
            backup_complement.add(int(operation['complement_id']))
        elif operation['operation'] == "connect":
            frame_data = operation['arg'].split('_')
            frame_id = int(frame_data[1])
            complement_id = int(frame_data[3])
            backup_frame.add(frame_id)
            backup_complement.add(complement_id)
        elif operation['operation'] == "disconnect":
            frame_data = operation['arg'].split('_')
            frame_id = int(frame_data[1])
            complement_id = int(frame_data[3])
            backup_frame.add(frame_id)
            backup_complement.add(complement_id)
        elif operation['operation'] == "assign_role":
            backup_frame.add(int(operation['frame_id']))
            backup_complement.add(int(operation['complement_id']))
        elif operation['operation'] == "change_units":
            backup_frame.add(int(operation['frame_id']))
        elif operation['operation'] == "add_preference":
            backup_frame.add(int(operation['frame_id']))
            backup_complement.add(int(operation['complement_id']))
            backup_preference.add(int(operation['complement_id']))
        elif operation['operation'] == "remove_preference":
            backup_frame.add(int(operation['frame_id']))
            backup_complement.add(int(operation['complement_id']))
            backup_preference.add(int(operation['complement_id']))
        else:
            pass
    backup_frames(list(backup_frame), list(backup_complement), list(backup_preference), author)

def backup_frames(frame_ids, complement_ids, preference_ids, author=None):

    dependent = get_extended_complement_ids(complement_ids)
    complement_ids = list(set(complement_ids) | set(dependent))
    preference_ids = list(set(preference_ids) | set(dependent))

    preference_mapping = {}
    for cid in preference_ids:
        if cid >= 0:
            c = Complement.objects.get(id=cid)
            pref = c.selective_preference
            if pref is None:
                sp = SelectivePreference()
                sp.save()
                c.selective_preference = sp
                c.save()
                pref = c.selective_preference
            sp = SelectivePreference()
            sp.save()
            sp.generals = pref.generals.all()
            sp.synsets = pref.synsets.all()
            sp.relations = pref.relations.all()
            sp.save()
            preference_mapping[cid] = sp.id
    
    complement_mapping = {}
    for cid in complement_ids:
        if cid >= 0:
            complement = Complement.objects.get(id=cid)
            c = Complement(frame=complement.frame)
            c.save()
            c.roles = complement.roles.all()
            c.selective_preference = complement.selective_preference
            c.realizations = complement.realizations.all()
            c.save()
            complement_mapping[complement.id] = c.id
        
    frame_mapping = {}
    for fid in frame_ids:
        if fid >= 0:
            frame = SemanticFrame.objects.get(id=fid)
            f = SemanticFrame()
            f.save()
            f.lexical_units = frame.lexical_units.all()
            f.complements = frame.complements.all()
            f.author = frame.author
            f.entry = frame.entry
            frame.author = author
            f.save()
            prev = SemanticFrame.objects.filter(next=frame)
            if len(prev) > 0:
                prev[0].next = f
                prev[0].save()
            f.next = frame
            f.save()
            frame_mapping[frame.id] = f.id
        
    # update relations
    for new in preference_mapping.values():
        to_remove = []
        to_add = []
        preference = SelectivePreference.objects.get(id=new)
        for relational_preference in preference.relations.all():
            if relational_preference.to.id in complement_mapping.keys():
                new_complement = Complement.objects.get(id=complement_mapping[relational_preference.to.id])
                new_relational_preference = RelationalSelectivePreference(relation=relational_preference.relation, to=new_complement)
                new_relational_preference.save()
                to_add.append(new_relational_preference)
                to_remove.append(relational_preference)
        for relational_preference in to_remove:
            preference.relations.remove(relational_preference)
        for relational_preference in to_add:
            preference.relations.add(relational_preference)
        preference.save()
        
    # update preferences
    for old, new in preference_mapping.items():
        complement = Complement.objects.get(id=complement_mapping[old])
        complement.selective_preference = SelectivePreference.objects.get(id=new)
        complement.save()
    
    # update complements and corresponding frames
    for old, new in complement_mapping.items():
        old_complement = Complement.objects.get(id=new)
        new_complement = Complement.objects.get(id=old)
        new_frame = SemanticFrame.objects.get(id=new_complement.frame.id)
        old_frames = SemanticFrame.objects.filter(complements=new_complement.id)
        for frame in old_frames:
            if frame.id != new_frame.id:
                frame.complements.remove(new_complement)
                frame.complements.add(old_complement)
                frame.save()
                if frame.next.id == new_frame.id:
                    old_complement.frame = frame
                    old_complement.save()
                    
    return frame_mapping.values()

def get_extended_complement_ids(complement_ids):
    dependent = set()
    increase = set()
    base = set(complement_ids)
    
    increased = True
    while increased:
        dependent |= increase
        base |= increase
        increase = set()
        increased = False
        for cid in complement_ids:
            if cid >= 0:
                complement = Complement.objects.get(id=cid)
                candidates = SemanticFrame.objects.get(complements__id=cid, next__isnull=True, removed=False).complements.all()
                for candidate in candidates:
                    if candidate.id not in dependent:
                        if candidate.selective_preference is not None:
                            if len(candidate.selective_preference.relations.filter(to__in=list(base))) > 0:
                                increase.add(candidate.id)
                                increased = True
                        
    return list(dependent)

def backup_lemma_and_get_frames(lemma):
    backup_frames_ids = backup_lemma(lemma.id)
    backup_frames = SemanticFrame.objects.filter(id__in=backup_frames_ids)
    return backup_frames

def backup_lemma(lemma_id):
    lemma = Lemma.objects.get(id=lemma_id, old=False)
    lexical_units = lemma.entry_obj.meanings.order_by('sense')
    
    frame_ids = []
    for lexical_unit in lexical_units:
        frame_ids.extend([f.id for f in lexical_unit.actual_frames()])

    backuped_frames_ids = backup_frames(list(set(frame_ids)), [], [])
    return backuped_frames_ids
