/*   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 "visu_data.h"


#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <math.h>

#include <GL/gl.h>
#include <GL/glu.h> 

#include "visu_object.h"
#include "visu_tools.h"
#include "visu_nodes.h"
#include "visu_extension.h"
#include "visu_rendering.h"
#include "openGLFunctions/objectList.h"

struct nodesProperties_struct
{
  /* This table has the same size and structure
     than the nodes table of a #VisuData object. */
  gpointer **data;

  /* These store the allocated size of the data table. */
  int sizeElement;
  int *sizeNode;

  /* This method is called for each stored token if not NULL when the table is freed. */
  GDestroyNotify freeTokenFunc;
};

struct dataProperties_struct
{
  /* A debug pointer on the key. */
  gchar* name;

  /* This is a pointer to the data stored. */
  gpointer data;
  
  /* This method is called if not NULL when the table is freed. */
  GDestroyNotify freeTokenFunc;
};

/**
 * @NodeRenderedChanged_signal_id: emitted when some #VisuNodes are hidden or revealed
 *                                 (after all changes have been done) ;
 * @NodePositionChanged_signal_id: emitted when some #VisuNodes are moved ;
 * @NodeAskForShowHide_signal_id: emitted when a method wants to change the
 *                                rendered attribute of a node. It asks for all
 *                                modules that deals with this attribute to update
 *                                it ;
 * @OpenGLFacetteChanged_signal_id: emitted whenever this rendered object must be computed again ;
 * @OpenGLThetaPhi_signal_id: emitted when the camera is moved ;
 * @OpenGLXsYs_signal_id: emitted when translation has been applied to rendering ;
 * @OpenGLGross_signal_id: emitted when the camera zooms ;
 * @OpenGLDRed_signal_id: emitted when the perspective is changed ;
 * @OpenGLExtens_signal_id: ??
 * @OpenGLNearFar_signal_id: emitted when the view is changed ;
 * @OpenGLWidthHeight_signal_id: emitted when the size of the window is changed ;
 */
enum {
  ELEMENT_RENDERED_CHANGED_SIGNAL,
  NODE_RENDERED_CHANGED_SIGNAL,
  NODE_POSITION_CHANGED_SIGNAL,
  NODE_ASK_FOR_SHOW_HIDE_SIGNAL,
  OPENGL_THETA_PHI_OMEGA_CHANGED_SIGNAL,
  OPENGL_XS_YS_CHANGED_SIGNAL,
  OPENGL_GROSS_CHANGED_SIGNAL,
  OPENGL_PERSP_CHANGED_SIGNAL,
  OPENGL_NEAR_FAR_CHANGED_SIGNAL,
  OPENGL_WIDTH_HEIGHT_CHANGED_SIGNAL,
  OPENGL_FACETTES_CHANGED_SIGNAL,
  LAST_SIGNAL
};


struct _VisuDataClass
{
  GObjectClass parent;

  int identifierAllNodes;
};

static GObjectClass *parent_class = NULL;

struct VisuData_private_struct
{
  gboolean dispose_has_run;

  /********************/
  /* Files attributes */
  /********************/
  /* Files that correspond to that VisuData.
     They are identified by a kind which is an integer. */
  GHashTable *files;
  /* Commentary associated to the rendered data. */
  gchar* commentary;

  /********************/
  /* Box   attributes */
  /********************/
  /* This is the geometry of the box. Array position 1 to 6
     correspond to xx, xy, yy, zx, zy and zz. */
  float boxGeometry[6];
  /* This is the unitary vector corresponding to boxGeometry. */
  float boxNorm[6];
  /* This is the matrix that transform cartesian coordinates to
     coordinates in the box geometry. Use visuDataConvert_XYZtoBoxCoordinates()
     to access this matrix. */
  float transformXYZtoBoxCoordinates[3][3];
  /* This is the matrix that transform box coordinates to
     cartesian coordinates. Use visuDataConvert_boxCoordinatestoXYZ()
     to access this matrix. */
  float transformBoxCoordinatestoXYZ[3][3];
  /* TRUE if the box is periodic. It is FALSE by default. */
  gboolean isBoxPeriodic;
  /* Translation applied to all nodes when rendered. */
  float translation[3];

  /********************/
  /* Misc. attributes */
  /********************/
  /* This is a table to store data, reachable with string keys.
     It should be accessed via visuDataSet_nodeProperty
     and visuDataGet_nodeProperty. */
  GHashTable *nodesProperties;

  /* This hashtable is usefull to store some data associated with the VisuData.
     It should be accessed with the visuDataSet_property()
     and the visuDataGet_property methods. */
  GHashTable *properties;

  /* This list contains pointers on source id, to be removed when the object
     is finalized. */
  GList *timeoutList;

  /* This pointer is used to gain access to the window the #VisuData may
     be attached to. */
  GenericRenderingWindow attachingWindow;

  /* This object is used to describe the geometry of the OpenGL
     context. */
  OpenGLView *attachedView;

  /* Callbacks of signals that this object listen to. */
  gulong dataLoadedSignalId;
};


static void visu_data_class_init(VisuDataClass *klass);
static void visu_data_init      (VisuData *obj);
static void visu_data_dispose   (GObject* obj);
static void visu_data_finalize  (GObject* obj);

/* Local callbacks. */
static void freeNodepropertiesStruct(gpointer data);
static void freeDatapropertiesStruct(gpointer data);
static void onDataLoadedSignal(GObject *obj, VisuData *visuData, gpointer data);
static void onAskForShowHideSignal(VisuData *visuData, gboolean *redraw, gpointer data);
static void visuData_rebuildList(VisuData *dataObj);


static guint visu_data_signals[LAST_SIGNAL] = { 0 };
static GList* allObjects;

GType visu_data_get_type(void)
{
  static GType visu_data_type = 0;

  if (!visu_data_type)
    {
      static const GTypeInfo visu_data_info =
      {
        sizeof (VisuDataClass),
        NULL, /* base_init */
        NULL, /* base_finalize */
        (GClassInitFunc)visu_data_class_init,
        NULL, /* class_finalize */
        NULL, /* class_data */
        sizeof (VisuData),
        0,
        (GInstanceInitFunc)visu_data_init,
	NULL
      };
      visu_data_type = g_type_register_static(G_TYPE_OBJECT, "VisuDataType",
						 &visu_data_info, 0);
      DBG_fprintf(stderr, "Visu data : creating the type VisuData %d.\n",
		  (int)visu_data_type);
    }

  return visu_data_type;
}

