# -*- 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 2.
# 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__ = 'Florian Boucault <florian@fluendo.com>'


from elisa.core import common
from elisa.core.component import Component
from elisa.base_components.view import View

from twisted.internet import reactor


class ViewNotSupported(Exception):
    def __init__(self, view_path, transition_path):
        Exception.__init__(self)
        self.view_path = view_path
        self.transition_path = transition_path

    def __str__(self):
        return "View of type %s is not supported by transition of type %s" \
                % (self.view_path, self.transition_path)

class Transition(Component):
    """
    Embodies a visual transition between two states of a L{View}.

    @cvar supported_views:  path of views that are supported by the transition
                            read only
    @type supported_views:  list of strings
    @ivar in_progress:      True if the transition is ongoing, False otherwise
                            read only
    @type in_progress:      boolean
    """

    supported_views = ()

    def __init__(self):
        Component.__init__(self)
        self.in_progress = False
        self._end_callback = None

    def apply(self, view, end_callback=None):
        """
        Start the transition on L{view}.

        If L{end_callback} is set, it will be called when the transition ends.

        @param view:          view on which the transition is applied
        @type view:           L{elisa.base_components.view.View}
        @param end_callback:  callback called at the end of the transition
        @type end_callback:   callable

        @raise ViewNotSupported: if the transition cannot be applied to the
                                 view 
        """
        if self.in_progress:
            self.stop()

        plugin_registry = common.application.plugin_registry
        view_classes = [View]
        for view_path in self.supported_views:
            ViewClass = plugin_registry.get_component_class(view_path)
            view_classes.append(ViewClass)
    
        for ViewClass in view_classes:
            if not isinstance(view, ViewClass):
                raise ViewNotSupported(view.path, self.path)

        self._end_callback = end_callback
        self.in_progress = True

    def stop(self):
        """
        Interrupt the transition where it is currently calling the end of
        transition callback if set.
        """
        self.in_progress = False
        if self._end_callback != None:
            reactor.callLater(0, self._end_callback)
