#!/usr/bin/env python
# -*- coding: utf-8 -*-
from django.db import models
from django.db.models.base import ModelBase
from django.utils.translation import ugettext_lazy as _

import copy
import datetime

class HistoryMixin(models.Model):
    history_datetime = models.DateTimeField(default=datetime.datetime.now)
    history_objectid = models.PositiveIntegerField() # these two are
    history_revision = models.PositiveIntegerField() # unique_together ?
    history_comment = models.CharField(max_length=1024, default="") # comment on history item
    
    class Meta:
        abstract = True

class HistoryModelBase(ModelBase):
    def __new__(cls, name, bases, dct):
        new_class = ModelBase.__new__(cls, name, bases, dct)
        if 'History' in dct:
            history_model = dct['History'].model
            for field in history_model._meta.fields:
                if 'AutoField' == field.__class__.__name__:
                    continue
                _field = copy.copy(field)
                if _field.unique:
                    _field.unique = False
                new_class.add_to_class(_field.name, _field)
            for mm in history_model._meta.many_to_many:
                _mm = copy.copy(mm)
                if _mm.unique:
                    _mm.unique = False
                new_class.add_to_class(_mm.name, _mm)
        return new_class
    
class HistoryModel(models.Model):
    __metaclass__ = HistoryModelBase

    history_datetime = models.DateTimeField(default=datetime.datetime.now)
    history_objectid = models.PositiveIntegerField() # these two are
    history_revision = models.PositiveIntegerField() # unique_together ?
    history_comment = models.CharField(max_length=1024, default="") # comment on history item
    
    class Meta:
        abstract = True

### Tests ###

class Manufacturer(models.Model):
    name = models.CharField(max_length=64, default="VW")
    def __unicode__(self): return u"<manufacturer name=%s>" % (self.name)
    class Admin: pass

class Color(models.Model):
    name = models.CharField(max_length=64, default="Green")
    def __unicode__(self): return u"<color name=%s>" % (self.name)
    class Admin: pass

class Car(models.Model):
    foo = models.CharField(max_length=64, default="foo")
    bar = models.TextField(default="bar")
    maker = models.ForeignKey(Manufacturer)
    colors = models.ManyToManyField(Color)
    slug = models.SlugField(unique=True)
    desc = models.TextField()
    
    
    def __unicode__(self): return u"<car foo=%s bar=%s maker=%s colors=%s slug=%s>" % (self.foo, self.bar, self.maker, self.colors, self.slug)
    class Admin: pass

class CarHistory(HistoryModel):
    class History:
        model = Car
    eggs = "eggs"
    def __unicode__(self): return u"<carhistory revision=%s>" % (self.history_revision)
    class Admin: pass

def history_save(sender, instance):
    if not instance.id:
        # initial save, don't have to do anything :)
        return
    # lookup history model if exists, otherwise return (quick exit if history is not managed)
    history_model = CarHistory # right now this is a quick shortcut to our test
    # lookup orginal unchanged object
    orginal = sender.objects.get(pk=instance.id)
    # copy orginal object into history
    history_obj = history_model()

    history_obj.history_objectid = orginal.id
    history_obj.history_revision = history_model.objects.filter(history_objectid=orginal.id).count()+1
    history_obj.history_comment = "pre_save history item <%s>" % (repr(orginal))
    
    for field in orginal._meta.fields:
        if 'AutoField' == field.__class__.__name__:
            continue
        setattr(history_obj, field.name, getattr(orginal, field.name))
    history_obj.save()
    for mm in orginal._meta.many_to_many:
        setattr(history_obj, mm.name, getattr(orginal, mm.name).all())
    history_obj.save()

from django.dispatch import dispatcher
from django.db.models import signals
dispatcher.connect(history_save, sender=Car, signal=signals.pre_save)