static void visu_data_class_init(VisuDataClass *klass)
{
  GType paramPointer[1] = {G_TYPE_POINTER};
  char *name = _("All elements");
  char *description = _("Draw all the nodes.");
  OpenGLExtension *extensionData;


  DBG_fprintf(stderr, "Visu data : creating the class of the object.\n");
  parent_class = g_type_class_peek_parent(klass);

  DBG_fprintf(stderr, "                - adding new signals ;\n");
  visu_data_signals[ELEMENT_RENDERED_CHANGED_SIGNAL] =
    g_signal_newv("ElementRenderedChanged",
		  G_TYPE_FROM_CLASS(klass),
		  G_SIGNAL_RUN_LAST | G_SIGNAL_NO_RECURSE | G_SIGNAL_NO_HOOKS,
		  NULL, NULL, NULL, g_cclosure_marshal_VOID__POINTER,
		  G_TYPE_NONE, 1, paramPointer);

  visu_data_signals[NODE_RENDERED_CHANGED_SIGNAL] =
    g_signal_newv("NodeRenderedChanged",
		  G_TYPE_FROM_CLASS(klass),
		  G_SIGNAL_RUN_LAST | G_SIGNAL_NO_RECURSE | G_SIGNAL_NO_HOOKS,
		  NULL, NULL, NULL, g_cclosure_marshal_VOID__VOID,
		  G_TYPE_NONE, 0, NULL);

  visu_data_signals[NODE_POSITION_CHANGED_SIGNAL] =
    g_signal_newv ("NodePositionChanged",
		   G_TYPE_FROM_CLASS (klass),
		   G_SIGNAL_RUN_LAST | G_SIGNAL_NO_RECURSE | G_SIGNAL_NO_HOOKS,
		   NULL , NULL, NULL, g_cclosure_marshal_VOID__VOID,
		   G_TYPE_NONE, 0, NULL);

  visu_data_signals[NODE_ASK_FOR_SHOW_HIDE_SIGNAL] =
    g_signal_newv ("NodeAskForShowHide",
		   G_TYPE_FROM_CLASS (klass),
		   G_SIGNAL_RUN_LAST | G_SIGNAL_NO_RECURSE | G_SIGNAL_NO_HOOKS,
		   NULL , NULL, NULL, g_cclosure_marshal_VOID__POINTER,
		   G_TYPE_NONE, 1, paramPointer);

  visu_data_signals[OPENGL_THETA_PHI_OMEGA_CHANGED_SIGNAL] =
    g_signal_newv ("OpenGLThetaPhiOmega", G_TYPE_FROM_CLASS (klass),
		   G_SIGNAL_RUN_LAST | G_SIGNAL_NO_RECURSE | G_SIGNAL_NO_HOOKS,
		   NULL , NULL, NULL, g_cclosure_marshal_VOID__POINTER,
		   G_TYPE_NONE, 1, paramPointer);

  visu_data_signals[OPENGL_XS_YS_CHANGED_SIGNAL] =
    g_signal_newv ("OpenGLXsYs", G_TYPE_FROM_CLASS (klass),
		   G_SIGNAL_RUN_LAST | G_SIGNAL_NO_RECURSE | G_SIGNAL_NO_HOOKS,
		   NULL , NULL, NULL, g_cclosure_marshal_VOID__POINTER,
		   G_TYPE_NONE, 1, paramPointer);

  visu_data_signals[OPENGL_GROSS_CHANGED_SIGNAL] =
    g_signal_newv ("OpenGLGross", G_TYPE_FROM_CLASS (klass),
		   G_SIGNAL_RUN_LAST | G_SIGNAL_NO_RECURSE | G_SIGNAL_NO_HOOKS,
		   NULL , NULL, NULL, g_cclosure_marshal_VOID__POINTER,
		   G_TYPE_NONE, 1, paramPointer);

  visu_data_signals[OPENGL_PERSP_CHANGED_SIGNAL] =
    g_signal_newv ("OpenGLPersp", G_TYPE_FROM_CLASS (klass),
		   G_SIGNAL_RUN_LAST | G_SIGNAL_NO_RECURSE | G_SIGNAL_NO_HOOKS,
		   NULL , NULL, NULL, g_cclosure_marshal_VOID__POINTER,
		   G_TYPE_NONE, 1, paramPointer);

  visu_data_signals[OPENGL_NEAR_FAR_CHANGED_SIGNAL] =
    g_signal_newv ("OpenGLNearFar", G_TYPE_FROM_CLASS (klass),
		   G_SIGNAL_RUN_LAST | G_SIGNAL_NO_RECURSE | G_SIGNAL_NO_HOOKS,
		   NULL , NULL, NULL, g_cclosure_marshal_VOID__POINTER,
		   G_TYPE_NONE, 1, paramPointer);

  visu_data_signals[OPENGL_WIDTH_HEIGHT_CHANGED_SIGNAL] =
    g_signal_newv ("OpenGLWidthHeight", G_TYPE_FROM_CLASS (klass),
		   G_SIGNAL_RUN_LAST | G_SIGNAL_NO_RECURSE | G_SIGNAL_NO_HOOKS,
		   NULL , NULL, NULL, g_cclosure_marshal_VOID__POINTER,
		   G_TYPE_NONE, 1, paramPointer);

  visu_data_signals[OPENGL_FACETTES_CHANGED_SIGNAL] =
    g_signal_newv ("OpenGLFacetteChanged", G_TYPE_FROM_CLASS (klass),
		   G_SIGNAL_RUN_LAST | G_SIGNAL_NO_RECURSE | G_SIGNAL_NO_HOOKS,
		   NULL , NULL, NULL, g_cclosure_marshal_VOID__VOID,
		   G_TYPE_NONE, 0, NULL);

  /* Connect freeing methods. */
  G_OBJECT_CLASS(klass)->dispose = visu_data_dispose;
  G_OBJECT_CLASS(klass)->finalize = visu_data_finalize;

  /* Initialise internal variables. */
  /* Get an OpenGL identifier to store all the materials. */
  klass->identifierAllNodes = openGLObjectList_new(NMAX_TP + 1);
  extensionData = OpenGLExtension_new(name, description,
				      klass->identifierAllNodes, visuData_rebuildList);
  OpenGLExtensionSet_priority(extensionData, OPENGL_EXTENSION_PRIORITY_FIRST);
  OpenGLExtensionSet_sensitiveToRenderingMode(extensionData, TRUE);
  extensionData->used = 1;
  OpenGLExtensionRegister(extensionData);

  allObjects = (GList*)0;
}

static void visu_data_init(VisuData *obj)
{
  int i;

  DBG_fprintf(stderr, "Visu data : initializing a new object (%p).\n",
	      (gpointer)obj);

  /* Connect a method to make all nodes rendered attribute to TRUE
     when the NodeAskForShowHide signal is emited. */
  g_signal_connect(G_OBJECT(obj), "NodeAskForShowHide",
		   G_CALLBACK(onAskForShowHideSignal), (gpointer)0);

  obj->private = g_malloc(sizeof(VisuData_private));
  obj->private->dispose_has_run = FALSE;

  /* Public data. */
  obj->ntype= 0;
  obj->fromVisuElementToInt = (GHashTable*)0;
  obj->fromNumberToVisuNode = (VisuNode**)0;
  obj->fromIntToVisuElement = (VisuElement**)0;
  obj->numberOfStoredNodes = (int*)0;
  obj->numberOfNodes = (int*)0;
  obj->nbOfAllStoredNodes = 0;
  obj->nodes = (VisuNode**)0;
  obj->setColor = (setColorFunc)0;

  /* Private data. */
  obj->private->files = (GHashTable*)0;
  obj->private->commentary = (gchar*)0;
  for (i = 0; i < 3; i++)
    obj->private->translation[i] = 0.;
  for (i = 0; i < 6; i++)
    obj->private->boxGeometry[i] = 0.;
  obj->private->isBoxPeriodic = FALSE;
  obj->private->timeoutList = (GList*)0;  
  obj->private->attachingWindow = (GenericRenderingWindow)0;
  obj->private->attachedView = (OpenGLView*)0;

  obj->private->dataLoadedSignalId =
    g_signal_connect_swapped(G_OBJECT(visu), "dataLoaded",
			     G_CALLBACK(onDataLoadedSignal),
			     (gpointer)obj);

  /* Initial allocations. */
  obj->private->files = g_hash_table_new_full(g_int_hash, g_int_equal, freeInt, freeString);
  if (!obj->private->files)
    exit(1);
  obj->private->nodesProperties = g_hash_table_new_full(g_str_hash, g_str_equal,
						NULL, freeNodepropertiesStruct);
  if (!obj->private->nodesProperties)
    exit(1);
  obj->private->properties = g_hash_table_new_full(g_str_hash, g_str_equal,
					   NULL, freeDatapropertiesStruct);
  if (!obj->private->properties)
    exit(1);
  obj->fromVisuElementToInt = g_hash_table_new_full(g_direct_hash, g_direct_equal,
						     NULL, freeInt);
  if (!obj->fromVisuElementToInt)
    exit(1);

  /* Add object from allObjects list. */
  allObjects = g_list_append(allObjects, (gpointer)obj);
}

/* This method can be called several times.
   It should unref all of its reference to
   GObjects. */
static void visu_data_dispose(GObject* obj)
{
  DBG_fprintf(stderr, "Visu data : dispose object %p.\n", (gpointer)obj);

  if (VISU_DATA(obj)->private->dispose_has_run)
    return;

  g_signal_handler_disconnect(visu, VISU_DATA(obj)->private->dataLoadedSignalId);

  VISU_DATA(obj)->private->dispose_has_run = TRUE;
  /* Chain up to the parent class */
  G_OBJECT_CLASS(parent_class)->dispose(obj);
}
/* This method is called once only. */
static void visu_data_finalize(GObject* obj)
{
  int i;
  VisuData *data;
  GList *lst;

  g_return_if_fail(obj);

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

  /* Remove object from allObjects list. */
  allObjects = g_list_remove(allObjects, (gpointer)obj);

  data = VISU_DATA(obj);

  /* Free public elements. */
  if (data->fromVisuElementToInt)
    g_hash_table_destroy(data->fromVisuElementToInt);
  if (data->fromIntToVisuElement)
    free(data->fromIntToVisuElement);
  if (data->fromNumberToVisuNode)
    free(data->fromNumberToVisuNode);
  if (data->nodes)
    {
      for(i = 0; i < data->ntype; i++)
	free(data->nodes[i]);
      free(data->nodes);
    }
  if (data->numberOfNodes)
    free(data->numberOfNodes);
  if (data->numberOfStoredNodes)
    free(data->numberOfStoredNodes);


  /* Free privates elements. */
  if (data->private)
    {
      if (data->private->files)
	g_hash_table_destroy(data->private->files);
      if (data->private->commentary)
	g_free(data->private->commentary);
      if (data->private->nodesProperties)
	g_hash_table_destroy(data->private->nodesProperties);
      if (data->private->properties)
	g_hash_table_destroy(data->private->properties);
      if (data->private->timeoutList)
	{
	  lst = data->private->timeoutList;
	  while (lst)
	    {
	      g_source_remove(*(guint*)lst->data);
	      g_free(lst->data);
	      lst = g_list_next(lst);
	    }
	  g_list_free(data->private->timeoutList);
	}

      g_free(data->private);
      if (data->private->attachedView)
	OpenGLViewFree(data->private->attachedView);
    }
  /* The free is called by g_type_free_instance... */
/*   free(data); */

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

  DBG_fprintf(stderr, "Visu data : freeing ... OK.\n");
}


