/* -*- c-file-style: "ruby"; indent-tabs-mode: nil -*- */

/*
 *  Copyright (C) 2007 Kouhei Sutou <kou@cozmixng.org>
 *
 *  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.
 */

#include <stdio.h>
#include <glib/gi18n.h>
#include "kz-rb-ext.h"

#include "kz-ext.h"
#include "kz-module-impl.h"

enum {
    PROP_0,
    PROP_INITIAL_ADDRESS
};

#define KZ_TYPE_RUBY_EXT		kz_type_ruby_ext
#define KZ_RUBY_EXT(obj)		(G_TYPE_CHECK_INSTANCE_CAST ((obj), KZ_TYPE_RUBY_EXT, KzRubyExt))
#define KZ_RUBY_EXT_CLASS(klass)	(G_TYPE_CHECK_CLASS_CAST ((klass), KZ_TYPE_RUBY_EXT, KzRubyExtClass))
#define KZ_IS_RUBY_EXT(obj)	(G_TYPE_CHECK_INSTANCE_TYPE ((obj), KZ_TYPE_RUBY_EXT))
#define KZ_IS_RUBY_EXT_CLASS(klass)	(G_TYPE_CHECK_CLASS_TYPE ((klass), KZ_TYPE_RUBY_EXT))
#define KZ_RUBY_EXT_GET_CLASS(obj)	(G_TYPE_INSTANCE_GET_CLASS ((obj), KZ_TYPE_RUBY_EXT, KzRubyExtClass))

typedef struct _KzRubyExt		KzRubyExt;
typedef struct _KzRubyExtClass		KzRubyExtClass;

struct _KzRubyExt
{
    GObject	parent;

    gpointer	initial_address;
};

struct _KzRubyExtClass
{
    GObjectClass parent_class;
};

static GType kz_type_ruby_ext = 0;
static GObjectClass *kz_ruby_ext_parent_class;

static void kz_ruby_ext_class_init	(KzRubyExtClass *klass);
static void kz_ruby_ext_iface_init	(KzExtIFace	*iface);

static void setup (KzExt *ext, KzWindow *window);

static void     dispose      (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 void
kz_ruby_ext_register_type (GTypeModule *module)
{
    static const GTypeInfo kz_ruby_ext_info =
	{
            sizeof (KzRubyExtClass),
            NULL,		/* base_init */
            NULL,		/* base_finalize */
            (GClassInitFunc) kz_ruby_ext_class_init,
            NULL,		/* class_finalize */
            NULL,		/* class_data */
            sizeof (KzRubyExt),
            0,		/* n_preallocs */
            NULL,
	};

    const GInterfaceInfo kz_ext_info =
	{
            (GInterfaceInitFunc) kz_ruby_ext_iface_init,
            NULL,
            NULL
	};

    kz_type_ruby_ext = g_type_module_register_type(module,
                                                   G_TYPE_OBJECT,
                                                   "KzRubyExt",
                                                   &kz_ruby_ext_info,
                                                   (GTypeFlags)0);

    g_type_module_add_interface(module,
                                KZ_TYPE_RUBY_EXT,
                                KZ_TYPE_EXT,
                                &kz_ext_info);
}

G_MODULE_EXPORT void
KZ_MODULE_IMPL_INIT (GTypeModule *module)
{
    kz_ruby_ext_register_type(module);
}

G_MODULE_EXPORT void
KZ_MODULE_IMPL_EXIT (void)
{
}

G_MODULE_EXPORT GObject *
KZ_MODULE_IMPL_INSTANTIATE (const gchar *first_property,
			    va_list      var_args)
{
    KzRubyExt *ext;

    ext = KZ_RUBY_EXT(g_object_new_valist(KZ_TYPE_RUBY_EXT,
                                          first_property, var_args));
    kz_rb_ext_init(ext->initial_address);
    return G_OBJECT(ext);
}

G_MODULE_EXPORT const gchar *
KZ_MODULE_IMPL_GET_NAME (void)
{
    static gchar *name = NULL;

    if (name)
        return name;

    if (_kz_rb_ext_version) {
        name = g_strdup_printf(_("Ruby extension %s"), _kz_rb_ext_version);
        return name;
    }

    return _("Ruby extension");
}


static void
kz_ruby_ext_class_init (KzRubyExtClass *klass)
{
    GObjectClass *gobject_class;

    kz_ruby_ext_parent_class = (GObjectClass *)g_type_class_peek_parent(klass);

    gobject_class   = (GObjectClass *) klass;

    gobject_class->dispose      = dispose;
    gobject_class->set_property = set_property;
    gobject_class->get_property = get_property;

    g_object_class_install_property
        (gobject_class,
         PROP_INITIAL_ADDRESS,
         g_param_spec_pointer(
             "initial-address",
             _("The initial address"),
             _("The initial address of the program"),
             (GParamFlags) G_PARAM_READWRITE));
}


static void
dispose (GObject *object)
{
    KzRubyExt *ext = KZ_RUBY_EXT(object);

    if (ext->initial_address) {
        ext->initial_address = 0;
        kz_rb_ext_cleanup();
    }

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

static void
set_property (GObject         *object,
              guint            prop_id,
              const GValue    *value,
              GParamSpec      *pspec)
{
    KzRubyExt *ext = KZ_RUBY_EXT(object);

    switch (prop_id)
    {
      case PROP_INITIAL_ADDRESS:
        ext->initial_address = g_value_get_pointer(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)
{
    KzRubyExt *ext = KZ_RUBY_EXT (object);

    switch (prop_id)
    {
      case PROP_INITIAL_ADDRESS:
        g_value_set_pointer(value, ext->initial_address);
        break;
      default:
        G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
        break;
    }
}


static void
kz_ruby_ext_iface_init (KzExtIFace *iface)
{
    iface->setup = setup;
}


static void
setup (KzExt *ext, KzWindow *window)
{
    kz_rb_ext_setup(window);
}
