/***************************************************************************
                          gins.c - main entry for gins
                             -------------------
    begin                : ven dic 31 2004
    copyright            : (C) 2004-2005 by Fabrix.xm
    email                : fabrix.xm@lombardiacom.it
 ***************************************************************************/

/***************************************************************************
 *                                                                         *
 *   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 of the License, or     *
 *   (at your option) any later version.                                   *
 *                                                                         *
 **************************************************************************/

#include <stdio.h>
#include <gtk/gtk.h>
#include <gdk/gdk.h>
#include <glade/glade.h>
#include <glib.h>
#include <string.h>
#include <stdlib.h>
#include <pthread.h>

#include "gins-references.c"


/*
	gchar arg1[100000];
	gchar arg2[100000];
	gchar arg3[100000];
	gchar arg4[100000];
	gchar arg5[100000];
*/
/*
	gchar *argcopy[100000];

	gchar edata[1024];
*/
#define VERSION "0.0.3"

// globals
GladeXML *xml;

LOCK=0;

gchar ginsbuffer1[1024];
gchar ginsbuffer2[1024];
gchar ginsbuffer3[1024];

int bufferfull = 0;

//
void removeNL(char *);

// event strings
/*
char* eventTypes[] = {
  "GDK_NOTHING",
  "GDK_DELETE",
  "GDK_DESTROY",
  "GDK_EXPOSE",
  "GDK_MOTION_NOTIFY",
  "GDK_BUTTON_PRESS",
  "GDK_2BUTTON_PRESS",
  "GDK_3BUTTON_PRESS",
  "GDK_BUTTON_RELEASE",
  "GDK_KEY_PRESS",
  "GDK_KEY_RELEASE",
  "GDK_ENTER_NOTIFY",
  "GDK_LEAVE_NOTIFY",
  "GDK_FOCUS_CHANGE",
  "GDK_CONFIGURE",
  "GDK_MAP",
  "GDK_UNMAP",
  "GDK_PROPERTY_NOTIFY",
  "GDK_SELECTION_CLEAR",
  "GDK_SELECTION_REQUEST",
  "GDK_SELECTION_NOTIFY",
  "GDK_PROXIMITY_IN",
  "GDK_PROXIMITY_OUT",
  "GDK_DRAG_ENTER",
  "GDK_DRAG_LEAVE",
  "GDK_DRAG_MOTION",
  "GDK_DRAG_STATUS",
  "GDK_DROP_START",
  "GDK_DROP_FINISHED",
  "GDK_CLIENT_EVENT",
  "GDK_VISIBILITY_NOTIFY",
  "GDK_NO_EXPOSE",
  "GDK_SCROLL",
  "GDK_WINDOW_STATE",
  "GDK_SETTING ",
  "GDK_OWNER_CHANGE"
};
*/
char* eventTypes[] = {
  "GDK_NOTHING",
  "GDK_DELETE",
  "GDK_DESTROY",
  "GDK_EXPOSE",
  "GDK_MOTION_NOTIFY",
  "GDK_BUTTON_PRESS",
  "GDK_2BUTTON_PRESS",
  "GDK_3BUTTON_PRESS",
  "GDK_BUTTON_RELEASE",
  "GDK_KEY_PRESS",
  "GDK_KEY_RELEASE",
  "GDK_ENTER_NOTIFY",
  "GDK_LEAVE_NOTIFY",
  "GDK_FOCUS_CHANGE",
  "GDK_CONFIGURE",
  "GDK_MAP",
  "GDK_UNMAP",
  "GDK_PROPERTY_NOTIFY",
  "GDK_SELECTION_CLEAR",
  "GDK_SELECTION_REQUEST",
  "GDK_SELECTION_NOTIFY",
  "GDK_PROXIMITY_IN",
  "GDK_PROXIMITY_OUT",
  "GDK_NOTHING",
  "GDK_NOTHING",
  "GDK_NOTHING",
  "GDK_DROP_START",
  "GDK_DROP_FINISHED",
  "GDK_CLIENT_EVENT",
  "GDK_VISIBILITY_NOTIFY",
  "GDK_NO_EXPOSE",
  "GDK_SCROLL",
  "GDK_WINDOW_STATE",
  "GDK_SETTING ",
  "GDK_OWNER_CHANGE"
};
//-- required by clist **text --
// 6 is number of arguments for gtk()