VisuData* visuDataNew()
{
  VisuData *data;

  data = VISU_DATA(g_object_new(VISU_DATA_TYPE, NULL));

  if (!data)
    return (VisuData*)0;

  data->private->attachedView = OpenGLViewNew();
  return data;
}

VisuData* visuDataNew_withOpenGLView(OpenGLView *view)
{
  VisuData *data;
  
  g_return_val_if_fail(view, (VisuData*)0);

  data = VISU_DATA(g_object_new(VISU_DATA_TYPE, NULL));

  if (!data)
    return (VisuData*)0;

  data->private->attachedView = OpenGLViewCopy(view);
  return data;
}


/* This is the maximum size (in drawing mode) of all the VisuElements
   that have at least one VisuNode registered. */
/* float maxDrawingSizeOfVisuElements; */


static void onAskForShowHideSignal(VisuData *visuData, gboolean *redraw, gpointer data)
{
  int i, j;

  DBG_fprintf(stderr, "Visu Data : caught the 'NodeAskForShowHide' signal,"
	      " setting all node rendered attribute to TRUE.\n");

  for (i = 0; i < visuData->ntype; i++)
    for(j = 0; j < visuData->numberOfStoredNodes[i]; j++)
      *redraw = visuNodeSet_visibility(&visuData->nodes[i][j], TRUE) || *redraw;

  DBG_fprintf(stderr, "             - returned redraw value : %d.\n", *redraw);
}
static void onDataLoadedSignal(GObject *obj, VisuData *visuData, gpointer data)
{
  double p1_x, p2_x, p3_x, p4_x, p5_x, p6_x, p7_x, p8_x;
  double p1_y, p2_y, p3_y, p4_y, p5_y, p6_y, p7_y, p8_y;
  double p1_z, p2_z, p3_z, p4_z, p5_z, p6_z, p7_z, p8_z;
  double sc, su;
  OpenGLBox *box;

  if (VISU_DATA(obj) != visuData)
    return;

  DBG_fprintf(stderr, "Visu Data (%p) : caught the 'dataLoaded' signal,"
	      " customising the view.\n", (gpointer)obj);

  box = visuData->private->attachedView->box;
  box->dxxs2 = 0.5 * (visuData->private->boxGeometry[VISU_DATA_BOX_DXX] +
		      visuData->private->boxGeometry[VISU_DATA_BOX_DYX] +
		      visuData->private->boxGeometry[VISU_DATA_BOX_DZX]);
  box->dyys2 = 0.5 * (visuData->private->boxGeometry[VISU_DATA_BOX_DYY] +
		      visuData->private->boxGeometry[VISU_DATA_BOX_DZY]);
  box->dzzs2 = 0.5 * (visuData->private->boxGeometry[VISU_DATA_BOX_DZZ]);
   
  p1_x = p1_y = p1_z = 0.0;
  p2_x = visuData->private->boxGeometry[VISU_DATA_BOX_DXX];
  p2_y = p2_z = 0.0;
  p4_x = visuData->private->boxGeometry[VISU_DATA_BOX_DYX];
  p4_y = visuData->private->boxGeometry[VISU_DATA_BOX_DYY];
  p4_z = 0.0;
  p5_x = visuData->private->boxGeometry[VISU_DATA_BOX_DZX];
  p5_y = visuData->private->boxGeometry[VISU_DATA_BOX_DZY];
  p5_z = visuData->private->boxGeometry[VISU_DATA_BOX_DZZ];
      
  p3_x = p2_x + p4_x;
  p3_y = p2_y + p4_y;
  p3_z = p2_z + p4_z;
      
  p6_x = p5_x + p2_x;
  p6_y = p5_y + p2_y;
  p6_z = p5_z + p2_z;
      
  p7_x = p5_x + p3_x;
  p7_y = p5_y + p3_y;
  p7_z = p5_z + p3_z;
      
  p8_x = p5_x + p4_x;
  p8_y = p5_y + p4_y;
  p8_z = p5_z + p4_z;
  box->p1[0] = p1_x;
  box->p1[1] = p1_y;
  box->p1[2] = p1_z;

  box->p2[0] = p2_x;
  box->p2[1] = p2_y;
  box->p2[2] = p2_z;

  box->p3[0] = p3_x;
  box->p3[1] = p3_y;
  box->p3[2] = p3_z;

  box->p4[0] = p4_x;
  box->p4[1] = p4_y;
  box->p4[2] = p4_z;

  box->p5[0] = p5_x;
  box->p5[1] = p5_y;
  box->p5[2] = p5_z;

  box->p6[0] = p6_x;
  box->p6[1] = p6_y;
  box->p6[2] = p6_z;

  box->p7[0] = p7_x;
  box->p7[1] = p7_y;
  box->p7[2] = p7_z;

  box->p8[0] = p8_x;
  box->p8[1] = p8_y;
  box->p8[2] = p8_z;

  /* calculate bare = 1/2 radius of centered sample */
  su = (p7_x-p1_x)*(p7_x-p1_x)+
    (p7_y-p1_y)*(p7_y-p1_y)+
    (p7_z-p1_z)*(p7_z-p1_z);
  sc = (p8_x-p2_x)*(p8_x-p2_x)+
    (p8_y-p2_y)*(p8_y-p2_y)+
    (p8_z-p2_z)*(p8_z-p2_z);
  if (sc > su) su = sc;
  sc = (p5_x-p3_x)*(p5_x-p3_x)+
    (p5_y-p3_y)*(p5_y-p3_y)+
    (p5_z-p3_z)*(p5_z-p3_z);
  if (sc > su) su = sc;
  sc = (p6_x-p4_x)*(p6_x-p4_x)+
    (p6_y-p4_y)*(p6_y-p4_y)+
    (p6_z-p4_z)*(p6_z-p4_z);
  if (sc > su) su = sc;
   
  box->extens = 1.1 * 0.5f * (float)sqrt(su);

  /* Not used anymore. */
/*   g_signal_emit (visu, VISU_GET_CLASS (visu)->OpenGLExtens_signal_id, */
/* 		 0 , NULL); */

  /* effectue les projections et force le recalcul des éléments
     dépendants des facettes. */
  openGLViewCompute_matrixAndView(visuData->private->attachedView);
  DBG_fprintf(stderr, "Visu Data : emitting 'OpenGLFacetteChanged' signal.\n");
  g_signal_emit(visuData, visu_data_signals[OPENGL_FACETTES_CHANGED_SIGNAL],
		0, NULL);
  visuData_createAllElements(visuData);
  DBG_fprintf(stderr, "Visu Data : emission done.\n");
}




/***************/
/* OpenGL Part */
/***************/

void visuData_createNodes(VisuData *data, VisuElement *ele)
{
  RenderingMethod *currentRenderingMethod;
  int *nEle;
  int j;
  int mat;

  g_return_if_fail(data && ele);

  nEle = (int*)g_hash_table_lookup(data->fromVisuElementToInt, (gpointer)ele);
  if (!nEle)
    {
      fprintf(stderr, "WARNING! 'visuData_createNodes' has been"
	      " called but the given VisuElement %p-'%s' is not used.\n",
	      (gpointer)ele, ele->name);
      return;
    }
  currentRenderingMethod = getRenderingMethodInUse();
  if (!currentRenderingMethod)
    {
      fprintf(stderr, "WARNING! 'visuData_createNodes' has been called but no"
	      " rendering method has been selected.\n");
      return;
    }
  if (!currentRenderingMethod->createNode)
    {
      fprintf(stderr, "WARNING! 'visuData_createNodes' has been called but"
	      " the current rendering method has no createNode method.\n");
      return;
    }

  if (!ele->materialIsUpToDate)
    visuElement_createMaterial(ele);
  
  glNewList(VISU_DATA_GET_CLASS(data)->identifierAllNodes + *nEle + 1, GL_COMPILE);
  if (ele->rendered)
    {
      DBG_fprintf(stderr, "Visu Data : creating glObjectList of nodes for '%s' - %d.\n",
		  ele->name, ele->openGLIdentifier);
      /* Set the material by default if available. */
      mat = visuElementGet_identifierMaterial(ele);
      if (!mat)
	g_warning("Can't find the material identifier for the"
		  " element '%s'.\n", ele->name);
      else
	glCallList(mat);
      for(j = 0; j < data->numberOfStoredNodes[*nEle]; j++)
	{
	  if (data->nodes[*nEle][j].rendered)
	    {
	      glLoadName((GLuint)data->nodes[*nEle][j].number);
	      currentRenderingMethod->createNode(data, &data->nodes[*nEle][j], ele);
	    }
	}
    }
  else
    DBG_fprintf(stderr, "Visu Data : skipping glObjectList of nodes for '%s' - %d.\n",
		ele->name, ele->openGLIdentifier);
  glEndList();
}

