/* -*- Mode: C; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
 *  Copyright (C) 2009 Hiroyuki Ikezoe
 *
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 2, or (at your option)
 *  any later version.
 *
 *  This program 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 General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 */

#ifdef HAVE_CONFIG_H
#include "config.h"
#endif /* HAVE_CONFIG_H */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <unistd.h>
#include <gtk/gtk.h>
#include <glib/gi18n.h>
#include <dbus/dbus-glib.h>
#include <dbus/dbus-glib-bindings.h>

#include "kz-embed.h"
#include "kz-dbus-embed-delegate.h"
#include "kz-dbus-embed-client-bindings.h"
#include "kz-marshalers.h"

#define KZ_TYPE_EMBED_PROCESS		       (kz_embed_process_get_type ())

enum {
    PROP_0,
    PROP_SOCKET_ADDRESS
};

enum {
    LOCATION,
    TITLE,
    NET_START,
    NET_STOP,
    PROGRESS,
    LINK_MESSAGE,
    DOM_MOUSE_DOWN,
    DOM_MOUSE_UP,
    DOM_MOUSE_CLICK,
    DOM_MOUSE_OVER,
    LAST_SIGNAL
};

static gint signals[LAST_SIGNAL] = {0};

typedef struct _KzEmbedProcess KzEmbedProcess;
typedef struct _KzEmbedProcessClass KzEmbedProcessClass;

struct _KzEmbedProcess
{
    GObject parent;
};

struct _KzEmbedProcessClass
{
    GObjectClass parent;
};

typedef struct _KzEmbedProcessPrivate	KzEmbedProcessPrivate;
struct _KzEmbedProcessPrivate
{
    KzEmbed *embed;
    DBusGProxy *proxy;
    DBusGConnection *connection;
    guint32 embed_id;
    gchar *socket_address;
};

#define KZ_EMBED_PROCESS_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), KZ_TYPE_EMBED_PROCESS, KzEmbedProcessPrivate))

GType        kz_embed_process_get_type (void) G_GNUC_CONST;
static GObject *constructor  (GType type,
                              guint n_props,
                              GObjectConstructParam *props);
static void  dispose      (GObject      *object);
static void  finalize     (GObject      *object);
static void  set_property (GObject      *object,
                           guint         prop_id,
                           const GValue *value,
                           GParamSpec   *pspec);
static void  get_property (GObject      *object,
                           guint         prop_id,
                           GValue       *value,
                           GParamSpec   *pspec);

static gboolean kz_embed_process_stop_load (KzEmbedProcess *object, GError **error);
static gboolean kz_embed_process_reload (KzEmbedProcess *object, GError **error);
static gboolean kz_embed_process_load_uri (KzEmbedProcess *object, const gchar *uri, GError **error);
static gboolean kz_embed_process_go_back (KzEmbedProcess *object, GError **error);
static gboolean kz_embed_process_go_forward (KzEmbedProcess *object, GError **error);
static gboolean kz_embed_process_can_go_back (KzEmbedProcess *object, gboolean *possible, GError **error);
static gboolean kz_embed_process_can_go_forward (KzEmbedProcess *object, gboolean *possible, GError **error);
static gboolean kz_embed_process_paste (KzEmbedProcess *object, GError **error);
static gboolean kz_embed_process_copy (KzEmbedProcess *object, GError **error);
static gboolean kz_embed_process_cut (KzEmbedProcess *object, GError **error);
static gboolean kz_embed_process_can_copy_selection (KzEmbedProcess *object, gboolean *possible, GError **error);
static gboolean kz_embed_process_can_cut_selection (KzEmbedProcess *object, gboolean *possible, GError **error);
static gboolean kz_embed_process_can_paste (KzEmbedProcess *object, gboolean *possible, GError **error);
static gboolean kz_embed_process_find (KzEmbedProcess *object, const gchar *keyword, gboolean backward, gboolean *found, GError **error);
static gboolean kz_embed_process_zoom (KzEmbedProcess *object, gdouble ratio, GError **error);
static gboolean kz_embed_process_get_history  (KzEmbedProcess *object,
                                               gchar ***titles,
                                               gchar ***uris,
                                               guint *current_position,
                                               GError **error);
