/**
 * @file 
 * File containing guihandler module
 */

#include "guihandler.h"

/** Used to create and editing rectangular 
    images made up of colored pixels.*/
static GdkPixmap *pixmap = NULL; 

/** Used to read informations from Glade build-in GUI.*/
GladeXML *xml;  

/** Variable of type currentGameState that contains the 
    state variables of the game.*/
currentGameState gameState;

/* Start function definition of guihandler module */

void gui(int argc, char **argv)
{
    gtk_init(&argc, &argv);
    
    /* loading the Graphic User Interface */
    xml = glade_xml_new(GLADE_GUI_FILE_NAME, 0, 0);
    
    /* connect the signals to Graphic User Interface */
    glade_xml_signal_autoconnect(xml);
	
    /* Set the window title*/
    GtkWidget *window = glade_xml_get_widget( xml , MAIN_WINDOW_NAME );

    /* Title separator characters*/
    const char titsep[2] = " v";

    char titl[ strlen(PRGNAME) + strlen(PRGVERS) + strlen(titsep) ];
    sprintf( titl, "%s%s%s", PRGNAME, titsep, PRGVERS );
    
    gtk_window_set_title( GTK_WINDOW(window), titl );
    gtk_window_set_icon_from_file( GTK_WINDOW(window), PRGLOGO, NULL );
	
    /* Needs to initialize the drawing area*/
    configure_event( glade_xml_get_widget(xml ,DRAW_AREA_NAME) , NULL , NULL );
	
    /* Initialize the variables of data struct currentGameState. */
    gameState = initializeCurrentGameState();

    /* Start the Graphic User Interface */
    gtk_main();
}


gboolean delete_event( GtkWidget *window, 
                       GdkEvent  *event,  
                       gpointer   data    
                     )
{

    D1(printf("\nGUIHANDLER.delete_event() - START\n"));

    window = glade_xml_get_widget( xml , MAIN_WINDOW_NAME );
    
    /* Create dialog only the first time we enter this callback.
     * After first time, just show it. */
    static GtkWidget *dialog = NULL;
    const unsigned short int YES = 1;
    const unsigned short int NO = 2;
    gint response;

    if( ! dialog )
    {
        D4(printf("\nGUIHANDLER.delete_event() - (! dialog) -> creation \n"));
        
        GtkWidget *label;
        GtkWidget *box;

        /* Create dialog */
        dialog = gtk_dialog_new();

        /* Set it modal and transient for main window. */
        gtk_window_set_modal( GTK_WINDOW( dialog ), TRUE );
        gtk_window_set_transient_for( GTK_WINDOW( dialog ),
                                      GTK_WINDOW( window ) );

        /* Set title */
        gtk_window_set_title( GTK_WINDOW( dialog ), "Confirm" );

        /* Add buttons. */
        gtk_dialog_add_button( GTK_DIALOG( dialog ), GTK_STOCK_YES, YES );
        gtk_dialog_add_button( GTK_DIALOG( dialog ), GTK_STOCK_NO,  NO );

        /* Create label */
        label = gtk_label_new( "Are you sure you want to quit?" );

        /* Pack label, taking API change in account. */
        box = gtk_dialog_get_content_area( GTK_DIALOG( dialog ) );

        gtk_box_pack_start( GTK_BOX( box ), label, TRUE, TRUE, 0 );

        /* Show dialog */
        gtk_widget_show_all( dialog );
    }

    /* Run dialog */
    response = gtk_dialog_run( GTK_DIALOG( dialog ) );
    gtk_widget_hide( dialog );
    
    D2(printf("\nAt question 'Exit?' user say %i (%s)\n",
                                       response,((response==YES)?"YES":"NO")));
    
    D1(printf("\nGUIHANDLER.delete_event() - END\n"));

    if( response == YES ){
        gtk_main_quit();
        return false;
    }
    
    assert( response != YES );

    return true;
}


void new_tournament( GtkWidget *window, 
                     GtkWidget *widget, 
                     gpointer data
                   )
{
    
    D1(printf("\nGUIHANDLER.new_tournament() - START\n"));
    
    GtkWidget *downlabel = glade_xml_get_widget( xml , DOWN_LABEL_NAME );

    gameState.numOfRound = NEW_GAME_ROUND;
    
    // If function is invoked by user (from menu) reset level,points
    if( window != NULL ){ 
        gameState.currentlevel = START_LEVEL;
        gameState.totalpoints = START_TOTAL_POINTS;
    }    

    char *schemafilename = get_schema_name( (gameState.currentlevel-1) );

    if( strcmp(schemafilename , "" ) == 0 )
    {
        char errmsg[MAX_ERR_BUFFER_LEN];
        sprintf( errmsg , "WARNING: No such file in ./%s/%s%u/",
                        GAMES_DIR,GAMES_LEVEL_DIR,(gameState.currentlevel-1) );

        gtk_label_set_text( GTK_LABEL(downlabel), errmsg);
        gameState.playing = false;
        free(schemafilename);
    }                        
    else
    {
        double loadsuccess = newgame( schemafilename , &gameState.bestrouteweight );
        free(schemafilename);

        if(loadsuccess<0){
            gtk_label_set_text( GTK_LABEL(downlabel),
                                "WARNING: Error in schema validating.");
            gameState.playing = false;
        }
        else
        { 
            clock_t tEnd, tStart = clock(); //Time start
            
            drawschema();
            
            tEnd = clock(); // Time end
            // Elapsed time in seconds
            double drawtime = (double)(tEnd-tStart)/CLOCKS_PER_SEC;
            
            char msg[MAX_OTH_BUFFER_LEN];
            unsigned int i=0;
            for(i=0;i<strlen(msg);i++) // Needs initialize
                msg[i] = NULLCHAR;
            
            sprintf( msg,
                        "Schema times in seconds: "\
                        "Loaded & validated in %.3lf. Printed in %.3lf.",
                        loadsuccess,
                        drawtime
                    );
            
            D2(printf("%s",msg));
            
            gtk_label_set_text( GTK_LABEL(downlabel), msg );
            
            // set current postition in start
            gameState.currentRow = schemaData.startRow;
            gameState.currentCol = schemaData.startCol;
            // set iterations to start weight
            gameState.iters = weight( schemaData.gameMap
                                            [gameState.currentRow]
                                            [gameState.currentCol] 
                                    );
            
            gameState.playing = true;
            
            time_t *tmpstart=NULL;
            gameState.starttime = time(tmpstart);
            free(tmpstart);
        }
    }
    
    D1(printf("\nGUIHANDLER.new_tournament() - END\n"));
}


