# -*- 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.

from elisa.plugins.pigment import maths

class Modifier(object):
    """
    DOCME
    """

    def __init__(self, obj, property, initial_value, target_value):
        self.object = obj
        self.property = property
        # list of [alpha, value] couples as lists so that they are mutable
        self.key_values = []

        self.initial_value = initial_value
        self.target_value = target_value

        current_value = getattr(obj, property)
        if isinstance(current_value, (list, tuple)):
            self._lerp = maths.lerp_seq
        else:
            self._lerp = maths.lerp

    def _initial_value__get(self):
        if self.key_values == []:
            raise AttributeError

        return self.key_values[0][1]

    def _initial_value__set(self, value):
        if self.key_values == []:
            self.key_values = [[0.0, value]]
        else:
            self.key_values[0][1] = value

    initial_value = property(_initial_value__get, _initial_value__set)

    def _target_value__get(self):
        n = len(self.key_values)
        if n == 2:
            return self.key_values[1][1]
        elif n < 2:
            raise AttributeError
        else:
            # we return the list of values, as it was set
            return [value for key, value in self.key_values[1:]]

    def _target_value__set(self, new_value):
        #FIXME: we don't support setting a list of key values if the property
        # is a list or a tuple.

        if self.key_values == []:
            raise AttributeError, "initial_value needs to be set before " \
                                  "setting target_value"

        current_value = getattr(self.object, self.property)

        # remove the old target value/key values
        self.key_values[1:] = []

        if not isinstance(new_value, (list, tuple)) \
                or isinstance(current_value, (list, tuple)):
            # generic case: new_value is not a list of key values
            self.key_values.append([1.0, new_value])
        else:
            # new_value is a list of key values
            n = len(new_value)
            for i, value in enumerate(new_value):
                self.key_values.append([float(i+1)/n, value])

    target_value = property(_target_value__get, _target_value__set)

    def _next_index(self, fraction):
        for i, (alpha, value) in enumerate(self.key_values):
            if alpha > fraction:
                return i

        # In case fraction >= 1, it will be clamped to 1
        return len(self.key_values) - 1

    # Public methods

    def update(self, fraction):
        """
        DOCME
        """
        next_index = self._next_index(fraction)
        previous_alpha, previous_value = self.key_values[next_index-1]
        next_alpha, next_value = self.key_values[next_index]

        # Linearly interpolate the new_fraction between the KeyFrame values.
        value = self._lerp(previous_value, next_value,
                    # the alpha we send to the lerp function is the position
                    # of fraction relative to [previous_alpha, next_alpha]
                       (fraction - previous_alpha)*(len(self.key_values)-1))

        # Assign the new value to 'object.property'
        setattr(self.object, self.property, value)