static gboolean kz_embed_process_set_history  (KzEmbedProcess *object,
                                               const gchar **titles,
                                               const gchar **uris,
                                               guint current_position,
                                               GError **error);
static gboolean kz_embed_process_set_encoding (KzEmbedProcess *object,
                                               const gchar *encoding,
                                               GError **error);
static gboolean kz_embed_process_get_encoding (KzEmbedProcess *object,
                                               gchar **encoding,
                                               GError **error);

#include "kz-embed-process-server-bindings.h"

G_DEFINE_TYPE(KzEmbedProcess, kz_embed_process, G_TYPE_OBJECT);

static void
kz_embed_process_class_init (KzEmbedProcessClass *klass)
{
	GObjectClass *object_class;

    object_class = G_OBJECT_CLASS(klass);
    object_class->constructor = constructor;
    object_class->dispose = dispose;
    object_class->finalize = finalize;
    object_class->set_property = set_property;
    object_class->get_property = get_property;

    g_object_class_install_property
        (object_class,
         PROP_SOCKET_ADDRESS,
         g_param_spec_string("socket-address",
             _("Socket Address"),
             _("The address for comunicate KzDBusServer"),
             NULL,
             G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));

    signals[LOCATION] = g_signal_new("location",
                                     G_TYPE_FROM_CLASS(klass),
                                     G_SIGNAL_RUN_LAST,
                                     0,
                                     NULL, NULL,
                                     g_cclosure_marshal_VOID__STRING,
                                     G_TYPE_NONE, 1,
                                     G_TYPE_STRING);
    signals[TITLE] = g_signal_new("title",
                                  G_TYPE_FROM_CLASS(klass),
                                  G_SIGNAL_RUN_LAST,
                                  0,
                                  NULL, NULL,
                                  g_cclosure_marshal_VOID__STRING,
                                  G_TYPE_NONE, 1,
                                  G_TYPE_STRING);
    signals[NET_START] = g_signal_new("net-start",
                                      G_TYPE_FROM_CLASS(klass),
                                      G_SIGNAL_RUN_LAST,
                                      0,
                                      NULL, NULL,
                                      g_cclosure_marshal_VOID__VOID,
                                      G_TYPE_NONE, 0,
                                      G_TYPE_NONE);
    signals[NET_STOP] = g_signal_new("net-stop",
                                      G_TYPE_FROM_CLASS(klass),
                                      G_SIGNAL_RUN_LAST,
                                      0,
                                      NULL, NULL,
                                      g_cclosure_marshal_VOID__VOID,
                                      G_TYPE_NONE, 0,
                                      G_TYPE_NONE);
    signals[PROGRESS] = g_signal_new("progress",
                                      G_TYPE_FROM_CLASS(klass),
                                      G_SIGNAL_RUN_LAST,
                                      0,
                                      NULL, NULL,
                                      g_cclosure_marshal_VOID__DOUBLE,
                                      G_TYPE_NONE, 1,
                                      G_TYPE_DOUBLE);
    signals[LINK_MESSAGE] = g_signal_new("link-message",
                                         G_TYPE_FROM_CLASS(klass),
                                         G_SIGNAL_RUN_LAST,
                                         0,
                                         NULL, NULL,
                                         g_cclosure_marshal_VOID__STRING,
                                         G_TYPE_NONE, 1,
                                         G_TYPE_STRING);
    signals[DOM_MOUSE_DOWN] = g_signal_new("dom-mouse-down",
                                           G_TYPE_FROM_CLASS(klass),
                                           G_SIGNAL_RUN_LAST,
                                           0,
                                           NULL, NULL,
                                           _kz_marshal_VOID__INT_STRING_STRING_STRING_STRING_INT_INT_INT_INT,
                                           G_TYPE_NONE, 9,
                                           G_TYPE_INT,
                                           G_TYPE_STRING,
                                           G_TYPE_STRING,
                                           G_TYPE_STRING,
                                           G_TYPE_STRING,
                                           G_TYPE_INT,
                                           G_TYPE_INT,
                                           G_TYPE_INT,
                                           G_TYPE_INT);
    signals[DOM_MOUSE_UP] = g_signal_new("dom-mouse-up",
                                           G_TYPE_FROM_CLASS(klass),
                                           G_SIGNAL_RUN_LAST,
                                           0,
                                           NULL, NULL,
                                           _kz_marshal_VOID__INT_STRING_STRING_STRING_STRING_INT_INT_INT_INT,
                                           G_TYPE_NONE, 9,
                                           G_TYPE_INT,
                                           G_TYPE_STRING,
                                           G_TYPE_STRING,
                                           G_TYPE_STRING,
                                           G_TYPE_STRING,
                                           G_TYPE_INT,
                                           G_TYPE_INT,
                                           G_TYPE_INT,
                                           G_TYPE_INT);
    signals[DOM_MOUSE_CLICK] = g_signal_new("dom-mouse-click",
                                           G_TYPE_FROM_CLASS(klass),
                                           G_SIGNAL_RUN_LAST,
                                           0,
                                           NULL, NULL,
                                           _kz_marshal_VOID__INT_STRING_STRING_STRING_STRING_INT_INT_INT_INT,
                                           G_TYPE_NONE, 9,
                                           G_TYPE_INT,
                                           G_TYPE_STRING,
                                           G_TYPE_STRING,
                                           G_TYPE_STRING,
                                           G_TYPE_STRING,
                                           G_TYPE_INT,
                                           G_TYPE_INT,
                                           G_TYPE_INT,
                                           G_TYPE_INT);
    signals[DOM_MOUSE_OVER] = g_signal_new("dom-mouse-over",
                                           G_TYPE_FROM_CLASS(klass),
                                           G_SIGNAL_RUN_LAST,
                                           0,
                                           NULL, NULL,
                                           _kz_marshal_VOID__INT_STRING_STRING_STRING_STRING_INT_INT_INT_INT,
                                           G_TYPE_NONE, 9,
                                           G_TYPE_INT,
                                           G_TYPE_STRING,
                                           G_TYPE_STRING,
                                           G_TYPE_STRING,
                                           G_TYPE_STRING,
                                           G_TYPE_INT,
                                           G_TYPE_INT,
                                           G_TYPE_INT,
                                           G_TYPE_INT);

    dbus_g_object_type_install_info(KZ_TYPE_EMBED_PROCESS, &dbus_glib_kz_embed_process_object_info);
	g_type_class_add_private(object_class, sizeof(KzEmbedProcessPrivate));
}

