lexeme_history.py 12.8 KB
# -*- coding: utf-8 -*-
from django.utils.encoding import force_unicode

from django.core.exceptions import ObjectDoesNotExist
from django.utils.translation import ugettext_lazy as _

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

attribute_translation_list = [
    # Leksem
    ('leksemy', 'haslo', _(u'entry')),
    ('leksemy', 'haslosuf', _(u'entry suffix')),
    ('leksemy', 'glosa', _(u'gloss')),
    ('leksemy', 'nota', _(u'note')),
    ('leksemy', 'extended_note', _(u'extended note')),
    ('leksemy', 'wymowa', _(u'pronunciation')),
    ('leksemy', 'valence', _(u'valence')),
    ('leksemy', 'pos', _(u'part of speech')),
    ('leksemy', 'slownik', _(u'owner dictionary')),
    ('leksemy', 'status', _(u'status')),
    ('leksemy', 'komentarz', _(u'comment')),
    ('leksemy', 'specialist', _(u'specialist')),
    ('leksemy', 'borrowing_source_id', _(u'borrowing source')),
    # Odmiana
    ('odmieniasie', 'oind', _(u'index')),
    ('odmieniasie', 'charfl', _(u'inflection characteristic')),
    ('odmieniasie', 'gender_id', _(u'gender')),
    ('odmieniasie', 'w_id', _(u'pattern')),
]

attribute_translation = dict(
    ((table, column), label)
    for table, column, label in attribute_translation_list)

lexeme_attribute_order = [
    _(u'entry'),
    _(u'entry suffix'),
    _(u'gloss'),
    _(u'note'),
    _(u'extended note'),
    _(u'pronunciation'),
    _(u'valence'),
    _(u'part of speech'),
    _(u'owner dictionary'),
    _(u'status'),
    _(u'comment'),
    _(u'specialist'),
    _(u'borrowing source'),
    # _(u'kwalifikator'),
    # _(u'klasyfikacja'),
    # _(u'slownik'),
    # _(u'odsyłacz'),
]

lip_attribute_order = [
    _(u'index'),
    _(u'inflection characteristic'),
    _(u'gender'),
    _(u'pattern'),
    # _(u'kwalifikator'),
]


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 == 'extended_note':
        return lexeme.extended_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
    elif attr == 'borrowing_source_id':
        if lexeme.borrowing_source:
            return lexeme.borrowing_source.label
        else:
            return ''


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


def prepare_value(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.all_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 or av.display_value, av.attribute.name)
        elif column == 'borrowing_source_id':
            prepared = BorrowingSource.objects.get(id=int(value)).label
        elif value == 'true':
            prepared = _(u'yes')
        elif value == 'false':
            prepared = _(u'no')
        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(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'qualifier'), before_after))
    for name, (before, after) in classifications.iteritems():
        attr = _(u'classification: %s') % name
        rows.append(
            (attr, (', '.join(before) or None, ', '.join(after) or None)))
    for before_after in vocabs:
        rows.append((_(u'dictionary'), before_after))
    for cr_data in crs.itervalues():
        attr = _(u'cross-reference')
        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'qualifier')
            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.all_objects.get(id=pattern_id)
                header = lip_header(gender, pattern)
            except ObjectDoesNotExist:  # stare DELETE...
                header = ''
            header += force_unicode(_(u'(deleted)'))
        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(
                    column, get_lexeme_attr(column, lexeme)), None)
            ))
    for q in lexeme.qualifiers.all():
        rows.append((_(u'qualifier'), (q.label, None)))
    for classification in lexeme.owner_vocabulary.classifications.all():
        attr = _(u'classification: %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'dictionary'), (vocab.id, None)))
    for cr in lexeme.refs_to.all():
        attr = _(u'cross-reference')
        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 or av.display_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'qualifier')
            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'(deleted)')  # 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_id=row['lexeme'], user_id=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)