lexeme_history.py 12.7 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, Inflection, InflectionCharacteristic, \
    ClassificationValue, Qualifier, CrossReferenceType, LexemeAttributeValue, \
    Gender, BorrowingSource
from history.models import History
from patterns.models import Pattern

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'),
]

inflection_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_inflection_attr(attr, inflection):
    if attr == 'oind':
        return inflection.index
    elif attr == 'gender_id':
        return inflection.gender.symbol if inflection.gender else ''
    elif attr == 'w_id':
        return inflection.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 inflection_header(gender, pattern):
    if gender:
        return u'%s/%s ' % (gender.symbol, pattern.name)
    else:
        return pattern.name


def transaction_table(frame):
    transaction_dict = {}
    inflections = GroupDict()
    extra_attributes = {}
    classifications = {}
    qualifiers = []
    vocabs = []
    crs = {}
    inflection_qualifiers = {}
    deleted = False
    for item in frame.history_set.all():
        table = item.table_name
        column = item.column_name
        if (table == 'leksemy' and column == 'usuniety' and
                item.new_value == 'true' and item.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 (item.old_value, item.new_value))
        before_after = (
            before if item.operation != 'INSERT' else None,
            after if item.operation != 'DELETE' else None)
        if attr:
            if table not in ('odmieniasie', 'kwalifikatory_odmieniasiow'):
                transaction_dict[attr] = before_after
            elif table == 'odmieniasie':
                if item.row_id not in inflections:
                    inflections[item.row_id] = {}
                inflections[item.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 item.row_id not in crs:
                crs[item.row_id] = {}
            crs[item.row_id][column] = before_after
        if table == 'kwalifikatory_odmieniasiow':
            if item.row_id not in inflection_qualifiers:
                inflection_qualifiers[item.row_id] = {}
            if column:  # stare DELETE nie będą widoczne
                inflection_qualifiers[item.row_id][column] = before_after
    if deleted:
        return deleted_lexeme_table(frame.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.inflection_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)))
    inflection_dict = GroupDict()
    for inflection_id, inflection_data in inflections.iteritems():
        for attr in inflection_attribute_order:
            if attr in inflection_data:
                inflection_dict.add(
                    inflection_id, (attr, inflection_data[attr]))
    for q_data in inflection_qualifiers.itervalues():
        if q_data:  # stare DELETE...
            attr = _(u'qualifier')
            inflection_data = q_data.get(
                'inflection_id', q_data['lexemeinflectionpattern_id'])
            inflection_id = int(inflection_data[0] or inflection_data[1])
            inflection_dict.add(inflection_id, (attr, q_data['qualifier_id']))
    inflection_tables = []
    for inflection_id, inflection_data in inflection_dict.iteritems():
        inflection = Inflection.all_objects.filter(pk=inflection_id)
        if inflection:
            inflection = inflection[0]
            header = inflection_header(inflection.gender, inflection.pattern)
        else:
            records = History.objects.filter(
                operation='DELETE', table_name='odmieniasie',
                row_id=inflection_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 = inflection_header(gender, pattern)
            except ObjectDoesNotExist:  # stare DELETE...
                header = ''
            header += force_unicode(_(u'(deleted)'))
        inflection_tables.append((header, inflection_data))
    return rows, inflection_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.inflection_data()['genders']]),
            None)))
    for av in lexeme.lexemeattributevalue_set.all():
        attr = av.attribute.name
        rows.append((attr, (av.value or av.display_value, None)))
    inflection_tables = []
    for inflection in lexeme.inflection_set.all():
        inflection_data = []
        for table, column, attr in attribute_translation_list:
            if table == 'odmieniasie' and column != 'charfl':
                inflection_data.append(
                    (attr, (get_inflection_attr(column, inflection), None)))
        for q in inflection.qualifiers.all():
            attr = _(u'qualifier')
            inflection_data.append((attr, (q.label, None)))
        header = inflection_header(inflection.gender, inflection.pattern)
        inflection_tables.append((header, inflection_data))
    return rows, inflection_tables


def lexeme_table(frame):
    rows, inflection_tables = transaction_table(frame)
    lexeme = frame.lexeme
    if lexeme is None:
        lexeme = _(u'(deleted)')  # aktualnie niemożliwe
    return {
        'rows': rows,
        'inflection_tables': inflection_tables,
        'user': frame.user,
        'date': frame.transaction_began,
        'lexeme': lexeme,
    }


def lexeme_tables(history_frames):
    return (lexeme_table(frame) for frame in history_frames)