// -*- 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 <glibmm/exceptionhandler.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 char** DBusSubtreeVTable_Enumerate_giomm_callback(
  GDBusConnection* connection, const char* sender, const char* object_path,
  void* user_data)
{
  Gio::DBus::SubtreeVTable* vtable =
    static_cast<Gio::DBus::SubtreeVTable*>(user_data);

  Gio::DBus::SubtreeVTable::SlotSubtreeEnumerate* the_slot =
    vtable->get_slot_enumerate();

  try
  {
    auto result =
      (*the_slot)(Glib::wrap(connection, true), sender, object_path);

    // This will be freed by the caller.
    char** ret = g_new(char*, result.size());

    for(std::vector<Glib::ustring>::size_type i = 0; i < result.size(); i++)
    {
      ret[i] = g_strdup(result[i].c_str());
    }

    return ret;
  }
  catch(...)
  {
    Glib::exception_handlers_invoke();
  }

  return nullptr;
}

static GDBusInterfaceInfo** DBusSubtreeVTable_Introspect_giomm_callback(
  GDBusConnection* connection, const char* sender, const char* object_path,
  const char* node, void* user_data)
{
  Gio::DBus::SubtreeVTable* vtable =
    static_cast<Gio::DBus::SubtreeVTable*>(user_data);

  Gio::DBus::SubtreeVTable::SlotSubtreeIntrospect* the_slot =
    vtable->get_slot_introspect();

  try
  {
    auto result =
      (*the_slot)(Glib::wrap(connection, true), sender, object_path, node);

    // This will be freed by the caller, along with unreferencing its members.
    GDBusInterfaceInfo** info = g_new(GDBusInterfaceInfo*, result.size());

    for(std::vector< Glib::RefPtr<Gio::DBus::InterfaceInfo> >::size_type i = 0;
      i < result.size(); i++)
    {
      info[i] = static_cast<GDBusInterfaceInfo*>(
        g_object_ref(result[i]->gobj()));
    }

    return info;
  }
  catch(...)
  {
    Glib::exception_handlers_invoke();
  }

  return nullptr;
}

static const GDBusInterfaceVTable* DBusSubtreeVTable_Dispatch_giomm_callback(
  GDBusConnection* connection, const char* sender, const char* object_path,
  const char* interface_name, const char* node, void** out_user_data,
  void* user_data)
{
  Gio::DBus::SubtreeVTable* vtable_subtree =
    static_cast<Gio::DBus::SubtreeVTable*>(user_data);

  Gio::DBus::SubtreeVTable::SlotSubtreeDispatch* the_slot =
    vtable_subtree->get_slot_dispatch();

  try
  {
    const Gio::DBus::InterfaceVTable* vtable_iface =
      (*the_slot)(Glib::wrap(connection, true), sender, object_path,
      interface_name, (node ? node : ""));

    *out_user_data = const_cast<Gio::DBus::InterfaceVTable*>(vtable_iface);

    return vtable_iface->gobj();
  }
  catch(...)
  {
    Glib::exception_handlers_invoke();
  }

  return nullptr;
}

} // extern "C"

}

namespace Gio
{

namespace DBus
{


SubtreeVTable::SubtreeVTable(
  const SlotSubtreeEnumerate& slot_enumerate,
  const SlotSubtreeIntrospect& slot_introspect,
  const SlotSubtreeDispatch& slot_dispatch
)
: slot_enumerate_(new SlotSubtreeEnumerate(slot_enumerate)),
  slot_introspect_(new SlotSubtreeIntrospect(slot_introspect)),
  slot_dispatch_(new SlotSubtreeDispatch(slot_dispatch))
{
  gobject_.enumerate = &DBusSubtreeVTable_Enumerate_giomm_callback;
  gobject_.introspect = &DBusSubtreeVTable_Introspect_giomm_callback;
  gobject_.dispatch = &DBusSubtreeVTable_Dispatch_giomm_callback;
}

SubtreeVTable::SubtreeVTable(SubtreeVTable&& other) noexcept
: gobject_(std::move(other.gobject_)),
  slot_enumerate_(std::move(other.slot_enumerate_)),
  slot_introspect_(std::move(other.slot_introspect_)),
  slot_dispatch_(std::move(other.slot_dispatch_))
{
  other.slot_enumerate_ = nullptr;
  other.slot_introspect_ = nullptr;
  other.slot_dispatch_ = nullptr;
}

SubtreeVTable& SubtreeVTable::operator=(SubtreeVTable&& other) noexcept
{
  delete slot_enumerate_;
  delete slot_introspect_;
  delete slot_dispatch_;

  gobject_ = std::move(other.gobject_);
  slot_enumerate_ = std::move(other.slot_enumerate_);
  slot_introspect_ = std::move(other.slot_introspect_);
  slot_dispatch_ = std::move(other.slot_dispatch_);

  other.slot_enumerate_ = nullptr;
  other.slot_introspect_ = nullptr;
  other.slot_dispatch_ = nullptr;

  return *this;
}

SubtreeVTable::~SubtreeVTable()
{
  delete slot_enumerate_;
  delete slot_introspect_;
  delete slot_dispatch_;
}

SubtreeVTable::SlotSubtreeEnumerate*
  SubtreeVTable::get_slot_enumerate() const
{
  return slot_enumerate_;
}

SubtreeVTable::SlotSubtreeIntrospect*
  SubtreeVTable::get_slot_introspect() const
{
  return slot_introspect_;
}

SubtreeVTable::SlotSubtreeDispatch*
  SubtreeVTable::get_slot_dispatch() const
{
  return slot_dispatch_;
}

} //namespace DBus

} // namespace Gio