void drawschema()
{
    D3(printf("\nGUIHANDLER.drawschema() - START\n"));
    char *col;
    
    GtkWidget *drawarea = glade_xml_get_widget( xml , DRAW_AREA_NAME );
    
    // Clear all area ( from (0,0) to (max X, max Y) )
    col = color(CLOSE);
    draw_brush( drawarea,
                0, 0,
                drawarea->allocation.width, drawarea->allocation.height,
                col
              );
    
    // WARNING: First time Rows and Cols could be 0 !
    const unsigned int drawX = 
        (unsigned int)( (drawarea->allocation.width) /
                        ( (schemaData.numCol>0)?(schemaData.numCol):(1) ) );
    
    const unsigned int drawY = 
        (unsigned int)( (drawarea->allocation.height) /
                        ( (schemaData.numRow>0)?(schemaData.numRow):(1) ) );
    
    unsigned int i=0, j=0;    
    for(i=0; i<schemaData.numRow; i++) // rows
        for(j=0; j<schemaData.numCol; j++) // cols
        {
            if( schemaData.gameMap[i][j] != FREE )
                col = color( schemaData.gameMap[i][j] );
            else
                col = colorVisited( schemaData.visitedCellInfo[i][j] );
                
            //(drawarea, x position, y position, x size, y size, color)
            draw_brush( drawarea, (j*drawX), (i*drawY), drawX, drawY, col );
        }
    
    free( col );
        
    D3(printf("\nGUIHANDLER.drawschema() - END\n"));
}


gboolean configure_event( GtkWidget *widget, 
                          GdkEventConfigure *event,
                          gpointer data
                        )
{
  D1(printf("\nGUIHANDLER.configure_event() - START\n"));

  if (pixmap)
    g_object_unref(pixmap);

  pixmap = gdk_pixmap_new(widget->window,
			  widget->allocation.width,
			  widget->allocation.height,
			  -1);
  
  gdk_draw_rectangle (pixmap,
		      widget->style->white_gc,
		      TRUE,
		      0, 0,
		      widget->allocation.width,
		      widget->allocation.height);

  drawschema();
  
  D1(printf("\nGUIHANDLER.configure_event() - END\n"));
  
  return true;
}


gboolean expose_event( GtkWidget *widget, 
                       GdkEventExpose *event, 
                       gpointer data
                     )
{
   D5(printf("\nGUIHANDLER.expose_event() - START\n"));
   
   gdk_draw_drawable(widget->window,
		    widget->style->fg_gc[GTK_WIDGET_STATE (widget)],
		    pixmap,
		    event->area.x, event->area.y,
		    event->area.x, event->area.y,
		    event->area.width, event->area.height);
		    
   D5(printf("\nGUIHANDLER.expose_event() - END\n"));
   
   return false;
}


void draw_brush (   GtkWidget *widget,
                    gdouble x,
                    gdouble y,
                    gdouble width,
                    gdouble height,
                    char *col
                 )
{
  D3(printf("\nGUIHANDLER.draw_brush() "\
            "rectangle[%.0lf,%.0lf] in (%.0lf,%.0lf) color %s",
                       width,height,       x ,  y      ,   col  ));
  
  GdkRectangle update_rect;

  update_rect.x = x; // x position
  update_rect.y = y; // y position
  update_rect.width = width; // width length
  update_rect.height = height;  // height length
  
  GdkGC *gc = gdk_gc_new(pixmap);
  GdkColor color;

  // set color from Exadec string col Es. "#FF0000"
  gdk_color_parse (col,&color); 
  gdk_gc_set_rgb_fg_color(gc, &color);

  gdk_draw_rectangle (pixmap,
                      gc,
          		      TRUE,
        		      update_rect.x, update_rect.y,
        		      update_rect.width, update_rect.height);
  
  gtk_widget_queue_draw_area (widget, 		      
                              update_rect.x, update_rect.y,
		                      update_rect.width, update_rect.height);
  
  gtk_widget_draw (glade_xml_get_widget( xml , DRAW_AREA_NAME ), &update_rect);
}



