#ifdef HAVE_CONFIG_H
#  include <config.h>
#endif

#include "../DPRSim.hxx"
#include "../WorldBuilder.hxx"

#include <gtk/gtk.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>

#include "callbacks.h"
#include "interface.h"
#include "support.h"

extern WorldBuilder builder;
///////////////////////////////////////////////
//
// "Settings" tab callbacks
//
///////////////////////////////////////////////

void
on_experimentButton_clicked            (GtkButton       *button,
                                        gpointer         user_data)
{
  GtkWidget * experiment = lookup_widget(GTK_WIDGET(button), "experimentFile");
  char *filename;

  // Open the experiment file chooser dialog
  GtkWidget * dialog = gtk_file_chooser_dialog_new ("Choose Experiment File",
						    NULL,
						    GTK_FILE_CHOOSER_ACTION_OPEN,
						    GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
						    GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT,
						    NULL);
  if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_ACCEPT) {
    filename = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (dialog));
    gtk_entry_set_text(GTK_ENTRY(experiment),filename);
  }
  else {
      gtk_widget_destroy (dialog);
      return;
  }
  gtk_widget_destroy (dialog);
  // End Open the experiment file chooser dialog

  // Check to see if filename is valid

  FILE * file;
  if( ( file = fopen(filename, "r") ) == NULL ) {
    fclose(file);
    return;
  }
  
  // End Check to see if filename is valid

  char * key;
  char * value;

  if ( file ) {
    char line [256];
    while ( fgets ( line, sizeof line, file ) ) {
      if( line[0] == '#') continue;
      key = strtok( line, "=" );
      value = strtok( NULL, "\n");

      // Parse the key/value pair and fill in the experiment details

      if( !strcmp( key, "\n" ) || !strcmp( value, "\n") ) {
      }
      else if( !strcmp( key, "WORLD" ) ) {
	GtkWidget * world = lookup_widget(GTK_WIDGET(button), "worldFile");
	gtk_entry_set_text(GTK_ENTRY(world), value );
      }
      else if( !strcmp( key, "TIMESTEPS" ) ) {
	GtkWidget * timesteps = lookup_widget(GTK_WIDGET(button), "timeSteps");
	gtk_entry_set_text(GTK_ENTRY(timesteps), value);
      }
      else if( !strcmp( key, "PHYSICS_TIME_STEP" ) ) {
	GtkWidget * physics = lookup_widget(GTK_WIDGET(button), "physicsTimeStep");
	gtk_entry_set_text(GTK_ENTRY(physics), value);
      }
      else if( !strcmp( key, "SIM_TIME_STEP" ) ) {
	GtkWidget * simTime = lookup_widget(GTK_WIDGET(button), "simTimeStep");
	gtk_entry_set_text(GTK_ENTRY(simTime), value);
      }
      else if( !strcmp( key, "MODULES" ) ) {
	GtkWidget * modules = lookup_widget(GTK_WIDGET(button), "modulesList");
	gtk_entry_set_text(GTK_ENTRY(modules), value);
      }
      else if( !strcmp( key, "SAVE" ) ) {
	GtkWidget * save = lookup_widget(GTK_WIDGET(button), "saveEveryNSteps");
	gtk_entry_set_text(GTK_ENTRY(save), value);
      }
      else {
	GtkWidget * extraKeyValues = lookup_widget(GTK_WIDGET(button), "keyValuePairs");
	GtkTextBuffer * pairText = gtk_text_view_get_buffer(GTK_TEXT_VIEW(extraKeyValues));
	GtkTextIter pairIter;
	gtk_text_buffer_get_end_iter (GTK_TEXT_BUFFER(pairText), &pairIter);
	gtk_text_buffer_insert (GTK_TEXT_BUFFER(pairText), &pairIter, key, -1);
	gtk_text_buffer_insert (GTK_TEXT_BUFFER(pairText), &pairIter, "=", -1);
	gtk_text_buffer_insert (GTK_TEXT_BUFFER(pairText), &pairIter, value, -1);
	gtk_text_buffer_insert (GTK_TEXT_BUFFER(pairText), &pairIter, "\n", -1);
	gtk_text_buffer_get_end_iter (GTK_TEXT_BUFFER(pairText), &pairIter);
	gtk_text_view_scroll_to_iter(GTK_TEXT_VIEW(extraKeyValues),&pairIter,0.0,FALSE,0.0,0.0);
      }
    }
  }

  fclose(file);
  // Close the file

  g_free (filename);
}


