# -*- 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.
#
# Authors: Guillaume Emont <guillaume@fluendo.com>

"""
Stuff to help in the use of dbus in an elisa context.
"""

from elisa.core.utils.defer import Deferred

import dbus
from dbus.exceptions import DBusException


class ElisaDBusException(Exception):
    dbus_name = ''
    pass

dbus_exceptions = {}

def translate_exception(exception):
    """
    Translates a DBusException into a more meaningful exception.
    """
    new_exception = None
    if isinstance(exception, DBusException):
        name = exception.get_dbus_name()

        if dbus_exceptions.has_key(name):
            exception_type = dbus_exceptions[name]
            new_exception = exception_type(exception.args)
            new_exception.message = exception_type.message
        else:
            new_exception = ElisaDBusException()

        return new_exception

    return exception

def call_sync_dbus_method(method, *args, **kwargs):
    try:
        return method(*args, **kwargs)
    except DBusException, exception:
        raise translate_exception(exception)

def call_async_dbus_method(method, *args, **kwargs):
    """
    Calls L{method} with the given arguments asynchronously, and returns a
    deferred.
    """
    dfr = Deferred()

    def _callback(retval):
        dfr.callback(retval)
    def _errback(exception):
        dfr.errback(translate_exception(exception))

    kwargs['reply_handler'] = _callback
    kwargs['error_handler'] = _errback

    method(*args, **kwargs)

    return dfr

if __name__ == '__main__':
    import dbus, gobject

    from dbus.mainloop.glib import DBusGMainLoop
    DBusGMainLoop(set_as_default=True)

    mainloop = gobject.MainLoop()

    bus = dbus.SystemBus()

    hal_manager = bus.get_object('org.freedesktop.Hal',
                                 '/org/freedesktop/Hal/Manager')

    hal_iface = dbus.Interface(hal_manager,
                               'org.freedesktop.Hal.Manager')

    def print_callback(arg):
        print arg
        mainloop.quit()

    dfr = call_async_dbus_method(hal_iface.FindDeviceByCapability, 'volume')

    dfr.addBoth(print_callback)
    
    mainloop.run()