void keypressed( GtkWidget *window, 
                 GdkEventKey *event, 
                 gpointer data
               )
{

  D1(printf("\nGUIHANDLER.keypressed() - START\n"));
 
  if( gameState.playing )
  {   
      assert( gameState.playing );

      GtkWidget *drawarea = glade_xml_get_widget( xml , DRAW_AREA_NAME );
      
      // WARNING: First time Rows and Cols could be 0 !
      const unsigned int drawX = 
        (unsigned int)( (drawarea->allocation.width) /
                        ( (schemaData.numCol>0)?(schemaData.numCol):(1) ) );
    
      const unsigned int drawY = 
        (unsigned int)( (drawarea->allocation.height) /
                        ( (schemaData.numRow>0)?(schemaData.numRow):(1) ) );
                            
      char key[MAX_OTH_BUFFER_LEN];
      unsigned int i = 0;
      for(i=0;i<strlen(key);i++)
        key[i] = NULLCHAR;
            
      checkKeyPressed( event->keyval, key, drawarea, drawX, drawY );
      
      D2(printf("\nPressed key: %s\n",key));
      
      gtk_label_set_text( GTK_LABEL(glade_xml_get_widget(xml,DOWN_LABEL_NAME)),
                          key);
      
      if(schemaData.gameMap[gameState.currentRow][gameState.currentCol]==DOOR)
        win();
  }
  else{
    assert( !gameState.playing );

    char key[] = "Select 'new game' or 'open game' from menu to play!";
    gtk_label_set_text( GTK_LABEL(glade_xml_get_widget( xml,DOWN_LABEL_NAME )),
                        key);
  }
    
  D1(printf("\nGUIHANDLER.keypressed() - END\n"));

}


void checkKeyPressed( int keyval, 
                      char *key,
                      GtkWidget *drawarea, 
                      unsigned int drawX, 
                      unsigned int drawY 
                    )
{
   D1(printf("\nGUIHANDLER.checkKeyPressed() - START\n"));

   enum point_type { WALL , SCHEMA_END , VALID } current_point;

   current_point = VALID;

   switch(keyval)
   {
        case GDK_Up:
        {
          strcpy(key,"UP");
          if(gameState.currentRow>0)
          {
              if( isaccessible( schemaData.gameMap[gameState.currentRow-1]
                                                  [gameState.currentCol]   ) )
              {
                    gameState.currentRow--;
                    updateSchemaCell(drawarea, drawX, drawY);
        	  }
        	  else
        	    { current_point = WALL; }
          }
          else
        	{ current_point = SCHEMA_END; }
          break;
        }
        
        case GDK_Down:
        {
          strcpy(key,"DOWN");
          if((gameState.currentRow+1)<schemaData.numRow)
          {
              if( isaccessible( schemaData.gameMap[gameState.currentRow+1]
                                                  [gameState.currentCol]   ) )
              {
                    gameState.currentRow++;
                    updateSchemaCell(drawarea, drawX, drawY);
        	  }
        	  else
        	    { current_point = WALL; }
          }
          else
        	{ current_point = SCHEMA_END; }
          break;
        }   
         
        case GDK_Right:
        {
          strcpy(key,"RIGHT");
          if((gameState.currentCol+1)<schemaData.numCol)
          {
              if( isaccessible( schemaData.gameMap[gameState.currentRow]
                                                  [gameState.currentCol+1] ) )
              {
                  gameState.currentCol++;
                  updateSchemaCell(drawarea, drawX, drawY);
        	  }
    	      else
    	        { current_point = WALL; }
    	  }
    	  else
        	{ current_point = SCHEMA_END; }
          break;
        } 
            
        case GDK_Left:
        {
          strcpy(key,"LEFT");
          if(gameState.currentCol>0)
          {
             if(isaccessible(schemaData.gameMap [gameState.currentRow]
                                                [gameState.currentCol-1] ) )
             {
                    gameState.currentCol--;
                    updateSchemaCell(drawarea, drawX, drawY);
        	 }
        	 else
        	   { current_point = WALL; }
    	  }
    	  else
        	{ current_point = SCHEMA_END; }
          break;
        }
          
        default: {
            strcpy(key,"UNKNOWN KEY! Use upper menu for any help...");
            break;
        }
   }

   assert( strlen(key) > 0 );

   char tmp_key[ strlen(key) ];
   strcpy( tmp_key , key );

   if( current_point == WALL )
        sprintf(key,"CAN'T GO %s! (This is a wall :)",tmp_key);
   else
       if( current_point == SCHEMA_END )
            sprintf(key,"CAN'T GO %s! (Schema's end)",tmp_key);

   D1(printf("\nGUIHANDLER.checkKeyPressed() - END\n")); 
}



void updateSchemaCell(GtkWidget *drawarea, 
                      unsigned int drawX, 
                      unsigned int drawY 
                     )
{

    D1(printf("\nGUIHANDLER.updateSchemaCell() - START\n"));

    gameState.iters += weight( schemaData.gameMap[gameState.currentRow]
                                                 [gameState.currentCol]
                             );
                            
    visitCell( gameState.currentRow, gameState.currentCol ); 
    
    draw_brush( drawarea,
                ( gameState.currentCol * drawX ),
                ( gameState.currentRow * drawY ),
                drawX,
                drawY,
                colorVisited( schemaData.visitedCellInfo[gameState.currentRow]
                                                        [gameState.currentCol]
                            )
              );

    D1(printf("\nGUIHANDLER.updateSchemaCell() - END\n"));
}

