/*   EXTRAITS DE LA LICENCE
	Copyright CEA, contributeurs : Luc BILLARD et Damien
	CALISTE, laboratoire L_Sim, (2001-2006)
  
	Adresse mèl :
	BILLARD, non joignable par mèl ;
	CALISTE, damien P caliste AT cea P fr.

	Ce logiciel est un programme informatique servant à visualiser des
	structures atomiques dans un rendu pseudo-3D. 

	Ce logiciel est régi par la licence CeCILL soumise au droit français et
	respectant les principes de diffusion des logiciels libres. Vous pouvez
	utiliser, modifier et/ou redistribuer ce programme sous les conditions
	de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA 
	sur le site "http://www.cecill.info".

	Le fait que vous puissiez accéder à cet en-tête signifie que vous avez 
	pris connaissance de la licence CeCILL, et que vous en avez accepté les
	termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel).
*/

/*   LICENCE SUM UP
	Copyright CEA, contributors : Luc BILLARD et Damien
	CALISTE, laboratoire L_Sim, (2001-2006)

	E-mail address:
	BILLARD, not reachable any more ;
	CALISTE, damien P caliste AT cea P fr.

	This software is a computer program whose purpose is to visualize atomic
	configurations in 3D.

	This software is governed by the CeCILL  license under French law and
	abiding by the rules of distribution of free software.  You can  use, 
	modify and/ or redistribute the software under the terms of the CeCILL
	license as circulated by CEA, CNRS and INRIA at the following URL
	"http://www.cecill.info". 

	The fact that you are presently reading this means that you have had
	knowledge of the CeCILL license and that you accept its terms. You can
	find a copy of this licence shipped with this software at Documentation/licence.en.txt.
*/
#include <gtk/gtksignal.h>
#include <gtk/gtkdialog.h>

#include "gtk_dumpDialogWidget.h"
#include <gtk_main.h>
#include <opengl.h>

static void dumpDialog_class_init          (DumpDialogClass *klass);
static void dumpDialog_init                (DumpDialog *dumpDialog);
static void dumpDialog_destroy             (GtkObject *object);


GtkDialogClass *parent_class;

struct DumpDialog_struct
{
  GtkDialog dialog;

  GtkWidget *fileChooser;

  GtkWidget *hBoxOptions;
  GtkWidget *comboType;
  DumpType *selectedFileFormat;
  GtkWidget *expanderFileFormat;
  GtkWidget *checkFileExtension;
  GtkWidget *spinWidth, *spinHeight;

  GtkWidget *progressBar;
  GtkWidget *cancelButton;

  gchar *dumpFileName;
};

struct DumpDialogClass_struct
{
  GtkDialogClass parent_class;

  void (*dumpDialog) (DumpDialog *dump);
};

/* Local callbacks */
static void onSpinPropertyChange(GtkSpinButton *spin, gpointer data);
static void onCheckPropertyChange(GtkToggleButton *toggle, gpointer data);
static void onComboFileFormatChange(GtkComboBox *combo, gpointer data);
static void onDumpDialogResponse(GtkDialog *dialog, gint id, gpointer *data);


GType dumpDialog_get_type(void)
{
  static GType dumpDialog_type = 0;

  if (!dumpDialog_type)
    {
      static const GTypeInfo dumpDialog_info =
      {
        sizeof (DumpDialogClass),
        NULL, /* base_init */
        NULL, /* base_finalize */
        (GClassInitFunc) dumpDialog_class_init,
        NULL, /* class_finalize */
        NULL, /* class_data */
        sizeof (DumpDialog),
        0,
        (GInstanceInitFunc) dumpDialog_init,
        NULL
      };
      dumpDialog_type = g_type_register_static (GTK_TYPE_DIALOG, "DumpDialog",
						   &dumpDialog_info, 0);
      DBG_fprintf(stderr, "Gtk DumpDialog : creating the type DumpDialog %p.\n",
		  (gpointer)dumpDialog_type);
    }

  return dumpDialog_type;
}

static void dumpDialog_class_init(DumpDialogClass *klass)
{
  GtkTreeIter iter;
  GList *colorLst;
  
  DBG_fprintf(stderr, "Gtk DumpDialog : creating the class of the widget.\n");

  parent_class = g_type_class_peek_parent(klass);
  GTK_OBJECT_CLASS(klass)->destroy = dumpDialog_destroy;
}