void visuData_createNode(VisuData *data, VisuNode *node)
{
  RenderingMethod *currentRenderingMethod;
  int mat;
  VisuElement *ele;

  currentRenderingMethod = getRenderingMethodInUse();
  if (!currentRenderingMethod)
    {
      fprintf(stderr, "WARNING! 'visuData_createNode' has been called but no"
	      " rendering method has been selected.\n");
      return;
    }
  if (!currentRenderingMethod->createNode)
    {
      fprintf(stderr, "WARNING! 'visuData_createNode' has been called but"
	      " the current rendering method has no createNode method.\n");
      return;
    }

  ele = data->fromIntToVisuElement[node->posElement];
  /* Set the material by default if available. */
  mat = visuElementGet_identifierMaterial(ele);
  if (!mat)
    g_warning("Can't find the material identifier for the"
	      " element '%s'.\n", ele->name);
  else
    glCallList(mat);

  glLoadName((GLuint)node->number);
  currentRenderingMethod->createNode(data, node, ele);
}

void visuData_createAllNodes(VisuData *data)
{
  int i, j;
  int mat, obj;
#if DEBUG == 1
  GTimer *timer;
  gulong fractionTimer;
#endif

  if (!data)
    {
      DBG_fprintf(stderr, "Visu Data : A file has just been loaded, but the"
		  " currentVisuData variable is empty!\n");
      return;
    }

  DBG_fprintf(stderr, "Visu Data : 'visuData_createAllNodes' called.\n");

#if DEBUG == 1
  timer = g_timer_new();
  g_timer_start(timer);
#endif

  for (i = 0; i < data->ntype; i++)
    visuData_createNodes(data, data->fromIntToVisuElement[i]);

  glNewList(VISU_DATA_GET_CLASS(data)->identifierAllNodes, GL_COMPILE);
  glLineWidth(1);
  for (i = 0; i < data->ntype; i++)
    {
      DBG_fprintf(stderr, "Visu Data : add list %d.\n",
		  VISU_DATA_GET_CLASS(data)->identifierAllNodes + i + 1);
/*       if (currentVisuData->fromIntToVisuElement[i]->rendered) */
      glCallList(VISU_DATA_GET_CLASS(data)->identifierAllNodes + i + 1);
    }
  glEndList();

#if DEBUG == 1
  g_timer_stop(timer);
  fprintf(stderr, "Visu Data : lists built in %gµs.\n", g_timer_elapsed(timer, &fractionTimer)/1e-6);
  g_timer_destroy(timer);
#endif
}
void visuData_createAllElements(VisuData *data)
{
  int i;
  RenderingMethod *method;

  if (!data)
    {
      fprintf(stderr, "WARNING! 'visuData_createAllElements' has"
	      " been called with a null 'data' argument.\n");
      return;
    }
  DBG_fprintf(stderr, "Visu Data : creating OpenGl elements for"
	      " all VisuElement used in given VisuData %p.\n", (gpointer)data);
  method = getRenderingMethodInUse();
  if (!method)
    {
      fprintf(stderr, "WARNING! 'visuData_createAllElements' has"
	      " been called but there is no selected rendering method.\n");
      return;
    }
  for (i = 0; i < data->ntype; i++)
    method->createElement(data->private->attachedView, data->fromIntToVisuElement[i]);
}

int visuDataGet_objectList(VisuData *data)
{
  return VISU_DATA_GET_CLASS(data)->identifierAllNodes;
}

static void visuData_rebuildList(VisuData *dataObj)
{
  int i;

  DBG_fprintf(stderr, "Visu Data : rebuilding object list for visuData %p.\n", (gpointer)dataObj);
  g_return_if_fail(dataObj);

  for (i = 0; i < dataObj->ntype; i++)
    visuElement_createMaterial(dataObj->fromIntToVisuElement[i]);
  visuData_createAllElements(dataObj);
  visuData_createAllNodes(dataObj);
}




int visuDataSet_population(VisuData *data, int nbOfTypes, int* nbOfNodesPerVisuElement,
			   VisuElement **visuElementUsed)
{
  int i, j;
  int *pos;
  int nb;

  DBG_fprintf(stderr, "Visu Data : populating VisuData %p", (gpointer)data);

  data->fromIntToVisuElement = malloc(sizeof(VisuElement*) * nbOfTypes);
  if (!data->fromIntToVisuElement)
    {
      DBG_fprintf(stderr, " ... Error!\nVisu Data : allocate fromIntToVisuElement failed.\n");
      return 0;
    }

  data->ntype = nbOfTypes;
  if (data->ntype <= 0)
    {
      DBG_fprintf(stderr, " ... Error!\nVisu Data : ntype <= 0 failed.\n");
      return 0;
    }
  data->nodes = malloc(sizeof(VisuNode*) * data->ntype);
  if (!data->nodes)
    {
      DBG_fprintf(stderr, " ... Error!\nVisu Data : allocate nodes failed.\n");
      return 0;
    }
  data->numberOfNodes = malloc(sizeof(int) * data->ntype);
  if (!data->numberOfNodes)
    {
      DBG_fprintf(stderr, " ... Error!\nVisu Data : allocate numberOfNodes failed.\n");
      return 0;
    }
  data->numberOfStoredNodes = malloc(sizeof(int) * data->ntype);
  if (!data->numberOfStoredNodes)
    {
      DBG_fprintf(stderr, " ... Error!\nVisu Data : allocate numberOfStoredNodes failed.\n");
      return 0;
    }

  nb = 0;
  for(i = 0; i < data->ntype; i++)
    {
      if (nbOfNodesPerVisuElement[i] <= 0)
	{
	  DBG_fprintf(stderr, " ... Error!\nVisu Data : nb nodes for '%s' <= 0.\n",
		      data->fromIntToVisuElement[i]->name);
	  return 0;
	}
      data->nodes[i] = malloc(sizeof(VisuNode) * nbOfNodesPerVisuElement[i]);
      if (!data->nodes[i])
	{
	  DBG_fprintf(stderr, " ... Error!\nVisu Data : allocate nodes[%d] failed.\n", i);
	  return 0;
	}
      nb += nbOfNodesPerVisuElement[i];
      data->numberOfNodes[i] = nbOfNodesPerVisuElement[i];
      data->numberOfStoredNodes[i] = 0;
      pos = malloc(sizeof(int));
      if (!pos)
	{
	  DBG_fprintf(stderr, " ... Error!\nVisu Data : allocate pos (%d) failed.\n", i);
	  return 0;
	}
      *pos = i;
      g_hash_table_insert(data->fromVisuElementToInt, (gpointer)visuElementUsed[i], (gpointer)pos);
      data->fromIntToVisuElement[i] = visuElementUsed[i];
    }
  data->nbOfAllStoredNodes = 0;
  data->fromNumberToVisuNode = malloc(sizeof(VisuNode*) * nb);
  if (!data->fromNumberToVisuNode)
    {
      DBG_fprintf(stderr, " ... Error!\nVisu Data : allocate fromNumberToVisuNode failed.\n");
      return 0;
    }

  DBG_fprintf(stderr, " ... OK\n");
  return 1;
}
void visuDataFree_population(VisuData *data)
{
  int i;

  if (!data)
    return;

  DBG_fprintf(stderr, "Visu Data : freeing the population of VisuData %p ...\n", (gpointer)data);

  if (data->fromVisuElementToInt)
    g_hash_table_destroy(data->fromVisuElementToInt);
  data->fromVisuElementToInt = g_hash_table_new_full(g_direct_hash, g_direct_equal,
						     NULL, freeInt);
  if (data->fromIntToVisuElement)
    free(data->fromIntToVisuElement);
  data->fromIntToVisuElement = (VisuElement**)0;

  if (data->fromNumberToVisuNode)
    free(data->fromNumberToVisuNode);
  data->fromNumberToVisuNode = (VisuNode**)0;
  
  if (data->nodes)
    {
      for(i = 0; i < data->ntype; i++)
	free(data->nodes[i]);
      free(data->nodes);
    }
  data->nodes = (VisuNode**)0;

  if (data->numberOfNodes)
    free(data->numberOfNodes);
  data->numberOfNodes = (int*)0;
  if (data->numberOfStoredNodes)
    free(data->numberOfStoredNodes);
  data->numberOfStoredNodes = (int*)0;

  if (data->private->nodesProperties)
    g_hash_table_destroy(data->private->nodesProperties);
  data->private->nodesProperties =
    g_hash_table_new_full(g_str_hash, g_str_equal,
			  NULL, freeNodepropertiesStruct);

  DBG_fprintf(stderr, "Visu Data : freeing ... OK.\n");
}

