#include <libgda/libgda.h>
#include <sql-parser/gda-sql-parser.h>
#include <glib.h>
#include <unistd.h>


GdaConnection *open_connection (gint version);
void create_table (GdaConnection *cnc);
void run_sql_non_select (GdaConnection *cnc, GdaSqlParser *parser, const gchar *sql);

#if 0
static gpointer
thread_statement (gpointer data)
{
	GdaConnection *cnc;	
	GdaStatement *stmt1, *stmt2;	
	GdaSet *plist1, *plist2;
	GdaSqlParser *sql_parser;
	
	g_message ("hello from thread");
	cnc = (GdaConnection *)data;	
	
	gint i, j;
	gchar* sql1 = "SELECT * from products where price =  ## /* name:'foopar2' type:gint */ ";
	gchar* sql2 = "INSERT INTO products (name, price) VALUES (## /* name:'foopar1' type:gchararray */, "
					"## /* name:'foopar2' type:gint */) ";	
	
	sql_parser = gda_connection_create_parser (cnc);	
	
	for (i=0; i < 100; i++) {
		for (j=0; j < 100; j++) {
			GdaHolder *param;
			GdaDataModel *res;
			GValue* value1;
			GValue* value2;
			GdaSet *last_inserted;			
			gchar *curr_val;
			
			value1 = gda_value_new (G_TYPE_INT);
			value2 = gda_value_new (G_TYPE_STRING);
			
			// set a random int.
			g_value_set_int (value1, j);	
			
			curr_val = g_strdup_printf ("hey%d%d", i, j);			
			g_value_set_string (value2, curr_val);
			// free curr_val
			g_free (curr_val);						
			

			stmt1 = gda_sql_parser_parse_string (sql_parser, sql1, NULL, NULL);	
			stmt2 = gda_sql_parser_parse_string (sql_parser, sql2, NULL, NULL);	
	
			gda_statement_get_parameters (stmt1,  &plist1, NULL);
			gda_statement_get_parameters (stmt2,  &plist2, NULL);

			//
			// stmt1
			//			
		
			if ((param = gda_set_get_holder (plist1, "foopar2")) == NULL)
			{	
				g_warning ("Error!!\n");
			}
			// set an int value.
			gda_holder_set_value(param, value1, NULL);
		
			res = gda_connection_statement_execute_select (cnc, (GdaStatement*)stmt1, 
														  (GdaSet*)plist1, NULL);
		
			// unreffing res!
			g_object_unref (res);


			//
			// stmt2
			//
			if ((param = gda_set_get_holder (plist2, "foopar1")) == NULL)
			{	
				g_warning ("Error!!\n");
			}
			// set a string value.
			gda_holder_set_value(param, value2, NULL);

			if ((param = gda_set_get_holder (plist2, "foopar2")) == NULL)
			{	
				g_warning ("Error!!\n");
			}
			gda_holder_set_value(param, value1, NULL);

			
			GError *err = NULL;
			if (gda_connection_statement_execute_non_select (cnc, 
														 (GdaStatement*)stmt2, 
														 (GdaSet*)plist2, &last_inserted,
														 &err) == -1)			
			{
				g_message ("Error: %s", err->message);
			}


			
			//
			// free the used object: this is not performant but this is just a 
			// test program.
			//
			
			gda_value_free (value1);
			gda_value_free (value2);
			g_object_unref (last_inserted);
			
			g_object_unref (stmt1);
			g_object_unref (stmt2);
			g_object_unref (plist1);
			g_object_unref (plist2);
		}

		g_message ("thread completed cycle" );
	}	
	
	g_object_unref (sql_parser);
	
	return NULL;
}
#endif



