#!/usr/bin/env python

import os
import dbus
import dbus.service
import dbus.glib # This as side effects, don't remove it!

from dbus.service import Object, BusName, method

from twisted.internet import glib2reactor
glib2reactor.install()
from twisted.internet import reactor

from landscape.lib.bpickle import loads
from landscape.lib.lock import lock_path, LockError
from landscape.reactor import TwistedReactor
from landscape.deployment import Configuration
from landscape.broker.amp import RemoteBrokerConnector


BUS_NAME = "com.canonical.landscape.Broker"
OBJECT_PATH = "/com/canonical/landscape/Broker"


def array_to_string(array):
    """Convert an L{Array} of L{Byte}s (or integers) to a Python str."""
    result = []
    for item in array:
        if item < 0:
            item = item + 256
        result.append(chr(item))
    return "".join(result)


class BrokerDBusObject(Object):
    """A DBus-published object proxing L{RemoteBroker.send_message}.

    It is used when upgrading from a DBus-based version of the Landscape client
    to the newer AMP-based one, for letting the old package-changer process
    performing the upgrade communicate with the new version of the client.
    """

    bus_name = BUS_NAME
    object_path = OBJECT_PATH

    def __init__(self, config):
        super(BrokerDBusObject, self).__init__(BusName(
            self.bus_name, dbus.SystemBus()), object_path=self.object_path)
        self.config = config

    @method(BUS_NAME)
    def send_message(self, message, urgent=True):
        """Queue the given message in the message exchange."""
        message = loads(array_to_string(message))

        def cb_connected(broker):
            result = broker.send_message(message, urgent=True)
            return result.addCallback(cb_done)

        def cb_done(ignored):
            return reactor.stop()

        twisted_reactor = TwistedReactor()
        connector = RemoteBrokerConnector(twisted_reactor, self.config)
        connected = connector.connect()
        connected.addCallback(cb_connected)


if __name__ == "__main__":
    config = Configuration()
    lock_dir = os.path.join(config.data_path, "package")
    if os.path.isdir(lock_dir):
        lock_filename = os.path.join(lock_dir, "changer.lock")
        try:
            lock_path(lock_filename)
        except LockError:
            # The package-changer is running, this means that we're upgrading from
            # a non-AMP version and that the upgrade is Landscape driven, so let's
            # expose the DBus broker proxy to give a chance to the package-changer
            # to send its result message.
            remote = BrokerDBusObject(config)
            reactor.run()