static void
cb_net_stop (KzEmbed *embed, KzEmbedProcess *process)
{
    g_signal_emit(process, signals[NET_STOP], 0);
}

static void
cb_net_start (KzEmbed *embed, KzEmbedProcess *process)
{
    g_signal_emit(process, signals[NET_START], 0);
}

static void
cb_title (KzEmbed *embed, const gchar *title, KzEmbedProcess *process)
{
    g_signal_emit(process, signals[TITLE], 0, title);
}

static void
cb_location (KzEmbed *embed, const gchar *location, KzEmbedProcess *process)
{
    g_signal_emit(process, signals[LOCATION], 0, location);
}

static void
cb_progress (KzEmbed *embed, gdouble progress, KzEmbedProcess *process)
{
    g_signal_emit(process, signals[PROGRESS], 0, progress);
}

static void
cb_link_message (KzEmbed *embed, const gchar *message, KzEmbedProcess *process)
{
    g_signal_emit(process, signals[LINK_MESSAGE], 0, message);
}

static void
setup_embed_signals (KzEmbedProcess *process)
{
    KzEmbedProcessPrivate *priv = KZ_EMBED_PROCESS_GET_PRIVATE(process);

    g_signal_connect(priv->embed, "kz-title", G_CALLBACK(cb_title), process);
    g_signal_connect(priv->embed, "kz-location", G_CALLBACK(cb_location), process);
    g_signal_connect(priv->embed, "kz-net-start", G_CALLBACK(cb_net_start), process);
    g_signal_connect(priv->embed, "kz-net-stop", G_CALLBACK(cb_net_stop), process);
    g_signal_connect(priv->embed, "kz-progress", G_CALLBACK(cb_progress), process);
    g_signal_connect(priv->embed, "kz-link-message", G_CALLBACK(cb_link_message), process);
}

