history.py 12.3 KB
#-*- coding:utf-8 -*-

from django.core.exceptions import ObjectDoesNotExist
from common.util import GroupDict
from dictionary.models import Lexeme, LexemeInflectionPattern, \
    Pattern, InflectionCharacteristic, ClassificationValue, Qualifier, History, \
    CrossReferenceType, LexemeAttributeValue, Gender

attribute_translation = {
    # Leksem
    ('leksemy', 'haslo'): u'hasło',
    ('leksemy', 'haslosuf'): u'sufiks hasła',
    ('leksemy', 'glosa'): u'glosa',
    ('leksemy', 'nota'): u'nota',
    ('leksemy', 'wymowa'): u'wymowa',
    ('leksemy', 'valence'): u'łączliwość',
    ('leksemy', 'pos'): u'część mowy',
    ('leksemy', 'slownik'): u'słownik właściciel',
    ('leksemy', 'status'): u'status',
    ('leksemy', 'komentarz'): u'komentarz',
    # Odmiana
    ('odmieniasie', 'oind'): u'kolejność',
    ('odmieniasie', 'charfl'): u'charakterystyka fleksyjna',
    ('odmieniasie', 'gender_id'): u'rodzaj',
    ('odmieniasie', 'w_id'): u'wzór',
}

# brzydkie - do pokazywania usuniętych leksemów
attribute_translation_list = [
    # Leksem
    ('leksemy', 'haslo', u'hasło'),
    ('leksemy', 'haslosuf', u'sufiks hasła'),
    ('leksemy', 'glosa', u'glosa'),
    ('leksemy', 'nota', u'nota'),
    ('leksemy', 'wymowa', u'wymowa'),
    ('leksemy', 'valence', u'łączliwość'),
    ('leksemy', 'pos', u'część mowy'),
    ('leksemy', 'slownik', u'słownik właściciel'),
    ('leksemy', 'status', u'status'),
    ('leksemy', 'komentarz', u'komentarz'),
    # Odmiana
    ('odmieniasie', 'oind', u'kolejność'),
    ('odmieniasie', 'charfl', u'charakterystyka fleksyjna'),
    ('odmieniasie', 'gender_id', u'rodzaj'),
    ('odmieniasie', 'w_id', u'wzór'),
]

lexeme_attribute_order = [
    u'hasło',
    u'sufiks hasła',
    u'glosa',
    u'nota',
    u'wymowa',
    u'łączliwość',
    u'część mowy',
    u'słownik właściciel',
    u'status',
    u'komentarz',
    #u'kwalifikator',
    #u'klasyfikacja',
    #u'slownik',
    #u'odsyłacz',
]


def get_lexeme_attr(attr, lexeme):
    if attr == 'haslo':
        return lexeme.entry
    elif attr == 'haslosuf':
        return lexeme.entry_suffix
    elif attr == 'glosa':
        return lexeme.gloss
    elif attr == 'wymowa':
        return lexeme.pronunciation
    elif attr == 'nota':
        return lexeme.note
    elif attr == 'valence':
        return lexeme.valence
    elif attr == 'pos':
        return lexeme.part_of_speech.symbol
    elif attr == 'slownik':
        return lexeme.owner_vocabulary.id
    elif attr == 'status':
        return lexeme.status
    elif attr == 'komentarz':
        return lexeme.comment


def get_lip_attr(attr, lip):
    if attr == 'oind':
        return lip.index
    elif attr == 'gender_id':
        return lip.gender.symbol if lip.gender else ''
    elif attr == 'w_id':
        return lip.pattern.name


lip_attribute_order = [
    u'kolejność',
    u'charakterystyka fleksyjna',
    u'rodzaj',
    u'wzór',
    #u'kwalifikator',
]