struct{
	gchar *text;
}returntext[6];



//-- empty textarry needed for clist_append --
gchar *textarray[1];

//-- this array stores the number of the currently selected row of a clist --
struct{
	guint selected;
}listselections[1000];

//-- needed to iterate the selections --
gint clistcounter = 0;


static int 
gignore_error (Display *d, XErrorEvent *e)
{
  	return 0;
}


void removeNL(char *text) {
	/*elimino un eventuale "acapo" in fondo alla stringa*/
	if (text[strlen(text)-1]=='\n') text[strlen(text)-1]='\0';
}


	GList* GTKwidgets=NULL;
	GList* GTKwidgetnames=NULL;
//	GList* GTKwidgettypes=NULL;


        int GOcount = 0;

struct{        
  gchar name[1024];
  gchar type[1024];
  GtkWidget *obj;

}GO[1000];
	guint lastfoundobject = -1;


//-- required for gtk_textbuf
GtkTextIter TextIter1, TextIter2 , TextIter3;

struct{
	GtkTextIter Iter; 
}TextIters[6];

struct{
	gchar retpoint[1024];
}pointervalues[6];


//-- gets an argument from the wxBasic stack and returns it as string --

gchar *getstringarg(){

	wVariant *variant;
	variant = (wVariant *)wMalloc( sizeof( wVariant ) );
	gchar *wstring;
	variant = wStackPopString();
    	wstring = wVariantToChar( variant, W_FALSE, 0 );
    	wVariantDeref( variant );
	//printf("-->>%s\n" , wstring);
	return (wstring);
}


//-- return a string to wxBasic

void returnstring(char *thestring){

        	wVariant *myvariant;
		myvariant = (wVariant *)wMalloc( sizeof( wVariant ) );
           	//-- create a string
           	wVariantFromChar( myvariant, thestring ,4,4 );
    		//-- return it to wxBasic
    		wVariantMove( wStackPushNothing(), myvariant );
   		//-- cleanup
    		wVariantDeref( myvariant );
    		wFree(myvariant);
}


//-- return a GSList as a list (table) to wxBasic

void returnlist(GSList *thelist){
	GSList* li = NULL;
	gchar *theline;

	//printf("---------------------ListStuff\n");
        gchar mystring[10000];
        wVariant *mylist;
        wVariant *myvariant;
        wVariant *mykey;
        int c=0;

	myvariant = (wVariant *)wMalloc( sizeof( wVariant ) );
	mylist = (wVariant *)wMalloc( sizeof( wVariant ) );

        wTableNew(mylist);
	mykey = (wVariant *)wMalloc( sizeof( wVariant ) );



	for(li = thelist; li != NULL; li = li->next){

		sprintf(theline , "%s" , li->data);
		//printf("--%s\n" , theline);

		//-- create a key
		sprintf( mystring,"%d" ,  c );
		wVariantFromChar( mykey, mystring ,3,3 );
		//-- create a string
		wVariantFromChar( myvariant, theline ,4,4 );
		//-- append it to the list
		wTableInsert(mylist , mykey, myvariant );  
		c++;
		wVariantDeref( myvariant );
		wVariantDeref( mykey );
	}
 	wVariantMove( wStackPushNothing(), mylist );

    //-- cleanup    
    wVariantDeref( myvariant );
    wFree(myvariant);
    wVariantDeref( mylist );
    wFree(mylist);
    wVariantDeref( mykey );
    wFree(mykey);

//    wFree(theline);
//printf("---test\n");
    return;

	//g_slist_free(thelist);
}

//-- search a widget in the internal gslist , or in the Glade objects if none was found --

