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


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

# we are a pigment view
from elisa.plugins.pigment.pigment_view import PigmentView

# the osd
from elisa.plugins.pigment_osd.osd import OSD
from elisa.plugins.pigment_osd.status_osd import StatusOsd
import os, os.path, md5

# widgets
from pgm.graph.image import Image

from twisted.internet import defer

from elisa.core import common

import pgm

"""
An Playback OSD for PigmentViews that want to show Playback in an OSD
"""

class PlaybackOSD(PigmentView,OSD):
    """
    A View that has an OSD inside. It gets automatically shown, when the
    playback gets changed for the time of {osd_duration} and automatically
    hides the OSD, when the focus gets lost.

    This is not a view for direct display, but a meta class containing a lot
    of usefull OSD-Features the Inheriting class can select.

    @ivar osd_duration: the time to show the OSD
    @type osd_duration: int

    @ivar status_bar:   the status osd on the buttom of the osd (contains the
                        progressbar)
    @type status_bar:   L{elisa.plugins.pigment_osd.status_osd.StatusOSD}
    @ivar back_button:  the Back-Button in the top-right corner of the osd
    @type back_button:  L{pgm.graph.image.Image}
    @ivar play_button:  the play-toggle button left of the osd
    @type play_button:  L{pgm.graph.image.Image}
    """

    supported_controllers = ('base:controller',)
    osd_duration = 3.0

    # internal reference size is : 1

    def __init__(self):
        super(PlaybackOSD, self).__init__()
        self.back_button = None
        self.play_button = None

        # the status bar part
        self.status_bar = None


    # main create_widgets
    def create_widgets(self):
        """
        Wrapper for all the create-methods.
        """
        super(PlaybackOSD, self).create_widgets()
        self.context_handle.add(self)
        self.create_group_size()
        self.create_back_button()
        self.create_play_button()
        self.create_status_bar()

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

    def create_group_size(self):
        """
        This is a work-a-round because of the relative size changes in the
        group. we put one invisible image in background that has the size 1
        and 1 so that we can position everything in the group relative to this
        changes. This should be removed as soon as the pigment-python-bug
        #FIXME is fixed
        """
        self.group_size = Image()
        self.group_size.size = (1, 1)
        self.add(self.group_size) 

    def create_back_button(self):
        """
        Creates a self.back_button. It is using the 'back_button'-image of the
        theme and connects self.back_button_clicked to the click event of the
        button. self.back_button does automatically get added to L{self.osd}.
        """
        offset = 0.005
        back_size = 0.15
        x_position = 1 - back_size

        self.back_button = Image()
        self.add(self.back_button)

        self.back_button.position = (x_position, offset, 0)
        self.back_button.bg_color = (0, 0, 0, 0)
        self.back_button.size = (back_size, back_size)
        self.back_button.connect("clicked", self.back_button_clicked)

        self.load_from_theme("back_button", self.back_button)
        self.back_button.visible = True


    def create_status_bar(self):
        """
        Create a self.status_bar. Use "dock_background_mouse" as the
        background of the status_bar, "dock_bar_fg" as the foreground of the
        progressbar and "dock_bar_bg" for the background of the progressbar.
        """
        # generate the position and the size of the status bar
        width = 0.65
        height = 0.15

        pos_x = 0.225
        pos_y = 0.775

        self.status_bar = StatusOsd()
        self.add(self.status_bar)

        self.status_bar.size = (width, height)

        self.status_bar.position = (pos_x, pos_y, 0)

        self.load_from_theme("dock_background_mouse",
                             self.status_bar.background)
        self.load_from_theme("dock_bar_fg",
                             self.status_bar.progressbar.foreground)
        self.load_from_theme("dock_bar_bg",
                             self.status_bar.progressbar.background)

        self.status_bar.visible = True

    def create_play_button(self):
        """
        Create a play-state-toggeling-button as self.play_button and add it to
        the osd. Also connect L{play_button_clicked} to the clicked-event of
        the image. 
        """
        width = 0.175
        height = 0.15

        pos_x = 0.10
        pos_y = 0.775

        self.play_button = Image()
        self.add(self.play_button)

        self.play_button.size = (width, height)
        self.play_button.bg_color = (0,0,0,0)

        self.play_button.position = (pos_x, pos_y, 0)

        self.play_button.connect("clicked", self.play_button_clicked)

        self.load_from_theme("play_button_mouse", self.play_button)

        self.play_button.visible = True

    # mouse events
    def play_button_clicked(self, drawable, x, y, z, button, time):
        """
        Toggle playing of self.controller. Check before if
        self.controller.focused and self.visible is set. If so toggle the
        value of self.controller.playing and stop processing the clicked
        event.
        """
        if not self.controller.focused or not self.visible:
            return False

        self.controller.playing = not self.controller.playing
        return True

    def back_button_clicked(self, drawable, x, y, z, button, time):
        """
        Hide the OSD and give self.controller.parent the focus. Check before
        if self.controller.focused and self.visible is set. If so, call
        L{hide} and self.controller.parent.focus.
        """
        if not self.controller.focused or not self.visible:
            return False

        self.hide()
        self.controller.parent.focus()
        return True

    def mouse_moved(self, viewport, event):
        """
        Show the OSD, when the mouse gets moved. Check before whether
        self.controller.focused is True.
        """
        if not self.controller.focused:
            return False

        self.show(self.osd_duration)
        return True

    # controller events
    def playing__set(self, playing):
        """
        If the playing was set, the play_button (if existing) toggle its state
        and the osd gets shown.
        """
        if self.play_button:
            if playing:
                self.load_from_theme("pause_button_mouse",
                                 self.play_button)
            else:
                self.load_from_theme("play_button_mouse",
                                 self.play_button)
        self.show(self.osd_duration)

    def frontend_changed(self, previous_frontend, new_frontend):
        """
        connect the motion-notify-event to the new context and resize the osd,
        when it is existing
        """
        if new_frontend == None:
            return

        super(PlaybackOSD,self).frontend_changed(previous_frontend, new_frontend)


        viewport = new_frontend.context.viewport_handle
        viewport.connect("motion-notify-event", self.mouse_moved)
        canvas = viewport.get_canvas()
        self.size = canvas.size


    def focused__set(self, focused):
        """
        If we loose the focus, we hide the osd
        """
        if not focused:
            self.hide()