static void dumpDialog_init(DumpDialog *dumpDialog)
{
  DBG_fprintf(stderr, "Gtk DumpDialog : initializing new object (%p).\n",
	      (gpointer)dumpDialog);

  dumpDialog->selectedFileFormat = (DumpType*)0;
  dumpDialog->dumpFileName = (gchar*)0;

  g_signal_connect(G_OBJECT(dumpDialog), "response",
		   G_CALLBACK(onDumpDialogResponse), (gpointer)dumpDialog);
}

static void dumpDialog_destroy(GtkObject *object)
{
  DumpDialog *dialog;

  DBG_fprintf(stderr, "Gtk DumpDialog : destroy widget %p.\n", (gpointer)object);
  dialog = DUMP_DIALOG(object);
  if (dialog->dumpFileName)
    g_free(dialog->dumpFileName);
/*   GTK_OBJECT_CLASS(parent_class)->destroy(object); */
}


GtkWidget* dumpDialog_new(VisuData *dataObj)
{
  DumpDialog *dumpDialog;
  gchar *directory, *labelType;
  GList *format;
  GtkWidget *hbox2, *hbox;
  GtkWidget *label;
  GtkWidget *wd;
  GtkWidget *vbox;
  OpenGLView *view;

  if (dataObj)
    view = visuDataGet_openGLView(dataObj);
  else
    view = (OpenGLView*)0;

  DBG_fprintf(stderr, "Gtk DumpDialog : creating a new DumpDialog object.\n");

  dumpDialog = DUMP_DIALOG(g_object_new(dumpDialog_get_type(), NULL));
  gtk_dialog_set_has_separator(GTK_DIALOG(dumpDialog), FALSE);
  gtk_window_set_modal(GTK_WINDOW(dumpDialog), TRUE);
  gtk_window_set_transient_for(GTK_WINDOW(dumpDialog), GTK_WINDOW(mainWindow));
  gtk_window_set_position(GTK_WINDOW(dumpDialog), GTK_WIN_POS_CENTER_ON_PARENT);

  dumpDialog->cancelButton = gtk_dialog_add_button(GTK_DIALOG(dumpDialog),
					       GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL);
  gtk_dialog_add_button(GTK_DIALOG(dumpDialog), GTK_STOCK_SAVE, GTK_RESPONSE_ACCEPT);
  gtk_dialog_set_default_response(GTK_DIALOG(dumpDialog), GTK_RESPONSE_ACCEPT);

  /* Create the file chooser part. */
  dumpDialog->fileChooser = gtk_file_chooser_widget_new(GTK_FILE_CHOOSER_ACTION_SAVE);
  gtk_widget_show(dumpDialog->fileChooser);
  gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dumpDialog)->vbox), dumpDialog->fileChooser, TRUE, TRUE, 2);
  gtk_file_chooser_set_select_multiple(GTK_FILE_CHOOSER(dumpDialog->fileChooser),
				       FALSE);

  /* Create the file options part. */
  dumpDialog->hBoxOptions = gtk_hbox_new(FALSE, 0);
  gtk_widget_show(dumpDialog->hBoxOptions);
  gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dumpDialog)->vbox),
		     dumpDialog->hBoxOptions, FALSE, FALSE, 2);

  vbox = gtk_vbox_new(FALSE, 0);
  gtk_widget_show(vbox);
  gtk_box_pack_start(GTK_BOX(dumpDialog->hBoxOptions), vbox, TRUE, TRUE, 2);
  hbox = gtk_hbox_new(FALSE, 0);
  gtk_widget_show(hbox);
  gtk_box_pack_start(GTK_BOX(vbox),
		     hbox, FALSE, FALSE, 0);
  /* Label to introduce the combobox which allow to choose the format */
  label = gtk_label_new(_("Choose the file format : "));
  gtk_misc_set_alignment(GTK_MISC(label), 0., 0.5);
  gtk_widget_show(label);
  gtk_box_pack_start(GTK_BOX(hbox), label, TRUE, TRUE, 0);
  dumpDialog->comboType = gtk_combo_box_new_text();
  /* Set the combo entry that let V_Sim detect the desired format through the extension. */
  gtk_combo_box_append_text(GTK_COMBO_BOX(dumpDialog->comboType), _("Autodetect format"));
  gtk_combo_box_set_active(GTK_COMBO_BOX(dumpDialog->comboType), 0);
  gtk_widget_show(dumpDialog->comboType);
  gtk_box_pack_start(GTK_BOX(hbox), dumpDialog->comboType, FALSE, FALSE, 0);
  /* Add an expander for file format options. */
  dumpDialog->expanderFileFormat = gtk_expander_new(_("File format option:"));
  gtk_widget_set_sensitive(dumpDialog->expanderFileFormat, FALSE);
  gtk_widget_show(dumpDialog->expanderFileFormat);
  gtk_box_pack_start(GTK_BOX(vbox),
		     dumpDialog->expanderFileFormat, FALSE, FALSE, 0);
  g_signal_connect(G_OBJECT(dumpDialog->comboType), "changed",
		   G_CALLBACK(onComboFileFormatChange), (gpointer)dumpDialog);
  /* Add a separator. */
  wd = gtk_vseparator_new();
  gtk_widget_show(wd);
  gtk_box_pack_start(GTK_BOX(dumpDialog->hBoxOptions),
		     wd, FALSE, FALSE, 0);
  /* Create common options part. */
  vbox = gtk_vbox_new(FALSE, 0);
  gtk_widget_show(vbox);
  gtk_box_pack_start(GTK_BOX(dumpDialog->hBoxOptions), vbox, TRUE, TRUE, 2);
  dumpDialog->checkFileExtension = gtk_check_button_new_with_label(_("Add extension"));
  gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(dumpDialog->checkFileExtension), TRUE);
  gtk_widget_set_sensitive(dumpDialog->checkFileExtension, FALSE);
  gtk_widget_show(dumpDialog->checkFileExtension);
  gtk_box_pack_start(GTK_BOX(vbox), dumpDialog->checkFileExtension, FALSE, FALSE, 0);
  hbox = gtk_hbox_new(FALSE, 0);
  gtk_widget_show(hbox);
  gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0);
  label = gtk_label_new(_("Width: "));
  gtk_misc_set_alignment(GTK_MISC(label), 0., 0.5);
  gtk_widget_show(label);
  gtk_box_pack_start(GTK_BOX(hbox), label, TRUE, TRUE, 0);
  dumpDialog->spinWidth = gtk_spin_button_new_with_range(0., 2000., 1.);
  if (view)
    gtk_spin_button_set_value(GTK_SPIN_BUTTON(dumpDialog->spinWidth),
			      (gdouble)view->window->width);
  gtk_widget_show(dumpDialog->spinWidth);
  gtk_box_pack_start(GTK_BOX(hbox), dumpDialog->spinWidth, FALSE, FALSE, 0);
  label = gtk_label_new(_("px"));
  gtk_widget_show(label);
  gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0);
  hbox = gtk_hbox_new(FALSE, 0);
  gtk_widget_show(hbox);
  gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0);
  label = gtk_label_new(_("Height: "));
  gtk_misc_set_alignment(GTK_MISC(label), 0., 0.5);
  gtk_widget_show(label);
  gtk_box_pack_start(GTK_BOX(hbox), label, TRUE, TRUE, 0);
  dumpDialog->spinHeight = gtk_spin_button_new_with_range(0., 2000., 1.);
  if (view)
    gtk_spin_button_set_value(GTK_SPIN_BUTTON(dumpDialog->spinHeight),
			      (gdouble)view->window->height);
  gtk_widget_show(dumpDialog->spinHeight);
  gtk_box_pack_start(GTK_BOX(hbox), dumpDialog->spinHeight, FALSE, FALSE, 0);
  label = gtk_label_new(_("px"));
  gtk_widget_show(label);
  gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0);
  

  
  /* Create the progress bar part. */
  hbox2 = gtk_hbox_new(FALSE, 0);
  gtk_widget_show(hbox2);
  gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dumpDialog)->vbox), hbox2, FALSE, FALSE, 2);
  /* Label to introduce the rogress bar */
  label = gtk_label_new(_("Dump progress : "));
  gtk_misc_set_alignment(GTK_MISC(label), 0., 0.5);
  gtk_widget_show(label);
  gtk_box_pack_start(GTK_BOX(hbox2), label, FALSE, FALSE, 0);
  dumpDialog->progressBar = gtk_progress_bar_new();
  gtk_widget_show(dumpDialog->progressBar);
  gtk_box_pack_start(GTK_BOX(hbox2), dumpDialog->progressBar, TRUE, TRUE, 2);

  /* Setting default values. */
  gtk_widget_set_name(GTK_WIDGET(dumpDialog), "filesel");
  directory = getLastOpenDirectory();
  if (directory)
    gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(dumpDialog->fileChooser), directory);
  format = getAllDumpModules();
  while (format)
    {
      labelType = fileFormatGet_label(((DumpType*)format->data)->fileType);
      if (labelType)
	gtk_combo_box_append_text(GTK_COMBO_BOX(dumpDialog->comboType), labelType);
      format = g_list_next(format);
    }

  return GTK_WIDGET(dumpDialog);
}