void
on_expClearButton_clicked              (GtkButton       *button,
                                        gpointer         user_data)
{
  GtkWidget * experiment = lookup_widget(GTK_WIDGET(button), "experimentFile");
  gtk_entry_set_text(GTK_ENTRY(experiment),"");
}


void
on_worldButton_clicked                 (GtkButton       *button,
                                        gpointer         user_data)
{
  GtkWidget * world = lookup_widget(GTK_WIDGET(button), "worldFile");
  char *filename;

  // Open the experiment file chooser dialog
  GtkWidget * dialog = gtk_file_chooser_dialog_new ("Choose World File",
						    NULL,
						    GTK_FILE_CHOOSER_ACTION_OPEN,
						    GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
						    GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT,
						    NULL);
  if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_ACCEPT) {
    filename = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (dialog));
    gtk_entry_set_text(GTK_ENTRY(world),filename);
  }
  else {
      gtk_widget_destroy (dialog);
      return;
  }
  gtk_widget_destroy (dialog);
  // End Open the experiment file chooser dialog

  // Check to see if filename is valid

  FILE * file;
  if( ( file = fopen(filename, "r") ) == NULL ) {
    fclose(file);
    return;
  }
  
  // End Check to see if filename is valid

  fclose(file);
  // Close the file

  g_free (filename);

}


void
on_worldClearButton_clicked            (GtkButton       *button,
                                        gpointer         user_data)
{
  GtkWidget * world = lookup_widget(GTK_WIDGET(button), "worldFile");
  gtk_entry_set_text(GTK_ENTRY(world),"");
}


void
on_simTimeSteps_value_changed          (GtkSpinButton   *spinbutton,
                                        gpointer         user_data)
{

}


void
on_physicsTimeStep_value_changed       (GtkSpinButton   *spinbutton,
                                        gpointer         user_data)
{

}


void
on_simTimeStep_value_changed           (GtkSpinButton   *spinbutton,
                                        gpointer         user_data)
{

}


void
on_modulesList_changed                 (GtkEditable     *editable,
                                        gpointer         user_data)
{

}


void
on_saveSteps_value_changed             (GtkSpinButton   *spinbutton,
                                        gpointer         user_data)
{

}


///////////////////////////////////////////////
//
// "Builder" tab callbacks
//
///////////////////////////////////////////////

void
on_objectButton_clicked                (GtkButton       *button,
                                        gpointer         user_data)
{
  GtkWidget * object = lookup_widget(GTK_WIDGET(button), "objectFile");
  char *filename;

  // Open the .obj file chooser dialog
  GtkWidget * dialog = gtk_file_chooser_dialog_new ("Choose 3D Model File (obj, stl)",
						    NULL,
						    GTK_FILE_CHOOSER_ACTION_OPEN,
						    GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
						    GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT,
						    NULL);
  if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_ACCEPT) {
    filename = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (dialog));
    gtk_entry_set_text(GTK_ENTRY(object),filename);
  }
  else {
      gtk_widget_destroy (dialog);
      return;
  }
  gtk_widget_destroy (dialog);
  // End Open the .obj file chooser dialog

  // Check to see if filename is valid

  FILE * file;
  if( ( file = fopen(filename, "r") ) == NULL ) {
    fclose(file);
    return;
  }
  
  // End Check to see if filename is valid

  fclose(file);
  // Close the file

  g_free (filename);

}


void
on_clearObjectButton_clicked           (GtkButton       *button,
                                        gpointer         user_data)
{
  GtkWidget * object = lookup_widget(GTK_WIDGET(button), "objectFile");
  gtk_entry_set_text(GTK_ENTRY(object),"");
}


void
on_importObjectButton_clicked          (GtkButton       *button,
                                        gpointer         user_data)
{
  GtkEntry * file  = (GtkEntry*)lookup_widget(GTK_WIDGET(button), "objectFile");
  string filename(gtk_entry_get_text(file));
  
  GtkSpinButton * scale  = (GtkSpinButton*)lookup_widget(GTK_WIDGET(button), "catomScale");
  int size = (gtk_spin_button_get_value_as_int(scale));
  
  GtkToggleToolButton * flip  = (GtkToggleToolButton*)lookup_widget(GTK_WIDGET(button), "flipYZ");
  bool flipYZ = (gtk_toggle_tool_button_get_active(flip));
  
  GtkToggleToolButton * cursor  = (GtkToggleToolButton*)lookup_widget(GTK_WIDGET(button), "insertAtCursor");
  bool iac = (gtk_toggle_tool_button_get_active(cursor));
  
  GtkSpinButton * shell  = (GtkSpinButton*)lookup_widget(GTK_WIDGET(button), "shellThickness");
  int thickness = (gtk_spin_button_get_value_as_int(shell));
  
  builder.import(filename, size, thickness, flipYZ, iac); 
}


