# -*- coding: utf-8 -*-
# http://djangosnippets.org/snippets/2672/
# myapp/management/commands/reversion_clean.py
u'''
If you use this pattern to track changes in the auth user table:

    from django.contrib.auth.models import User
    from reversion.helpers import patch_admin
    patch_admin(User)

you can't see important changes, since a version is created for every
login if a user. If you want to get rid of changes which only change
unimportant stuff you can use this middleware.


Edit your settings. Example:

REVERSION_CLEAN={
    'django.contrib.auth': {'User': ['last_login']},
    }

Usage: manage.py reversion_clean
'''
import logging

from django.conf import settings
from django.core.management.base import NoArgsCommand, CommandError
from django.utils import importlib
from django.contrib.contenttypes.models import ContentType
from reversion.models import Version

class Command(NoArgsCommand):
    help = "Clean unimportant changes in reversion history. Example: settings.py: REVERSION_CLEAN={'django.contrib.auth': {'User': ['last_login']}}"

    requires_model_validation = False

    def handle_noargs(self, **options):
        rootLogger = logging.getLogger('')
        rootLogger.setLevel(logging.INFO)
        ignores=getattr(settings, 'REVERSION_CLEAN', None)
        if not ignores:
            raise CommandError('Error: settings.REVERSION_CLEAN is not set or empty.')
        empty_count=0
        only_ignore_count=0
        ok_count=0
        layout_count=0
        for app, models in ignores.items():
            import_str='%s.models' % app
            modul=importlib.import_module(import_str)
            for model, ignore_changes_attrs in models.items():
                model_class=getattr(modul, model)
                ct=ContentType.objects.get_for_model(model_class)
                last=None
                for version in Version.objects.filter(content_type=ct).order_by('object_id', 'id'):
                    if last is None:
                        last=version.get_field_dict()
                        continue
                    this=version.get_field_dict()
                    if set(this.keys())-set(last.keys()):
                        layout_count+=1
                        continue # DB Layout has changed. Don't delete
                    diff=dict()
                    for (this_key, this_value), (last_key, last_value) in zip(sorted(this.items()), sorted(last.items())):
                        assert this_key==last_key
                        if this_value==last_value:
                            continue
                        diff[this_key]=(this_value, last_value)
                    if not diff:
                        logging.info('no changes in Version %s' % version)
                        version.delete()
                        empty_count+=1
                        continue
                    if set(diff.keys()).issubset(ignore_changes_attrs):
                        logging.info('only changes to ignore: %s' % diff)
                        version.delete()
                        only_ignore_count+=1
                        continue
                    ok_count+=1
        logging.info('Empty version: %s (del) Only ignore columns changed: %s (del) DB-Layout changed: %s (no-del) unchanged: %s (no-del)' % (
                empty_count, only_ignore_count, layout_count, ok_count))