def prepare_value(table, column, value):
    try:
        if column == 'qualifier_id':
            prepared = Qualifier.all_objects.get(id=int(value)).label
        elif column == 'status':
            prepared = dict(Lexeme.STATUS_CHOICES).get(value)
        elif column == 'charfl':
            prepared = InflectionCharacteristic.objects.get(
                id=int(value)).symbol
        elif column == 'gender_id':
            prepared = Gender.objects.get(id=int(value)).symbol
        elif column == 'w_id':
            prepared = Pattern.objects.get(id=int(value)).name
        elif column in ('classification_value_id', 'classificationvalue_id'):
            cv = ClassificationValue.all_objects.get(id=int(value))
            prepared = (cv.label, cv.classification.name)
        elif column == 'attribute_value_id':
            av = LexemeAttributeValue.objects.get(id=int(value))
            prepared = (av.value, av.attribute.name)
        else:
            prepared = value
    except ObjectDoesNotExist:
        prepared = None
    except ValueError:
        prepared = None
    return prepared


def lip_header(gender, pattern):
    if gender:
        return u'%s/%s ' % (gender.symbol, pattern.name)
    else:
        return pattern.name


def transaction_table(transaction_data):
    transaction_dict = {}
    lips = GroupDict()
    extra_attributes = {}
    classifications = {}
    qualifiers = []
    vocabs = []
    crs = {}
    lip_qualifiers = {}
    deleted = False
    for item1 in transaction_data:
        table = item1.table_name
        column = item1.column_name
        if (table == 'leksemy' and column == 'usuniety' and
                item1.new_value == 'true' and item1.old_value == 'false'):
            deleted = True
        attr = None
        if (table, column) in attribute_translation:
            attr = attribute_translation[(table, column)]
        before, after = tuple(
            prepare_value(table, column, v)
                for v in (item1.old_value, item1.new_value))
        before_after = (
            before if item1.operation != 'INSERT' else None,
            after if item1.operation != 'DELETE' else None)
        if attr:
            if table not in ('odmieniasie', 'kwalifikatory_odmieniasiow'):
                transaction_dict[attr] = before_after
            elif table == 'odmieniasie':
                if item1.row_id not in lips:
                    lips[item1.row_id] = {}
                lips[item1.row_id][attr] = before_after
        if column == 'attribute_value_id':
            if before:
                value, attr = before
                which = 0
            else: # after
                value, attr = after
                which = 1
            if attr not in extra_attributes:
                extra_attributes[attr] = ([], [])
            extra_attributes[attr][which].append(value)
        if column in ('classification_value_id', 'classificationvalue_id'):
            if before:
                value, classification_name = before
                which = 0
            else: # after
                value, classification_name = after
                which = 1
            if classification_name not in classifications:
                classifications[classification_name] = ([], [])
            classifications[classification_name][which].append(value)
        if table == 'kwalifikatory_leksemow' and column == 'qualifier_id':
            qualifiers.append(before_after)
        if table == 'leksemy_w_slownikach' and column == 'slownik':
            vocabs.append(before_after)
        if table == 'odsylacze':
            if item1.row_id not in crs:
                crs[item1.row_id] = {}
            crs[item1.row_id][column] = before_after
        if table == 'kwalifikatory_odmieniasiow':
            if item1.row_id not in lip_qualifiers:
                lip_qualifiers[item1.row_id] = {}
            if column: # stare DELETE nie będą widoczne
                lip_qualifiers[item1.row_id][column] = before_after
    if deleted:
        return deleted_lexeme_table(transaction_data[0].lexeme)
    rows = []
    for attr in lexeme_attribute_order:
        if attr in transaction_dict:
            rows.append((attr, transaction_dict[attr]))
    for attr, (before, after) in extra_attributes.iteritems():
        rows.append(
            (attr, (', '.join(before) or None, ', '.join(after) or None)))
    for before_after in qualifiers:
        rows.append((u'kwalifikator', before_after))
    for name, (before, after) in classifications.iteritems():
        attr = u'klasyfikacja: %s' % name
        rows.append(
            (attr, (', '.join(before) or None, ', '.join(after) or None)))
    for before_after in vocabs:
        rows.append((u'słownik', before_after))
    for cr_data in crs.itervalues():
        attr = u'odsyłacz'
        before_after = []
        for i in (0, 1):
            try:
                if cr_data['l_id_do'][i] is not None:
                    l = Lexeme.all_objects.get(id=int(cr_data['l_id_do'][i]))
                    genders = l.lip_data()['genders']
                    cr_type = CrossReferenceType.objects.get(
                        pk=cr_data['typods_id'][i])
                    prepared = ' '.join((cr_type.symbol, unicode(l), genders))
                else:
                    prepared = None
            except Lexeme.DoesNotExist:
                prepared = None
            before_after.append(prepared)
        rows.append((attr, tuple(before_after)))
    lip_dict = GroupDict()
    for lip_id, lip_data in lips.iteritems():
        for attr in lip_attribute_order:
            if attr in lip_data:
                lip_dict.add(lip_id, (attr, lip_data[attr]))
    for q_data in lip_qualifiers.itervalues():
        if q_data: # stare DELETE...
            attr = u'kwalifikator'
            lip_data = q_data['lexemeinflectionpattern_id']
            lip_id = int(lip_data[0] or lip_data[1])
            lip_dict.add(lip_id, (attr, q_data['qualifier_id']))
    lip_tables = []
    for lip_id, lip_data in lip_dict.iteritems():
        lip = LexemeInflectionPattern.all_objects.filter(pk=lip_id)
        if lip:
            lip = lip[0]
            header = lip_header(lip.gender, lip.pattern)
        else:
            records = History.objects.filter(
                operation='DELETE', table_name='odmieniasie', row_id=lip_id)
            try:
                gender_id = records.get(column_name='gender_id').old_value
                pattern_id = records.get(column_name='w_id').old_value
                gender = Gender.objects.get(id=gender_id)
                pattern = Pattern.objects.get(id=pattern_id)
                header = lip_header(gender, pattern)
            except ObjectDoesNotExist: # stare DELETE...
                header = ''
            header += u'(usunięta)'
        lip_tables.append((header, lip_data))
    return rows, lip_tables