void visuDataAdd_file(VisuData *data, gchar* file, int kind)
{
  gchar *cpFile;
  int *key;

  if (!data)
    {
      fprintf(stderr, "WARNING! No data parameter specified in"
	      " the call of 'visuDataAddFileFunc'.\n");
      return;
    }
  cpFile = g_strdup(file);
  key = malloc(sizeof(int));
  *key = kind;
  g_hash_table_insert(data->private->files, key, (gpointer)cpFile);
  DBG_fprintf(stderr, "Visu Data : adding '%s' filename (key: %d) to the VisuData %p.\n",
	      cpFile, kind, (gpointer)data);
}
void visuDataRemove_allFiles(VisuData *data)
{
  if (!data)
    {
      fprintf(stderr, "WARNING! No data parameter specified in"
	      " the call of 'visuDataAddFileFunc'.\n");
      return;
    }
  g_hash_table_destroy(data->private->files);
  data->private->files = g_hash_table_new_full(g_int_hash, g_int_equal, freeInt, freeString);
  if (data->private->commentary)
    {
      g_free(data->private->commentary);
      data->private->commentary = (gchar*)0;
    }
}
gchar* visuDataGet_file(VisuData *data, int kind)
{
  if (!data)
    {
      fprintf(stderr, "WARNING! No data parameter specified in"
	      " the call of 'visuDataAddFileFunc'.\n");
      return (gchar*)0;
    }
  DBG_fprintf(stderr, "Visu Data : retrieve filename with key %d from the VisuData %p.\n",
	      kind, (gpointer)data);
  return g_hash_table_lookup(data->private->files, (gpointer)&kind);
}
void visuDataSet_fileCommentary(VisuData *data, gchar* commentary)
{
  g_return_if_fail(data);
  
  data->private->commentary = g_strdup(commentary);
}
gchar* visuDataGet_fileCommentary(VisuData *data)
{
  g_return_val_if_fail(data, (gchar*)0);

  return data->private->commentary;
}

gboolean visuData_compareElements(VisuData *data1, VisuData *data2)
{
  int i;

  g_return_val_if_fail(data1 && data2, FALSE);

  DBG_fprintf(stderr, "Visu Data : comparing composition of '%p' and '%p'.\n",
	      (gpointer)data1, (gpointer)data2);
  if (data1->ntype != data2->ntype)
    return FALSE;

  for (i = 0; i< data1->ntype; i++)
    if (!g_hash_table_lookup(data2->fromVisuElementToInt,
			     (gpointer)data1->fromIntToVisuElement[i]))
      return FALSE;

  for (i = 0; i< data2->ntype; i++)
    if (!g_hash_table_lookup(data1->fromVisuElementToInt,
			     (gpointer)data2->fromIntToVisuElement[i]))
      return FALSE;

  return TRUE;
}
void visuDataSet_changeElementFlag(VisuData *data, gboolean changeElement)
{
  gboolean *val;

  g_return_if_fail(data);

  /* Test if already exists */
  val = (gboolean*)visuDataGet_property(data, "changeElementListFlag");
  if (!val)
    {
      val = g_malloc(sizeof(gboolean));
      visuDataSet_property(data, "changeElementListFlag", val);
    }
  *val = changeElement;
}
gboolean visuDataGet_changeElementFlag(VisuData *data)
{
  gboolean *val;

  g_return_val_if_fail(data, FALSE);

  val = (gboolean*)visuDataGet_property(data, "changeElementListFlag");
  if (val)
    return *val;
  else
    return FALSE;
}


void visuDataSet_ColorFunc(VisuData *data, setColorFunc func)
{
  g_return_if_fail(data);

  DBG_fprintf(stderr, "Visu Data : set the color method to %d.\n",
	      GPOINTER_TO_INT(func));
  data->setColor = func;
}

/**
 * visuDataAdd_VisuElement:
 * @data: the #VisuData where to add the new #VisuNode ;
 * @ele: the #VisuElement kind of the new #VisuNode ;
 * @x: its x coordinate ;
 * @y: its y coordinate ;
 * @z: its z coordinate ;
 * @number: its position in the input file (or anything else that can uniqualy
 *          identify this new #VisuNode).
 *
 * This method adds a new #VisuNode to the specified #VisuData. Rotation is set to 0.
 *
 * Returns: 0 if everything is allright.
 */
int visuDataAdd_VisuElement(VisuData *data, VisuElement *ele,
			    double x, double y, double z, int number)
{
  int *pos;

  if (!data)
    return 1;

  pos = (int*)g_hash_table_lookup(data->fromVisuElementToInt, (gpointer)ele);
  if (!pos)
    return 1;

  if (*pos > data->ntype || *pos < 0)
    {
      g_warning("The hashtable from VisuElement to position"
		" of the VisuData %d is malformed since the VisuElement '%s' has a"
		" position %d.\n", GPOINTER_TO_INT(data), ele->name, *pos);
      return 1;
    }
  data->nbOfAllStoredNodes += 1;
  visuNodeSet_newValues(data->nodes[*pos] + data->numberOfStoredNodes[*pos],
			x, y, z, 0., 0., data->nbOfAllStoredNodes, 1, *pos,
			data->numberOfStoredNodes[*pos]);
  data->fromNumberToVisuNode[data->nbOfAllStoredNodes - 1] =
    data->nodes[*pos] + data->numberOfStoredNodes[*pos];
  data->numberOfStoredNodes[*pos] += 1;
  return 0;
}
/**
 * visuDataAdd_VisuElementWithRotation:
 * @data: the #VisuData where to add the new #VisuNode ;
 * @ele: the #VisuElement kind of the new #VisuNode ;
 * @x: its x coordinate ;
 * @y: its y coordinate ;
 * @z: its z coordinate ;
 * @theta: rotation around the z axis;
 * @phi: rotation around the y axis;
 * @number: its position in the input file (or anything else that can uniqualy
 *          identify this new #VisuNode).
 *
 * This method adds a new #VisuNode to the specified #VisuData.
 *
 * Returns: 0 if everything is allright.
 */
int visuDataAdd_VisuElementWithRotation(VisuData *data, VisuElement *ele,
					double x, double y, double z, 
					double theta, double phi, int number)
{
  int *pos;

  if (!data)
    return 1;

  pos = (int*)g_hash_table_lookup(data->fromVisuElementToInt, (gpointer)ele);
  if (!pos)
    return 1;

  if (*pos > data->ntype || *pos < 0)
    {
      g_warning("The hashtable from VisuElement to position"
		" of the VisuData %d is malformed since the VisuElement '%s' has a"
		" position %d.\n", GPOINTER_TO_INT(data), ele->name, *pos);
      return 1;
    }
  data->nbOfAllStoredNodes += 1;
  visuNodeSet_newValues(data->nodes[*pos] + data->numberOfStoredNodes[*pos],
			x, y, z, theta, phi, data->nbOfAllStoredNodes, 1,
			*pos, data->numberOfStoredNodes[*pos]);
  data->fromNumberToVisuNode[data->nbOfAllStoredNodes - 1] =
    data->nodes[*pos] + data->numberOfStoredNodes[*pos];
  data->numberOfStoredNodes[*pos] += 1;
  return 0;
}
/**
 * visuDataAdd_int:
 * @data: the #VisuData where to add the new #VisuNode ;
 * @position: a integer corresponding to the position of
 *            a #VisuElement in the array **nodes in the structure;
 * @x: its x coordinate ;
 * @y: its y coordinate ;
 * @z: its z coordinate ;
 * @number: its position in the input file (or anything else that can uniqualy
 *          identify this new #VisuNode).
 *
 * This method adds a new #VisuNode to the specified #VisuData. Position must be
 * chosen between 0 and (ntype - 1) and corresponds to the position of the array
 * of #VisuNodes of a #VisuElement.
 *
 * Returns: 0 if everything is allright.
 */
int visuDataAdd_int(VisuData *data, int position,
		    double x, double y, double z, int number)
{
  if (!data)
    return 1;

  if (position > data->ntype || position < 0)
    return 1;

  data->nbOfAllStoredNodes += 1;
  visuNodeSet_newValues(data->nodes[position] + data->numberOfStoredNodes[position],
			x, y, z, 0., 0., data->nbOfAllStoredNodes, 1,
			position, data->numberOfStoredNodes[position]);
  data->fromNumberToVisuNode[data->nbOfAllStoredNodes - 1] =
    data->nodes[position] + data->numberOfStoredNodes[position];
  data->numberOfStoredNodes[position] += 1;
  return 0;
}