void win(){
    
    D1(printf("\nGUIHANDLER.win() - START\n"));
    
    GtkWidget *window = glade_xml_get_widget( xml , MAIN_WINDOW_NAME );
    GtkWidget *downlabel = glade_xml_get_widget( xml , DOWN_LABEL_NAME );
    GtkWidget *windialog = NULL;

    char labeltxt[MAX_OTH_BUFFER_LEN];
    unsigned int i = 0;
    for(i=0;i<strlen(labeltxt);i++)
        labeltxt[i] = NULLCHAR;

    gameState.totalpoints = calcSchemaResults( labeltxt , gameState );

    windialog = gtk_message_dialog_new( GTK_WINDOW(window),
                                        GTK_DIALOG_MODAL,
                                        GTK_MESSAGE_INFO,
                                        GTK_BUTTONS_OK,
                                        "%s",labeltxt
                                      );
    gtk_window_set_title(GTK_WINDOW(windialog), "Win current schema.");
    gtk_window_set_transient_for( GTK_WINDOW( windialog ),
                                  GTK_WINDOW( window ) );
    

    gtk_dialog_run( GTK_DIALOG( windialog ) );
    gtk_widget_destroy ( windialog );
    
    D2(printf("\nCurrent level %u of %u\n",
                gameState.currentlevel,gameState.numOfRound));

    if( gameState.currentlevel < gameState.numOfRound )
    {   // Win current schema -> next schema
        gameState.currentlevel++;
        new_tournament(NULL, NULL, NULL); //first argument Must be NULL !
    }
    else 
    {   // Win the 'tournament' -> end
        /* Show message in down label */
        sprintf(labeltxt,"Tournament finished! Total points: %u",
                                                    gameState.totalpoints);
        gtk_label_set_text(GTK_LABEL(downlabel),labeltxt);
        
        /* If tournament (new_tournament) display advise */
        if( gameState.numOfRound > START_ROUND_NUMBER ){
            GtkWidget *winalldialog = NULL;
            
            sprintf(labeltxt,"Tournament finished, YOU WIN!\n\nTotal points: %u",
                    gameState.totalpoints);
            
            winalldialog = gtk_message_dialog_new( GTK_WINDOW(window),
                                                GTK_DIALOG_MODAL,
                                                GTK_MESSAGE_INFO,
                                                GTK_BUTTONS_OK,
                                                "%s",labeltxt
                                              );
            gtk_window_set_title(GTK_WINDOW(winalldialog), "Tournament win!");
            gtk_window_set_transient_for( GTK_WINDOW( winalldialog ),
                                          GTK_WINDOW( window ) );
            

            gtk_dialog_run( GTK_DIALOG( winalldialog ) );
            gtk_widget_destroy ( winalldialog );
        }

        char playerName[ MAX_OTH_BUFFER_LEN ];
        for( i=0; i<strlen(playerName); i++ )
            playerName[i] = NULLCHAR;
        
        if( get_player_name( GTK_WIDGET(window), playerName ) )
		    save_record( playerName,
                         gameState.totalpoints,
                         gameState.currentlevel );
        
        /* Reset */
        gameState.totalpoints = START_TOTAL_POINTS;
        gameState.currentlevel = START_LEVEL;
        gameState.playing = false;
        
        /* Manage records */
        show_records(NULL,GTK_WINDOW(window));
    }
    
    D1(printf("\nGUIHANDLER.win() - END\n"));
}



void show_records( GtkWidget *widget, 
                   GtkWindow *window
                 )
{
    
    D1(printf("\nGUIHANDLER.show_records() - START\n"));

    unsigned int numRecord = 0, i = 0;

    bool check = false;
    check = readSetGameRecord( &numRecord );
    
    char *labeltxt = (char *)malloc( sizeof(char) * 
                                     MAX_OTH_BUFFER_LEN * 
                                     (numRecord+1)             );
                                    
    for( i=0; i<strlen(labeltxt); i++ )
        labeltxt[i] = NULLCHAR;
    
    if( ! check )
    {
        sprintf( labeltxt, "Record file corrupted or missing.");
        sprintf( labeltxt, "%s\n\nPlease save a record to resolve.", labeltxt);
        remove( RECORD_FILE_NAME );
    }
	else
	{   
	    if( numRecord == 0 )
	        sprintf( labeltxt , "No record saved." );
        else
        for( i=0; i<numRecord ; i++ ){
            sprintf( labeltxt,"%s%u) %s  -  score: %u   level: %u   \n",
                     labeltxt, (i+1) ,gameRecord[i].name, gameRecord[i].points, 
                                                        gameRecord[i].level  );
        }
    }


    GtkWidget *windialog = NULL;

    windialog = gtk_message_dialog_new( GTK_WINDOW(window),
                                        GTK_DIALOG_MODAL,
                                        GTK_MESSAGE_INFO,
                                        GTK_BUTTONS_OK,
                                        "%s",labeltxt
                                      );
    gtk_window_set_title(GTK_WINDOW(windialog), "Records");
    gtk_window_set_transient_for( GTK_WINDOW( windialog ),
                                  GTK_WINDOW( window ) );
    

    gtk_dialog_run( GTK_DIALOG( windialog ) );
    gtk_widget_destroy ( windialog );
    
    free(labeltxt);

    D1(printf("\nGUIHANDLER.show_records() - END\n"));
}