///////////////////////////////////////////////
//
// Bottom Control Buttons' Callbacks
//
///////////////////////////////////////////////

void
on_startButton_toggled                 (GtkToggleButton *togglebutton,
                                        gpointer         user_data)
{
  simPause(!simGetPaused());
}

void
on_renderButton_toggled                (GtkToggleButton *togglebutton,
                                        gpointer         user_data)
{
  writeframes ^= 1;
  if (writeframes)
    printf("Now writing frames to PNG files\n");
}

void
on_shadowButton_toggled                (GtkToggleButton *togglebutton,
                                        gpointer         user_data)
{
  dsSetShadows(dsGetShadows() ^ 1);
}

void
on_hudButton_toggled                   (GtkToggleButton *togglebutton,
                                        gpointer         user_data)
{
  dsSetHud(dsGetHud() ^ 1);
}

void
on_speechButton_toggled                (GtkToggleButton *togglebutton,
                                        gpointer         user_data)
{
  dsSetSpeech(dsGetSpeech() ^ 1);
}


///////////////////////////////////////////////
//
// GTK specific callbacks
//
///////////////////////////////////////////////

void
on_main_window_destroy                 (GtkObject       *object,
                                        gpointer         user_data)
{
  gtk_main_quit();
}


void
on_navigateButton_toggled              (GtkToggleToolButton *toggletoolbutton,
                                        gpointer         user_data)
{
  if(gtk_toggle_tool_button_get_active(toggletoolbutton))
    builder.setMode(-1);
}


void
on_insertButton_toggled                (GtkToggleToolButton *toggletoolbutton,
                                        gpointer         user_data)
{
  if(gtk_toggle_tool_button_get_active(toggletoolbutton))
    builder.setMode(0);
}


void
on_eraseButton_toggled                 (GtkToggleToolButton *toggletoolbutton,
                                        gpointer         user_data)
{
  if(gtk_toggle_tool_button_get_active(toggletoolbutton))
    builder.setMode(1);
}


void
on_selectButton_toggled                (GtkToggleToolButton *toggletoolbutton,
                                        gpointer         user_data)
{
  if(gtk_toggle_tool_button_get_active(toggletoolbutton))
    builder.setMode(2);
}

void
on_mwcameraButton_toggled              (GtkToggleToolButton *toggletoolbutton,
                                        gpointer         user_data)
{
  if(gtk_toggle_tool_button_get_active(toggletoolbutton))
    builder.setScrollMode(0); 
}

void
on_mwcursorButton_toggled              (GtkToggleToolButton *toggletoolbutton,
                                        gpointer         user_data)
{
  if(gtk_toggle_tool_button_get_active(toggletoolbutton))
    builder.setScrollMode(1);
}

void
on_setGUIDButton_clicked               (GtkButton       *button,
                                        gpointer         user_data)
{
  char** endptr = NULL;
  GtkEntry * guidentry = (GtkEntry*)lookup_widget(GTK_WIDGET(button), "GUIDEntry");
  string entry(gtk_entry_get_text(guidentry));
  unsigned long int newGUID = strtol(entry.c_str(), endptr, 10);
  
  //Make sure that the new GUID is valid
  if(newGUID<=0){
    gtk_entry_set_text(guidentry, "Invalid GUID");
  }
  else{
    //if so, request the GUID change from builder
    gtk_entry_set_text(guidentry, "");
    builder.requestGUIDChange(newGUID);
  }
}


void
on_catomColorButton_color_set          (GtkColorButton  *colorbutton,
                                        gpointer         user_data)
{
  GdkColor *c = new GdkColor();
  gtk_color_button_get_color(colorbutton, c);
  builder.setColor((int)(c->red),(int)(c->green), (int)(c->blue));
  delete c;
}


void
on_aboutDPRSim_clicked                 (GtkButton       *button,
                                        gpointer         user_data)
{
  GtkWidget * dialog = gtk_message_dialog_new ((GtkWindow*)gtk_widget_get_toplevel((GtkWidget*)button),
				   GTK_DIALOG_DESTROY_WITH_PARENT,
				   GTK_MESSAGE_INFO,
				   GTK_BUTTONS_CLOSE,
				   "Author: Casey Helfrich [casey.j.helfrich@intel.com]\n\nContributors: Michael Ryan, Daniel Dewey, Ben Rister, Seth Goldstein, Babu Pillai, and many more...\n\nhttp://www.pittsburgh.intel-research.net/dprweb/\nfor more info.");
  gtk_dialog_run (GTK_DIALOG (dialog));
  gtk_widget_destroy (dialog);
}


