# -'- Encoding: utf-8 -*-

import os

from django.conf import settings
from django.core.urlresolvers import reverse
from django.db import models
from django.utils.translation import ugettext as _
import pyexiv2

from utils import OverwriteStorage
from kasu import image_models


def get_upload_path(instance, filename):
    """
    Generates the desired file path and filename for an uploaded Image.
    With this function Django can save the uploaded images to subfolders that
    also have a meaning for humans.

    @param instance: an Django Object for which the Image has been uploaded.
    @type instance: a instace of an models.Model sub-class.
    @param filename: The filename of the uploaded image.
    @type filename: String
    """
    extension = filename[filename.rfind('.') + 1:]
    if isinstance(instance, Photo):
        return "events/%s/%s" % (instance.event.id, filename)


class PhotoManager(models.Manager):
    def get_random(self, startpage=True):
        if startpage:
            queryset = self.filter(on_startpage=True)
        else:
            queryset = self.all().order_by('?')[0]
        try:
            return queryset.order_by('?')[0]
        except IndexError:
            return Photo()


class Photo(image_models.ImageModel):
    name = models.CharField(_("Name"), max_length=100, blank=True)
    image = models.ImageField(_("Image"), upload_to=get_upload_path,
                              storage=OverwriteStorage())
    anchor_horizontal = models.FloatField(
        _('horizontal Anchorpoint'),
        choices=image_models.CHOICES_HORIZONTAL,
        blank=True, null=True,
        help_text='Der Ankerpunkt ist der interessante Teil des Bildes,\
        welcher nie abgeschnitten werden darf'
    )
    anchor_vertical = models.FloatField(
        _('vertical Anchorpoint'),
        choices=image_models.CHOICES_VERTICAL,
        blank=True, null=True,
        help_text='Wenn kein Ankerpunkt von Hand (horizontal und vertikal)\
        festgelegt wird, versucht die Software diesen selbst zu erraten.'
    )

    event = models.ForeignKey('events.Event')
    description = models.TextField(
        _("Description"),
        max_length=300,
        blank=True
    )
    photographer = models.ForeignKey(settings.AUTH_USER_MODEL)
    on_startpage = models.BooleanField(
        _("Startpage"),
        default=False,
        help_text=_('Display this Photo on the Startpage Teaser')
    )
    created_date = models.DateTimeField(_("Published on"))
    views = models.PositiveIntegerField(
        _("Number of views"),
        editable=False,
        default=0
    )
    objects = PhotoManager()
    metadata = None
    orientation = 1

    class Meta:
        get_latest_by = "created_date"
        ordering = ["created_date"]
        db_table = 'events_photo'
        verbose_name = _('Event Image')
        verbose_name_plural = _('Event Images')


    def __unicode__(self):
        return os.path.basename(self.image.name)

    def read_metadata(self):
        image_path = os.path.join(settings.MEDIA_ROOT, self.image.name)
        self.metadata = pyexiv2.ImageMetadata(image_path)
        self.metadata.read()
        try:
            self.orientation = self.metadata['Exif.Image.Orientation'].value
        except:
            self.orientation = 1

    def save_metadata(self):
        if not self.metadata:
            self.read_metadata()
        self.metadata['Exif.Image.DateTime'] = self.created_date
        self.metadata['Exif.Image.ImageDescription'] = self.description
        self.metadata['Exif.Image.Artist'] = self.photographer.username
        self.metadata['Exif.Image.Orientation'] = self.orientation or 1
        self.metadata.write()

    def rotate(self, rotate):
        """
        Sets an the Exif tag in an image to set the right direction.
        This provides lossless image rotation.
        @param rotate: 'clockwise' or 'counter-clockwise' the direction in
        which we should rotate the image in 90° steps.
        """
        if not self.metadata:
            self.read_metadata()
        if rotate == 'clockwise':
            if self.orientation == 1:
                self.orientation = 6
            elif self.orientation == 6:
                self.orientation = 3
            elif self.orientation == 3:
                self.orientation = 8
            else:
                self.orientation = 1
        elif rotate == 'counter-clockwise':
            if self.orientation == 1:
                self.orientation = 8
            elif self.orientation == 8:
                self.orientation = 3
            elif self.orientation == 3:
                self.orientation = 6
            else:
                self.orientation = 1
        self.save()

    def get_absolute_url(self):
        return reverse(
            'event-photo',
            kwargs={'event': self.event.id, 'pk': self.id}
        )

    @property
    def next_photo(self):
        return self.get_next_by_created_date(event=self.event)

    @property
    def previous_photo(self):
        return self.get_previous_by_created_date(event=self.event)

    def save(self, **kwargs):
        """
        Triggers to save related Event to save. This should force an update for
        the denormalized Photo count.
        """
        super(Photo, self).save()
        self.save_metadata()


def update_event(sender, instance=None, created=False, raw=False, **kwargs):
    image_models.regenerate_image_cache(sender, instance=instance)
    instance.event.save()


models.signals.post_save.connect(update_event, sender=Photo)
models.signals.post_delete.connect(update_event, sender=Photo)
