// -*- Mode: C++; indent-tabs-mode: nil; c-basic-offset: 2 -*-

/* Copyright (C) 2010 The giomm Development Team
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free
 * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 */

#include <gio/gio.h>
#include <giomm/dbusauthobserver.h>
#include "slot_async.h"

namespace Gio
{

DBusConnection::DBusConnection(const Glib::RefPtr<IOStream>& stream,
  const Glib::ustring& guid, DBusConnectionFlags flags,
  const Glib::RefPtr<DBusAuthObserver>& observer,
  const SlotAsyncReady& slot,
  const Glib::RefPtr<Cancellable>& cancellable)
:
  _CONSTRUCT("stream", Glib::unwrap(stream),
    "guid", (guid.empty() ? 0 : guid.c_str()),
    "flags", static_cast<GDBusConnectionFlags>(flags),
    "authentication-observer", Glib::unwrap(observer))
{
  init_async(slot, cancellable);
}

DBusConnection::DBusConnection(const Glib::ustring& address,
  DBusConnectionFlags flags, const Glib::RefPtr<DBusAuthObserver>& observer,
  const SlotAsyncReady& slot,
  const Glib::RefPtr<Cancellable>& cancellable)
:
  _CONSTRUCT("address", (address.empty() ? 0 : address.c_str()),
    "flags", static_cast<GDBusConnectionFlags>(flags),
    "observer", Glib::unwrap(observer))
{
  init_async(slot, cancellable);
}

DBusConnection::DBusConnection(const Glib::RefPtr<IOStream>& stream,
  const Glib::ustring& guid, DBusConnectionFlags flags,
  const Glib::RefPtr<DBusAuthObserver>& observer,
  const Glib::RefPtr<Cancellable>& cancellable)
:
  _CONSTRUCT("stream", Glib::unwrap(stream),
    "guid", (guid.empty() ? 0 : guid.c_str()),
    "flags", static_cast<GDBusConnectionFlags>(flags),
    "authentication-observer", Glib::unwrap(observer))
{
  init(cancellable);
}

DBusConnection::DBusConnection(const Glib::ustring& address,
  DBusConnectionFlags flags, const Glib::RefPtr<DBusAuthObserver>& observer,
  const Glib::RefPtr<Cancellable>& cancellable)
:
  _CONSTRUCT("address", (address.empty() ? 0 : address.c_str()),
    "flags", static_cast<GDBusConnectionFlags>(flags),
    "observer", Glib::unwrap(observer))
{
  init(cancellable);
}

void DBusConnection::create(const Glib::RefPtr<IOStream>& stream,
  const Glib::ustring& guid, DBusConnectionFlags flags,
  const Glib::RefPtr<DBusAuthObserver>& observer,
  const SlotAsyncReady& slot,
  const Glib::RefPtr<Cancellable>& cancellable)
{
  // Note that this does not return anything, because it is async - see create_finish().

  // Create the connection, taking an extra reference without returning it.
  // The extra reference is taken so the connection is not destroyed when it
  // goes out of scope.  The finished connection will be returned in the slot
  // by calling create_finish().
  Glib::RefPtr<DBusConnection>(new DBusConnection(stream, guid, flags,
    observer, slot, cancellable))->reference();
}

Glib::RefPtr<DBusConnection> DBusConnection::create(
  const Glib::RefPtr<IOStream>& stream,
  const Glib::ustring& guid, DBusConnectionFlags flags,
  const Glib::RefPtr<DBusAuthObserver>& observer,
  const Glib::RefPtr<Cancellable>& cancellable)
{
  return Glib::RefPtr<DBusConnection>(new DBusConnection(stream, guid, flags,
    observer, cancellable));
}


void DBusConnection::create_for_address(const Glib::ustring& address,
  DBusConnectionFlags flags, const Glib::RefPtr<DBusAuthObserver>& observer,
  const SlotAsyncReady& slot,
  const Glib::RefPtr<Cancellable>& cancellable)
{
  // Note that this does not return anything, because it is async - see create_finish().

  // Create the connection, taking an extra reference without returning it.
  // The extra reference is taken so the connection is not destroyed when it
  // goes out of scope.  The finished connection will be returned in the slot
  // by calling create_finish().
  Glib::RefPtr<DBusConnection>(new DBusConnection(address, flags,
    observer, slot, cancellable))->reference();
}

Glib::RefPtr<DBusConnection> DBusConnection::create_for_address(
  const Glib::ustring& address,
  DBusConnectionFlags flags, const Glib::RefPtr<DBusAuthObserver>& observer,
  const Glib::RefPtr<Cancellable>& cancellable)
{
  return Glib::RefPtr<DBusConnection>(new DBusConnection(address, flags,
    observer, cancellable));
}

void DBusConnection::get(BusType bus_type, const SlotAsyncReady& slot,
  const Glib::RefPtr<Cancellable>& cancellable)
{
  SlotAsyncReady* slot_copy = new SlotAsyncReady(slot);

  g_bus_get(static_cast<GBusType>(bus_type), Glib::unwrap(cancellable),
    &SignalProxy_async_callback, slot_copy);
}


void DBusConnection::close()
{
  g_dbus_connection_close(gobj(), 0, 0, 0);
}

void DBusConnection::close(const SlotAsyncReady& slot, const Glib::RefPtr<Cancellable>& cancellable)
{
  SlotAsyncReady* slot_copy = new SlotAsyncReady(slot);

  g_dbus_connection_close(gobj(),
                    Glib::unwrap(cancellable),
                    &SignalProxy_async_callback,
                    slot_copy);
}

void DBusConnection::close(const SlotAsyncReady& slot)
{
  SlotAsyncReady* slot_copy = new SlotAsyncReady(slot);

  g_dbus_connection_close(gobj(),
                    0,
                    &SignalProxy_async_callback,
                    slot_copy);
}

void DBusConnection::close_sync()
{
  GError* gerror = 0;
  g_dbus_connection_close_sync(gobj(), 0, &(gerror));
  if(gerror)
    ::Glib::Error::throw_exception(gerror);
}

void DBusConnection::flush()
{
  g_dbus_connection_flush(gobj(), 0, 0, 0);
}

void DBusConnection::flush(const SlotAsyncReady& slot, const Glib::RefPtr<Cancellable>& cancellable)
{
  SlotAsyncReady* slot_copy = new SlotAsyncReady(slot);

  g_dbus_connection_flush(gobj(),
                    Glib::unwrap(cancellable),
                    &SignalProxy_async_callback,
                    slot_copy);
}

void DBusConnection::flush(const SlotAsyncReady& slot)
{
  SlotAsyncReady* slot_copy = new SlotAsyncReady(slot);

  g_dbus_connection_flush(gobj(),
                    0,
                    &SignalProxy_async_callback,
                    slot_copy);
}

void DBusConnection::flush_sync()
{
  GError* gerror = 0;
  g_dbus_connection_flush_sync(gobj(), 0, &(gerror));
  if(gerror)
    ::Glib::Error::throw_exception(gerror);
}

void DBusConnection::send_message_with_reply(const Glib::RefPtr<DBusMessage>& message, int timeout_msec,const SlotAsyncReady& slot, const Glib::RefPtr<Cancellable>& cancellable)
{
  SlotAsyncReady* slot_copy = new SlotAsyncReady(slot);
  volatile guint32 out_serial;
  g_dbus_connection_send_message_with_reply(gobj(), Glib::unwrap(message),
                                      static_cast<GDBusSendMessageFlags>(message->get_flags()),
                                      timeout_msec, &out_serial,
                                      Glib::unwrap(cancellable), &SignalProxy_async_callback,
                                      slot_copy);
  message->set_serial(out_serial);
}

} // namespace Gio
