/***************************************************************************
                          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>



#define VERSION "0.0.2"

// globals
GladeXML *xml;

LOCK=0;

gchar ginsbuffer1[255];
gchar ginsbuffer2[255];
gchar ginsbuffer3[255];

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_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[255];
  gchar type[255];
  GtkWidget *obj;

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


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

struct{
	GtkTextIter Iter; 
}TextIters[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 );
	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++;
	}
 	wVariantMove( wStackPushNothing(), mylist );

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

    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[255];
	GList *li = NULL; /* an iterator variable */
	GtkWidget *TESTobj;
	gchar *fcobjectname;
	int i;
        GList *li1 = NULL;

	lastfoundobject = -1;

	fcobjectname = strstr(arg0 , ":");
	if(fcobjectname){
		i = 0;	

		if (g_list_length(GTKwidgetnames) > 0){
			for(li = GTKwidgetnames; li != NULL; li = li->next){
	
        			sprintf(tempobjectname , ":%s", (char *)li->data);
				if (!strcmp(  tempobjectname , fcobjectname )) {
					li1 = g_list_nth(GTKwidgets , i);
					lastfoundobject = i;
//printf("----> gtkobject %s\n" , fcobjectname );
					break;
				}
				i++;

 
				if( i == g_list_length(GTKwidgetnames)){

					for(i=0;i<strlen(fcobjectname);i++){
						fcobjectname[i] = fcobjectname[i+1];
					}

					TESTobj = glade_xml_get_widget(xml, fcobjectname);

					li1 = g_list_prepend(li1 , TESTobj);
					li1 = g_list_first(li1);

				}   
			}
		}else{
			for(i=0;i<strlen(fcobjectname);i++){
				fcobjectname[i] = fcobjectname[i+1];
			}

			TESTobj = glade_xml_get_widget(xml, fcobjectname);

			li1 = g_list_prepend(li1 , TESTobj);
			li1 = g_list_first(li1);

		}
	}
//g_static_mutex_unlock (&mutex);

	li = NULL;
	return( li1 );
}


//-- external clist support --

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


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

void wBuiltin_gdk_flush(){


    //LOCK=1;
    static GStaticMutex mutex = G_STATIC_MUTEX_INIT;
    g_static_mutex_lock (&mutex);
    gdk_threads_enter();
	//gdk_flush();
	gdk_flush();
//GdkDisplay *display = gdk_display_get_default ();
//XFlush (GDK_DISPLAY_XDISPLAY (display);
    gdk_threads_leave();
    g_static_mutex_unlock (&mutex);
    //LOCK=0;

}
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[255];

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

//if( eventTypes[(int)event->type + 1] == "(null)"){
//return TRUE;
//}
snprintf(ginsbuffer2, 256, "%s", eventTypes[(int)event->type + 1]);


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


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

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

				snprintf(ginsbuffer1, 256, ":%s", data);
				//  snprintf(ginsbuffer1, 256, "%s", Gtk_widgetname());
			}


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

			
	
			//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();
//		usleep(100000);
//gdk_threads_leave();
g_static_mutex_unlock (&mutex);
		return TRUE;
	}
//gdk_threads_leave();
g_static_mutex_unlock (&mutex);
	return FALSE;
}




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[255];
	gchar objectname[255];
	gchar arg0[255];
	gchar arg1[255];

	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 , "GtkButton")) {
        	GO[GOcount].obj = gtk_button_new();
		ok = 1;
	}
	 if (!strcmp( objecttype , "GtkButtonWithLabel")) {
        	GO[GOcount].obj = gtk_button_new_with_label(arg0);
		ok = 1;
		//gtk_drag_dest_add_text_targets(GO[GOcount].obj);  
	}

	 if (!strcmp( objecttype , "GtkLabel")) {
        	GO[GOcount].obj = gtk_label_new(arg0);
		ok = 1;
	}
	 if (!strcmp( objecttype , "GtkTextView")) {
        	GO[GOcount].obj = gtk_text_view_new();
		ok = 1;
 		doconnect = 0;
	}
 	 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);
		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;
	}




	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 , 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);

	GOcount++;
}
void wBuiltin_gtk_setobjectname(){

	gchar objectname[255];
	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[255];
        sprintf (result , "%s" , returntext[myindex].text);
        returnstring ( result );
}


void wBuiltin_gtk(){

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

//gdk_flush();
//usleep(100);
    static GStaticMutex mutex = G_STATIC_MUTEX_INIT;
    g_static_mutex_lock (&mutex);
//LOCK=1;

gdk_threads_enter();


		//	GList *lix; /* an iterator variable */
		//	int ix=1;
		//	for(lix = GTKwidgetnames; lix != NULL; lix = lix->next){
		//		printf("NAME %d: %s\n", ix , (char *)lix->data);
		//		ix++;
		//	}

	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];

	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;
	gchar tempobjectname[255];

	GList *li = NULL; /* an iterator variable */
	GtkWidget *TESTobj;

	gchar *objectname;

        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);

//--------

objectname = strstr(arg0 , ":");
if(! objectname){
	obj = glade_xml_get_widget(xml, arg0);
//printf("glade: %s\n" , arg0);
}else{

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

        	sprintf(tempobjectname , ":%s", (char *)li->data);
		if (!strcmp(  tempobjectname , objectname )) {
			li = g_list_nth(GTKwidgets , i);
			obj = li->data;
//printf("gtk: %s\n" , objectname);
			break;
		}
		i++;
	}

}


	gdouble arg1double;
	gboolean resultgboolean;
	guint resultguint;
	gdouble resultgdouble;
	gint resultgint;
//-- testfunctions

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







  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