bool get_player_name( GtkWidget *window, 
                      gchar *input_text
                    )
{
    D1(printf("\nGUIHANDLER.get_player_name() - START\n"));
    
    GtkWidget *dialog;
    GtkWidget *label;
    GtkWidget *input;
    GtkWidget *box;

    bool returnresponse = true;
    bool go = true;

    do
    {
        /* Create dialog */
        dialog = gtk_dialog_new();

        /* Set it modal and transient for main window. */
        gtk_window_set_modal( GTK_WINDOW( dialog ), TRUE );
        gtk_window_set_transient_for( GTK_WINDOW( dialog ),
                                      GTK_WINDOW( window ) );

        /* Set title */
        gtk_window_set_title( GTK_WINDOW( dialog ), "Save record" );
        
        const unsigned short int OK = 1, CANCEL = 2;
        
        /* Add buttons. */
        gtk_dialog_add_button( GTK_DIALOG( dialog ), GTK_STOCK_OK, OK );
        gtk_dialog_add_button( GTK_DIALOG( dialog ), GTK_STOCK_CANCEL, CANCEL);

        /* Create label */
        label = gtk_label_new( "Insert your name:" );

        /* Create input text box and set max length */
        input = gtk_entry_new();
        gtk_entry_set_max_length( GTK_ENTRY(input) , MAX_RECORDNAME_LEN - 1 );
        if(input_text != NULL )
            if( strlen(input_text)>0 )
                gtk_entry_set_text( GTK_ENTRY(input) , input_text );

        /* Pack label and text box, taking API change in account. */
        box = gtk_dialog_get_content_area( GTK_DIALOG( dialog ) );

        gtk_box_pack_start( GTK_BOX( box ), label, TRUE, TRUE, 0 );
        gtk_box_pack_start( GTK_BOX( box ), input, TRUE, TRUE, 0 );

        /* Show dialog */
        gtk_widget_show_all( dialog );

        /* Get response */
        gint response = gtk_dialog_run( GTK_DIALOG( dialog ) );
    
        go = true;
        
        if( response==OK )
        {
            strcpy( input_text, gtk_entry_get_text(GTK_ENTRY(input)) );

            go = checkResponseNameError(window, input_text);    
        }
        else
            returnresponse = false;        
    
        gtk_widget_destroy( dialog );

        D2(printf("\nUser pressed %s and insert value %s that is %s.\n",
                            (response==OK)?("OK"):("CANCEL"),
                            input_text, go?"VALID":"NOT VALID"    ));
    }
    while(!go);
                  
	D1(printf("\nGUIHANDLER.get_player_name() - END\n"));
	
	return returnresponse;
}


bool checkResponseNameError(GtkWidget *window, char *input_text)
{
  	D1(printf("\nGUIHANDLER.checkResponseNameError() - START\n"));

    bool go = true;
    unsigned int i = 0, j = 0; // iterators
    
    char labeltxt[MAX_ERR_BUFFER_LEN];
    for( j=0; j<strlen(labeltxt); j++ )
            labeltxt[j] = NULLCHAR;
    
    if( strlen( input_text ) <= 0)
    {
        sprintf( labeltxt , "\nName is empty!");
        go = false;
    }
    
    for(i = 0; ( i<strlen(input_text) )&& go; i++ )
        if( ! isallowedchar( LOWERCASE + UPPERCASE + DIGITS , input_text[i] ) )
        {
            sprintf( labeltxt , "Name error:\n\n");
            sprintf( labeltxt , "%s  %uth character not allowed!\n",
                                labeltxt, (i+1)                      );
            sprintf( labeltxt , "%s  Display character is %c\n",
                                labeltxt,           input_text[i] );
            sprintf( labeltxt , "%s  ASCII value is %i\n", 
                                labeltxt, (int)input_text[i] );
            go = false;
        }
        
     if( !go )
     {
        GtkWidget *errdialog = NULL;

        errdialog = gtk_message_dialog_new( GTK_WINDOW(window),
                                            GTK_DIALOG_MODAL,
                                            GTK_MESSAGE_WARNING,
                                            GTK_BUTTONS_OK,
                                            "%s",labeltxt
                                            );
        gtk_window_set_title( GTK_WINDOW(errdialog), 
                                "Name error." );
        gtk_window_set_transient_for( GTK_WINDOW( errdialog ),
                                        GTK_WINDOW( window ) );
        

        gtk_dialog_run( GTK_DIALOG( errdialog ) );
        gtk_widget_destroy ( errdialog );
     }

  	D1(printf("\nGUIHANDLER.checkResponseNameError() - END\n"));

    return go;

}

void drawingAndSetSchemaInfo( double loadsuccess )
{
    D1(printf("\nGUIHANDLER.drawingAndSetSchemaInfo() - START\n"));
    
    clock_t tEnd, tStart;
    
    tStart = clock(); //Time start
    
    drawschema();
    
    tEnd = clock(); // Time end
    
    // Elapsed time in seconds
    double drawtime = (double)(tEnd-tStart)/CLOCKS_PER_SEC;

    unsigned int i=0;
            
    char msg[MAX_OTH_BUFFER_LEN];
    for(i=0;i<strlen(msg);i++)
        msg[i] = NULLCHAR;
    
    sprintf( msg,
                "Schema times in seconds: "\
                "Loaded & validated in %.3lf. Printed in %.3lf.",
                                loadsuccess,      drawtime
            );
    
    D2(printf("%s",msg));
    
    gtk_label_set_text( GTK_LABEL(glade_xml_get_widget(xml, DOWN_LABEL_NAME) ),
                        msg
                        );
    
    // set current postition in start
    gameState.currentRow = schemaData.startRow;
    gameState.currentCol = schemaData.startCol;
    
    // set iterations to start weight
    gameState.iters = weight( schemaData.gameMap[gameState.currentRow]
                                                [gameState.currentCol]  );
    
    gameState.playing = true;
    
    time_t *tmpstart=NULL;
    gameState.starttime = time(tmpstart);
    free(tmpstart);

    D1(printf("\nGUIHANDLER.drawingAndSetSchemaInfo() - END\n"));
}