GSList *findobject(gchar *arg0){

	//    static GStaticMutex mutex = G_STATIC_MUTEX_INIT;
	//    g_static_mutex_lock (&mutex);

	//printf("----> g... %s\n" , arg0 );
	gchar tempobjectname[1024];
	GList *li = NULL; /* an iterator variable */
	int i;
        GList *li1 = NULL;
	GtkWidget *obj;
	lastfoundobject = -1;


	gchar *argcopy[100000];
	sprintf(argcopy , "%s" , arg0);

	obj = glade_xml_get_widget(xml, arg0);

	if( ! obj){

		i = 0;
		for(li = GTKwidgetnames; li != NULL; li = li->next){

	        	sprintf(tempobjectname , "%s", (char *)li->data);
			if (!strcmp(  tempobjectname , arg0 )) {
				li1 = g_list_nth(GTKwidgets , i);
				lastfoundobject = i;
				break;
			}
			i++;
		}
	}else{
			li1 = g_list_prepend(li1 , obj);
			li1 = g_list_first(li1);
	}


	li = NULL;
	//sprintf(argcopy , "");
	return( li1 );

}


GtkWidget *findwidget(char *widgetname ){

	int i;
	GtkWidget *obj;
	gchar tempobjectname[1024];
	GList *li = NULL; /* an iterator variable */

	obj = glade_xml_get_widget(xml, widgetname);

	if( ! obj){

		i = 0;
		for(li = GTKwidgetnames; li != NULL; li = li->next){

        		sprintf(tempobjectname , "%s", (char *)li->data);
			if (!strcmp(  tempobjectname , widgetname )) {
				li = g_list_nth(GTKwidgets , i);
				obj = li->data;
				break;
			}
			i++;
		}
	}
	return(obj);

}


//-- some stuff to try to solve xlib-sync errors --

void wBuiltin_gdk_flush(){

	static GStaticMutex mutex = G_STATIC_MUTEX_INIT;
	g_static_mutex_lock (&mutex);
	gdk_threads_enter();
	gdk_flush();
	gdk_threads_leave();
	g_static_mutex_unlock (&mutex);

}
void wBuiltin_gdk_error_trap_push(){
	gdk_error_trap_push();
}
void wBuiltin_gdk_error_trap_pop(){
	gdk_error_trap_pop();
}



//-- Main Event-handler --
gboolean signal_handler(GtkWidget *widget, GdkEvent* event, gpointer data) {

	if (LOCK == 1){
	  return;
	}

	//char buffer[255];
	if (event==NULL) {
		return FALSE;
	}


	static GStaticMutex mutex = G_STATIC_MUTEX_INIT;
	g_static_mutex_lock (&mutex);
	//gdk_threads_enter();
	if(bufferfull == 0){
	
		gchar edata[1024];

	//	if (eventTypes[(int)event->type + 1]!="DROP"){

			//if( eventTypes[(int)event->type + 1] == "(null)"){
			//return TRUE;
			//}

			snprintf(ginsbuffer2, 1024, "%s", eventTypes[(int)event->type + 1]);


			// added by //MU
			snprintf(edata, 256, "null");
			if ((GdkEventButton*)event){
				snprintf(edata, 1024, "%d" , ((GdkEventButton*)event)->button );
			}

			snprintf(ginsbuffer1, 1024, "%s", glade_get_widget_name(widget));

			if (!strcmp(ginsbuffer1 , "(null)") ){

				snprintf(ginsbuffer1, 1024, "%s", data);

			}


			bufferfull = 1;
			snprintf(ginsbuffer3, 1024, "%s", edata);

/*			if (!strcmp(ginsbuffer2 , "GDK_DESTROY") ){
				exit(0);
			}	
			if (!strcmp(ginsbuffer2 , "GDK_DELETE") ){
				exit(0);
			}
*/
			//if (!strcmp(ginsbuffer2 , "GDK_3BUTTON_PRESS") ){
			//	return TRUE;
			//}
			if (!strcmp(ginsbuffer2 , "GDK_BUTTON_RELEASE") ){
			//      snprintf(ginsbuffer2, 256, "%s", "BUTTON_PRESS");
			//---	gtk_widget_activate(GTK_WIDGET(widget) ); 
			//---	gdk_flush();
			//	usleep(40000);
			//	return TRUE;
			}

			LOCK=0;

	//	}
	}
	

	if (!strcmp(ginsbuffer2 , "GDK_DELETE") ){
		// must hide here, not in Basic, due to bugs in JWM
		//gdk_flush();
		gtk_widget_hide(GTK_WIDGET(widget) );
		gdk_flush();

		g_static_mutex_unlock (&mutex);
		return TRUE;
	}


	g_static_mutex_unlock (&mutex);
	return FALSE;
}

