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

class ManagerController(Controller):

    supported_models = ('raval:manager_model',)
    current_path = []

    bindings = (('location', 'location'),
                ('context', 'context'),
                ('current_content_type', 'current_content_type'))

    current = None
    model_loading = None
    
    def focus(self):
        self.current.focus()
    
    def focused_changed(self, old_focus, new_focus):
        self.context_active = new_focus and len(self.current_path) > 1
        
    def enter_context_bar(self):
        if len(self.context.model) > 0:
            self.context.focus()
            
    def current_content_type__set(self, content_type):
        if len(self.current_path) <= 1:
            return 

        model = self.current_path[-1].model
        if hasattr(model, 'content_type') and content_type == model.content_type:
            return
        
        model.content_type = content_type
        self.update_controller()
        
        
    def handle_input(self, input_event):
        if input_event.action == EventAction.MENU:
            try:
               self.exit_node()
               return True
            except IndexError, exc:
                # We are at the main menu
                return False
    
        elif input_event.action in (EventAction.GO_RIGHT, EventAction.GO_LEFT,
                                    EventAction.GO_UP, EventAction.GO_DOWN):
            self.enter_context_bar()
            return True

        return False

    def exit_node(self):
        """
        @raise IndexError: if there would be no items left after exiting
        """
        self.debug("exiting from %s" % self.current.model)

        self.model_loading = None

        if len(self.current_path) <= 1:
            raise IndexError("Root node reached")

        old_current = self.current_path.pop(-1)
        self.current = self.current_path[-1]
        self.current.focus()
        try:
            model = old_current.model
            model.activity.unload(model)
            # FIXME: it is suggesting that the controller is a list controller
            # and that the model is a list model containing models, that have
            # a .children attribute which is the model we are currently
            # unloading -> FIXME: needs to be removed in the rest-branch!!!!
            try:
                self.current.model[self.current.current_index].children = None
            except Exception, Exc:
                # breaking the reference did not work, but we want to simply
                # go it because the children attribute wasn't there, what is
                # not bad
                pass
        except AttributeError:
            self.warning("%s is missing an activity. could not unload it",
                         old_current.model)
        except IndexError, exc:
            self.warning("The activity '%s' could not unload %r",
                         old_current.model.activity, old_current.model)
        
        if len(self.model.location):
            # update the current location
            self.model.location.pop(-1)
            
        self.context_visible = len(self.current_path) > 1
        
    def update_controller(self):
        model = self.current_path[-1].model
        prev_controller =  self.current_path.pop(-1)
        prev_controller.backend = None
        prev_controller.parent = None
        prev_controller.model = None
        
        if hasattr(model, 'content_type'):
            content_type = model.content_type
        else:
            content_type = None
            
        controller = self._create_controller(model, content_type)

        # FIXME: in case of list controllers, the current selected item is
        # shared. This is a particular case that should not be hardcoded.
        plugin_registry = common.application.plugin_registry
        ListController = plugin_registry.get_component_class("raval:list_controller")
        if isinstance(prev_controller, ListController) and \
           isinstance(controller, ListController):
            controller.current_index = prev_controller.current_index

        self.current_path.append(controller)
        self.current = controller
        self.current.focus()  
           
    def _create_controller(self, model, content_type=None):        
        if content_type == None and hasattr(model, 'content_type'):
                content_type = model.content_type
            
        controller_path = self.backend.get_controller_path(model.path,
                                                           content_type)
        plugin_registry = common.application.plugin_registry
        controller = plugin_registry.create_component(controller_path)
        controller.backend = self.backend
        controller.parent = self
        controller.model = model
        return controller
        
            
    def enter_node(self, model):
        if not self.model_loading:
            self.model_loading = model
        else:
            self.debug("Already entering a node: %r", self.model_loading)
            return

        self.debug("entering: %s" % model)
        if not model.has_children:
            self.model_loading = None
            return

        def model_loaded(model, parent):
            self.debug("model returned by the activity: %r", model)
            # create a corresponding controller

            # If the parent is not in the upper list, we suggest, that the
            # user went somewhere else and so, we do NOT load this
            # controller
            if parent != self.model_loading:
                return

            controller = self._create_controller(model)
            self.current_path.append(controller)
            self.context_visible = len(self.current_path) > 1

            self.current = controller
            self.current.focus()

            # update the current location
            if len(self.current_path) > 1:
                if len(self.current_path) == 2:
                    self.context.icon = parent.theme_icon
                    self.context.text = parent.text
                else:
                    self.model.location.append(parent)

            self.model_loading = None

        def got_errback(error):
            self.model_loading = None
            # FIXME: we should also do something clever over here ;)
            return error

        dfr = model.activity.loadmore(model)
        dfr.addCallback(model_loaded, model).addErrback(got_errback)