void open_game( GtkWidget *window, 
                GtkWidget *widget, 
                gpointer data
              )
{   
    D1(printf("\nGUIHANDLER.open_game() - START\n"));
    
    gameState.numOfRound = START_ROUND_NUMBER;
    gameState.currentlevel = START_LEVEL;
    gameState.totalpoints = START_TOTAL_POINTS;
    
    GtkWidget *dialog;
     
    dialog = gtk_file_chooser_dialog_new(  "Open Game",
                                           NULL,
                                           GTK_FILE_CHOOSER_ACTION_OPEN,
                                           GTK_STOCK_CANCEL, 
                                           GTK_RESPONSE_CANCEL,
                                           GTK_STOCK_OPEN, 
                                           GTK_RESPONSE_ACCEPT,
                                           NULL
                                         );

    gtk_file_chooser_set_current_folder( GTK_FILE_CHOOSER(dialog), GAMES_DIR );
     
    if( gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_ACCEPT )
    {
        char *filename;
     
        filename = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(dialog));

        double loadsuccess = newgame( filename, &gameState.bestrouteweight );
        
        gtk_widget_destroy( dialog );
        
        g_free( filename );
            
        if( loadsuccess<0 ){
            gtk_label_set_text( GTK_LABEL( glade_xml_get_widget( xml , 
                                                              DOWN_LABEL_NAME )
                                         ),
                                "WARNING: Error in schema validating."
                              );
            gameState.playing = false;
        }
        else
            drawingAndSetSchemaInfo( loadsuccess );
        
    }
    else
        gtk_widget_destroy (dialog);
    
    D1(printf("\nGUIHANDLER.open_game() - END\n"));
}


void generate_game( GtkWidget *widget, 
                    GtkWindow *window
                  )
{
    D1(printf("\nGUIHANDLER.generate_game() - START\n"));
    
    /* Select file name */
    GtkWidget *dialog;
     
    dialog = gtk_file_chooser_dialog_new( "Save File",
                                          window,
                                          GTK_FILE_CHOOSER_ACTION_SAVE,
                                          GTK_STOCK_CANCEL, 
                                          GTK_RESPONSE_CANCEL,
                                          GTK_STOCK_SAVE, 
                                          GTK_RESPONSE_ACCEPT,
                                          NULL
                                        );

    gtk_file_chooser_set_do_overwrite_confirmation( GTK_FILE_CHOOSER (dialog),
                                                    TRUE                     );
    
    gtk_file_chooser_set_current_folder( GTK_FILE_CHOOSER(dialog), GAMES_DIR );

    gtk_file_chooser_set_current_name( GTK_FILE_CHOOSER(dialog), 
                                       "Select file name"           );
    
    /* return if not OK */
    if( gtk_dialog_run(GTK_DIALOG(dialog)) != GTK_RESPONSE_ACCEPT ){
        gtk_widget_destroy( dialog );
        D1(printf("\nGUIHANDLER.generate_game() - CANCEL and END\n"));
        return;
    }
    
    char *filename;
    filename = gtk_file_chooser_get_filename( GTK_FILE_CHOOSER( dialog ) );

    gtk_widget_destroy(dialog);
    
    unsigned int rows, cols, difficult;
    if( ! request_generate_parameters( window, &rows, &cols, &difficult ) ){
        D1(printf("\nRequest_generate_parameters() CANCEL or ERROR\n"));
        D1(printf("\nGUIHANDLER.generate_game() - END (1)\n"));
        return;
    }
    
    if( ! generateSchema( filename, rows, cols, difficult) ){
        D1(printf("\nGenerateSchema() ERROR\n"));
        D1(printf("\nGUIHANDLER.generate_game() - END (2)\n"));
        return;
    }
    
    gameState.numOfRound = START_ROUND_NUMBER;
    gameState.currentlevel = START_LEVEL;
    gameState.totalpoints = START_TOTAL_POINTS;
    
    double loadsuccess = newgame( filename, &gameState.bestrouteweight );
    
    g_free(filename);
            
    if( loadsuccess<0 ){
        gtk_label_set_text(GTK_LABEL(glade_xml_get_widget(xml,DOWN_LABEL_NAME)),
                           "WARNING: Error in schema validating.");
        gameState.playing = false;
    }
    else
        drawingAndSetSchemaInfo( loadsuccess );    

    D1(printf("\nGUIHANDLER.generate_game() - END\n"));
}