gboolean signal_handler2(GtkWidget *widget, GtkWidget *source_widget,gchar *textdata) {

	//-- this is used by clists to tell gtkbasic what was dropped on them

	gchar sourcename[1024];
	GList *li = NULL; /* an iterator variable */

	for(li = GTKwidgets; li != NULL; li = li->next){
		if( GTK_WIDGET(li->data) == source_widget ){

			snprintf(sourcename, 1024, "%s", gtk_widget_get_name(source_widget)  );
			break;
		}
	}

	for(li = GTKwidgets; li != NULL; li = li->next){
		if( GTK_WIDGET(li->data) == widget ){

			snprintf(ginsbuffer1, 1024, "%s", gtk_widget_get_name(widget)  );
			snprintf(ginsbuffer2, 1024, "DND_RECEIVED" );
			bufferfull = 1;
			snprintf(ginsbuffer3, 1024, "%s:%s",sourcename, textdata);
			break;
		}
	}



}
//-- external clist support --

#include "lists.h"
#include "lists.c"
#include "pixmap.c"


//-- unneeded objects should be destroyed to free memory (usually pixmaps/masks)
void wBuiltin_gtk_destroyobject(){

	static GStaticMutex mutex = G_STATIC_MUTEX_INIT;
	g_static_mutex_lock (&mutex);
	gdk_threads_enter ();

	gchar arg0[1024];
	sprintf(arg0 , "%s" , getstringarg());

	GtkWidget *obj;
	int i;
	gchar tempobjectname[1024];
	GList *li = NULL; /* an iterator variable */

	//gchar *argcopy[100000];
	//sprintf(argcopy , "%s" , arg0);

	obj = glade_xml_get_widget(xml, arg0);

	if( obj){

gtk_widget_destroy(obj);
	}else{
		i = 0;
		for(li = GTKwidgetnames; li != NULL; li = li->next){

        		sprintf(tempobjectname , "%s", (char *)li->data);
			if (!strcmp(  tempobjectname , arg0 )) {
				li = g_list_nth(GTKwidgets , i);
				obj = li->data;
				gtk_widget_destroy(obj);
				g_list_remove(GTKwidgets,i);
				g_list_remove(GTKwidgetnames,i);
				break;
			}
			i++;
		}
	}


	gdk_threads_leave ();
	g_static_mutex_unlock (&mutex);
	return;
}
void wBuiltin_gtk_createobject(){


    static int current_number = 0;
    int ret_val;
    static GStaticMutex mutex = G_STATIC_MUTEX_INIT;
    g_static_mutex_lock (&mutex);
    gdk_threads_enter ();
	gchar objecttype[1024];
	gchar objectname[1024];
	gchar arg0[1024];
	gchar arg1[1024];

	sprintf(arg1 , "%s" , getstringarg());
	sprintf(arg0 , "%s" , getstringarg());
	sprintf(objectname , "%s" , getstringarg());
	sprintf(objecttype , "%s" , getstringarg());

	gboolean ok = 0;
	gint doconnect = 1;

 	 if (!strcmp( objecttype , "GtkWindow")) {
		if (!strcmp( arg0 , "GTK_WINDOW_POPUP")) {
	        	GO[GOcount].obj = gtk_window_new(GTK_WINDOW_POPUP);
		}else{
	        	GO[GOcount].obj = gtk_window_new(GTK_WINDOW_TOPLEVEL);
		}
		ok = 1;
	}

/*
	 if (!strcmp( objecttype , "GtkHBox")) {
        	GO[GOcount].obj = gtk_hbox_new(atoi(arg0) , atoi(arg1));
		ok = 1;
 		doconnect = 0;
	}
	 if (!strcmp( objecttype , "GtkVBox")) {
        	GO[GOcount].obj = gtk_vbox_new(atoi(arg0) , atoi(arg1));
		ok = 1;
 		doconnect = 0;
	}
	 if (!strcmp( objecttype , "GtkFileFilter")) {
        	GO[GOcount].obj = gtk_file_filter_new ();
		ok = 1;
 		doconnect = 0;
	}
*/
	 if (!strcmp( objecttype , "GtkBasicList")) {

        	GO[GOcount].obj = do_create_lists (arg0, arg1,objectname);
		ok = 1;
 		//doconnect = 0;
	}
	 if (!strcmp( objecttype , "PixmapwidFromFile")) {

        	GO[GOcount].obj = do_create_PixmapFromFile (arg0);
		ok = 1;
 		//doconnect = 0;
	}
	 if (!strcmp( objecttype , "GdkPixmap")) {

        	GO[GOcount].obj = do_create_Pixmap (arg0);
		ok = 1;
 		//doconnect = 0;
	}
/*
	 if (!strcmp( objecttype , "GdkMask")) {

        	GO[GOcount].obj = do_create_Mask (arg0);
		ok = 1;
 		//doconnect = 0;
	}
*/

	 if (!strcmp( objecttype , "FileChooserDialog")) {

		GList *li1 = NULL;
		li1 = findobject(arg0);
	 	if (!strcmp( arg1 , "1")) {

        		GO[GOcount].obj = gtk_file_chooser_dialog_new  ("open file",
 					li1->data,
				        GTK_FILE_CHOOSER_ACTION_OPEN,
				        GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
				        GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT,
				        NULL);
			ok = 1;
 			doconnect = 0;
		}
	}
	if ( ok == 0){
		gdk_threads_leave ();
		g_static_mutex_unlock (&mutex);
		return;
	}


	gtk_widget_set_name (GO[GOcount].obj , objectname);

	sprintf(GO[GOcount].name , "%s" , objectname);
	//sprintf(GO[GOcount].type , "%s" , objecttype);

	GTKwidgets = g_list_append(GTKwidgets , GO[GOcount].obj);
	GTKwidgetnames = g_list_append(GTKwidgetnames , GO[GOcount].name);
	//GTKwidgettypes = g_list_append(GTKwidgettypes , GO[GOcount].type);


	//g_signal_connect (GO[GOcount].obj, "event", G_CALLBACK (signal_handler), NULL);

	if(doconnect == 1){
		g_signal_connect (GO[GOcount].obj, "event", G_CALLBACK (signal_handler), GO[GOcount].name);
	}
	GOcount++;

	//printf("created new object: %s of type: %s\n" , objectname, objecttype);

	gdk_threads_leave ();
	g_static_mutex_unlock (&mutex);
	return;
}

