// -*- 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 <glibmm/object.h>
#include <glibmm/variant.h>
#include <glibmm/utility.h>
#ifdef G_OS_UNIX
# include <giomm/unixfdlist.h>
#endif

_DEFS(giomm,gio)
_PINCLUDE(glibmm/private/object_p.h)

namespace Gio
{

namespace DBus
{

_WRAP_ENUM(MessageType, GDBusMessageType, s#^DBUS_##, NO_GTYPE)
_WRAP_ENUM(MessageFlags, GDBusMessageFlags, s#^DBUS_##, NO_GTYPE)
_WRAP_ENUM(MessageHeaderField, GDBusMessageHeaderField, s#^DBUS_##, NO_GTYPE)
_WRAP_ENUM(CapabilityFlags, GDBusCapabilityFlags, s#^DBUS_##, NO_GTYPE)

_GMMPROC_EXTRA_NAMESPACE(DBus)

/** A type for representing D-Bus messages that can be sent or received on a
 * Connection.
 *
 * @newin{2,28}
 * @ingroup DBus
 */
class Message : public Glib::Object
{
  _CLASS_GOBJECT(Message, GDBusMessage, G_DBUS_MESSAGE, Glib::Object, GObject)

protected:
  _CTOR_DEFAULT
  _IGNORE(g_dbus_message_new)

public:
  _WRAP_METHOD_DOCS_ONLY(g_dbus_message_new)
  _WRAP_CREATE()

  // Note that we can't use _WRAP_CTOR() and _WRAP_CREATE() because the C functions do more than just call g_object_new():
  // See http://bugzilla.gnome.org/show_bug.cgi?id=624977

  // See here about whether the parameters should be ustring or std::string:
  // http://dbus.freedesktop.org/doc/dbus-specification.html#message-protocol-names
  // They are generally UTF-8 that can only contain the ASCII subset, 
  // so ustring still seems preferrable to std::string, which generally implies an unknown endoding for us.

  _WRAP_METHOD(static Glib::RefPtr<Message> create_signal(const Glib::ustring& path, const Glib::ustring& interface, const Glib::ustring& signal), g_dbus_message_new_signal)
  _WRAP_METHOD(static Glib::RefPtr<Message> create_method_call(const Glib::ustring& name, const Glib::ustring& path, const Glib::ustring& interface, const Glib::ustring& method), g_dbus_message_new_method_call)
  _WRAP_METHOD(static Glib::RefPtr<Message> create_method_reply(const Glib::RefPtr<Message>& method_call_message), g_dbus_message_new_method_reply)
  _WRAP_METHOD(static Glib::RefPtr<Message> create_method_error_literal(const Glib::RefPtr<const Message>& method_call_message, const Glib::ustring& error_name, const Glib::ustring& error_message), g_dbus_message_new_method_error_literal)


  _WRAP_METHOD(static Glib::RefPtr<Message> create_from_blob(const guchar* blob,  gsize blob_len, CapabilityFlags capabilities = CAPABILITY_FLAGS_NONE), g_dbus_message_new_from_blob, errthrow)


  _WRAP_METHOD(Glib::ustring print(guint indent), g_dbus_message_print)

  _WRAP_METHOD(bool get_locked() const, g_dbus_message_get_locked)
  _WRAP_METHOD(void lock() ,g_dbus_message_lock)
  _WRAP_METHOD(Glib::RefPtr<Message> copy() const, g_dbus_message_copy, errthrow)

  _WRAP_METHOD(MessageType get_message_type() const, g_dbus_message_get_message_type)
  _WRAP_METHOD(void set_message_type(MessageType type), g_dbus_message_set_message_type)

  //gmmproc can't handle the character literals, and this won't be expanded in future,
  //so we just wrap it by hand.
  enum ByteOrder
  {
    BYTE_ORDER_BIG_ENDIAN    = 'B',
    BYTE_ORDER_LITTLE_ENDIAN = 'l'
  };

  #m4 _CONVERSION(`ByteOrder',`GDBusMessageByteOrder',`(GDBusMessageByteOrder)($3)')
  #m4 _CONVERSION(`GDBusMessageByteOrder',`ByteOrder',`(ByteOrder)($3)')

  _WRAP_METHOD(ByteOrder get_byte_order() const, g_dbus_message_get_byte_order)
  _WRAP_METHOD(void set_byte_order(ByteOrder byte_order), g_dbus_message_set_byte_order)

  _WRAP_METHOD(guint32 get_serial() const, g_dbus_message_get_serial)
  _WRAP_METHOD(void set_serial(guint32 serial), g_dbus_message_set_serial)

  _WRAP_METHOD(MessageFlags get_flags() const, g_dbus_message_get_flags)
  _WRAP_METHOD(void set_flags(MessageFlags flags), g_dbus_message_set_flags)

  /** Gets the body of a message.  The body is returned in @a value.
   * @param value Location in which to store the header.
   */
  void get_body(Glib::VariantBase& value) const;
  _IGNORE(g_dbus_message_get_body)

  _WRAP_METHOD(void set_body(const Glib::VariantBase& body), g_dbus_message_set_body)

  _WRAP_METHOD(Glib::RefPtr<UnixFDList> get_unix_fd_list(), g_dbus_message_get_unix_fd_list, ifdef G_OS_UNIX)
  _WRAP_METHOD(Glib::RefPtr<const UnixFDList> get_unix_fd_list() const, g_dbus_message_get_unix_fd_list, constversion, ifdef G_OS_UNIX)
  _WRAP_METHOD(void set_unix_fd_list(const Glib::RefPtr<UnixFDList>& fd_list), g_dbus_message_set_unix_fd_list, ifdef G_OS_UNIX)

#ifdef G_OS_UNIX
  /** Clears the existing UNIX file descriptor list.
   */
  void unset_unix_fd_list();
#endif //G_OS_UNIX

  _WRAP_METHOD(guint32 get_num_unix_fds() const, g_dbus_message_get_num_unix_fds)
  _WRAP_METHOD(void set_num_unix_fds(guint32 value), g_dbus_message_set_num_unix_fds)

  //TODO: _WRAP_METHOD(std::vector<whattypeshallweuse>) get_header_fields() const, g_dbus_message_get_header_fields)

  /** Gets a header field on the message.  The header is returned in @a value.
   * @param value Location in which to store the header.
   * @param header_field The header field type.
   */
  void get_header(Glib::VariantBase& value, MessageHeaderField header_field) const;
  _IGNORE(g_dbus_message_get_header)

  _WRAP_METHOD(void set_header(MessageHeaderField header_field, const Glib::VariantBase& value), g_dbus_message_set_header)

  #m4 _CONVERSION(`guchar*',`Glib::ArrayHandle<guchar>',`Glib::ArrayHandle<guchar>($3)')
  _WRAP_METHOD(Glib::ArrayHandle<guchar> get_header_fields() const, g_dbus_message_get_header_fields)

  _WRAP_METHOD(Glib::ustring get_destination() const, g_dbus_message_get_destination)
  _WRAP_METHOD(void set_destination(const Glib::ustring& value), g_dbus_message_set_destination)

  _WRAP_METHOD(Glib::ustring get_error_name() const, g_dbus_message_get_error_name)
  _WRAP_METHOD(void set_error_name(const Glib::ustring& value), g_dbus_message_set_error_name)

  _WRAP_METHOD(Glib::ustring get_interface() const, g_dbus_message_get_interface)
  _WRAP_METHOD(void set_interface(const Glib::ustring& value), g_dbus_message_set_interface)

  _WRAP_METHOD(Glib::ustring get_member() const, g_dbus_message_get_member)
  _WRAP_METHOD(void set_member(const Glib::ustring& value), g_dbus_message_set_member)

  _WRAP_METHOD(Glib::ustring get_path() const, g_dbus_message_get_path)
  _WRAP_METHOD(void set_path(const Glib::ustring& value), g_dbus_message_set_path)

  _WRAP_METHOD(guint32 get_reply_serial() const, g_dbus_message_get_reply_serial)
  _WRAP_METHOD(void set_reply_serial(guint32 value), g_dbus_message_set_reply_serial)

  _WRAP_METHOD(Glib::ustring get_sender() const, g_dbus_message_get_sender)
  _WRAP_METHOD(void set_sender(const Glib::ustring& value), g_dbus_message_set_sender)

  _WRAP_METHOD(Glib::ustring get_signature() const, g_dbus_message_get_signature)
  _WRAP_METHOD(void set_signature(const Glib::ustring& value), g_dbus_message_set_signature)

  _WRAP_METHOD(Glib::ustring get_arg0() const, g_dbus_message_get_arg0)

  _WRAP_METHOD(static gssize bytes_needed(const guchar* blob, gsize blob_len), g_dbus_message_bytes_needed, errthrow)

  _WRAP_METHOD(guchar* to_blob(gsize& out_size, CapabilityFlags capabilities = CAPABILITY_FLAGS_NONE), g_dbus_message_to_blob, errthrow)

  _WRAP_METHOD(void to_exception(), g_dbus_message_to_gerror, errthrow)

  _WRAP_PROPERTY("locked", bool)
};

} //namespace DBus

} // namespace Gio