bool request_generate_parameters( GtkWindow *window, 
                                  unsigned int *rows,
                                  unsigned int *cols,
                                  unsigned int *difficult 
                                )
{
    D1(printf("\nGUIHANDLER.request_generate_parameters() - START\n"));
    
    unsigned int i = 0;
    bool returnresponse = true;
    bool go = true;
    const unsigned short int OK = 1, CANCEL = 2;
    
    GtkWidget *dialog;
    GtkWidget *label_rows;
    GtkWidget *input_rows;
    GtkWidget *label_cols;
    GtkWidget *input_cols;
    GtkWidget *label_difficult;
    GtkWidget *input_difficult;
    GtkWidget *box;

    do
    {
        /* Create dialog */
        dialog = gtk_dialog_new();
        /* Set it modal and transient for main window. */
        gtk_window_set_modal( GTK_WINDOW( dialog ), TRUE );
        gtk_window_set_transient_for( GTK_WINDOW( dialog ),
                                      GTK_WINDOW( window ) );
        /* Set title */
        gtk_window_set_title( GTK_WINDOW( dialog ), "Set generate parameters");
        /* Add buttons. */
        gtk_dialog_add_button( GTK_DIALOG( dialog ), GTK_STOCK_OK, OK );
        gtk_dialog_add_button( GTK_DIALOG( dialog ), GTK_STOCK_CANCEL, CANCEL);
        
        /* Create labels */
        char labmsg[MAX_OTH_BUFFER_LEN];
        for(i = 0; i<strlen(labmsg); i++)
            labmsg[i] = NULLCHAR;
        
        sprintf(labmsg,"Insert number of ROWS (%u-%u):",MINR,MAXR);
        label_rows      = gtk_label_new( labmsg );
        sprintf(labmsg,"Insert number of COLS (%u-%u):",MINC,MAXC);
        label_cols      = gtk_label_new( labmsg );
        sprintf(labmsg,"Set difficult (%u-%u):",MIN_DIFFICULT,MAX_DIFFICULT);
        label_difficult = gtk_label_new( labmsg );

        /* Create input(s) text box, text vars and set max length(s) */
        input_rows      = gtk_entry_new();
        input_cols      = gtk_entry_new();
        input_difficult = gtk_entry_new();
        
        char *rows_text = set_gtk_entry_text_from_num( MAXR , input_rows );
        char *cols_text = set_gtk_entry_text_from_num( MAXC , input_cols );
        char *difficult_text = set_gtk_entry_text_from_num( MAX_DIFFICULT ,
                                                            input_difficult );
        
        /* Pack label and text box, taking API change in account. */
        box = gtk_dialog_get_content_area( GTK_DIALOG( dialog ) );

        gtk_box_pack_start( GTK_BOX( box ), label_rows, TRUE, TRUE, 0 );
        gtk_box_pack_start( GTK_BOX( box ), input_rows, TRUE, TRUE, 0 );
        gtk_box_pack_start( GTK_BOX( box ), label_cols, TRUE, TRUE, 0 );
        gtk_box_pack_start( GTK_BOX( box ), input_cols, TRUE, TRUE, 0 );
        gtk_box_pack_start( GTK_BOX( box ), label_difficult, TRUE, TRUE, 0 );
        gtk_box_pack_start( GTK_BOX( box ), input_difficult, TRUE, TRUE, 0 );

        gtk_widget_show_all( dialog ); /* Show dialog */

        gint response = gtk_dialog_run( GTK_DIALOG(dialog) ); /* Get response*/
        
        go = true;
        
        if(response==OK)
        {
            /* Get and copy the parameters inserted by user */
            strcpy( rows_text, gtk_entry_get_text(GTK_ENTRY(input_rows) ) );
            strcpy( cols_text, gtk_entry_get_text(GTK_ENTRY(input_cols) ) );
            strcpy( difficult_text,
                    gtk_entry_get_text(GTK_ENTRY(input_difficult) ) );
            
            go = checkResponseErrorGenerateParameters(  window, 
                                                        rows_text, 
                                                        cols_text, 
                                                        difficult_text,
                                                        rows,
                                                        cols,
                                                        difficult
                                                      );
        }
        else
             returnresponse = false;        
        
        gtk_widget_destroy( dialog );

        D2(printf("\nUser pressed %s and insert values that are %s.\n",
                      (response==OK)?("OK"):("CANCEL"),go?"VALID":"NOT VALID"));

        free(rows_text);
        free(cols_text);
        free(difficult_text);

    }
    while(!go);
                     
	D1(printf("\nGUIHANDLER.request_generate_parameters() - END\n"));
	
	return returnresponse;

}


char *set_gtk_entry_text_from_num( unsigned int number,
                                    GtkWidget *entry
                                 )
{
    D1(printf("\nGUIHANDLER.set_gtk_entry_text_from_num() - START\n"));
    
    unsigned int numDigits = countDigits( number );
    const unsigned short int ADDITIONAL_CHAR_NUMBER = 1;
    
    gtk_entry_set_max_length( GTK_ENTRY( entry ) , numDigits );
    
    char *text = (char *)malloc( sizeof(char) * ( numDigits + 
                                                 ADDITIONAL_CHAR_NUMBER
                                               )
                               );
    sprintf(text,"%u",number);
    
    gtk_entry_set_text( GTK_ENTRY(entry) , text );
    
    D1(printf("\nGUIHANDLER.set_gtk_entry_text_from_num() - END\n"));
    return text;
}



