// -*- 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 <giomm/dbusintrospection.h>
#include <giomm/dbusmethodinvocation.h>
#include <giomm/dbusconnection.h>
#include <giomm/dbuserror.h>
#include "slot_async.h"

namespace
{

extern "C"
{

static void DBusInterfaceVTable_MethodCall_giomm_callback(
  GDBusConnection* connection, const char* sender, const char* object_path,
  const char* interface_name, const char* method_name, GVariant* parameters,
  GDBusMethodInvocation* invocation, void* user_data)
{
  Gio::DBus::InterfaceVTable* vtable =
    static_cast<Gio::DBus::InterfaceVTable*>(user_data);

  Gio::DBus::InterfaceVTable::SlotInterfaceMethodCall* the_slot =
    vtable->get_slot_method_call();

  try
  {
    // Note that we use VariantContainerBase instead of VariantBase for the
    // GVariant, because it is documented as being a tuple (list of values).
    (*the_slot)(Glib::wrap(connection, true), (sender ? sender : ""),
      object_path, interface_name, method_name,
      Glib::VariantContainerBase(parameters, true), Glib::wrap(invocation, true));
  }
  catch(...)
  {
    Glib::exception_handlers_invoke();
  }
}

static GVariant* DBusInterfaceVTable_GetProperty_giomm_callback(
  GDBusConnection* connection, const char* sender, const char* object_path,
  const char* interface_name, const char* property_name, GError** error,
  void* user_data)
{
  Gio::DBus::InterfaceVTable* vtable =
    static_cast<Gio::DBus::InterfaceVTable*>(user_data);

  Gio::DBus::InterfaceVTable::SlotInterfaceGetProperty* the_slot =
    vtable->get_slot_get_property();

  try
  {
    Glib::VariantBase result;

    (*the_slot)(result, Glib::wrap(connection, true), sender, object_path,
      interface_name, property_name);
    return result.gobj_copy();
  }
  catch(const Glib::Error& ex)
  {
    if(error)
      *error = g_error_copy(ex.gobj());
  }
  catch(...)
  {
    Glib::exception_handlers_invoke();
  }

  return 0;
}

static gboolean DBusInterfaceVTable_SetProperty_giomm_callback(
  GDBusConnection* connection, const char* sender, const char* object_path,
  const char* interface_name, const char* property_name, GVariant* value,
  GError** error, void* user_data)
{
  Gio::DBus::InterfaceVTable* vtable =
    static_cast<Gio::DBus::InterfaceVTable*>(user_data);

  Gio::DBus::InterfaceVTable::SlotInterfaceSetProperty* the_slot =
    vtable->get_slot_set_property();

  try
  {
    return static_cast<gboolean>((*the_slot)(Glib::wrap(connection, true),
      sender, object_path, interface_name, property_name,
      Glib::VariantBase(value, true)));
  }
  catch(const Glib::Error& ex)
  {
    if(error)
      *error = g_error_copy(ex.gobj());
  }
  catch(...)
  {
    Glib::exception_handlers_invoke();
  }

  return false;
}

} // extern "C"

}

namespace Gio
{

namespace DBus
{

InterfaceVTable::InterfaceVTable(
  const SlotInterfaceMethodCall& slot_method_call,
  const SlotInterfaceGetProperty& slot_get_property,
  const SlotInterfaceSetProperty& slot_set_property
)
: slot_method_call_(new SlotInterfaceMethodCall(slot_method_call)),
  slot_get_property_(new SlotInterfaceGetProperty(slot_get_property)),
  slot_set_property_(new SlotInterfaceSetProperty(slot_set_property))
{
  gobject_.method_call = &DBusInterfaceVTable_MethodCall_giomm_callback;
  gobject_.get_property = &DBusInterfaceVTable_GetProperty_giomm_callback;
  gobject_.set_property = &DBusInterfaceVTable_SetProperty_giomm_callback;
}

InterfaceVTable::~InterfaceVTable()
{
  delete slot_method_call_;
  delete slot_get_property_;
  delete slot_set_property_;
}

InterfaceVTable::SlotInterfaceMethodCall*
  InterfaceVTable::get_slot_method_call() const
{
  return slot_method_call_;
}

InterfaceVTable::SlotInterfaceGetProperty*
  InterfaceVTable::get_slot_get_property() const
{
  return slot_get_property_;
}

InterfaceVTable::SlotInterfaceSetProperty*
  InterfaceVTable::get_slot_set_property() const
{
  return slot_set_property_;
}

} //namespace DBus

} // namespace Gio