void visuDataSet_nodeProperty(VisuData* data, VisuNode* node, char* key, gpointer value)
{
  struct nodesProperties_struct *storedData;

  g_return_if_fail(data && node && key);

  storedData = (struct nodesProperties_struct*)g_hash_table_lookup(data->private->nodesProperties,
								   (gpointer)key);
  if (!storedData)
    {
      g_warning("The data %p has no nodesProperties"
		" identified by the key '%s'\n", (gpointer)data, key);
      return;
    }
/*   DBG_fprintf(stderr, "Visu Data : set a new value to the node" */
/* 	      " property called '%s' : %p.\n", key, value); */
  if (storedData->freeTokenFunc)
    storedData->freeTokenFunc(storedData->data[node->posElement][node->posNode]);
  storedData->data[node->posElement][node->posNode] = value;
}
gpointer visuDataGet_nodeProperty(VisuData* data, VisuNode* node, char* key)
{
  struct nodesProperties_struct *storedData;
  
  g_return_val_if_fail(data && node && key, (gpointer)0);

  storedData = (struct nodesProperties_struct*)g_hash_table_lookup(data->private->nodesProperties,
								   (gpointer)key);
  if (!storedData)
    return (gpointer*)0;
  else
    return storedData->data[node->posElement][node->posNode];
}
void visuDataRemove_nodeProperty(VisuData* data, char* key)
{
  g_return_if_fail(data && key);

  g_hash_table_remove(data->private->nodesProperties, key);
  DBG_fprintf(stderr, "Visu Data : removing the nodes property called '%s'.\n", key);
}
void visuDataAdd_nodeProperty(VisuData* data, char* key, GDestroyNotify freeFunc)
{
  struct nodesProperties_struct *storedData;
  int i, j;
  
  g_return_if_fail(data && key);

  storedData = g_hash_table_lookup(data->private->nodesProperties, key);
  if (storedData)
    {
      g_warning("The key '%s' is already associated.\n", key);
      return;
    }
  DBG_fprintf(stderr, "Visu Data : adding a new nodes property, called '%s'.\n", key);
  storedData = malloc(sizeof(struct nodesProperties_struct));
  if (!storedData)
    {
      allocationProblems();
      exit(1);
    }
  storedData->freeTokenFunc = freeFunc;
  storedData->data = malloc(sizeof(gpointer*) * data->ntype);
  if (!storedData->data)
    {
      allocationProblems();
      exit(1);
    }
  storedData->sizeElement = data->ntype;
  storedData->sizeNode = malloc(sizeof(int) * data->ntype);
  if (!storedData->sizeNode)
    {
      allocationProblems();
      exit(1);
    }
  for (i = 0; i < data->ntype; i++)
    {
      storedData->data[i] = malloc(sizeof(gpointer) * data->numberOfNodes[i]);
      if (!storedData->data[i])
	{
	  allocationProblems();
	  exit(1);
	}
      storedData->sizeNode[i] = data->numberOfNodes[i];
      for (j = 0; j < data->numberOfNodes[i]; j++)
	storedData->data[i][j] = (gpointer)0;
    }
  g_hash_table_insert(data->private->nodesProperties, (gpointer)key, (gpointer)storedData);
}

static void freeDatapropertiesStruct(gpointer data)
{
  struct dataProperties_struct *dataSt;

  dataSt = (struct dataProperties_struct *)data;
  DBG_fprintf(stderr, "Visu Data : free the node property '%s' (%p).\n", dataSt->name, data);
  if (dataSt->freeTokenFunc)
    dataSt->freeTokenFunc(dataSt->data);
  else
    g_free(dataSt->data);
  g_free(dataSt);
}
void visuDataSet_property(VisuData* data, char* key, gpointer value)
{
  visuDataSet_propertyWithDestroyFunc(data, key, value, (GDestroyNotify)0);
}
void visuDataSet_propertyWithDestroyFunc(VisuData* data, char* key, gpointer value,
					 GDestroyNotify freeFunc)
{
  struct dataProperties_struct *dataSt;

  if (!data || !key)
    {
      fprintf(stderr, "WARNING! 'visuDataSet_property' has been called with"
	      " a null data parameter or a null key parameter.\n");
      return;
    }
  DBG_fprintf(stderr, "Visu Data : set a new value (with free method) to the "
	      "property called '%s' : %p.\n", key, value);
  dataSt = g_malloc(sizeof(struct dataProperties_struct));
  dataSt->name = key;
  dataSt->data = value;
  dataSt->freeTokenFunc = (GDestroyNotify)freeFunc;
  g_hash_table_insert(data->private->properties, (gpointer)key, (gpointer)dataSt);
}
gpointer visuDataGet_property(VisuData* data, char* key)
{
  struct dataProperties_struct *dataSt;

  if (!data || !key)
    {
      fprintf(stderr, "WARNING! 'visuDataGet_property' has been called with"
	      " a null data parameter or a null key parameter.\n");
      return (gpointer)0;
    }
  DBG_fprintf(stderr, "Visu Data : get the value associated to the "
	      " property called '%s'.\n", key);
  dataSt = (struct dataProperties_struct *)g_hash_table_lookup(data->private->properties,
							       (gpointer)key);
  if (!dataSt)
    return (gpointer)0;
  else
    return dataSt->data;
}
void visuDataRemove_property(VisuData* data, char* key)
{
  if (!data || !key)
    {
      fprintf(stderr, "WARNING! 'visuDataRemove_property' has been called with"
	      " a null data parameter or a null key parameter.\n");
      return;
    }
  g_hash_table_remove(data->private->properties, (gpointer)key);
}


float* visuDataGet_XYZtranslation(VisuData* data)
{
  float *trans;
  int i;

  if (!data)
    {
      fprintf(stderr, "WARNING! 'visuDataGet_translation' has been called with no 'data'"
	      " attribute.\n");
      return (float*)0;
    }
  trans = malloc(sizeof(float) * 3);
  if (!trans)
    {
      allocationProblems();
      exit(1);
    }
  for (i = 0; i < 3; i++)
    trans[i] = data->private->translation[i];
  return trans;
}
int visuDataSet_XYZtranslation(VisuData* data, float xyz[3])
{
  int i, res;

  if (!data || !xyz)
    {
      fprintf(stderr, "WARNING! 'visuDataAdd_translation' has been called with no 'data'"
	      " attribute.\n");
      return 0;
    }

  res = 0;
  for (i = 0; i < 3; i++)
    {
      if (data->private->translation[i] != xyz[i])
	{
	  data->private->translation[i] = xyz[i];
	  res = 1;
	}
    }
  DBG_fprintf(stderr, "Visu Data : set translation to : %f %f %f\n",
	      data->private->translation[0], data->private->translation[1],
	      data->private->translation[2]);

  return res;
}

void visuDataGet_boxMatrix(VisuData *data, float matrix[3][3])
{
  int i, j;

  g_return_if_fail(IS_VISU_DATA_TYPE(data) && matrix);

  for (i = 0; i < 3; i++)
    for (j = 0; j < 3; j++)
      matrix[i][j] = data->private->transformBoxCoordinatestoXYZ[i][j];
}
void visuDataConvert_XYZtoBoxCoordinates(VisuData *data, float boxCoord[3], float xyz[3])
{
  int i, j;

  g_return_if_fail(data && boxCoord && xyz);

  for (i = 0; i < 3; i++)
    {
      boxCoord[i] = 0.;
      for (j = 0; j < 3; j++)
	boxCoord[i] += data->private->transformXYZtoBoxCoordinates[i][j] * xyz[j];
    }
}

void visuDataConvert_boxCoordinatestoXYZ(VisuData *data, float xyz[3], float boxCoord[3])
{
  float transformMatrix[3][3];
  int i, j;

  if (!data || !boxCoord || !xyz)
    {
      fprintf(stderr, "WARNING! 'visuDataConvert_boxCoordinatestoXYZ' has been called"
	      " with no 'data' or no 'boxCoord' or no 'xyz' argument.\n");
      return;
    }
  for (i = 0; i < 3; i++)
    {
      xyz[i] = 0.;
      for (j = 0; j < 3; j++)
	xyz[i] += data->private->transformBoxCoordinatestoXYZ[i][j] * boxCoord[j];
    }
}