bool checkResponseErrorGenerateParameters(GtkWindow *window, 
                                          char *rows_text, 
                                          char *cols_text, 
                                          char *difficult_text,
                                          unsigned int *rows,
                                          unsigned int *cols,
                                          unsigned int *difficult
                                         )
{
   D1(printf("\nGUIHANDLER.checkResponseErrorGenerateParameters() - START\n"));

    bool go = true;
    
    char err[MAX_ERR_BUFFER_LEN];
    char err_label[MAX_OTH_BUFFER_LEN];
    
    strcpy( err_label , "ROWS" );
    go = check_if_text_is_number( go , rows_text, err, err_label );
    
    strcpy( err_label , "COLS" );
    go = check_if_text_is_number( go , cols_text, err, err_label );
    
    strcpy( err_label , "DIFFICULT" );
    go = check_if_text_is_number( go , difficult_text, err, err_label );
    
    /* The texts are composed only by numbers */
    if( go ){
        *rows      = atoi(rows_text);
        *cols      = atoi(cols_text);
        *difficult = atoi(difficult_text);
        
        if( (*rows<MINR) || (*rows>MAXR) ){
            go = false;
            sprintf(err, "Error in ROWS:\n\n"  );
            sprintf(err, "%s   Wrong size: %u",err,*rows);
        }
        
        if( (*cols<MINC) || (*cols>MAXC) ){
            go = false;
            sprintf(err, "Error in COLS:\n\n"  );
            sprintf(err, "%s   Wrong size: %u",err,*cols);
        }
        
        if( (*difficult<MIN_DIFFICULT) || (*difficult>MAX_DIFFICULT) ){
            go = false;
            sprintf(err, "Error in DIFFICULT:\n\n"  );
            sprintf(err, "%s   Wrong size: %u",err,*difficult);
        }
    }
    
    if( !go ){ 
            
        GtkWidget *errdialog = NULL;

        errdialog = gtk_message_dialog_new( GTK_WINDOW(window),
                                            GTK_DIALOG_MODAL,
                                            GTK_MESSAGE_WARNING,
                                            GTK_BUTTONS_OK,
                                            "%s",err
                                            );
        gtk_window_set_title( GTK_WINDOW(errdialog), "Parameters error." );
        gtk_window_set_transient_for( GTK_WINDOW( errdialog ),
                                        GTK_WINDOW( window ) );
        

        gtk_dialog_run( GTK_DIALOG( errdialog ) );
        gtk_widget_destroy ( errdialog );
    }

    D1(printf("\nGUIHANDLER.checkResponseErrorGenerateParameters() - END\n"));

    return  go;
}


void show_help( GtkWidget *widget, 
                GtkWidget *window, 
                gpointer data
              )
{
    D1(printf("\nGUIHANDLER.show_help() - START\n"));
    
    window = glade_xml_get_widget( xml , MAIN_WINDOW_NAME );
   
    /* Create dialog only the first time we enter this callback.
     * After first time, just use it. */
    static GtkWidget *dialog = NULL;

    if( ! dialog )
    {
        D4(printf("\nGUIHANDLER.show_help() - (! dialog) -> creation \n"));
        
        dialog = gtk_message_dialog_new(
                    GTK_WINDOW(window),
                    GTK_DIALOG_MODAL,
                    GTK_MESSAGE_INFO,
                    GTK_BUTTONS_OK,
                    "HELP:\nsee README file for more informations.\n\n"\
                    "Game keys:\nUse the arrows to move UP,DOWN,LEFT,RIGHT."
                                        );

        gtk_window_set_title(GTK_WINDOW(dialog), "Help");
        gtk_window_set_transient_for( GTK_WINDOW( dialog ),
                                      GTK_WINDOW( window ) );
    }

    /* Run dialog and hide it after it returns. */
    gtk_dialog_run( GTK_DIALOG( dialog ) );
    gtk_widget_hide( dialog );
    
    D1(printf("\nGUIHANDLER.show_help() - END\n"));
}


void show_about( GtkWidget *widget,
                 GtkWidget *window
               )
{
    D1(printf("\nGUIHANDLER.show_about() - START\n"));
    
    /* Create dialog only the first time we enter this callback.
     * After first time, just use it. */
    static GtkWidget *dialog = NULL;

    if( ! dialog )
    {
        D4(printf("\nGUIHANDLER.show_about() - (! dialog) -> creation \n"));
        
        /* This is just a convenience to avoid castings. */
        GtkAboutDialog *about;
        const gchar    *auth[] = { PRGAUTH , NULL };
	    GdkPixbuf *logo =  gdk_pixbuf_new_from_file(PRGLOGO, NULL);

        /* Create dialog */
        dialog = gtk_about_dialog_new();
        gtk_window_set_transient_for( GTK_WINDOW( dialog ),
                                      GTK_WINDOW( window ) );
        about = GTK_ABOUT_DIALOG( dialog );

        /* Set it's properties */
        gtk_about_dialog_set_program_name( about, PRGNAME );
        gtk_about_dialog_set_version( about, PRGVERS );
        gtk_about_dialog_set_copyright( about, PRGCPYR );
	    gtk_about_dialog_set_license( about, PRGLICS );
	    gtk_about_dialog_set_comments( about, PRGAIMS );
        gtk_about_dialog_set_website( about, PRGWBLK );
        gtk_about_dialog_set_authors( about, auth );
	    gtk_about_dialog_set_logo(about,logo);
	    g_object_unref(logo), logo = NULL;

        /* Show dialog */
        gtk_widget_show_all( dialog );
    }

    /* Run dialog and hide it after it returns. */
    gtk_dialog_run( GTK_DIALOG( dialog ) );
    gtk_widget_hide( dialog );
    
    D1(printf("\nGUIHANDLER.show_about() - END\n"));
}

/* End function definition of guihandler module */