static void
execute_statement (GdaConnection *cnc)
{
	GdaStatement *stmt, *stmt2;	
	GdaSet *plist;
	GdaHolder *param;
	GdaSqlParser *sql_parser;
	gint i, j;
	gchar* sql = "SELECT * from products where name =  ## /* name:'foopar' type:gchararray */ ";

	g_message ("hello from execute_statement ");

	sql_parser = gda_connection_create_parser (cnc);
	
	stmt = gda_sql_parser_parse_string (sql_parser, sql, NULL, NULL);	
	stmt2 = gda_sql_parser_parse_string (sql_parser, sql, NULL, NULL);	
	
	gda_statement_get_parameters (stmt,  &plist, NULL);

	gdouble tot = 0.0;
	
	GTimer *timer;
	timer = g_timer_new ();
	GValue* value = gda_value_new (G_TYPE_STRING);	
	g_value_set_static_string (value, "hello");
	for (i=0; i < 200; i++) {
		for (j=0; j < 100; j++) {
			gboolean ret_bool;
		
			// even with GdaDataModelArray the leak is present.
			GdaDataModel *res;		
		
		
			if ((param = gda_set_get_holder (plist, "foopar")) == NULL)
			{	
				printf ("error");
				return ;
			}
			
			/* I suppose memleak appears here */
			gda_holder_take_static_value (param, value, &ret_bool, NULL); 
			
			/* the memleak appears also uncommenting the row below. */
//			gda_holder_set_value(param, value, NULL);
	
			
		
			res = gda_connection_statement_execute_select (cnc, (GdaStatement*)stmt, 
														  (GdaSet*)plist, NULL);
		
			// unreffing res!
			g_object_unref (res);		
		}

		gdouble elapsed = g_timer_elapsed (timer, NULL);
		gda_connection_clear_events_list (cnc);
		tot += elapsed;
		g_print ("elapsed %f av %f\n", elapsed, tot / (double)(i+1) );
		
		g_timer_reset (timer);

	}	
	
	
	g_message ("destroyng stmt");
	
	g_object_unref (stmt);
	g_object_unref (stmt2);
	g_object_unref (plist);
	g_object_unref (sql_parser);
//	gda_connection_close (cnc);
	g_message ("d0ne");
	
}


/*
 * Open a connection to the example.db file
 */
GdaConnection *
open_connection (gint version)
{
    GdaConnection *cnc;
    GError *error = NULL;

	/* open connection */
	if (version == 1)
	{		 
        cnc = gda_connection_open_from_string ("SQLite", "DB_DIR=.;DB_NAME=example_db1", NULL,
					       GDA_CONNECTION_OPTIONS_NONE,
					       &error);
	}
	
	if (version == 2)
	{
        cnc = gda_connection_open_from_string ("SQLite", "DB_DIR=.;DB_NAME=example_db2", NULL,
					       GDA_CONNECTION_OPTIONS_NONE,
					       &error);
	}
	
    if (!cnc) 
	{
              g_print ("Could not open connection to SQLite database in example_db.db file: %s\n",
                        error && error->message ? error->message : "No detail");
               exit (1);
    }
	return cnc;
}

/*
 * Create a "products" table
 */
void
create_table (GdaConnection *cnc)
{
	GdaSqlParser *parser;
	
	parser = gda_connection_create_parser (cnc);
	
	run_sql_non_select (cnc, parser, "DROP table IF EXISTS products");
        run_sql_non_select (cnc, parser, "CREATE table products (project_id integer PRIMARY KEY AUTOINCREMENT, "
                            "name string not null, price integer)");
	run_sql_non_select (cnc, parser, "INSERT INTO products (name, price) VALUES ('chair', 2)");
	run_sql_non_select (cnc, parser, "INSERT INTO products (name, price) VALUES ('table', 5)");

	run_sql_non_select (cnc, parser, "INSERT INTO products (name, price) VALUES ('glass', 1)");
	
	
	g_object_unref (parser);
}


/*
 * run a non SELECT command and stops if an error occurs
 */
void
run_sql_non_select (GdaConnection *cnc, GdaSqlParser *parser, const gchar *sql)
{
       GdaStatement *stmt;
       GError *error = NULL;
       gint nrows;
	const gchar *remain;

	stmt = gda_sql_parser_parse_string (parser, sql, &remain, &error);
	if (remain) 
		g_print ("REMAINS: %s\n", remain);

        nrows = gda_connection_statement_execute_non_select (cnc, stmt, NULL, NULL, &error);
        if (nrows == -1)
                g_error ("NON SELECT error: %s\n", error && error->message ? error->message : "no detail");
	g_object_unref (stmt);
}


int
main (int argc, char *argv[])
{
    gda_init ();

	GdaConnection *cnc1, *cnc2;

	/* open connections */
	cnc1 = open_connection (1);
	create_table (cnc1);

	
	cnc2 = open_connection (2);
	create_table (cnc2);
	
	/* go with thread */
	/*
	g_thread_create ((GThreadFunc)thread_statement, cnc2, 
					 FALSE, NULL);

	g_thread_create ((GThreadFunc)thread_statement, cnc2, 
					 FALSE, NULL);
*/
	/* normal func */
	execute_statement (cnc2);
	
	sleep (10000);
    return 0;
}