void createnewreturnobject(char *objectname , char *objecttype){

	sprintf(GO[GOcount].name , "%s" , objectname);
	//sprintf(GO[GOcount].type , "%s" , objecttype);

	GTKwidgets = g_list_append(GTKwidgets , GO[GOcount].obj);
	GTKwidgetnames = g_list_append(GTKwidgetnames , GO[GOcount].name);
	//GTKwidgettypes = g_list_append(GTKwidgettypes , GO[GOcount].type);

	g_signal_connect (GO[GOcount].obj, "event", G_CALLBACK (signal_handler), GO[GOcount].name);

	GOcount++;
}
void createnewreturnobjectnosignal(char *objectname){

	sprintf(GO[GOcount].name , "%s" , objectname);

	GTKwidgets = g_list_append(GTKwidgets , GO[GOcount].obj);
	GTKwidgetnames = g_list_append(GTKwidgetnames , GO[GOcount].name);

	GOcount++;
}
void wBuiltin_gtk_setobjectname(){

	gchar objectname[1024];
	sprintf(objectname , "%s" , getstringarg());
	sprintf(GO[GOcount-1].name , "%s" , objectname);
}


wBuiltin_g_locale_to_utf8(){

	const gchar *arg0;
	gchar *result;
	wVariant *variant;


	variant = wStackPopString();
    	arg0 = wVariantToChar( variant, W_FALSE, 0 );

    	wVariantDeref( variant );


	//	gsize bytes_written;

	//	result = g_locale_to_utf8(arg0,strlen(arg0),NULL,&bytes_written,NULL);

	result = g_locale_to_utf8(arg0,strlen(arg0),NULL,NULL,NULL);

	//printf("...%d\n" , bytes_written);

	free(arg0);
	returnstring(result);
	//printf("-------%s\n" , result);

}