#define DEFINE_DOM_MOUSE_EVENT(type)                                            \
static gboolean                                                                 \
cb_ ## type (KzEmbed *embed, KzEmbedEventMouse *event, KzEmbedProcess *process) \
{                                                                               \
g_print(#type "\n");\
    g_signal_emit_by_name(process, #type,                                       \
                          event->cinfo.context,                                 \
                          event->cinfo.link,                                    \
                          event->cinfo.linktext,                                \
                          event->cinfo.img,                                     \
                          event->cinfo.frame_src,                               \
                          event->button,                                        \
                          event->modifier,                                      \
                          event->x,                                             \
                          event->y);                                            \
    return FALSE;                                                               \
}

DEFINE_DOM_MOUSE_EVENT(dom_mouse_down)
DEFINE_DOM_MOUSE_EVENT(dom_mouse_up)
DEFINE_DOM_MOUSE_EVENT(dom_mouse_click)
DEFINE_DOM_MOUSE_EVENT(dom_mouse_over)

static void
connect_embed_dom_signals (KzEmbedProcess *process)
{
    KzEmbedProcessPrivate *priv = KZ_EMBED_PROCESS_GET_PRIVATE(process);

    g_signal_connect(priv->embed, "kz-dom-mouse-down", G_CALLBACK(cb_dom_mouse_down), process);
    g_signal_connect(priv->embed, "kz-dom-mouse-up", G_CALLBACK(cb_dom_mouse_up), process);
    g_signal_connect(priv->embed, "kz-dom-mouse-click", G_CALLBACK(cb_dom_mouse_click), process);
    g_signal_connect(priv->embed, "kz-dom-mouse-over", G_CALLBACK(cb_dom_mouse_over), process);
}

static void
disconnect_embed_dom_signals (KzEmbedProcess *process)
{
    KzEmbedProcessPrivate *priv = KZ_EMBED_PROCESS_GET_PRIVATE(process);

    g_signal_handlers_disconnect_by_func(priv->embed, G_CALLBACK(cb_dom_mouse_down), process);
    g_signal_handlers_disconnect_by_func(priv->embed, G_CALLBACK(cb_dom_mouse_up), process);
    g_signal_handlers_disconnect_by_func(priv->embed, G_CALLBACK(cb_dom_mouse_click), process);
    g_signal_handlers_disconnect_by_func(priv->embed, G_CALLBACK(cb_dom_mouse_over), process);
}

static gboolean
cb_visibility_notify (GtkWidget *widget, GdkEventVisibility *event, KzEmbedProcess *process)
{
    if (event->state == GDK_VISIBILITY_FULLY_OBSCURED)
        disconnect_embed_dom_signals(process);
    else
        connect_embed_dom_signals(process);
    return FALSE;
}

static gboolean
create_widget (KzEmbedProcess *object,
               guint32 embed_id,
               const gchar *engine_name)
{
    KzEmbedProcessPrivate *priv = KZ_EMBED_PROCESS_GET_PRIVATE(object);
    GtkWidget *plug;

    priv = KZ_EMBED_PROCESS_GET_PRIVATE(object);
    priv->embed_id = embed_id;

    plug = gtk_plug_new(embed_id);

    priv->embed = KZ_EMBED(kz_embed_new(engine_name, engine_name));
    gtk_container_add(GTK_CONTAINER(plug), GTK_WIDGET(priv->embed));
    gtk_widget_show(GTK_WIDGET(priv->embed));
    gtk_widget_show(plug);

    g_signal_connect(plug, "visibility-notify-event", G_CALLBACK(cb_visibility_notify), object);

    setup_embed_signals(object);

    return TRUE;
}

static gboolean
kz_embed_process_load_uri (KzEmbedProcess *object, const gchar *uri, GError **error)
{
    KzEmbedProcessPrivate *priv = KZ_EMBED_PROCESS_GET_PRIVATE(object);

    kz_embed_load_uri(priv->embed, uri);

    return TRUE;
}

static gboolean
kz_embed_process_stop_load (KzEmbedProcess *object, GError **error)
{
    KzEmbedProcessPrivate *priv = KZ_EMBED_PROCESS_GET_PRIVATE(object);

    kz_embed_stop_load(priv->embed);

    return TRUE;
}

static gboolean
kz_embed_process_reload (KzEmbedProcess *object, GError **error)
{
    KzEmbedProcessPrivate *priv = KZ_EMBED_PROCESS_GET_PRIVATE(object);

    kz_embed_reload(priv->embed, KZ_EMBED_RELOAD_NORMAL);

    return TRUE;
}

static gboolean
kz_embed_process_go_forward (KzEmbedProcess *object, GError **error)
{
    KzEmbedProcessPrivate *priv = KZ_EMBED_PROCESS_GET_PRIVATE(object);

    kz_embed_go_forward(priv->embed);

    return TRUE;
}

static gboolean
kz_embed_process_go_back (KzEmbedProcess *object, GError **error)
{
    KzEmbedProcessPrivate *priv = KZ_EMBED_PROCESS_GET_PRIVATE(object);

    kz_embed_go_back(priv->embed);

    return TRUE;
}

static gboolean
kz_embed_process_can_go_back (KzEmbedProcess *object, gboolean *possible, GError **error)
{
    KzEmbedProcessPrivate *priv = KZ_EMBED_PROCESS_GET_PRIVATE(object);

    *possible = kz_embed_can_go_back(priv->embed);

    return TRUE;
}

static gboolean
kz_embed_process_can_go_forward (KzEmbedProcess *object, gboolean *possible, GError **error)
{
    KzEmbedProcessPrivate *priv = KZ_EMBED_PROCESS_GET_PRIVATE(object);

    *possible = kz_embed_can_go_forward(priv->embed);

    return TRUE;
}

static gboolean
kz_embed_process_paste (KzEmbedProcess *object, GError **error)
{
    KzEmbedProcessPrivate *priv = KZ_EMBED_PROCESS_GET_PRIVATE(object);

    kz_embed_paste(priv->embed);

    return TRUE;
}

static gboolean
kz_embed_process_cut (KzEmbedProcess *object, GError **error)
{
    KzEmbedProcessPrivate *priv = KZ_EMBED_PROCESS_GET_PRIVATE(object);

    kz_embed_cut_selection(priv->embed);

    return TRUE;
}

static gboolean
kz_embed_process_copy (KzEmbedProcess *object, GError **error)
{
    KzEmbedProcessPrivate *priv = KZ_EMBED_PROCESS_GET_PRIVATE(object);

    kz_embed_copy_selection(priv->embed);

    return TRUE;
}

static gboolean
kz_embed_process_can_copy_selection (KzEmbedProcess *object, gboolean *possible, GError **error)
{
    KzEmbedProcessPrivate *priv = KZ_EMBED_PROCESS_GET_PRIVATE(object);

    *possible = kz_embed_can_copy_selection(priv->embed);

    return TRUE;
}

static gboolean
kz_embed_process_can_cut_selection (KzEmbedProcess *object, gboolean *possible, GError **error)
{
    KzEmbedProcessPrivate *priv = KZ_EMBED_PROCESS_GET_PRIVATE(object);

    *possible = kz_embed_can_cut_selection(priv->embed);

    return TRUE;
}

static gboolean
kz_embed_process_can_paste (KzEmbedProcess *object, gboolean *possible, GError **error)
{
    KzEmbedProcessPrivate *priv = KZ_EMBED_PROCESS_GET_PRIVATE(object);

    *possible = kz_embed_can_cut_selection(priv->embed);

    return TRUE;
}

static gboolean
kz_embed_process_zoom (KzEmbedProcess *object, gdouble ratio, GError **error)
{
    KzEmbedProcessPrivate *priv = KZ_EMBED_PROCESS_GET_PRIVATE(object);

    kz_embed_zoom(priv->embed, ratio);

    return TRUE;
}

static gboolean
kz_embed_process_find (KzEmbedProcess *object, const gchar *keyword, gboolean backward, gboolean *found, GError **error)
{
    KzEmbedProcessPrivate *priv = KZ_EMBED_PROCESS_GET_PRIVATE(object);

    *found = kz_embed_find(priv->embed, keyword, backward);

    return TRUE;
}

static gboolean
kz_embed_process_get_history (KzEmbedProcess *object,
                              gchar ***titles,
                              gchar ***uris,
                              guint *current_position,
                              GError **error)
{
    KzEmbedProcessPrivate *priv = KZ_EMBED_PROCESS_GET_PRIVATE(object);
	GList *node;
    GList *history = NULL;
    gint i, n_children;
    gchar **ret_titles = NULL;
    gchar **ret_uris = NULL;

    kz_embed_get_history(priv->embed, &history, current_position);

    n_children = g_list_length(history);

    ret_titles = g_new0(gchar*, n_children + 1);
    ret_uris = g_new0(gchar*, n_children + 1);
    for (node = g_list_first(history), i = 0; node; node = g_list_next(node), i++) {
        KzSite *site = (KzSite*)(node->data);
        ret_titles[i] = g_strdup(site->title);
        ret_uris[i] = g_strdup(site->uri);
    }

    *titles = ret_titles;
    *uris = ret_uris;
    kz_site_list_free(history);

    return TRUE;
}

static gboolean
kz_embed_process_set_history (KzEmbedProcess *object,
                              const gchar **titles,
                              const gchar **uris,
                              guint current_position,
                              GError **error)
{
    KzEmbedProcessPrivate *priv = KZ_EMBED_PROCESS_GET_PRIVATE(object);
    gint i, n_children = 0;
    GList *history = NULL;

    if (titles)
        n_children = g_strv_length((gchar **)titles);
    for (i = 0; i < n_children; i++) {
        KzSite *site;

        site = kz_site_new(titles[i], uris[i]);
        history = g_list_append(history, site);
    }
    kz_embed_set_history(priv->embed, history, current_position);
    kz_site_list_free(history);

    return TRUE;
}

static gboolean
kz_embed_process_set_encoding (KzEmbedProcess *object, const gchar *encoding, GError **error)
{
    KzEmbedProcessPrivate *priv = KZ_EMBED_PROCESS_GET_PRIVATE(object);

    kz_embed_set_encoding(priv->embed, encoding);

    return TRUE;
}

static gboolean
kz_embed_process_get_encoding (KzEmbedProcess *object, gchar **encoding, GError **error)
{
    KzEmbedProcessPrivate *priv = KZ_EMBED_PROCESS_GET_PRIVATE(object);
    gboolean forced = FALSE;

    kz_embed_get_encoding(priv->embed, encoding, &forced);

    return TRUE;
}

static void
setup_dbus (GObject *object)
{
    GError *error = NULL;
    KzEmbedProcessPrivate *priv;
    guint32 embed_id;
    gchar *engine_name = NULL;

    priv = KZ_EMBED_PROCESS_GET_PRIVATE(object);

    priv->connection = dbus_g_connection_open(priv->socket_address, &error);
    if (error) {
        g_print("Error:%s\n", error->message);
        g_error_free(error);
    } 

    dbus_g_connection_register_g_object(priv->connection,
                                        KZ_EMBED_PROCESS_PATH,
                                        object);
    priv->proxy = dbus_g_proxy_new_for_peer(priv->connection,
                                            KZ_DBUS_EMBED_DELEGATE_PATH,
                                            KZ_DBUS_EMBED_DELEGATE_INTERFACE);
    if (!org_kazehakase_Embed_Delegate_ready(priv->proxy, getpid(), &embed_id, &engine_name, &error)) {
        g_print("%s\n", error->message);
        g_error_free(error);
    }
    create_widget((KzEmbedProcess *)object, embed_id, engine_name);
}

static void
dispose (GObject *object)
{
    KzEmbedProcessPrivate *priv = KZ_EMBED_PROCESS_GET_PRIVATE(object);

    if (priv->proxy) {
        g_object_unref(priv->proxy);
        priv->proxy = NULL;
    }
    if (priv->connection) {
        dbus_g_connection_unref(priv->connection);
        priv->connection = NULL;
    }

    if (G_OBJECT_CLASS(kz_embed_process_parent_class)->dispose)
        G_OBJECT_CLASS(kz_embed_process_parent_class)->dispose(object);
}

static void
finalize (GObject *object)
{
    KzEmbedProcessPrivate *priv = KZ_EMBED_PROCESS_GET_PRIVATE(object);

    g_free(priv->socket_address);

    if (G_OBJECT_CLASS(kz_embed_process_parent_class)->finalize)
        G_OBJECT_CLASS(kz_embed_process_parent_class)->finalize(object);
}

static void
set_property (GObject         *object,
              guint            prop_id,
              const GValue    *value,
              GParamSpec      *pspec)
{
    KzEmbedProcessPrivate *priv = KZ_EMBED_PROCESS_GET_PRIVATE(object);

    switch (prop_id)
    {
    case PROP_SOCKET_ADDRESS:
        priv->socket_address = g_value_dup_string(value);
        break;
    default:
        G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
        break;
    }
}


static void
get_property (GObject         *object,
              guint            prop_id,
              GValue          *value,
              GParamSpec      *pspec)
{
    KzEmbedProcessPrivate *priv = KZ_EMBED_PROCESS_GET_PRIVATE(object);

    switch (prop_id)
    {
    case PROP_SOCKET_ADDRESS:
        g_value_set_string(value, priv->socket_address);
        break;
    default:
        G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
        break;
    }
}

static GObject*
constructor (GType                  type,
             guint                  n_props,
             GObjectConstructParam *props)
{
	GObject *object;
	GObjectClass *klass = G_OBJECT_CLASS(kz_embed_process_parent_class);

	object = klass->constructor(type, n_props, props);

    setup_dbus(object);

	return object;
}

static void
kz_embed_process_init (KzEmbedProcess *object)
{
    KzEmbedProcessPrivate *priv = KZ_EMBED_PROCESS_GET_PRIVATE(object);

    priv->embed_id = 0;
    priv->embed = NULL;
    priv->socket_address = NULL;
}

static KzEmbedProcess *
kz_embed_process_new (const gchar *socket_address)
{
    return g_object_new(KZ_TYPE_EMBED_PROCESS,
                        "socket-address", socket_address,
                        NULL);
}

int
main (int argc, char *argv[])
{
    KzApp *app;
    KzEmbedProcess *process;

    if (argc < 2)
        exit(EXIT_FAILURE);

    if (!g_thread_supported()) g_thread_init(NULL);
    dbus_g_thread_init();

    gtk_init(&argc, &argv);

    /* We need KzApp to obtain the directory in which embed modules is stored */
    app = kz_app_new(argc, argv);
    process = kz_embed_process_new(argv[1]);

    gtk_main();

    g_object_unref(process);
    g_object_unref(app);

    exit(EXIT_SUCCESS);
}

/* 
vi:ts=4:nowrap:ai:expandtab:sw=4
*/