void visuDataSet_boxGeometry(VisuData *data, float geometry[6], gboolean periodic)
{
  int i;
  float normY, normZ;

  if (!data || !geometry)
    {
      fprintf(stderr, "WARNING! 'visuDataSet_boxGeometry' has been called with no 'data'"
	      " or no 'geometry' attribute.\n");
      return;
    }
  data->private->isBoxPeriodic = periodic;
  for (i = 0; i < 6; i++)
    data->private->boxGeometry[i] = geometry[i];
  normY = sqrt(geometry[VISU_DATA_BOX_DYX] * geometry[VISU_DATA_BOX_DYX] +
	       geometry[VISU_DATA_BOX_DYY] * geometry[VISU_DATA_BOX_DYY]);
  normZ = sqrt(geometry[VISU_DATA_BOX_DZX] * geometry[VISU_DATA_BOX_DZX] +
	       geometry[VISU_DATA_BOX_DZY] * geometry[VISU_DATA_BOX_DZY] +
	       geometry[VISU_DATA_BOX_DZZ] * geometry[VISU_DATA_BOX_DZZ]);
  data->private->boxNorm[0] = 1.;
  for (i = 1; i < 3; i++)
    data->private->boxNorm[i] = geometry[i] / normY;
  for (i = 3; i < 6; i++)
    data->private->boxNorm[i] = geometry[i] / normZ;
  DBG_fprintf(stderr, "Visu Data : the bounding box is set to :\n %f %f %f\n %f %f %f\n",
	      geometry[0], geometry[1], geometry[2], geometry[3],
	      geometry[4], geometry[5]);

  /* Create the transformation matrix. */
  data->private->transformXYZtoBoxCoordinates[0][0] =
    1 / data->private->boxGeometry[VISU_DATA_BOX_DXX];
  data->private->transformXYZtoBoxCoordinates[0][1] =
    - data->private->boxGeometry[VISU_DATA_BOX_DYX] /
    data->private->boxGeometry[VISU_DATA_BOX_DXX] /
    data->private->boxGeometry[VISU_DATA_BOX_DYY];
  data->private->transformXYZtoBoxCoordinates[0][2] =
    - (data->private->boxGeometry[VISU_DATA_BOX_DZX] /
       data->private->boxGeometry[VISU_DATA_BOX_DXX] +
       data->private->boxGeometry[VISU_DATA_BOX_DYX] *
       data->private->boxGeometry[VISU_DATA_BOX_DZY] / 
       data->private->boxGeometry[VISU_DATA_BOX_DXX] / 
       data->private->boxGeometry[VISU_DATA_BOX_DYY] ) /
    data->private->boxGeometry[VISU_DATA_BOX_DZZ];
  data->private->transformXYZtoBoxCoordinates[1][0] = 0.;
  data->private->transformXYZtoBoxCoordinates[1][1] =
    1 / data->private->boxGeometry[VISU_DATA_BOX_DYY];
  data->private->transformXYZtoBoxCoordinates[1][2] =
    - data->private->boxGeometry[VISU_DATA_BOX_DZY] /
    data->private->boxGeometry[VISU_DATA_BOX_DYY] /
    data->private->boxGeometry[VISU_DATA_BOX_DZZ];
  data->private->transformXYZtoBoxCoordinates[2][0] = 0.;
  data->private->transformXYZtoBoxCoordinates[2][1] = 0.;
  data->private->transformXYZtoBoxCoordinates[2][2] = 1 /
    data->private->boxGeometry[VISU_DATA_BOX_DZZ];

  data->private->transformBoxCoordinatestoXYZ[0][0] = data->private->boxGeometry[VISU_DATA_BOX_DXX];
  data->private->transformBoxCoordinatestoXYZ[0][1] = data->private->boxGeometry[VISU_DATA_BOX_DYX];
  data->private->transformBoxCoordinatestoXYZ[0][2] = data->private->boxGeometry[VISU_DATA_BOX_DZX];
  data->private->transformBoxCoordinatestoXYZ[1][0] = 0.;
  data->private->transformBoxCoordinatestoXYZ[1][1] = data->private->boxGeometry[VISU_DATA_BOX_DYY];
  data->private->transformBoxCoordinatestoXYZ[1][2] = data->private->boxGeometry[VISU_DATA_BOX_DZY];
  data->private->transformBoxCoordinatestoXYZ[2][0] = 0.;
  data->private->transformBoxCoordinatestoXYZ[2][1] = 0.;
  data->private->transformBoxCoordinatestoXYZ[2][2] = data->private->boxGeometry[VISU_DATA_BOX_DZZ];
}
float visuDataGet_boxGeometry(VisuData *data, int vector)
{
  if (!data)
    {
      fprintf(stderr, "WARNING! 'visuDataGet_boxGeometry' has been called with no 'data'"
	      " attribute.\n");
      return -1.;
    }
  if (vector < 0 || vector >= 6)
    {
      fprintf(stderr, "WARNING! 'visuDataGet_boxGeometry' has been called"
	      " with a wrong 'vector' attribute (%d).\n", vector);
      return -1.;
    }
  return data->private->boxGeometry[vector];
}
gboolean visuDataGet_periodic(VisuData *data)
{
  if (!data)
    {
      fprintf(stderr, "WARNING! 'visuDataGet_boxGeometry' has been called with no 'data'"
	      " attribute.\n");
      return FALSE;
    }
  return data->private->isBoxPeriodic;
}
int visuData_constrainedElementInTheBox(VisuData *data, VisuElement *element)
{
  int *indexEle, i, j, k;
  gboolean moved, changed;
  float cartCoord[3], boxCoord[3];

  if (!data || !element)
    {
      fprintf(stderr, "WARNING! 'visuData_constrainedElementInTheBox' has been"
	      " called with no 'data' or no 'element' attribute.\n");
      return 0;
    }
  indexEle = (int*)g_hash_table_lookup(data->fromVisuElementToInt, (gpointer)element);
  if (!indexEle)
    {
      fprintf(stderr, "WARNING! 'visuData_constrainedElementInTheBox' has been"
	      " called with an 'element' attribute that is not in 'data' attribute.\n");
      return 0;
    }
  i = *indexEle;

  if (!data->fromIntToVisuElement[i]->rendered)
    return 0;

  DBG_fprintf(stderr, "Visu Data : Checking for nodes of element '%s' to be in the box.\n",
	      element->name);
  changed = FALSE;
  for(j = 0; j < data->numberOfStoredNodes[i]; j++)
    {
      cartCoord[0] = data->nodes[i][j].x + data->private->translation[0] +
	data->nodes[i][j].translation[0];
      cartCoord[1] = data->nodes[i][j].y + data->private->translation[1] +
	data->nodes[i][j].translation[1];
      cartCoord[2] = data->nodes[i][j].z + data->private->translation[2] +
	data->nodes[i][j].translation[2];
      visuDataConvert_XYZtoBoxCoordinates(data, boxCoord, cartCoord);
      moved = FALSE;
      for (k = 0; k < 3; k++)
	{
	  while (boxCoord[k] < 0.)
	    {
	      moved = TRUE;
	      boxCoord[k] += 1.;
	    }
	  while (boxCoord[k] > 1.)
	    {
	      moved = TRUE;
	      boxCoord[k] -= 1.;
	    }
	}
      if (moved)
	{
	  changed = TRUE;
	  visuDataConvert_boxCoordinatestoXYZ(data, cartCoord, boxCoord);
	  data->nodes[i][j].translation[0] = cartCoord[0] - data->nodes[i][j].x -
	    data->private->translation[0];
	  data->nodes[i][j].translation[1] = cartCoord[1] - data->nodes[i][j].y -
	    data->private->translation[1];
	  data->nodes[i][j].translation[2] = cartCoord[2] - data->nodes[i][j].z -
	    data->private->translation[2];
	}
    }
  return changed;
}
int visuData_constrainedInTheBox(VisuData *data)
{
  int i;
  gboolean changed;

  if (!data)
    {
      fprintf(stderr, "WARNING! 'visuData_constrainedInTheBox' has been called with no 'data'"
	      " attribute.\n");
      return 0;
    }
  changed = FALSE;
  for (i = 0; i < data->ntype; i++)
    changed = visuData_constrainedElementInTheBox(data, data->fromIntToVisuElement[i]) || changed;
  if (changed)
    return 1;
  else
    return 0;
}
int visuData_constrainedFree(VisuData *data)
{
  int i, j, k;

  if (!data)
    {
      fprintf(stderr, "WARNING! 'visuData_constrainedInTheBox' has been called with no 'data'"
	      " attribute.\n");
      return 0;
    }
  for (i = 0; i < data->ntype; i++)
    for(j = 0; j < data->numberOfStoredNodes[i]; j++)
      for (k = 0; k < 3; k++)
	data->nodes[i][j].translation[k] = 0.;
  return 1;
}

void visuDataGet_nodePosition(VisuData *data, VisuNode *node, float coord[3])
{
  if (!data || !node || !coord)
    {
      fprintf(stderr, "WARNING! 'visuDataGet_nodePosition' has been called"
	      " with no 'data' or no 'node' or no 'coord' argument.\n");
      return;
    }
  coord[0] = node->x + node->translation[0] + data->private->translation[0];
  coord[1] = node->y + node->translation[1] + data->private->translation[1];
  coord[2] = node->z + node->translation[2] + data->private->translation[2];
}

VisuNode* visuDataGet_nodeFromId(VisuData *data, int eleId, int posId)
{
  g_return_val_if_fail(data && eleId >= 0 && posId >= 0, (VisuNode*)0);

  if (eleId < data->ntype &&
    posId < data->numberOfStoredNodes[eleId])
    return &data->nodes[eleId][posId];
  else
    return (VisuNode*)0;
}
VisuNode* visuDataGet_nodeFromNumber(VisuData *data, int number)
{
  g_return_val_if_fail(data && number > 0, (VisuNode*)0);

  if (number <= data->nbOfAllStoredNodes)
    return data->fromNumberToVisuNode[number - 1];
  else
    return (VisuNode*)0;
}


/**
 * visuDataTrace:
 * @data: the #VisuData to trace.
 *
 * This method gives informations about the argument.
 */
void visuDataTrace(VisuData *data)
{
  VisuElement *ele;
  int i;

  if (!data)
    return;

  fprintf(stderr, "Visu Data : data %d.\n", GPOINTER_TO_INT(data));
  fprintf(stderr, " | nb VisuElements : %d\n", data->ntype);
  for (i = 0; i < data->ntype; i++)
    {
      ele = data->fromIntToVisuElement[i];
      fprintf(stderr, " | VisuElements '%s' (%d), %d allocated VisuNodes and %d stored.\n",
	      data->fromIntToVisuElement[i]->name, GPOINTER_TO_INT(data->fromIntToVisuElement[i]),
	      data->numberOfNodes[i], data->numberOfStoredNodes[i]);
    }
}

