# -*- 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__ = 'Lionel Martin <lionel@fluendo.com>'


from elisa.base_components.controller import Controller
from elisa.core import player
from elisa.core import common
from elisa.core.input_event import *
from elisa.core import plugin_registry

ListModelClass = plugin_registry.get_component_class('base:list_model')

class PlayerController(Controller):

    supported_models = ('base:player_model',)
    bindings = (('playlist', 'playlist'),
                ('seek_to', 'seek_to'),
                ('volume', 'volume'),
                ('muted', 'muted'),
                ('pause_requested', 'pause_requested'),
                ('uri', 'uri'),
                ('media_type', 'media_type'),
                ('state', 'state'))

    # FIXME: make more extensive use of bindings
    state = None
    stopped = False

    # FIXME: add a documentation for the configuration options
    default_config = {'volume_increment_step': '0.02',
                      'volume_decrement_step': '0.02',
                      'seek_forward_step': '30',
                      'seek_backward_step': '15',
                      'show_status_on_ok': '0'
                      }
    
    def __init__(self):
        Controller.__init__(self)
        self._position_when_seek = -1
        self._uri = None
        self._playlist_index = -1
        self._state = None

    def initialize(self):
        Controller.initialize(self)
        config = self.config
        self._show_status_on_ok = int(config['show_status_on_ok'])
        self._volume_increment_step = float(config['volume_increment_step'])
        self._volume_decrement_step = float(config['volume_decrement_step'])
        forward_step = int(config['seek_forward_step'])
        backward_step = int(config['seek_backward_step'])
        self._seek_forward_step = forward_step * 1000000000
        self._seek_backward_step = backward_step * 1000000000
        
    def model_changed(self, old_model, new_model):
        self.state = self.model.state

    def uri__set(self, new_uri):
        self.state = None
        self._uri = new_uri
        
    def uri__get(self):
        return self._uri

    def handle_input(self, input_event):
        self.debug("Handling input event with action %r", input_event.action)
        
        if input_event.action == EventAction.PLAY:
            self.stopped = False
            self.model.state = player.STATES.PLAYING
        
        elif input_event.action == EventAction.PAUSE:
            self.stopped = False
            self.model.state = player.STATES.PAUSED
        
        elif input_event.action == EventAction.STOP:
            self.stopped = True
            self.model.state = player.STATES.STOPPED
        
        elif input_event.action in (EventAction.GO_UP, EventAction.VOL_UP):
            self.model.volume = min(2.0, self.model.volume + \
                                         self._volume_increment_step)
            
        elif input_event.action in (EventAction.GO_DOWN,
                                    EventAction.VOL_DOWN):
            self.model.volume = max(0.0, self.model.volume - \
                                         self._volume_decrement_step)
            
        elif input_event.action in (EventAction.GO_RIGHT,
                                    EventAction.SEEK_FORWARD):
            if self._position_when_seek > 0 and \
                   self._position_when_seek == self.model.position:
                seek_to = self.model.seek_to + self._seek_forward_step
            else:
                self._position_when_seek = self.model.position
                seek_to = self.model.position + (self._seek_forward_step * 2)
            self.model.seek_to = seek_to
        elif input_event.action == EventAction.MUTE:
            self.model.muted = not self.model.muted
            
        elif input_event.action == EventAction.NEXT:
            # next track in playlist
            uri = self.model.uri            
            if uri != None and \
                   isinstance(self.model.playlist, ListModelClass) and \
                   self.model.state in (player.STATES.PAUSED,
                                        player.STATES.PLAYING):
                self._next_track()

        elif input_event.action == EventAction.PREVIOUS:
            # previous track in playlist
            uri = self.model.uri            
            if uri != None and \
                   isinstance(self.model.playlist, ListModelClass) and \
                   self.model.state in (player.STATES.PAUSED,
                                        player.STATES.PLAYING):
                self._previous_track()
            
        elif input_event.action in (EventAction.GO_LEFT,
                                    EventAction.SEEK_BACKWARD):
            if self._position_when_seek > 0 and \
                   self._position_when_seek == self.model.position:
                seek_to = self.model.seek_to - self._seek_backward_step
            else:
                self._position_when_seek = self.model.position
                seek_to = self.model.position - self._seek_backward_step
            self.model.seek_to = seek_to
        
        elif input_event.action == EventAction.OK:
            if self._show_status_on_ok:
                # First time user presses OK we remember it and next time
                # we toggle player model's state

                if self.model.state == player.STATES.PLAYING:
                    self.model.pause_requested = True

                elif self.model.state == player.STATES.PAUSED:
                    self.model.state = player.STATES.PLAYING
            else:
                if self.model.state == player.STATES.PAUSED:
                    self.model.state = player.STATES.PLAYING
                else:
                    self.model.state = player.STATES.PAUSED
        return False

    def state__set(self, state):
        if state == self._state:
            return
        self._state = state

        if state == player.STATES.PLAYING:
            self.state_changed(state)
        elif state == player.STATES.PAUSED:
            self.pause_requested = False
            self.state_changed(state)
        elif state == player.STATES.STOPPED:
            self.pause_requested = False
            self._position_when_seek = -1
            self.state_changed(state)

    def state__get(self):
        return self._state

    def _next_track(self):
        new_idx = self._playlist_index + 1
        if len(self.model.playlist) > new_idx:
            self._playlist_index = new_idx
            self._play_indexed_track()
            return True
        return False

    def _play_indexed_track(self):
        new_uri = self.model.playlist[self._playlist_index].uri
        self.model.uri = new_uri
        self.state = player.STATES.PLAYING
        self.model.state = player.STATES.PLAYING

    def _previous_track(self):
        new_idx = self._playlist_index - 1
        if len(self.model.playlist) and new_idx > 0:
            self._playlist_index = new_idx
            self._play_indexed_track()
            return True
        return False

    def state_changed(self, state):
        uri = self.model.uri
        uri_list = [model.uri for model in self.model.playlist]

        if uri in uri_list:
            self._playlist_index = uri_list.index(uri)

        if uri == None and state == player.STATES.PLAYING:
            if self._next_track():
                self.focus()
            else:
                self.state = player.STATES.STOPPED
            return
        
        elif state == player.STATES.STOPPED and not self.stopped:
            if self._next_track():
                return
            elif self.focused:
                self.parent.focus()

        elif state == player.STATES.PLAYING and not self.focused \
                                    and not self.model.preview_mode:
                self.focus()

        elif self.focused and state == player.STATES.STOPPED:
                self.parent.focus()
 