/*******************/
/* Local callbacks */
/*******************/
static void onSpinPropertyChange(GtkSpinButton *spin, gpointer data)
{
  fileFormatSet_propertyInteger((FileFormatProperty*)data,
				(int)gtk_spin_button_get_value(spin));
}
static void onCheckPropertyChange(GtkToggleButton *toggle, gpointer data)
{
  fileFormatSet_propertyBoolean((FileFormatProperty*)data,
				gtk_toggle_button_get_active(toggle));
}
static void onComboFileFormatChange(GtkComboBox *combo, gpointer data)
{
  int formatInt, i;
  GList *dumpTypes, *formatProperties;
  GtkWidget *wd, *label, *hbox, *vbox;

  g_return_if_fail(IS_DUMP_DIALOG(data));

  /* Empty the expander for properties. */
  wd = gtk_bin_get_child(GTK_BIN(DUMP_DIALOG(data)->expanderFileFormat));
  if (wd)
    gtk_widget_destroy(wd);

  dumpTypes = getAllDumpModules();
  formatInt = gtk_combo_box_get_active(combo);
  DBG_fprintf(stderr, "Gtk DumpDialog : On file format change (%d).\n", formatInt);
  /* Select auto file format -> no properties. */
  if (formatInt == 0)
    {
      gtk_widget_set_sensitive(DUMP_DIALOG(data)->expanderFileFormat, FALSE);
      gtk_widget_set_sensitive(DUMP_DIALOG(data)->checkFileExtension, FALSE);
      return;
    }
  else
    /* Search for the selected property. */
    for(i = 0; i < formatInt - 1; i++) dumpTypes = g_list_next(dumpTypes);
  /* Set the check box for extension auto completion. */
  gtk_widget_set_sensitive(DUMP_DIALOG(data)->checkFileExtension, TRUE);
  /* Get properties if exist for this format. */
  formatProperties = fileFormatGet_propertiesList(((DumpType*)(dumpTypes->data))->fileType);
  if (!formatProperties)
    {
      gtk_widget_set_sensitive(DUMP_DIALOG(data)->expanderFileFormat, FALSE);
      return;
    }
  gtk_widget_set_sensitive(DUMP_DIALOG(data)->expanderFileFormat, TRUE);
  vbox = gtk_vbox_new(FALSE, 0);
  gtk_widget_show(vbox);
  gtk_container_add(GTK_CONTAINER(DUMP_DIALOG(data)->expanderFileFormat), vbox);
  while (formatProperties)
    {
      hbox = gtk_hbox_new(FALSE, 0);
      gtk_widget_show(hbox);
      gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0);
      label = gtk_label_new(fileFormatGet_propertyLabelUTF8((FileFormatProperty*)
							    (formatProperties->data)));
      gtk_misc_set_alignment(GTK_MISC(label), 1., 0.5);
      gtk_misc_set_padding(GTK_MISC(label), 10, 0);
      gtk_widget_show(label);
      gtk_box_pack_start(GTK_BOX(hbox), label, TRUE, TRUE, 0);
      switch (fileFormatGet_propertyType((FileFormatProperty*)
					 (formatProperties->data)))
	{
	case fileFormat_type_integer:
	  wd = gtk_spin_button_new_with_range(0., 100., 1.);
	  gtk_spin_button_set_value(GTK_SPIN_BUTTON(wd),
				    (gdouble)fileFormatGet_propertyInteger((FileFormatProperty*)
									   (formatProperties->data)));
	  gtk_widget_show(wd);
	  gtk_box_pack_start(GTK_BOX(hbox), wd, FALSE, FALSE, 0);
	  g_signal_connect(G_OBJECT(wd), "value-changed",
			   G_CALLBACK(onSpinPropertyChange), (gpointer)(formatProperties->data));
	  break;
	case fileFormat_type_boolean:
	  wd = gtk_check_button_new();
	  gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(wd),
				       fileFormatGet_propertyBoolean((FileFormatProperty*)
								     (formatProperties->data)));
	  gtk_widget_show(wd);
	  gtk_box_pack_start(GTK_BOX(hbox), wd, FALSE, FALSE, 0);
	  g_signal_connect(G_OBJECT(wd), "toggled",
			   G_CALLBACK(onCheckPropertyChange), (gpointer)(formatProperties->data));
	  break;
	default:
	  g_warning("Unknown, or nsupprted file format property"
		    " given to 'onComboFileFormatChange'.");
	};

      formatProperties = g_list_next(formatProperties);
    }
}
static void onDumpDialogResponse(GtkDialog *dialog, gint id, gpointer *data)
{
  gchar *filename, *directory;
  int formatInt, i;
  gchar *labelType, *ext, *pattern;
  GList *dumpTypes;
  DumpDialog *dumpDialog;

  g_return_if_fail(IS_DUMP_DIALOG(data));

  dumpDialog = DUMP_DIALOG(data);

  DBG_fprintf(stderr, "Gtk DumpDialog : catch the 'response' signal.\n");
  /* Get the filename. */
  filename = (gchar*)0;
  formatInt = -1;
  if (id == GTK_RESPONSE_ACCEPT)
    {
      filename = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(dumpDialog->fileChooser));
      formatInt = gtk_combo_box_get_active(GTK_COMBO_BOX(dumpDialog->comboType));
      if (!filename)
	{
	  /* Autodetect failed, no format match the given filename */
	  raiseAlertDialog(_("No filename chosen."));
	  g_signal_stop_emission_by_name(G_OBJECT(dumpDialog), "response");
	  return;
	}
    }
  /* Set the last browsed directory. */
  directory = gtk_file_chooser_get_current_folder(GTK_FILE_CHOOSER(dumpDialog->fileChooser));
  setLastOpenDirectory((char*)directory);
  g_free(directory);

  if (formatInt >= 0)
    {
      dumpTypes = getAllDumpModules();
      if (formatInt == 0)
	/* The automatic format has been selected, we look in the pattern list to
	   find a matching pattern. */
	while (dumpTypes && !fileFormatUse_match( ((DumpType*)dumpTypes->data)->fileType,
						  filename))
	  dumpTypes = g_list_next(dumpTypes);
      else
	for(i = 0; i < formatInt - 1; i++) dumpTypes = g_list_next(dumpTypes);
      if (!dumpTypes)
	{
	  /* Autodetect failed, no format match the given filename */
	  raiseAlertDialog(_("The filename doesn't match any know format."));
	  g_free(filename);
	  g_signal_stop_emission_by_name(G_OBJECT(dumpDialog), "response");
	  return;
	}
      
      if (formatInt > 0 &&
	  gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(dumpDialog->checkFileExtension)))
	{
	  if (!fileFormatUse_match( ((DumpType*)dumpTypes->data)->fileType,
				    filename))
	    {
	      pattern = (gchar*)(((DumpType*)dumpTypes->data)->fileType->fileType->data);
	      ext = g_strrstr(pattern, ".");
	      dumpDialog->dumpFileName = g_strdup_printf("%s%s", filename, ext);
	      g_free(filename);
	    }
	  else
	    dumpDialog->dumpFileName = filename;
	}
      else
	dumpDialog->dumpFileName = filename;
      dumpDialog->selectedFileFormat = (DumpType*)dumpTypes->data;
      /* Put everything except the progress bar insensitive */
      gtk_widget_set_sensitive(dumpDialog->fileChooser, FALSE);
      gtk_widget_set_sensitive(dumpDialog->hBoxOptions, FALSE);
      DBG_fprintf(stderr, "Gtk DumpDialog : '%s' file format chosen.\n",
		  dumpDialog->selectedFileFormat->fileType->description);
    }
}

