# -*- 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.
#
# Author: Olivier Tilloy <olivier@fluendo.com>

"""
Base controller for an option screen used for configuration.
"""

from elisa.core.utils import defer
from elisa.core.input_event import EventValue

from elisa.plugins.pigment.pigment_controller import PigmentController

import gobject


class OptionScreen(PigmentController):

    """
    Base controller for an option screen used for configuration.

    It may be used either as a step of a configuration wizard, or as a
    standalone option screen controller.

    An option screen may use a backend to populate its data, retrieve the
    current state of the configuration and save the new state back to the
    configuration.
    Initial population should be implemented in the L{setup} method (and this
    method should be explicitely called after the initialization of the screen
    is done, this is not done automatically).
    Saving back the new state of the configuration should be implemented in the
    L{save} method.

    @cvar actions:    a list of possible actions
    @type actions:    C{list} of C{str}
    @ivar standalone: whether the screen is standalone or part of a wizard
    @type standalone: C{bool}
    """

    # The 'closed' signal is emitted when the screen is closed, with a string
    # parameter for the action selected by the user.
    __gsignals__ = {'closed': (gobject.SIGNAL_RUN_LAST,
                               gobject.TYPE_NONE,
                               (gobject.TYPE_STRING,)),
                   }

    # Default actions. Override if needed.
    actions = ['prev', 'next']

    def __init__(self):
        super(OptionScreen, self).__init__()
        self.standalone = True

    def setup(self):
        """
        Set up the screen (i.e. retrieve the current state of the configuration
        and populate its data).

        @return: a deferred fired when the set up is complete
        @rtype:  L{elisa.core.utils.defer.Deferred}
        """
        return defer.fail(NotImplementedError())

    def close(self, action, save=False):
        """
        Close the configuration screen, and optionally save back the new state
        of the configuration.

        @param action:     the action chosen by the user
        @type action:      C{str}
        @param save:       whether to save the new state of the configuration
        @type save:        C{bool}
        @raise ValueError: when action is unknown
        """
        if save:
            self.save()

        if action not in self.actions:
            msg = "Unknown action: '%s'" % action
            raise ValueError(msg)

        self.emit('closed', action)

    def save(self):
        """
        Save back the new state of the configuration.
        This method should be implemented by every specific option screen.
        """
        raise NotImplementedError()

    def handle_input_ok(self):
        """
        Default handling of the C{OK} event.

        Save the new configuration and close the screen.
        """
        self.close('next', True)

    def handle_input_cancel(self):
        """
        Default handling of the C{Return} event.

        Close the screen without altering the current configuration.
        """
        self.close('prev', False)

    def go_back(self):
        """
        In standalone mode, go up one level in the history of controllers.

        @attention: should not be called when not in standalone mode.
        """
        browser = self.frontend.retrieve_controllers('/poblesec/browser')[0]
        browser.history.go_back()

    def handle_input(self, manager, input_event):
        if input_event.value in (EventValue.KEY_OK, EventValue.KEY_RETURN):
            self.handle_input_ok()
            if self.standalone:
                self.go_back()
            return True
        elif input_event.value == EventValue.KEY_MENU:
            self.handle_input_cancel()
            return not self.standalone
        return super(OptionScreen, self).handle_input(manager, input_event)