void freeNodepropertiesStruct(gpointer data)
{
  struct nodesProperties_struct *storedData;
  int i, j;

  DBG_fprintf(stderr, "Visu Data : freeing the allocated area of"
	      " a nodes property.\n");
  storedData = (struct nodesProperties_struct *)data;
  if (storedData->freeTokenFunc)
    for (i = 0; i < storedData->sizeElement; i++)
      for (j = 0; j < storedData->sizeNode[i]; j++)
	if (storedData->data[i][j])
	  storedData->freeTokenFunc(storedData->data[i][j]);
  for (i = 0; i < storedData->sizeElement; i++)
    free(storedData->data[i]);
  free(storedData->data);
  free(storedData->sizeNode);
}

void visuDataEmit_askForShowHideNodes(VisuData *data, gboolean *redraw)
{
  g_return_if_fail(data && redraw);

  *redraw = FALSE;
  DBG_fprintf(stderr, "Visu data : %p emit the 'NodeAskForShowHide' signal.\n", (gpointer)data);
  g_signal_emit(data, visu_data_signals[NODE_ASK_FOR_SHOW_HIDE_SIGNAL],
		0 , (gpointer)redraw, NULL);
}
void visuDataEmit_nodePositionChanged(VisuData *data)
{
  g_return_if_fail(data);

  DBG_fprintf(stderr, "Visu data : %p emit the 'NodePositionChanged' signal.\n", (gpointer)data);
  g_signal_emit(data, visu_data_signals[NODE_POSITION_CHANGED_SIGNAL],
		0 , NULL);
}
void visuDataEmit_elementRenderedChange(VisuData *data, VisuElement *element)
{
  g_return_if_fail(data && element);

  DBG_fprintf(stderr, "Visu data : %p emit the 'ElementRenderedChanged'"
	      " signal for element '%s'.\n", (gpointer)data, element->name);
  g_signal_emit(data, visu_data_signals[ELEMENT_RENDERED_CHANGED_SIGNAL],
		0 , (gpointer)element, NULL);
}
void visuDataEmit_nodeRenderedChange(VisuData *data)
{
  g_return_if_fail(data);

  DBG_fprintf(stderr, "Visu data : %p emit the 'NodeRenderedChanged' signal.\n", (gpointer)data);
  g_signal_emit(data, visu_data_signals[NODE_RENDERED_CHANGED_SIGNAL],
		0 , NULL);
}



guint visuDataAdd_timeout(VisuData *data, guint time, GSourceFunc func, gpointer user_data)
{
  guint *id;

  g_return_val_if_fail(IS_VISU_DATA_TYPE(data) && func, (guint)0);

  id = g_malloc(sizeof(guint));
  *id = g_timeout_add(time, func, user_data);
  data->private->timeoutList = g_list_append(data->private->timeoutList, (gpointer)id);
  DBG_fprintf(stderr, "Visu data : create a new timeout callback : %d.\n", *id);
  return *id;
}
gboolean visuDataRemove_timeout(VisuData *data, guint timeoutId)
{
  GList *lst;
  gboolean found;

  g_return_val_if_fail(IS_VISU_DATA_TYPE(data), FALSE);

  DBG_fprintf(stderr, "Visu data : trying to remove a timeout callback (%d) ... ", timeoutId);
  found = FALSE;
  lst = data->private->timeoutList;
  while(lst)
    {
      if (*(guint*)lst->data == timeoutId)
	{
	  found = g_source_remove(timeoutId);
	  data->private->timeoutList =
	    g_list_delete_link(data->private->timeoutList, lst);
	  DBG_fprintf(stderr, "OK (%d).\n", found);
	  return found;
	}
      lst = g_list_next(lst);
    }
  DBG_fprintf(stderr, "not found.\n");
  return found;
}
GenericRenderingWindow visuDataGet_renderingWindow(VisuData *data)
{
  g_return_val_if_fail(IS_VISU_DATA_TYPE(data), (GenericRenderingWindow)0);

  return data->private->attachingWindow;
}
void visuDataSet_renderingWindow(VisuData *data, GenericRenderingWindow window)
{
  g_return_if_fail(IS_VISU_DATA_TYPE(data));

  data->private->attachingWindow = window;
}

OpenGLView* visuDataGet_openGLView(VisuData *data)
{
  g_return_val_if_fail(IS_VISU_DATA_TYPE(data), (OpenGLView*)0);

  return data->private->attachedView;
}
int visuDataSet_angleOfView(VisuData *data, float valueTheta,
			    float valuePhi, float valueOmega, int mask)
{
  int res;

  g_return_val_if_fail(IS_VISU_DATA_TYPE(data), 0);
  
  res = openGLViewSet_thetaPhiOmega(data->private->attachedView, valueTheta,
				    valuePhi, valueOmega, mask);
  if (res)
    g_signal_emit(data, visu_data_signals[OPENGL_THETA_PHI_OMEGA_CHANGED_SIGNAL],
		  0, data->private->attachedView, NULL);
    
  return res;
}
int visuDataSet_positionOfView(VisuData *data, float valueX, float valueY, int mask)
{
  int res;

  g_return_val_if_fail(IS_VISU_DATA_TYPE(data), 0);
  
  res = openGLViewSet_XsYs(data->private->attachedView, valueX,
			   valueY, mask);
  if (res)
    {
      g_signal_emit(data, visu_data_signals[OPENGL_NEAR_FAR_CHANGED_SIGNAL],
		    0, data->private->attachedView, NULL);
      g_signal_emit(data, visu_data_signals[OPENGL_XS_YS_CHANGED_SIGNAL],
		    0, data->private->attachedView, NULL);
    }
    
  return res;
}
int visuDataSet_zoomOfView(VisuData *data, float value)
{
  int res;

  g_return_val_if_fail(IS_VISU_DATA_TYPE(data), 0);
  
  res = openGLViewSet_gross(data->private->attachedView, value);
  if (res)
    {
      g_signal_emit(data, visu_data_signals[OPENGL_NEAR_FAR_CHANGED_SIGNAL],
		    0, data->private->attachedView, NULL);
      g_signal_emit(data, visu_data_signals[OPENGL_GROSS_CHANGED_SIGNAL],
		    0 , data->private->attachedView, NULL);
      g_signal_emit(data, visu_data_signals[OPENGL_FACETTES_CHANGED_SIGNAL],
		    0 , NULL);
      visuData_createAllElements(data);
    }
    
  return res;
}
int visuDataSet_perspectiveOfView(VisuData *data, float value)
{
  int res;

  g_return_val_if_fail(IS_VISU_DATA_TYPE(data), 0);
  
  res = openGLViewSet_persp(data->private->attachedView, value);
  if (res)
    {
      g_signal_emit(data, visu_data_signals[OPENGL_NEAR_FAR_CHANGED_SIGNAL],
		    0, data->private->attachedView, NULL);
      g_signal_emit(data, visu_data_signals[OPENGL_PERSP_CHANGED_SIGNAL],
		    0 , data->private->attachedView, NULL);
      g_signal_emit(data, visu_data_signals[OPENGL_FACETTES_CHANGED_SIGNAL],
		    0 , NULL);
      visuData_createAllElements(data);
    }
    
  return res;
}
int visuDataSet_sizeOfView(VisuData *data, guint width, guint height)
{
  int res;

  g_return_val_if_fail(IS_VISU_DATA_TYPE(data), 0);
  
  res = OpenGLViewSet_windowSize(data->private->attachedView, width, height);
  if (res)
    {
      g_signal_emit(data, visu_data_signals[OPENGL_NEAR_FAR_CHANGED_SIGNAL],
		    0, data->private->attachedView, NULL);
      g_signal_emit(data, visu_data_signals[OPENGL_WIDTH_HEIGHT_CHANGED_SIGNAL],
		    0 , data->private->attachedView, NULL);
      g_signal_emit(data, visu_data_signals[OPENGL_FACETTES_CHANGED_SIGNAL],
		    0 , NULL);
      visuData_createAllElements(data);
    }
    
  return res;
}
void visuDataEmit_facettesChanged(VisuData *data)
{
  g_return_if_fail(IS_VISU_DATA_TYPE(data));
  
  g_signal_emit(data, visu_data_signals[OPENGL_FACETTES_CHANGED_SIGNAL],
		0 , NULL);
}



GList* visuDataGet_allObjects()
{
  DBG_fprintf(stderr, "Visu Data : get the allObjects list.\n");
  return allObjects;
}

/**********************/
/* Obsolete functions */
/**********************/

/* Return the maxium size occupied by a VisuElement that has
   at least one VisuNode. */
/* float getMaxExtens() */
/* { */
/*   return maxDrawingSizeOfVisuElements; */
/* } */
/* Store a new value in maxDrawingSizeOfVisuElements that controls
   the maximum size occupied by a VisuElement. This function emits
   a signal () that is tarpped by opengl.c. Value must be positive or
   nul. */
/* void setMaxExtends(float value) */
/* { */
/*   if (value < 0.) */
/*     return; */

/*   maxDrawingSizeOfVisuElements = value; */

/*   g_signal_emit (visu, VISU_GET_CLASS (visu)->VisuElementSizeChanged, */
/* 		 0 , NULL); */

/* } */
