/* 
 * Libglade support for Java-GNOME
 *
 * The Java-Gnome bindings library is free software distributed under the
 * terms of the GNU Library General Public License version 2.
 * 
 * Authors: Avi Bryant, Jean van Wyk <jeanvanwyk@iname.com>
 * Copyright 2000 Java-GNOME team, all rights reserved. 
 *
 * Special thanks to Avi Bryant who created teh original version (GladeXML)
 * for GTK.
 */

#include <jni.h>
#include <string.h>
#include <stdio.h>

#include <glade/glade.h>
#include <gtk/gtk.h>

#define LIBGLADE_DOMAIN "libglade"

static jfieldID  gladeFID;
static jmethodID connectMID;

jclass getClass_GladeXMLException(JNIEnv *env) {
    static jclass cls = NULL;
    if (cls == NULL)
        cls = (*env)->FindClass(env, "org/gnu/glade/GladeXMLException");
    return cls;
}

struct jglade_info
{
    JNIEnv *env;
    jobject o;
};
 
void libglade_log_handler (const gchar    *log_domain,
			   GLogLevelFlags  log_level,
			   const gchar    *message,
			   gpointer	  user_data)
{
    if (user_data) {
	JNIEnv *env = (JNIEnv*)user_data;
	(*env)->ThrowNew(env, getClass_GladeXMLException(env), message);
    }
}

guint set_log_handler(JNIEnv* env) 
{
      // GLogLevelFlags fatal_mask;

      //      fatal_mask = g_log_set_always_fatal (G_LOG_FATAL_MASK);
      //      fatal_mask |= G_LOG_LEVEL_WARNING | G_LOG_LEVEL_CRITICAL;
      //      g_log_set_always_fatal (fatal_mask);
      return g_log_set_handler (LIBGLADE_DOMAIN, 
				G_LOG_LEVEL_ERROR | G_LOG_LEVEL_CRITICAL
				| G_LOG_LEVEL_WARNING | G_LOG_FLAG_FATAL,
				libglade_log_handler, (gpointer)env);
}

void remove_log_handler(guint handler_id)
{
    g_log_remove_handler(LIBGLADE_DOMAIN, handler_id);
}

static void xml_connect(const gchar *handler_name, GObject *_source, 
			const gchar *signal_name, const gchar *signal_data,
			GObject *_target, gboolean after, gpointer i)
{
    JNIEnv *env = ((struct jglade_info *)i)->env;
    jobject obj = ((struct jglade_info *)i)->o;
    //jclass cls;
    //jmethodID getWidgetMID;

    jstring handler, signal, data;
    //jobject source, target;

    if ((*env)->ExceptionCheck(env)) {
	// debug
	char* name = handler_name ? (char*)handler_name : "<null>";
	fprintf(stderr, "xml_connect: skipping %s\n", name);
	// debug
	return;
    }

    handler = handler_name ? (*env)->NewStringUTF(env, handler_name) : 0L;
    signal = signal_name ? (*env)->NewStringUTF(env, signal_name) : 0L;
    data = signal_data ? (*env)->NewStringUTF(env, signal_data) : 0L;

    (*env)->CallVoidMethod(env, obj, connectMID, handler, _source,
			   signal, data, _target, after);
    // no need to check for exception since we're returning anyway...
}

JNIEXPORT jstring JNICALL Java_org_gnu_glade_LibGlade_getWidgetName (
    JNIEnv *env, jobject o, jint nativepeer)
{
    GtkWidget* gtk;
    if (nativepeer == 0)
	return (jstring)NULL;
    gtk = (GtkWidget*)(nativepeer);
    return (*env)->NewStringUTF(env, glade_get_widget_name(gtk));
}

JNIEXPORT jint JNICALL Java_org_gnu_glade_LibGlade_getNativeWidget (
    JNIEnv *env, jobject o, jstring namestr)
{
    char *name = (char *)(*env)->GetStringUTFChars(env, namestr, 0);
    GladeXML* xml = (GladeXML*)(int)(*env)->GetIntField(env, o, gladeFID);
    jint result;
    guint handler_id;

    handler_id = set_log_handler(env);
    result = (jint) glade_xml_get_widget(xml, name);
    remove_log_handler(handler_id);
    
    (*env)->ReleaseStringUTFChars(env, namestr, name);

    return result;  // any pending exception will be handled on return.
}

/*
 * int glade_xml_new_from_buffer(byte[], String)
 */
JNIEXPORT void JNICALL 
Java_org_gnu_glade_LibGlade_glade_1xml_1new_1from_1buffer(
  JNIEnv *env, jobject o, jbyteArray buffer, jstring root) 
{
    GladeXML *xml;
    // struct jglade_info i;
    char *rootname;
    guint handler_id;
    // jthrowable exc;
    jbyte *buf;
    int len;

    len = (*env)->GetArrayLength(env, buffer);
    buf = (*env)->GetByteArrayElements(env, buffer, NULL);
    if (buf == NULL)
	return;

    rootname = root ? (char *)(*env)->GetStringUTFChars(env, root, 0) : NULL;

    handler_id = set_log_handler(env);
    xml = glade_xml_new_from_buffer((char *)buf, len, rootname, NULL);
    remove_log_handler(handler_id);

    (*env)->ReleaseByteArrayElements(env, buffer, buf, 0);

    if ((*env)->ExceptionCheck(env))
	return;
	
    (*env)->SetIntField(env, o, gladeFID, (jint)xml);
}

JNIEXPORT void JNICALL
Java_org_gnu_glade_LibGlade_glade_1xml_1signal_1autoconnect_1full (
    JNIEnv *env, jobject o)
{
    GladeXML* xml = (GladeXML*)(int)(*env)->GetIntField(env, o, gladeFID);
    struct jglade_info i;
    guint handler_id;

    i.env = env;
    i.o = o;

    handler_id = set_log_handler(env);
    glade_xml_signal_autoconnect_full(xml, xml_connect, &i);
    remove_log_handler(handler_id);
}	

JNIEXPORT void JNICALL Java_org_gnu_glade_LibGlade_initIDs (
    JNIEnv *env, jclass cls)
{
    gladeFID = (*env)->GetFieldID(env, cls, "gladeHandle", "I");
    connectMID = (*env)->GetMethodID(env, cls, "connect",
	"(Ljava/lang/String;ILjava/lang/String;Ljava/lang/String;IZ)V");
}
