/*   EXTRAITS DE LA LICENCE
	Copyright CEA, contributeurs : Damien
	CALISTE, laboratoire L_Sim, (2011-2011)
  
	Adresse 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 : Damien
	CALISTE, laboratoire L_Sim, (2011-2011)

	E-mail address:
	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/gtk.h>
#include <string.h>

#include "gtk_fieldChooser.h"
#include <visu_tools.h>
#include <support.h>
#include <visu_gtk.h>
#include <gtk_main.h>
#include <extraFunctions/scalarFields.h>

/**
 * SECTION:gtk_fieldChooser
 * @short_description: Defines a widget to choose a scalar field or an
 * isosurface.
 * 
 * <para>TODO.</para>
 */

enum {
  VALIDATE_SIGNAL,
  LAST_SIGNAL
};

static void visu_ui_field_chooser_dispose (GObject *obj);
static void visu_ui_field_chooser_finalize(GObject *obj);

struct _VisuUiFieldChooser
{
  GtkFileChooserDialog dialog;
  GtkWidget *fitToBox, *fitToSurface, *fitNone;
  VisuScalarFieldMethod *validFormat;
  GList* allFilters;
  GtkWidget *vbox, *addWd;
  gchar *preFilename;

  /* Memory gestion. */
  gboolean dispose_has_run;
};

struct _VisuUiFieldChooserClass
{
  GtkFileChooserDialogClass parent_class;
};

/* Local callbacks */
static void onFieldChooserResponse(GtkDialog *dialog, gint id, gpointer *data);

static guint visu_ui_field_chooser_signals[LAST_SIGNAL] = { 0 };

G_DEFINE_TYPE(VisuUiFieldChooser, visu_ui_field_chooser, GTK_TYPE_FILE_CHOOSER_DIALOG)

static void visu_ui_field_chooser_class_init(VisuUiFieldChooserClass *klass)
{
  DBG_fprintf(stderr, "VisuUi FieldChooser: creating the class of the widget.\n");

  DBG_fprintf(stderr, "                - adding new signals ;\n");
  /**
   * VisuUiFieldChooser::validate:
   * @chooser: the object which emit the signal ;
   * @field: the chosen #VisuScalarField object.
   *
   * Gets emitted when the user choose a file and a format has been
   * validated for it.
   *
   * Since: 3.7
   */
  visu_ui_field_chooser_signals[VALIDATE_SIGNAL] =
    g_signal_new("validate", G_TYPE_FROM_CLASS(klass),
                 G_SIGNAL_RUN_LAST | G_SIGNAL_NO_RECURSE,
                 0, NULL, NULL, g_cclosure_marshal_VOID__OBJECT,
                 G_TYPE_NONE, 1, VISU_TYPE_SCALAR_FIELD_METHOD, NULL);

  G_OBJECT_CLASS(klass)->dispose = visu_ui_field_chooser_dispose;
  G_OBJECT_CLASS(klass)->finalize = visu_ui_field_chooser_finalize;
}

static void visu_ui_field_chooser_init(VisuUiFieldChooser *fieldChooser)
{
  DBG_fprintf(stderr, "VisuUi FieldChooser: initializing new object (%p).\n",
	      (gpointer)fieldChooser);

  fieldChooser->validFormat = (VisuScalarFieldMethod*)0;
  fieldChooser->allFilters = (GList*)0;
  fieldChooser->addWd = (GtkWidget*)0;
  fieldChooser->preFilename = g_strdup("");

  g_signal_connect(G_OBJECT(fieldChooser), "response",
		   G_CALLBACK(onFieldChooserResponse), (gpointer)fieldChooser);
}

static void visu_ui_field_chooser_dispose(GObject *obj)
{
  DBG_fprintf(stderr, "VisuUi FieldChooser: dispose object %p.\n", (gpointer)obj);

  if (VISU_UI_FIELD_CHOOSER(obj)->dispose_has_run)
    return;

  VISU_UI_FIELD_CHOOSER(obj)->dispose_has_run = TRUE;
  /* Chain up to the parent class */
  G_OBJECT_CLASS(visu_ui_field_chooser_parent_class)->dispose(obj);
}
static void visu_ui_field_chooser_finalize(GObject *obj)
{
  VisuUiFieldChooser *dialog;
  GList *tmpLst;

  g_return_if_fail(obj);

  DBG_fprintf(stderr, "VisuUi FieldChooser: finalize object %p.\n", (gpointer)obj);

  dialog = VISU_UI_FIELD_CHOOSER(obj);

  for (tmpLst = dialog->allFilters; tmpLst; tmpLst = g_list_next(tmpLst))
    g_free(tmpLst->data);
  g_list_free(dialog->allFilters);

  if (dialog->preFilename)
    g_free(dialog->preFilename);

  /* Chain up to the parent class */
  G_OBJECT_CLASS(visu_ui_field_chooser_parent_class)->finalize(obj);

  DBG_fprintf(stderr, "VisuUi FieldChooser: freeing ... OK.\n");
}