void
on_dprsimHelp_clicked                  (GtkButton       *button,
                                        gpointer         user_data)
{
  GtkWidget * dialog = gtk_message_dialog_new ((GtkWindow*)gtk_widget_get_toplevel((GtkWidget*)button),
				   GTK_DIALOG_DESTROY_WITH_PARENT,
				   GTK_MESSAGE_INFO,
				   GTK_BUTTONS_CLOSE,
				   "\nKeyboard Commands:\n\nCtrl-P: Pause / Unpause\nCtrl-S: Toggle Shadows\nCtrl-W: Write frames to disk as .png files\nCtrl-E: Toggle Catom speech bubbles\n\nCtrl-X: Quit\n\nMove the camera with the arrow keys.\nPress and hold the right mouse button to point the camera.\nClick with the left mouse button to select a Catom.\nScroll the mouse wheel to move up and down vertically.");
  gtk_dialog_run (GTK_DIALOG (dialog));
  gtk_widget_destroy (dialog);
}


void
on_shellFillButton_toggled             (GtkToggleToolButton *toggletoolbutton,
                                        gpointer         user_data)
{
if(gtk_toggle_tool_button_get_active(toggletoolbutton))
    builder.setFillStyle(false);  
}


void
on_solidFillButton_toggled             (GtkToggleToolButton *toggletoolbutton,
                                        gpointer         user_data)
{
if(gtk_toggle_tool_button_get_active(toggletoolbutton))
    builder.setFillStyle(true);  
}


void
on_clearButton_clicked                 (GtkButton       *button,
                                        gpointer         user_data)
{
  //Inform the user that this will clear their previous work
  GtkWidget * dialog = gtk_message_dialog_new ((GtkWindow*)gtk_widget_get_toplevel((GtkWidget*)button),
				   GTK_DIALOG_DESTROY_WITH_PARENT,
				   GTK_MESSAGE_WARNING,
				   GTK_BUTTONS_YES_NO,
				   "This action will clear the world of catoms. Continue?");
  gint response = gtk_dialog_run (GTK_DIALOG (dialog));
  gtk_widget_destroy (dialog);

  //if they said yes, go ahead and clear
  if(response == GTK_RESPONSE_YES) {
    builder.clearAll();
  }
}

void
on_insertAtCursor_toggled              (GtkToggleToolButton *toggletoolbutton,
                                        gpointer         user_data)
{

}


void
on_objectTool_toggled                  (GtkToggleToolButton *toggletoolbutton,
                                        gpointer         user_data)
{

}

void
on_advanceButton_clicked               (GtkButton       *button,
                                        gpointer         user_data)
{
  GtkEntry *stepsWidget = (GtkEntry*)lookup_widget(GTK_WIDGET(button), "stepsEntry");
  string steps_str(gtk_entry_get_text(stepsWidget));
  int steps = atoi(steps_str.c_str());
  
  if (simGetPaused()) {
    simAdvanceSteps(steps);
  }
}


void
on_latticeType_changed                 (GtkComboBox     *combobox,
                                        gpointer         user_data)
{
  int lt = (gtk_combo_box_get_active(combobox));

  switch(lt){
  case 0:
    builder.setLattice("cubic");
    break;
  case 1:
    builder.setLattice("hexp");
    break;
  case 2:
    builder.setLattice("fcc");
    break;
  case 3:
    builder.setLattice("bcc");
    break;
  }

}


void
on_saveAsButton_clicked                (GtkButton       *button,
                                        gpointer         user_data)
{
  string filename;

  // Open the .obj file chooser dialog
  GtkWidget * dialog = gtk_file_chooser_dialog_new ("Save world as...",
						    NULL,
						    GTK_FILE_CHOOSER_ACTION_SAVE,
						    GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
						    GTK_STOCK_SAVE, GTK_RESPONSE_ACCEPT,
						    NULL);
  if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_ACCEPT) {
    filename = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (dialog));
    gtk_widget_destroy (dialog);
    if(filename.find(".world") == string::npos)
      filename = filename + ".world";
    builder.saveWorldAs(filename);
  }
  else {
    gtk_widget_destroy (dialog);
    return;
  }
}

