# Copyright 2014 The Chromium OS Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.

import dbus
import logging

from autotest_lib.client.bin import utils


DBUS_INTERFACE_OBJECT_MANAGER = 'org.freedesktop.DBus.ObjectManager'
DBUS_ERROR_SERVICEUNKNOWN = 'org.freedesktop.DBus.Error.ServiceUnknown'


def dbus2primitive(value):
    """Convert values from dbus types to python types.

    @param value: dbus object to convert to a primitive.

    """
    if isinstance(value, dbus.Boolean):
        return bool(value)
    elif isinstance(value, int):
        return int(value)
    elif isinstance(value, dbus.UInt16):
        return long(value)
    elif isinstance(value, dbus.UInt32):
        return long(value)
    elif isinstance(value, dbus.UInt64):
        return long(value)
    elif isinstance(value, float):
        return float(value)
    elif isinstance(value, str):
        return str(value)
    elif isinstance(value, unicode):
        return str(value)
    elif isinstance(value, list):
        return [dbus2primitive(x) for x in value]
    elif isinstance(value, tuple):
        return tuple([dbus2primitive(x) for x in value])
    elif isinstance(value, dict):
        return dict([(dbus2primitive(k), dbus2primitive(v))
                     for k,v in value.items()])
    else:
        logging.error('Failed to convert dbus object of class: %r',
                      value.__class__.__name__)
        return value


def get_objects_with_interface(service_name, object_manager_path,
                               dbus_interface, path_prefix=None,
                               bus=None):
    """Get objects that have a particular interface via a property manager.

    @param service_name: string remote service exposing the object manager
            to query (e.g. 'org.chromium.peerd').
    @param object_manager_path: string DBus path of object manager on remote
            service (e.g. '/org/chromium/peerd')
    @param dbus_interface: string interface of object we're interested in.
    @param path_prefix: string prefix of DBus path to filter for.  If not
            None, we'll return only objects in the remote service whose
            paths start with this prefix.
    @param bus: dbus.Bus object, defaults to dbus.SystemBus().  Note that
            normally, dbus.SystemBus() multiplexes a single DBus connection
            among its instances.
    @return dict that maps object paths to dicts of interface name to properties
            exposed by that interface.  This is similar to the structure
            returned by org.freedesktop.DBus.ObjectManaber.GetManagedObjects().

    """
    if bus is None:
        bus = dbus.SystemBus()
    object_manager = dbus.Interface(
            bus.get_object(service_name, object_manager_path),
            dbus_interface=DBUS_INTERFACE_OBJECT_MANAGER)
    objects = dbus2primitive(object_manager.GetManagedObjects())
    logging.debug('Saw objects %r', objects)
    # Filter by interface.
    objects = [(path, interfaces)
               for path, interfaces in objects.iteritems()
               if dbus_interface in interfaces]
    if path_prefix is not None:
        objects = [(path, interfaces)
                   for path, interfaces in objects
                   if path.startswith(path_prefix)]
    objects = dict(objects)
    logging.debug('Filtered objects: %r', objects)
    return objects

def get_dbus_object(bus, service_name, object_manager_path, timeout=None):
    """Keeps trying to get the a DBus object until a timeout expires.
    Useful if a test should wait for a system daemon to start up.

    @param bus: dbus.Bus object.
    @param service_name: string service to look up (e.g. 'org.chromium.peerd').
    @param object_manager_path: string DBus path of object manager on remote
            service (e.g. '/org/chromium/peerd')
    @param timeout: maximum time in seconds to wait for the bus object.
    @return The DBus object or None if the timeout expired.

    """

    def try_get_object():
        try:
            return bus.get_object(service_name, object_manager_path)
        except dbus.exceptions.DBusException as e:
            # Only handle DBUS_ERROR_SERVICEUNKNOWN, which is thrown when the
            # service is not running yet. Otherwise, rethrow.
            if e.get_dbus_name() == DBUS_ERROR_SERVICEUNKNOWN:
                return None
            raise

    return utils.poll_for_condition(
            condition=try_get_object,
            desc='Get bus object "%s" / "%s"' % (service_name,
                                                 object_manager_path),
            timeout=timeout or 0)
