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

import pgm, gobject
from pgm.graph.group import Group
from pgm.graph.image import Image
from pgm.timing import implicit

"""
Progress Bar Widget for Pigment Views
"""

__maintainer__ = "Benjamin Kampmann <benjamin@fluendo.com>"


class ProgressBarOsd(Group):
    """
    The Progress Bar Widget has a L{foreground} and a L{background} image.
    Depending on L{length} and L{cursor_position} the foreground size gets
    aranged. 

    Beside this it uses the values to send the position-click signals on a
    drag, pressed or scrolled on any of the images

    @ivar foreground:       the color filling the bar
    @type foreground:       L{pgm.graph.image.Image}
    @ivar background:       the background filling of the bar
    @type background:       L{pgm.graph.image.Image}

    @ivar length:           the virtual length of progress
    @type length:           float
    @ivar cursor_position:  the virtual position of the progress
    @type cursor_position:  float
    """

    __gsignals__ = {'position-click': (gobject.SIGNAL_RUN_LAST, gobject.TYPE_BOOLEAN,
                    (gobject.TYPE_FLOAT,))}

    def __init__(self):
        super(ProgressBarOsd, self).__init__()

        self._cursor_position = 0
        self._absolute_x = 0

        self.background = Image()
        self.background.layout = pgm.IMAGE_FILLED
        self.background.alignment = pgm.IMAGE_LEFT
        self.background.height = 1.0
        self.background.width = 4.0
        self.background.bg_color = (0, 0, 0, 0)
        self.background.visible = True
        self.background.connect('pressed', self._got_pressed)
        self.background.connect('drag-begin', self._got_motion_start)
        self.background.connect('drag-motion', self._got_motion)
        self.background.connect('scrolled', self._got_scrolled)

        self.foreground = Image()
        self.foreground.layout = pgm.IMAGE_FILLED
        self.foreground.alignment = pgm.IMAGE_LEFT
        self.foreground.height = 1.0
        self.foreground.width = 4.0
        self.foreground.size = (0, 0)
        self.foreground.bg_color = (0, 0, 0, 0)
        self.foreground.visible = True
        self.foreground.connect('pressed', self._got_pressed)
        self.foreground.connect('drag-begin', self._got_motion_start)
        self.foreground.connect('drag-motion', self._got_motion)
        self.foreground.connect('scrolled', self._got_scrolled)

        self._animated_foreground = implicit.AnimatedObject(self.foreground)
        self._animated_foreground.mode = implicit.REPLACE
        self._animated_foreground.setup_next_animations(duration = 200)

        self.add(self.background)
        self.add(self.foreground)

        self.length = 0

    def size__set(self, size):
        self.background.size = size
        # Needed for nicer animations
        self.foreground.height = size[1]
        self._paint_foreground(animated = False)

    def length__set(self, length):
        """
        Set the length. The bar is automatically new painted
        @param length: the length of the process
        @type length: as above: something to do mathematic stuff
        """
        self._length = length
        if self._length <= 0:
            self._length = 1
        if self._cursor_position > self._length:
             self._cursor_position = self._length
        self._paint_foreground()

    def length__get(self):
        """
        to get the length:
        @return: returns the length
        """
        return self._length

    def _paint_foreground(self, animated=True):
        """
        Here the position is calculated and the bar is painted
        """
        next_pos = self.background.size[0] / self.length * \
                                    self._cursor_position
        if animated:
            self._animated_foreground.width = next_pos
        else:
            self._animated_foreground.stop_animations()
            self.foreground.width = next_pos

    def cursor_position__set(self, position):
        """
        Set the position of the cursor. The bar is automatically new painted
        (with animation)
        @param position: the position to set to
        @type position: something to do mathematic stuff with
        """
        self._cursor_position = position
        self._cursor_position = max(0, min(self._cursor_position, self._length))
        self._paint_foreground()

    def cursor_position__get(self):
        """
        returns the position of the cursor
        @return : the position of the cursor
        """
        return self._cursor_position

    def jump_to_position(self, position):
        """
        Jump to this position. This means that the cursor doesn't go there
        with animation but that it is there immediatly
        @param position: the position to jump to
        @type position: something to do mathematic stuff with
        """
        self._cursor_position = position
        self._cursor_position = max(0, min(self._cursor_position, self.length))
        self._paint_foreground(animated=False)

    def _get_parents_x(self, parent=None):
        if not parent:
            parent = self

        if parent.parent == None:
            return parent.x

        return self._get_parents_x(parent.parent) + parent.x

    def _got_scrolled(self, img, x, y, z, direction, time):
        ten_percent = self.length / 10.
        if direction == pgm.SCROLL_UP:
            self.emit('position-click', self._cursor_position + ten_percent)
        else:
            self.emit('position-click', self._cursor_position - ten_percent)
                

    def _got_pressed(self, img, x, y, z, button, l):
        # we currently don't do anything
        if not self.visible:
            return

        real_x = self._get_parents_x()

        new_x = (x - real_x) / self.width * self.length
        self.emit('position-click', new_x)
        return True

    def _got_motion_start(self, img, x, y, z, button, l):
        self._motion_counter = 0
        self._absolute_x = self._get_parents_x()

    def _got_motion(self, img, x, y, z, button, l):
        # only react on every 5th event
        # FIXME: make this configurable as a public variable
        if self._motion_counter < 5:
            self._motion_counter += 1
            return

        new_x = (x - self._absolute_x) / self.width * self.length
        self.emit('position-click', new_x)
        return True