/**
 * visu_ui_field_chooser_new:
 * @parent: (allow-none): the parent window.
 *
 * Create a filechooser, specific for #VisuScalarField files.
 *
 * Since: 3.7
 *
 * Returns: (transfer full): a newly created file chooser.
 **/
GtkWidget* visu_ui_field_chooser_new(GtkWindow *parent)
{
  VisuUiFieldChooser *fieldChooser;
  const gchar *directory;
  GList *scalarMethods, *allMethods;
  const gchar *type[] = {"*.surf", (char*)0};
  const gchar *descr = _("Isosurfaces files");

  if (!parent)
    parent = visu_ui_getRenderWindow();

  DBG_fprintf(stderr, "VisuUi FieldChooser: creating a new VisuUiFieldChooser object.\n");

  fieldChooser = VISU_UI_FIELD_CHOOSER(g_object_new(VISU_TYPE_UI_FIELD_CHOOSER, NULL));
  gtk_window_set_title(GTK_WINDOW(fieldChooser),
		       _("Open a surface/density file"));
  /* This is to avoid a bug in gtk 2.4 */
#if GTK_MAJOR_VERSION > 2 || GTK_MINOR_VERSION > 5
  gtk_window_set_modal(GTK_WINDOW(fieldChooser), TRUE);
#endif
  gtk_window_set_transient_for(GTK_WINDOW(fieldChooser), GTK_WINDOW(parent));
  gtk_window_set_position(GTK_WINDOW(fieldChooser), GTK_WIN_POS_CENTER_ON_PARENT);

  gtk_dialog_add_button(GTK_DIALOG(fieldChooser), TOOL_ICON_CANCEL, GTK_RESPONSE_CANCEL);
  gtk_dialog_add_button(GTK_DIALOG(fieldChooser), TOOL_ICON_OPEN, GTK_RESPONSE_ACCEPT);
  gtk_dialog_set_default_response(GTK_DIALOG(fieldChooser), GTK_RESPONSE_ACCEPT);

  directory = visu_ui_main_getLastOpenDirectory(visu_ui_main_class_getCurrentPanel());
  if (directory)
    gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(fieldChooser), directory);

  fieldChooser->fitNone = gtk_radio_button_new_with_label(NULL, _("Keep surface box as defined"));
  gtk_widget_set_tooltip_text(fieldChooser->fitNone, 
                              _("Don't modify the surface coordinates."));
  fieldChooser->fitToBox = gtk_radio_button_new_with_label_from_widget
    (GTK_RADIO_BUTTON(fieldChooser->fitNone), _("Fit surfaces to box"));
  gtk_widget_set_tooltip_text(fieldChooser->fitToBox, 
		       _("Makes surfaces fit to the current"
			 " loaded bounding box."));
  fieldChooser->fitToSurface = gtk_radio_button_new_with_label_from_widget
    (GTK_RADIO_BUTTON(fieldChooser->fitToBox), _("Fit box to surfaces"));
  gtk_widget_set_tooltip_text(fieldChooser->fitToSurface, 
		       _("Makes the current bounding box fit"
			 " to the surfaces."));
  gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(fieldChooser->fitNone), TRUE);
  fieldChooser->vbox = gtk_vbox_new(FALSE, 0);
  gtk_box_pack_start(GTK_BOX(fieldChooser->vbox), fieldChooser->fitNone, FALSE, FALSE, 0);
  gtk_box_pack_start(GTK_BOX(fieldChooser->vbox), fieldChooser->fitToBox, FALSE, FALSE, 0);
  gtk_box_pack_start(GTK_BOX(fieldChooser->vbox), fieldChooser->fitToSurface, FALSE, FALSE, 0);
  gtk_file_chooser_set_extra_widget(GTK_FILE_CHOOSER(fieldChooser), fieldChooser->vbox);

  allMethods = (GList*)0;
  allMethods = g_list_append(allMethods, tool_file_format_new(descr, type));
  for (scalarMethods = visu_scalar_field_method_getAll(); scalarMethods;
       scalarMethods = g_list_next(scalarMethods))
    allMethods = g_list_append(allMethods, TOOL_FILE_FORMAT(g_object_ref(scalarMethods->data)));
  fieldChooser->allFilters = visu_ui_createFilter(allMethods,
                                                             GTK_WIDGET(fieldChooser));
  g_list_free_full(allMethods, (GDestroyNotify)g_object_unref);

  gtk_widget_show_all(GTK_WIDGET(fieldChooser));

  return GTK_WIDGET(fieldChooser);
}


