# -*- 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 pgm
from pgm.widgets import sliced_image, scrollbar, const

from raval_widgets.scrolled_list import ScrolledList
from raval_widgets.selector import Selector
import constants

from pgm.graph.group import Group
from pgm.graph.image import Image
from pgm.graph.text import Text

class ListItem(Group):

    def load(self):
        spacing = 0.03
        thumbnail_width = 1.0

        self.thumbnail = Image()
        self.add(self.thumbnail)
        self.thumbnail.position = (0.0, 0.0, 0.0)
        self.thumbnail.width = thumbnail_width
        self.thumbnail.bg_color = (200, 0, 0, 0)
        self.thumbnail.layout = pgm.IMAGE_SCALED
        self.thumbnail.visible = True

        text_x = thumbnail_width + spacing
        text_width = thumbnail_width*4.0

        self._description = self._create_text()
        self.add(self._description)
        self._description.visible = True
        self._description.position = (text_x, 0.0, 0.0)
        self._description.width = text_width
        self._description.font_height = 0.8
        self._description.bg_color = (0, 200, 0, 0)

    def _create_text(self):
        txt = Text()
        txt.font_family = "Nimbus Sans L"
        txt.weight = pgm.TEXT_WEIGHT_BOLD
        txt.bg_color = (0, 0, 0, 0)
        txt.alignment = pgm.TEXT_ALIGN_LEFT
        txt.ellipsize = pgm.TEXT_ELLIPSIZE_MIDDLE
        txt.opacity = 255
        return txt

    def unload(self):
        self.remove(self._description)
        self.remove(self.thumbnail)

    def description__set(self, text):
        self._description.label = text

    def description__get(self):
        return self._description

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

