# -*- 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.
#
# Authors: Guillaume Emont <guillaume@fluendo.com>

import pgm, gst
from elisa.core.utils.i18n import install_translation
from elisa.core.input_event import *
from elisa.plugins.poblesec.player_video import Player, VideoPlayerController
from elisa.plugins.poblesec.videoplayer_controls import PlayPauseControl, \
                                                        StopControl, \
                                                        SkipPreviousControl, \
                                                        SkipNextControl, \
                                                        VolumeUpControl, \
                                                        VolumeDownControl
from elisa.plugins.poblesec.widgets.player.control_ribbon import Control
from elisa.plugins.pigment.widgets.const import *

import platform

_ = install_translation('dvd')

# FIXME: for some reason, when seeking in DVDs using these controls, we never
# get the released event on the button, and seeking never stops. Seeking has
# been temporarily disabled for that reason.
class PreviousChapterControl(SkipPreviousControl):
    """
    DOCME
    """
    _caption_table = { 'seek': _("Previous Chapter"), \
                       'noseek': _("Previous Chapter") }

    def _player_skip(self):
        self.slave.previous_chapter()

    def _player_seek(self):
        return -1

class NextChapterControl(SkipNextControl):
    """
    DOCME
    """
    _caption_table = { 'seek': _("Next Chapter"), \
                       'noseek': _("Next Chapter") }

    def _player_skip(self):
        self.slave.next_chapter()

    def _player_seek(self):
        return -1

class DvdMenuControl(Control):
    """
    DOCME
    """
    caption = _("DVD Menu")
    glyphs = \
            {STATE_NORMAL: 'elisa.plugins.dvd.menu_normal',
             STATE_SELECTED: 'elisa.plugins.dvd.menu_selected',
             STATE_PRESSED: 'elisa.plugins.dvd.menu_pressed',
            }

    def activate(self):
        self.slave.menu()

class DvdPlayer(Player):
# FIXME: is that stuff still needed?

    # We need this hack because playbin needs a dvd:// uri to play the stuff
    # correctly.
    def play_model(self, model):
        if model.uri.scheme == 'file':
            model.uri.scheme = 'dvd'
            # Broken gstreamer elements expect 'dvd://X:/foo/bar' and not
            # 'dvd:///X:/foo/bar'
            if model.uri.path and not model.uri.host:
                model.uri.host = model.uri.path
                model.uri.path=''
                if platform.system() == 'Windows' \
                        and len(model.uri.host) >=3 \
                        and model.uri.host[0] == '/' \
                        and model.uri.host[2] == ':':
                            model.uri.host = model.uri.host.lstrip('/')

        super(DvdPlayer, self).play_model(model)
        

class DvdPlayerController(VideoPlayerController):
    """Specific controller handling a player that behaves for DVDs."""

    PlayerClass = DvdPlayer

    structure_string = \
        "application/x-gst-navigation,event=(string)key-press,key=(string)%s"

    MENU_KEY = 'm'
    PREVIOUS_CHAPTER_KEY = 'comma'
    NEXT_CHAPTER_KEY = 'period'

    log_category = "dvd_player"

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

        self.sink_pad = self.player.pgm_sink.get_pad("sink")
        self.sink_pad.add_event_probe(self._sink_pad_event_cb)

        self.in_menu = False

    def initialize(self):
        dfr = super(DvdPlayerController, self).initialize()
        self.player_osd.time_before_hiding = 3
        return dfr

    def setup_ribbon_controls(self):
        # video controls
        ribbon = self.player_osd.control_ribbon
        ribbon.add_control(DvdMenuControl(self))
        ribbon.add_control(PreviousChapterControl(self))
        ribbon.add_control(PlayPauseControl(self))
        ribbon.add_control(StopControl(self))
        ribbon.add_control(NextChapterControl(self))
        ribbon.add_control(VolumeDownControl(self))
        ribbon.add_control(VolumeUpControl(self))

    def _enter_menu(self):
        self.debug("enter menu")
        self.in_menu = True
        self.player.pgm_sink.set_property("events",
            pgm.IMAGE_SINK_MOTION | pgm.IMAGE_SINK_RELEASED)
        self.player_osd.visible = False

    def _leave_menu(self):
        self.debug("leave menu")
        self.in_menu = False
        self.player.pgm_sink.set_property("events", 0)
        self.player_osd.visible = True

        # FIXME: this is (almost) cut and pasted code from
        # PlayerController._player_status_cb(). We should instead reset that
        # whenever it is likely to change (at each new segment?)
        duration = self.player.get_duration()
        osd_details = self.player_osd.status.status_display_details
        if duration > 0:
            duration_in_min = duration / (gst.SECOND * 60)
            if duration_in_min > 0:
                osd_details.details.label = "%s %s" % (duration_in_min, _('min'))

        
    # FIXME: very hackish way of knowing^Wguessing whether we're in a menu.
    # Does not allow differentiation between "main" menu and submenus.
    def _sink_pad_event_cb(self, pad, event):
        structure = event.get_structure()
        if structure and structure.has_name('application/x-gst-dvd'):
            if structure['event'] == 'dvd-spu-highlight' and not self.in_menu:
                self._enter_menu()

            elif structure['event'] == 'dvd-spu-reset-highlight' \
                                                and self.in_menu:
                self._leave_menu()
        return True
                
    def send_key(self, key_name):
        structure = gst.structure_from_string(self.structure_string % key_name)
        self.sink_pad.push_event(gst.event_new_navigation(structure))

    def handle_input(self, manager, input_event):
        if not self.in_menu:
            return super(DvdPlayerController, self). \
                                handle_input(manager, input_event)

        # we're in a menu
        key_translation = {
            EventValue.KEY_OK: "Return",
            EventValue.KEY_SPACE: "Return",
            EventValue.KEY_GO_UP: "Up",
            EventValue.KEY_GO_DOWN: "Down",
            EventValue.KEY_GO_LEFT: "Left",
            EventValue.KEY_GO_RIGHT: "Right"}

        if key_translation.has_key(input_event.value):
            self.send_key(key_translation[input_event.value])
            return True

        return False

    # This is a hack in order not to show the OSD when we go in playing mode,
    # because else that happens in transition between menus, which is ugly.
    def _player_status_cb(self, player, status):
        # player_osd.visible determines whether the osd can be shown.
        # player_osd.show() and player_osd.hide() show and hide it with an
        # animation. PlayerController does a player_osd.show() that we don't
        # want when status == PLAYING.
        if status == player.PLAYING and self.player_osd.visible:
            self.player_osd.visible = False
            ret = super(DvdPlayerController, self)._player_status_cb(player,
                                                                     status)
            self.player_osd.hide()
            self.player_osd.visible = True
            return ret

        return super(DvdPlayerController, self)._player_status_cb(player,
                                                                  status)

    def previous_chapter(self):
        self.send_key(self.PREVIOUS_CHAPTER_KEY)

    def next_chapter(self):
        self.send_key(self.NEXT_CHAPTER_KEY)

    def menu(self):
        self.send_key(self.MENU_KEY)