/*******************/
/* Local callbacks */
/*******************/
static void onFieldChooserResponse(GtkDialog *dialog, gint id, gpointer *data _U_)
{
  gchar *filename, *directory;
  VisuUiFieldChooser *fieldChooser;
  GList *scalarMethods;

  g_return_if_fail(VISU_IS_UI_FIELD_CHOOSER(dialog));

  fieldChooser = VISU_UI_FIELD_CHOOSER(dialog);
  fieldChooser->validFormat = (VisuScalarFieldMethod*)0;

  DBG_fprintf(stderr, "VisuUi FieldChooser: catch the 'response' signal:"
	      " %d (ACCEPT is %d).\n", id, GTK_RESPONSE_ACCEPT);
  if (id == GTK_RESPONSE_ACCEPT)
    {
      /* Get the filename. */
      filename = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(fieldChooser));
      if (!filename)
	{
	  /* Autodetect failed, no format match the given filename */
	  visu_ui_raiseWarning(_("Opening a file"),
			       _("No filename chosen."),
			       GTK_WINDOW(dialog));
	  g_signal_stop_emission_by_name(G_OBJECT(dialog), "response");
	  return;
	}
      /* Get the directory. */
      directory = 
        (char*)gtk_file_chooser_get_current_folder(GTK_FILE_CHOOSER(fieldChooser));
      visu_ui_main_setLastOpenDirectory(visu_ui_main_class_getCurrentPanel(),
                                        directory, VISU_UI_DIR_SURFACE);
      /* We test here the file format for formats that support
         poking. */
      for (scalarMethods = visu_scalar_field_method_getAll(); scalarMethods;
           scalarMethods = g_list_next(scalarMethods))
        if (tool_file_format_validate(TOOL_FILE_FORMAT(scalarMethods->data), filename))
          break;
      if (scalarMethods && strcmp(fieldChooser->preFilename, filename))
        {
          fieldChooser->validFormat = VISU_SCALAR_FIELD_METHOD(scalarMethods->data);
          /* Call hook in case we found a valid file format. */
          DBG_fprintf(stderr, "VisuUi FieldChooser: '%s' is a valid %s format.\n",
                      filename, tool_file_format_getName
                      (TOOL_FILE_FORMAT(fieldChooser->validFormat)));
          g_signal_emit(G_OBJECT(fieldChooser),
                        visu_ui_field_chooser_signals[VALIDATE_SIGNAL], 0,
                        scalarMethods->data, NULL);
        }
      if (fieldChooser->preFilename)
        g_free(fieldChooser->preFilename);
      fieldChooser->preFilename = filename;
    }
}

/******************/
/* Public methods */
/******************/

/**
 * visu_ui_field_chooser_getFileFormat:
 * @dialog: a #VisuUiFieldChooser object.
 *
 * After the @dialog returns, it has validate the selected file on
 * possible file formats.
 *
 * Since: 3.7
 *
 * Returns: (transfer none): the #VisuScalarFieldMethod that correspond to the selected file.
 **/
VisuScalarFieldMethod* visu_ui_field_chooser_getFileFormat(VisuUiFieldChooser *dialog)
{
  g_return_val_if_fail(dialog, (VisuScalarFieldMethod*)0);
  return dialog->validFormat;
}
/**
 * visu_ui_field_chooser_getFit:
 * @dialog: a #VisuUiFieldChooser object.
 *
 * The #VisuScalarField objects can be fitted on the #visuData box or
 * impose their boxes to #VisuData.
 *
 * Since: 3.7
 *
 * Returns: if the box should be fitted or not.
 **/
VisuUiBoxFit visu_ui_field_chooser_getFit(VisuUiFieldChooser *dialog)
{
  g_return_val_if_fail(dialog, VISU_UI_FIT_TO_BOX);
  
  if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(dialog->fitNone)))
    return VISU_UI_NO_FIT;
  else if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(dialog->fitToBox)))
    return VISU_UI_FIT_TO_BOX;
  else if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(dialog->fitToSurface)))
    return VISU_UI_FIT_TO_SURFACE;
  else
    return VISU_UI_NO_FIT;
}
/**
 * visu_ui_field_chooser_setOptions:
 * @dialog:  a #VisuUiFieldChooser object.
 * @wd: some additional options to add to the dialog.
 *
 * One can add widgets to add more options to the chooser. If the
 * chooser already has some option widgets, they are destroyed.
 *
 * Since: 3.7
 **/
void visu_ui_field_chooser_setOptions(VisuUiFieldChooser *dialog, GtkWidget *wd)
{
  g_return_if_fail(dialog);

  if (dialog->addWd)
    gtk_widget_destroy(dialog->addWd);
  /* Add the new widgets to provide additional options. */
  dialog->addWd = wd;
  gtk_box_pack_end(GTK_BOX(dialog->vbox), wd, FALSE, FALSE, 0);
  gtk_widget_show_all(wd);
  
  /* Freeze the filechooser itself. */
  
  /* Stop the response action. */
  g_signal_stop_emission_by_name(G_OBJECT(dialog), "response");
}
