#include "jg_jnu.h"
#include <sys/types.h>
#include <glib.h>
#include <glib-object.h>

#ifdef __cplusplus
extern "C" {
#endif


static volatile GSource *source;
static volatile GMainContext *context;
static volatile jclass class;
static volatile jmethodID mid;
static volatile GSourceFuncs *source_funcs;
static volatile gboolean events_pending = FALSE;
static volatile GMainContext *mainContext;

gboolean function( gpointer data ){
    JNIEnv *env = JNU_GetEnv();
    jboolean exceptionThrown;
    
    (*env)->CallStaticVoidMethod(env, class, mid);

    exceptionThrown = (*env)->ExceptionCheck(env);
    if (exceptionThrown) {
		// We cannot throw this exception, since this timer was called by GLib.
		(*env)->ExceptionDescribe(env);  // ExceptionDescribe clears exception
    }
	return TRUE;
}

gboolean prepare(GSource    *source, gint       *timeout_){
	return events_pending;
}
gboolean check    (GSource    *source){
	return events_pending;
}
gboolean dispatch (GSource    *source,
			GSourceFunc callback,
			gpointer    user_data){
	return callback( user_data );
}

JNIEXPORT void JNICALL Java_org_gnu_glib_CustomEvents_init (
    JNIEnv *env, jclass cls)
{	
	source_funcs = (GSourceFuncs *) g_new( GSourceFuncs, 1 );
	source_funcs->prepare = &prepare;
	source_funcs->check = &check;
	source_funcs->dispatch = &dispatch;
	source_funcs->finalize = NULL;
	
	class = (jclass) (*env)->NewGlobalRef(env, cls);
    mid = (*env)->GetStaticMethodID(env, cls, "runEvents", "()V");
	source = g_source_new( source_funcs, sizeof( GSource ) );
	mainContext = g_main_context_default();
	g_source_set_can_recurse( source, FALSE );
	g_source_set_callback( source, (GSourceFunc) function, NULL, NULL );
	g_source_attach( source, mainContext );
	g_source_set_priority( source, G_PRIORITY_HIGH_IDLE );
}

JNIEXPORT void JNICALL Java_org_gnu_glib_CustomEvents_setEventsPending( JNIEnv *env, jclass cls, jboolean pending ){
	events_pending = pending;
	g_main_context_wakeup( mainContext );
}


JNIEXPORT void JNICALL Java_org_gnu_glib_CustomEvents_cleanup( JNIEnv *env, jclass cls ){
	g_source_destroy( source );	
	g_free( source_funcs );
	(*env)->DeleteGlobalRef(env, class);
}

#ifdef __cplusplus
}
#endif