class ShadedListView(BaseListView, ScrolledList):

    def __init__(self): 
        super(ShadedListView, self).__init__()
        super(ScrolledList, self).__init__()
        self._index_set_before = False

    def compute_zoom_height(self, index):
        return 0.7

    def update_details(self):
        self._update_preview()
    
    def selector_visible__set(self, visible):
        self.debug("Selector should become visible: %s" % visible)
        self._list_selector.visible = visible

    def _update_preview(self):
        self.debug("updating the preview")
        if not hasattr(self, 'preview'):
            self._create_child_view('preview', 'raval:preview')

            canvas = self.frontend.context.viewport_handle.get_canvas()
            self.preview.width = canvas.width * 0.37
            self.preview.height = canvas.height * 0.7
            x = canvas.width*0.95 - self.preview.width
            y = (self.height - self.preview.height) / 2.0 + \
                self.preview.height/7.0
            self.preview.position = (x, y, 0.0)
            self.preview.visible = True

        if self.selected_item >= 0 and len(self.controller.model):
            self.preview.update()
            
    def frontend_changed(self, previous_frontend, new_frontend):
        super(ShadedListView, self).frontend_changed(previous_frontend,
                                                     new_frontend)

        if self.frontend:
            self._list_selector.loading_image_path = self.frontend.theme.get_media('small_waiting_icon')
            self._list_selector.action_done_image_path = self.frontend.theme.get_media('action_done_icon')
        
        #FIXME find a way to remove this
        if hasattr(self, 'preview'):
            self.preview.frontend_changed(previous_frontend, new_frontend)
            
    def clean(self):
        BaseListView.clean(self)
        self.selector.stop_animation()
        self.canvas = None
        self.preview.canvas = None

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

        canvas = self.frontend.context.viewport_handle.get_canvas()
        theme = self.frontend.theme
 
        gradient_top = theme.get_media("list_mode_gradient_top")
        gradient_bottom = theme.get_media("list_mode_gradient_bottom")

        self.top_shade = gradient_top
        self.bottom_shade = gradient_bottom

        list_x = canvas.width / 100.
        self.visible_range_size = 9
        
        top_bar_height_px = canvas.height  * (constants.status_bar_height + constants.context_bar_height) / 100. 
        margin_px = canvas.height * constants.list_menu_height_margin / 100.        
        back_button_px = canvas.height * constants.back_button_height / 100.
        top_bar_height_px = canvas.height  * (constants.status_bar_height + constants.context_bar_height) / 100. 
        
        self.position = (list_x, top_bar_height_px  + margin_px, 0)
        self.width = canvas.width * 0.45
        self.height = canvas.height * 0.7
        self.height = canvas.height - top_bar_height_px - margin_px * 2.0 - back_button_px

        bar_bg = sliced_image.SlicedImage()
        bar_bg.top_file = theme.get_media("scrollbar_top")
        bar_bg.bottom_file = theme.get_media("scrollbar_bottom")
        bar_bg.body_file = theme.get_media("scrollbar_body")

        cursor = sliced_image.SlicedImage()
        cursor.top_file = theme.get_media("cursor_top")
        cursor.bottom_file = theme.get_media("cursor_bottom")
        cursor.body_file = theme.get_media("cursor_body")

        # Vertical scrollbar on the left side of the list
        bar = scrollbar.Scrollbar(items_number=9, background=bar_bg,
                                  cursor=cursor, spacing=0.01, thickness=0.07)
        self.set_vertical_scrollbar(bar, const.LEFT, spacing=0.05)

        sel_left = theme.get_media("selector_left")
        sel_right = theme.get_media("selector_right")
        sel_body = theme.get_media("selector_body")
        back_sel_left = theme.get_media("back_selector_left")
        back_sel_right = theme.get_media("back_selector_right")
        back_sel_body = theme.get_media("back_selector_body")
        #arrow = theme.get_media("selector_arrow")
        
        # TODO: make Selector parameters optional
        sel_pictos = (sel_left, sel_right, sel_body,
                      back_sel_left, back_sel_right, back_sel_body)
        
        self._list_selector = Selector(orientation=const.HORIZONTAL, *sel_pictos)

        # 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._back_img.set_from_file(theme.get_media('list_mode_back_button'))
        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 selected_item__set(self, index):
        if not self._index_set_before:
            self._index_set_before = True
            self.selector_visible = False
            self.set_selector(self._list_selector)
        super(ShadedListView, self).selected_item__set(index)

    def create_item(self, model):
        widget = ListItem()
        return widget

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

        widget.load()

        self.load_from_theme(model.theme_icon, widget.thumbnail)

        text = self.frontend.translate_text(model.text)
        widget.description = text

        def error_eater(error):
            # We don't want to show a warning to the user, if the thumbnailing
            # errors. We simply don't do anything in that case.
            self.debug("Eating error: %s" % error.getBriefTraceback())
            return None

        uri = model.thumbnail_source
        if uri != None:
            dfr = self._model_thumbnail_to_image(model, widget.thumbnail)
            dfr.addErrback(error_eater)

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

    def do_clicked(self, x, y, z, button, time):
        # The controller could already have been removed, when we get the
        # events
        if self.controller is None or not self.controller.focused:
            return False

        return super(ShadedListView, self).do_clicked(x, y, z, button, time)

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

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

        if index == old_selected:
            # click while selected, activate
            self.controller.activate_item(self.frontend)

    def do_drag_begin(self, x, y, z, button, time):
        if self.controller is None or not self.controller.focused:
            return False
        
        return super(ShadedListView, self).do_drag_begin(x, y, z, button, time)

    def do_drag_motion(self, x, y, z, button, time):
        if self.controller is None or not self.controller.focused:
            return False

        return super(ShadedListView, self).do_drag_motion(x, y, z, button, time)
    
    def do_drag_end(self, x, y, z, button, time):
        if self.controller is None or not self.controller.focused:
            return False

        return super(ShadedListView, self).do_drag_end(x, y, z, button, time)

    def do_selected_item_changed(self, index):
        self.controller.current_index = index
        
    def element_attribute_set(self, position, key, old_value, new_value):
        super(ShadedListView, 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):
                model = self.controller.model[position]
                self._model_thumbnail_to_image(model, self[position].thumbnail)
        elif key == "loading":
            self.selector.loading = new_value

    def action_called__set(self, new_value):
        if new_value:
            self.selector.action_done = new_value

