# -*- coding: utf-8 -*-
# Elisa - Home multimedia server
# Copyright (C) 2006-2008 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 Elisa with Fluendo's plugins.
#
# The GPL part of Elisa is also available under a commercial licensing
# agreement from Fluendo.
# See "LICENSE.Elisa" in the root directory of this distribution package
# for details on that license.

from elisa.core import common
import constants

import pgm
from pgm.graph.group import Group
from pgm.graph.image import Image
from pgm.graph.text import Text
from pgm.utils import maths
from pgm.widgets.list_ng import List
from pgm.widgets import const
from pgm.utils.image import cairo_gradient


class ListItem(Group):

    def load(self):
        # preview drawable
        self.image = Image()
        self.add(self.image, True)
        self.image.bg_a = 0
        self.image.layout = pgm.IMAGE_ZOOMED
#        self.image.layout = pgm.IMAGE_SCALED
        self.image.alignment = pgm.IMAGE_BOTTOM
        self.image.border_inner_color = (255, 255, 255, 255)
        self.image.border_outer_color = (255, 255, 255, 255)
        self.image.visible = True

        # reflection drawable
        self.reflection = Image()
        self.add(self.reflection)
        flip_matrix = pgm.mat4x4_new_predefined(pgm.MAT4X4_FLIP_VERTICAL)
        self.reflection.mapping_matrix = flip_matrix
        self.reflection.bg_a = 0
        self.reflection.layout = pgm.IMAGE_ZOOMED
#        self.reflection.layout = pgm.IMAGE_SCALED
        self.reflection.opacity = 100
        self.reflection.y += self.image.height#*0.98
        self.reflection.alignment = pgm.IMAGE_TOP
        self.reflection.visible = True

    def unload(self):
        self.remove(self.image)
        self.remove(self.reflection)

plugin_registry = common.application.plugin_registry
BaseListView = plugin_registry.get_component_class('raval:list_view')