def deleted_lexeme_table(lexeme):
    rows = []
    for table, column, attr in attribute_translation_list:
        if table == 'leksemy':
            rows.append(
                (attr,
                (prepare_value(table, column, get_lexeme_attr(column, lexeme)),
                None)))
    for q in lexeme.qualifiers.all():
        rows.append((u'kwalifikator', (q.label, None)))
    for classification in lexeme.owner_vocabulary.classifications.all():
        attr = u'klasyfikacja: %s' % classification.name
        cvs = lexeme.classification_values(classification)
        for cv in cvs:
            rows.append((attr, (cv.label, None)))
    for vocab in lexeme.vocabularies.all():
        rows.append((u'słownik', (vocab.id, None)))
    for cr in lexeme.refs_to.all():
        attr = u'odsyłacz'
        rows.append((attr, (
            ' '.join([cr.type.symbol, cr.to_lexeme.entry,
                cr.to_lexeme.lip_data()['genders']]),
            None)))
    for av in lexeme.lexemeattributevalue_set.all():
        attr = av.attribute.name
        rows.append((attr, (av.value, None)))
    lip_tables = []
    for lip in lexeme.lexemeinflectionpattern_set.all():
        lip_data = []
        for table, column, attr in attribute_translation_list:
            if table == 'odmieniasie' and column != 'charfl':
                lip_data.append((attr, (get_lip_attr(column, lip), None)))
        for q in lip.qualifiers.all():
            attr = u'kwalifikator'
            lip_data.append((attr, (q.label, None)))
        header = lip_header(lip.gender, lip.pattern)
        lip_tables.append((header, lip_data))
    return rows, lip_tables


def lexeme_table(transaction_data, last_tb):
    rows, lip_tables = transaction_table(transaction_data)
    try:
        lexeme = transaction_data[0].lexeme
    except Lexeme.DoesNotExist:
        lexeme = u'(usunięty)' # aktualnie niemożliwe
    return {
        'rows': rows,
        'lip_tables': lip_tables,
        'user': transaction_data[0].user,
        'date': last_tb,
        'lexeme': lexeme,
    }


def lexeme_table_from_row(row):
    transaction_data = History.objects.filter(
        lexeme__pk=row['lexeme'], user__pk=row['user'],
        transaction_began=row['transaction_began'])
    return lexeme_table(transaction_data, row['transaction_began'])


def lexeme_tables(history_items):
    transaction_data = []
    last_tb = None
    for item in history_items:
        if last_tb and item.transaction_began != last_tb:
            yield lexeme_table(transaction_data, last_tb)
            transaction_data = []
        last_tb = item.transaction_began
        transaction_data.append(item)
    if transaction_data:
        yield lexeme_table(transaction_data, last_tb)