# -*- coding: utf-8 -*-
# Moovida - Home multimedia server
# Copyright (C) 2006-2009 Fluendo Embedded S.L. (www.fluendo.com).
# All rights reserved.
#
# This file is available under one of two license agreements.
#
# This file is licensed under the GPL version 3.
# See "LICENSE.GPL" in the root of this distribution including a special
# exception to use Moovida with Fluendo's plugins.
#
# The GPL part of Moovida is also available under a commercial licensing
# agreement from Fluendo.
# See "LICENSE.Moovida" in the root directory of this distribution package
# for details on that license.
#
# Authors: Benjamin Kampmann <benjamin@fluendo.com>
#          Olivier Tilloy <olivier@fluendo.com>
#          Philippe Normand <philippe@fluendo.com>

"""
Common models related to image.
"""

from elisa.core import common
from elisa.core.components.model import Model
from elisa.core.utils.i18n import install_translation
from elisa.core.utils import defer, caching

import os.path
from math import pi

ROTATED_0=1
HORIZ_MIRROR=2
ROTATED_180=3
VERT_MIRROR=4
HORIZ_MIRROR_ROTATED_90_CCW=5
ROTATED_90_CW=6
HORIZ_MIRROR_ROTATED_90_CW=7
ROTATED_90_CCW=8

_ = install_translation('base')

# Constants detailing the various possible Image orientations
# These come from the EXIF spec and contain PgmImage rotation settings
# for earch orientation value.
IMAGE_ORIENTATIONS={ROTATED_0: (_('Horizontal (normal)'),
                                {'rx': 0, 'ry': 0, 'rz': 0}),
                    HORIZ_MIRROR: (_('Mirrored horizontally'),
                                   {'rx': 0, 'ry': pi, 'rz': 0}),
                    ROTATED_180: (_('Rotated 180°'), {'rx': 0, 'ry': 0, 'rz': pi}),
                    VERT_MIRROR: (_('Mirrored vertically'),
                                  {'rx': pi, 'ry': 0, 'rz': 0}),
                    HORIZ_MIRROR_ROTATED_90_CCW: (_('Mirrored horizontally then rotated 90° counter-clock-wise'),
                                                  {'rx': 0, 'ry': pi, 'rz': pi * 1.5}),
                    ROTATED_90_CW: (_('Rotated 90° clock-wise'),
                                    {'rx': 0, 'ry': 0, 'rz': pi * 0.5}),
                    HORIZ_MIRROR_ROTATED_90_CW: (_('Mirrored horizontally then rotated 90° clock-wise'),
                                                 {'rx': 0, 'ry': pi, 'rz': pi * 0.5}),
                    ROTATED_90_CCW: (_('Rotated 90° counter-clock-wise'),
                                     {'rx': 0, 'ry': 0, 'rz': pi * 1.5})
                    }


class ImageModel(Model):

    """
    Representation of an image.

    An image model contains a list of references to image files that are in
    fact one image in various dimensions.
    This list is ordered by increasing size of image.
    This allows to easily retrieve the largest or the smallest representation
    of an image.

    'A simple example': the image is used as the cover art of an
    L{elisa.plugins.base.models.audio.AlbumModel}. A resource provider fills
    this image model with a thumbnail and a huge high contrast image. Now the
    UI can decide that it does not want to show such a high quality image
    because it is going to be used as an icon in a list. It uses
    C{model.cover.references[0]} (the first one, the smallest image) and the
    amount of data to load is minimal. Later the user decides to play a track
    of the album and the UI wants to show it in fullscreen, it always uses the
    last image in the list because it is the largest one (and very probably the
    one with the best quality for a huge picture):
    C{model.cover.references[-1]}.

    @ivar references:  images ordered by increasing size of raw data
    @type references:  C{list} of L{elisa.core.media_uri.MediaUri}
    @ivar orientation: orientation of the image, its meaning is the same as
                       the orienation EXIF field
    @type orientation: one of the keys of C{IMAGE_ORIENTATIONS}
    @ivar can_rotate:  can the image represented by the model be rotated?
    @type can_rotate:  C{bool}
    """

    def __init__(self):
        """
        Constructor. Initialize all the fields.
        """
        super(ImageModel, self).__init__()
        self.references = []
        self.orientation = ROTATED_0
        self.can_rotate = True

    def get_cached_data_path(self, reference_num):
        """
        Return the path to the locally cached reference.
        If needed, retrieve and cache it first.

        @param reference_num: the index of the reference
        @type reference_num:  C{int}

        @return: a deferred fired when done with the path to the cached file
        @rtype:  L{elisa.core.utils.defer.Deferred} fired with a C{unicode}
        """
        uri = self.references[reference_num]
        path = caching.get_cached_image_path(uri)

        if os.path.exists(path):
            # already cached
            return defer.succeed(path)

        model, dfr = common.application.resource_manager.get(uri)
        dfr.addCallback(lambda model: caching.cache_to_file(model.data, path))
        return dfr