void wBuiltin_gtk_returntext(){
	// this returns text stored in a gchar pointer by a gtk_function
	gchar arg0[2];

	sprintf(arg0 , "%s" , getstringarg());

	int myindex = atoi(arg0);
        gchar result[100000];
        sprintf (result , "%s" , returntext[myindex].text);
        returnstring ( result );
}

void wBuiltin_gtk_returnpointervalue(){

	gchar arg0[2];

	sprintf(arg0 , "%s" , getstringarg());

	gchar resultbuffer[1024];
	gint theindex;
	theindex = atoi(arg0);
	sprintf(resultbuffer , "%s" , pointervalues[theindex].retpoint);
	returnstring(resultbuffer);
}

void wBuiltin_gtk(){

 	int (*gmyold_handler) (Display *, XErrorEvent *);
	gmyold_handler= XSetErrorHandler (gignore_error);


	static GStaticMutex mutex = G_STATIC_MUTEX_INIT;
	g_static_mutex_lock (&mutex);
	gdk_threads_enter();



	gchar *resultbuffer = "Nothing";
	gchar arg0[1024];
	gchar thefunction[1024];
	gchar result[1024];
/*
	gchar arg1[1024];
	gchar arg2[1024];
	gchar arg3[1024];
	gchar arg4[1024];
	gchar arg5[1024];
*/


	gchar arg1[100000];
	gchar arg2[100000];
	gchar arg3[100000];
	gchar arg4[100000];
	gchar arg5[100000];

	sprintf(arg5 , "%s" , getstringarg());
	sprintf(arg4 , "%s" , getstringarg());
	sprintf(arg3 , "%s" , getstringarg());
	sprintf(arg2 , "%s" , getstringarg());
	sprintf(arg1 , "%s" , getstringarg());
	sprintf(arg0 , "%s" , getstringarg());
	sprintf(thefunction , "%s" , getstringarg());

	GtkWidget *obj;

	int i;
	int n;



        GList *li1 = NULL;
        GList *li2 = NULL;
        GList *li3 = NULL;
        GList *li4 = NULL;
        GList *li5 = NULL;

	li1 = findobject(arg1);
	li2 = findobject(arg2);
	li3 = findobject(arg3);
	li4 = findobject(arg4);
	li5 = findobject(arg5);

//--------


	obj = findwidget(arg0);

	gdouble arg1double;
	gboolean resultgboolean;
	guint resultguint;
	gdouble resultgdouble;
	gint resultgint;

	// for clist
	gchar emptytextarray0[10240] = "";
	gchar emptytextarray1[10240] = "";
	gchar emptytextarray2[10240] = "";
	gchar emptytextarray3[10240] = "";
	gchar emptytextarray4[10240] = "";
	gchar emptytextarray5[10240] = "";

// not used yet, will be needed for pointers to floats, ints
gfloat gf0;
gfloat gf1;
gfloat gf2;
gfloat gf3;
gfloat gf4;
gfloat gf5;

gfloat gi0;
gfloat gi1;
gfloat gi2;
gfloat gi3;
gfloat gi4;
gfloat gi5;


  if (!strcmp( thefunction , "gtk_container_add")) {
	gtk_container_add (GTK_CONTAINER (obj), li1->data);
        returnstring("Nothing");
        gdk_threads_leave();
	g_static_mutex_unlock (&mutex);
	LOCK=0;
	return;
  }

  if (!strcmp( thefunction , "gtk_file_chooser_get_filenames")) {
	GSList* thefilenames = gtk_file_chooser_get_filenames (GTK_FILE_CHOOSER (obj));
        returnlist(thefilenames);
        gdk_threads_leave();
	g_static_mutex_unlock (&mutex);
	LOCK=0;
	return;
  }


//////////////////////

// here a LOT of GTK functions can be added...

//GiNsTaBlE1StArT