/******************/
/* Public methods */
/******************/
gchar* dumpDialogGet_fileName(DumpDialog *dialog)
{
  g_return_val_if_fail(dialog, (gchar*)0);
  return dialog->dumpFileName;
}
DumpType* dumpDialogGet_dumpType(DumpDialog *dialog)
{
  g_return_val_if_fail(dialog, (DumpType*)0);
  return dialog->selectedFileFormat;
}
FileFormat* dumpDialogGet_fileFormat(DumpDialog *dialog)
{
  g_return_val_if_fail(dialog, (FileFormat*)0);
  if (dialog->selectedFileFormat)
    return dialog->selectedFileFormat->fileType;
  else
    return (FileFormat*)0;
}
GtkProgressBar* dumpDialogGet_progressBar(DumpDialog *dialog)
{
  g_return_val_if_fail(dialog, (GtkProgressBar*)0);
  return GTK_PROGRESS_BAR(dialog->progressBar);
}
GtkButton* dumpDialogGet_cancelButton(DumpDialog *dialog)
{
  g_return_val_if_fail(dialog, (GtkButton*)0);
  return GTK_BUTTON(dialog->cancelButton);
}
gint dumpDialogGet_widthValue(DumpDialog *dialog)
{
  g_return_val_if_fail(dialog, 0);
  return (gint)gtk_spin_button_get_value(GTK_SPIN_BUTTON(dialog->spinWidth));
}
gint dumpDialogGet_heightValue(DumpDialog *dialog)
{
  g_return_val_if_fail(dialog, 0);
  return (gint)gtk_spin_button_get_value(GTK_SPIN_BUTTON(dialog->spinHeight));
}