class CoverflowListView(BaseListView, List):

    def create_widgets(self):
        super(CoverflowListView, self).create_widgets()

        canvas = self.frontend.context.viewport_handle.get_canvas()
        theme = self.frontend.theme

        self.orientation = const.HORIZONTAL
        self.width = canvas.width * 0.9
        self.height = canvas.height * 0.8
        self.x = (canvas.width - self.width)/2.0
        self.y = (canvas.height - self.height)/2.0
        self.visible_range_size = 9
 
        self.sub_description = Text()
        self.add(self.sub_description)
        self.sub_description.font_family = "Nimbus Sans L Bold"
        self.sub_description.fg_color = (150, 150, 150, 255)
        self.sub_description.alignment = pgm.TEXT_ALIGN_CENTER
        self.sub_description.ellipsize = pgm.TEXT_ELLIPSIZE_MIDDLE
        self.sub_description.font_height = 0.9
        self.sub_description.bg_a = 0
        self.sub_description.width = self.width * 0.95
        self.sub_description.height = self.height * 0.1
        x = (self.width - self.sub_description.width) / 2.0
        y = self.height - self.sub_description.height / 2.0
        self.sub_description.position = (x, y, 0.0)
        self.sub_description.visible = True

        self.description = Text()
        self.add(self.description)
        self.description.font_family = "Nimbus Sans L Bold"
        self.description.alignment = pgm.TEXT_ALIGN_CENTER
        self.description.ellipsize = pgm.TEXT_ELLIPSIZE_MIDDLE
        self.description.font_height = 1.0
        self.description.bg_a = 0
        self.description.width = self.width * 0.95
        self.description.height = self.height * 0.1
        x = (self.width - self.description.width) / 2.0
        y = self.height - self.sub_description.height - self.description.height / 2.0
        self.description.position = (x, y, 0.0)
        self.description.visible = True

        #back button at bottom left corner of the list
        self._back_img = Image()
        self._back_img.connect("clicked", self._back_button_clicked)
        self._back_img.layout = pgm.IMAGE_SCALED
        self.load_from_theme("list_mode_back_button", self._back_img)
        self._back_img.bg_color = (0, 0, 0, 0)
        self._back_img.visible = True
        height = canvas.height * constants.back_button_height / 100.
        width = canvas.width / 8.0
        y = canvas.height - self.y - height
        x = -self.x
        self._back_img.alignment = pgm.IMAGE_BOTTOM_LEFT
        self._back_img.position = (x, y, 0)
        self._back_img.size = (width, height)
        self.add(self._back_img)
        
    def _back_button_clicked(self, drawable, x, y, z, button, time):
        canvas = self.frontend.context.viewport_handle.get_canvas()
        canvas.remove(self._back_img)
        self.controller.parent.exit_node()
        return True
 
    def create_item(self, model):
        widget = ListItem()
        return widget

    def load_item(self, index):
        gradient = 0.4
        model = self.controller.model[index]
        widget = self[index]

        widget.load()

        self.load_from_theme(model.theme_icon, widget.image)
        icon = self.frontend.theme.get_media(model.theme_icon)
        cairo_gradient(icon, widget.reflection, gradient)

        uri = model.thumbnail_source
        if uri != None:
            self._model_thumbnail_to_image(model, widget)
        else:
            self._create_image_stack(model, widget.image,
                                     reflection=widget.reflection,
                                     gradient = gradient)

    def unload_item(self, widget):
        widget.unload()

    def insert(self, index, widget):
        widget.connect('clicked', self._child_clicked)
        super(CoverflowListView, self).insert(index, widget)

    def _child_clicked(self, drawable, x, y, z, button, time):
        index = self.widgets.index(drawable)
        self.emit('child-clicked', index)
        return True

    def do_clicked(self, x, y, z, button, time):
        # always let the children handle the clicks
        return False

    def do_child_clicked(self, index):
        if self.controller is None or not self.controller.focused:
            return False

        old_selected = self.selected_item
        super(CoverflowListView, self).do_child_clicked(index)

        if old_selected == self.selected_item:
            return self.controller.activate_item(self.frontend)

    def do_selected_item_changed(self, index):
        self._controller.current_index = index

    def element_attribute_set(self, position, key, old_value, new_value):
        super(CoverflowListView, self).element_attribute_set(position, key,
                                                          old_value, new_value)
        if key == "text":
            text = self.frontend.translate_text(new_value)
            self[position].description = text
        elif key == "thumbnail_source":
            if self.is_widget_visible(position):
                self._thumbnail_source_to_image(new_value, self[position])

    def _piecewise_interpolation(self, x, y, factor):
        factor += 0.5
        t = self._visible_range_size
        x = map(lambda a: t*a, x)

        # clamp after lower and upper limits
        if factor < x[0]:
            return y[0]
        elif factor > x[-1]:
            return y[-1]
        else:
            # general case: looking for the segment where factor belongs
            i = 0
            while factor > x[i+1]:
                i += 1

            # factor must be between 0.0 and 1.0
            new_factor = (factor - x[i]) / (x[i+1] - x[i])
            return maths.lerp(y[i], y[i+1], new_factor)

    def compute_x(self, index):
        w = self._width
        x = [0.0, 0.4, 0.5, 0.6, 1.0]
        y = [0.0, w*0.1, w*0.5, w*0.9, w]
        y = [e-self._widget_width/2.0 for e in y]

        return self._piecewise_interpolation(x, y, index)

    def compute_y(self, index):
        # center the items
        # assuming that each item has a reflection of the same height as
        # itself
        return self._height/4.0

    def compute_z(self, index):
        min_z = -200.0
        max_z = 200.0

        x = [0.0, 0.4, 0.5, 0.6, 1.0]
        y = [min_z, min_z/2.0, max_z, min_z/2.0, min_z]

        return self._piecewise_interpolation(x, y, index)

    def compute_opacity(self, index):
        x = [0.0, 0.4, 0.47, 0.53, 0.6, 1.0]
        y = [50, 200, 255, 255, 200, 50]

        return self._piecewise_interpolation(x, y, index)

    def layout_widget(self, widget, position):
        zoom = 0.9
        width = self._widget_height/2.0*zoom
        height = self._widget_height*zoom

        # update widget properties
        x = self.compute_x(position)-(width-self._widget_width)/2.0
        y = self.compute_y(position)-(height-self._widget_height)/2.0
        z = self.compute_z(position)
        widget.position = (x, y, z)

        # FIXME: hackish
        o = self.compute_opacity(position)
        c = (o, o, o, 255)
        widget.image.fg_color = c
        widget.image.border_inner_a = o
        widget.image.border_outer_a = o
        widget.reflection.fg_color = c
        widget.opacity = 255

        widget.size = (width, height)

    def selected_item__get(self):
        return self._selected_item

    def selected_item__set(self, index):
        super(CoverflowListView, self).selected_item__set(index)
        self._stop_deceleration()
        index = maths.clamp(index, 0, len(self.widgets)-1)
        index = int(round(index))

        half_size = (self.visible_range_size-1.0)/2.0
        prev_selected = self._selected_item
        self._selected_item = index
        self._animated.visible_range_start = index-half_size

        if prev_selected != index:
            self.emit('selected-item-changed', index)

    def _model_thumbnail_to_image(self, model, image):
        uri = model.thumbnail_source

        def error(error):
            self.debug("Got error: %s . Going to use the theme_icon" % error)
            if self.frontend:
                self.load_from_theme(model.theme_icon, image.image)
                image_path = self.frontend.theme.get_media(model.theme_icon)
                cairo_gradient(image_path, image.reflection, 0.4)
                return image_path

        def display(result):
            image_path = result[0]

            def load_reflection(drawable):
                image.image.border_width = self._widget_width*0.04
                cairo_gradient(result[0], image.reflection, 0.4)

            image.image.connect("pixbuf-loaded", load_reflection)
            image.image.set_from_file(image_path)
            return image_path

        dfr = common.application.thumbnailer.get_thumbnail(uri, 256,
                                                           model.file_type)
        dfr.addCallback(display).addErrback(error)
        return dfr

    def update_details(self):
        self.debug("updating the title")
        if self.selected_item >= 0 and len(self.controller.model):
            model = self.controller.model[self.selected_item]
            text = self.frontend.translate_text(model.text)
            sub_text = self.frontend.translate_text(model.sub_text)
            self.description.label = text
            self.sub_description.label = sub_text
