# -*- 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 player
from elisa.core import common
from elisa.core.input_event import *
from elisa.base_components.controller import Controller

from elisa.core.epm.exceptions import *
from elisa.extern.epr.egg_parser import EggParser

try:
    # FIXME: need to import like the sender ist doing :(
    plugin_registry = common.application.plugin_registry
    ElisaUpdateMessage = plugin_registry.get_component_class('updater:elisa_update_message')
    ElisaUpgrader = plugin_registry.get_component_class('updater:elisa_upgrade_action')
except ImportError:
    ElisaUpdateMessage = None
    # import didn't work because the plugin is not there

from elisa.plugins.pigment.dropped_plugin_message import DroppedPluginMessage

# translation support for the popup
from elisa.extern.translation import gettexter, N_
T_ = gettexter('elisa-raval')

# needed for the passthrought hack
from elisa.core.utils.signal import Signal

class ElisaController(Controller):
    supported_models = ('base:elisa_model',)
    bindings = (('manager', 'manager'),)

    children = ["slideshow", "player", "manager"]

    def initialize(self):
        dfr = Controller.initialize(self)

        # FIXME: should not retrieve the fullscreen information through the
        # configuration file but asking directly to the context
        config = common.application.config
        fullscreen = config.get_option('start_fullscreen',
                                       section='pigment:pigment_context')
        if fullscreen == '1':
            self.fullscreen = True
        else:
            self.fullscreen = False

        self._last_player = None

        self._create_child_controller("slideshow",
                                      "slideshow:slideshow_controller")

        self._create_child_controller("player",
                                      "player:player_controller")

        self._create_child_controller("popup",
                                      "raval:popup_controller")
        bus = common.application.bus

        self.show_popup = False

        if ElisaUpdateMessage != None:
            self._upgrader = ElisaUpgrader()
            bus.register(self._got_update_message, ElisaUpdateMessage)
        bus.register(self._got_dropped_plugin, DroppedPluginMessage)

        return dfr

    def backend_changed(self, old_backend, new_backend):
        # FIXME
        self.slideshow.backend = new_backend
        self.popup.backend = new_backend
        self.player.backend = new_backend
        
    def attribute_set(self, origin, key, old_value, new_value):
        super(ElisaController, self).attribute_set(origin, key, old_value, new_value)
        if key == 'menu_visible':
            if new_value == True:
                if self.slideshow.focused:
                    self._last_player = self.slideshow
                elif self.player.focused:
                    self._last_player = self.player 
                self.focus()
            elif self._last_player != None and \
                            self._last_player.model != None:
                self._last_player.focus()
            else:
                self.focus()
                
        elif key == 'stop_player':
            if new_value == True:
                self.slideshow.playing = False
                self.slideshow.current_index = -1
                self.slideshow.model = None
                self.player.playing = False
                self.player.state = player.STATES.STOPPED
                self.player.model = None
            elif self._last_player != None and \
                            self._last_player.model != None:
                self._last_player.playing = True


    def handle_input(self, input_event):
        if input_event.action == EventAction.TOGGLE_FULLSCREEN:
            self.fullscreen = not self.fullscreen
            return True
        elif input_event.action == EventAction.EXIT:
            common.application.stop()
            return True

        elif input_event.action == EventAction.MENU:
            if self.slideshow.focused or self.player.focused:
                self.model.menu_visible = True
            else:
                self.model.menu_visible = False
            return True

        return False

    def model_changed(self, old_model, new_model):
        self.manager.enter_node(self.model.menu)

    def _got_dropped_plugin(self, msg, sender):
        if self.show_popup or not ElisaUpdateMessage:
            # popup already visible or the plugin is not installed
            return

        parser = EggParser()
        metadata = {}
        try:
            metadata = parser.parse_egg_file(msg.uri.path)
        except Exception, e:
            path = common.application.log_traceback()
            self.warning("Unexpected exception while parsing the egg file:\n" \
                         "full output at : %s" % (path))

        if not metadata.get('plugin_name', None):
            self.popup.signal.connect(self._close_signal)
            self._show_popup(T_(N_("The file is not an Elisa plugin")))
            return

        #FIXME: big hack to passthrought the uri
        self.popup.signal.connect(lambda value, *args:
                                    self._install_plugin(value, msg.uri) )
        self._show_popup(T_(N_("You are about to install plugin %s, " \
                               "continue?"), (metadata['plugin_name'])))

    def _install_plugin(self, value, uri):
        # overwrite the signal, because we don't really now how to disconnect
        # it
        self.popup.signal = Signal('popup-signal', int)
        self._popup_gone()

        if value:
            action = plugin_registry.create_component('updater:elisa_plugin_install_action')
            action.uri = uri
            dfr = action(self, None)
            dfr.addCallback(self._got_update_done)
            dfr.addErrback(self._got_update_error)

    def _got_update_message(self, msg, sender):
        if not len(msg.upgradeable_plugins):
            return

        if self.show_popup:
            return
        
        self.popup.signal.connect(self._update_signal)
        message = T_(N_("Plugins update available."\
                        " Would you like to download and install it now?"))
        self._show_popup(message)


    def _update_signal(self, value):
        self.popup.signal.disconnect(self._update_signal)
        self._popup_gone()
        if value != 0:
            dfr = self._upgrader(self, None)
            dfr.addCallback(self._got_update_done)

    def _restart_signal(self, value):
        self.popup.signal.disconnect(self._restart_signal)
        self._popup_gone()
        if value:
            common.application.stop()

    def _close_signal(self, value):
        self.popup.signal.disconnect(self._close_signal)
        self._popup_gone()

    def _got_update_done(self, lst):
        errors = filter(lambda res: res[0] == False, lst)
        ok = filter(lambda res: res[0] == True, lst)

        if errors:
            msgs = map(lambda e: e[1].getErrorMessage(), errors)
            self.warning("Errors while installing: %s" % msgs)
            self._got_update_error(None)
            return

        self.popup.signal.connect(self._restart_signal)
        message = T_(N_("Plugins update completed."\
                       " Elisa should be restarted, would you like to shutdown Elisa?"))
        self._show_popup(message)

    def _got_update_error(self, err):
        self.popup.signal.connect(self._close_signal)

        if err and err.check(AlreadyInstalledError):
            self._show_popup(T_(N_("The plugin is already installed")))
        else:
            self._show_popup(T_(N_("Errors installing plugins")))

    def _show_popup(self, text='really?'):
        self.popup.label = text
        self.show_popup = True
        for key in self.children:
            child_controller = getattr(self, key)
            child_controller.focused = False
        self.popup.focus()

    def _popup_gone(self, *args):
        self.show_popup = False
        self.popup.focused = False
        child_controller = getattr(self, self.focused_window)
        child_controller.focused = True
        child_controller.focus()

    def focus(self):
        self.manager.focus()

    def focused_changed(self, old_focused, new_focused):
        # FIXME: this relies on the fact that the actions system somehow
        # make the controllers (player, slideshow, etc.) to focus and that the
        # focus notification is going up to their parent (ElisaController)

        for key in self.children:
            child_controller = getattr(self, key)
            if child_controller.focused:
                self.focused_window = key
                child_controller.hidden = False
                break

        if self.focused_window == 'slideshow' and self.player.model is not None:

            if self.player.current_model.file_type != "audio":
                # Pause the playback
                self.player.playing = False

            # hide it
            self.player.hidden = True

        elif self.focused_window == 'player' and self.slideshow.model is not None:
            # hide th slideshow
            self.slideshow.hidden = True

