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

#include "visu_tools.h"
#include "visu_object.h"

#include <stdlib.h>
#include <string.h>
#include <unistd.h> /* For the access markers R_OK, W_OK ... */

#define PARAMETER_HEADER     "#V_Sim parameters file v"
#define RESOURCE_HEADER      "#V_Sim resources file v"
#define VERSION_HEADER       "3.0"
#define RESOURCES_FILE_NAME  "v_sim.res"
#define PARAMETERS_FILE_NAME "v_sim.par"

#define FLAG_RESOURCES_PATH "main_resourcesPath"
#define DESC_RESOURCES_PATH "Favorite paths to find and save the resources file ; chain[:chain]"
#define DEFAULT_RESOURCES_PATH ""
gboolean readResourcesPaths(gchar **lines, int nbLines,
			    int position, GString *errorMessage);
gboolean exportResourcesPaths(GString *data, int *nbLinesWritten);


struct VisuConfigFileEntry_struct
{
  /* Name of the key. */
  gchar *key;
  gchar *description;

  /* A parameter or a resource */
  int kind;

  /* Number of line used by this resources.
     This is not used if the entry is a parameter
     since, parameters are on the same line than 
     the key and are one line. */
  int nbLines;

  /* This method is called when a file is read
     and the entry is found. */
  visuConfigFileReadFunc read;

  /* Tag, tags are used to ignore or not some
     entries when a file is read. */
  gchar *tag;
};

struct writeFunc_struct
{
  visuConfigFileExportFunc writeFunc;
};

/* This hashtable stores all the known entries.
   The keys are the name of the entry (its key), and
   the value is a pointer to a VisuConfigFileEntry. */
GHashTable *visuConfigFile_entryList;
GList *registeredResources, *registeredParameters;
GList *visuConfigFile_exportResourcesList, *visuConfigFile_exportParametersList;
GHashTable *knownTags;

/* Store the paths to where it is possible to store
   and/or read resource files. This list is ordered
   and first element is the most prefered path. */
GList *resourcesPath;
/* Store the paths to where it is possible to store
   parameters files. This list is ordered and first element is
   the most prefered path.*/
GList *parametersPath;


gint compareStringsInGList(gconstpointer a, gconstpointer b)
{
  return strcmp((char*)a, (char*)b);
}

VisuConfigFileEntry* visuConfigFileAdd_entry(int kind, gchar *key, gchar* description,
					     int nbLines, visuConfigFileReadFunc readFunc)
{
  VisuConfigFileEntry *entry;

  if (!key)
    {
      fprintf(stderr, "WARNING! 'visuConfigFileAdd_entry' has been called with"
	      " a null 'key' argument, it should not.\n");
      return (VisuConfigFileEntry*)0;
    }
  if (nbLines < 1 || (kind != VISU_CONFIGFILE_PARAMETER && kind != VISU_CONFIGFILE_RESOURCE))
    {
      fprintf(stderr, "WARNING! 'visuConfigFileAdd_entry' has been called with"
	      " a wrong 'nbLines' or 'kind' arguments.\n");
      return (VisuConfigFileEntry*)0;
    }
  if (g_hash_table_lookup(visuConfigFile_entryList, (gpointer)key))
    {
      fprintf(stderr, "WARNING! Can't add this new entry, it's label"
	      " ('%s') already exists.\n", key);
      return (VisuConfigFileEntry*)0;
    }

  entry = malloc(sizeof(VisuConfigFileEntry));
  if (!entry)
    {
      allocationProblems();
      return (VisuConfigFileEntry*)0;
    }
  entry->key = g_strdup(key);
  entry->description = g_strdup(description);
  entry->kind = kind;
  if (kind == VISU_CONFIGFILE_PARAMETER)
    entry->nbLines = 1;
  else
    entry->nbLines = nbLines;
  entry->read = readFunc;
  entry->tag = (gchar*)0;

  g_hash_table_insert(visuConfigFile_entryList, (gpointer)entry->key, (gpointer)entry);

  if (kind == VISU_CONFIGFILE_RESOURCE)
    registeredResources = g_list_append(registeredResources, (gpointer)entry);
  else if (kind == VISU_CONFIGFILE_PARAMETER)
    registeredParameters = g_list_append(registeredParameters, (gpointer)entry);
  return entry;
}

/* Method to add a new known tag. */
void visuConfigFileAdd_knownTag(gchar* tag)
{
  if (!tag)
    {
      fprintf(stderr, "WARNING! 'addKnownTag' has just been called with a null string.\n");
      return;
    }

  g_hash_table_insert(knownTags, (gpointer)tag, GINT_TO_POINTER(1));
}

void visuConfigFileAdd_exportFunction(int kind, visuConfigFileExportFunc writeFunc)
{
  struct writeFunc_struct *str;

  if (!writeFunc)
    return;
  if (kind != VISU_CONFIGFILE_RESOURCE && kind != VISU_CONFIGFILE_PARAMETER)
    {
      fprintf(stderr, "WARNING! 'visuConfigFileAdd_exportFunction' has been called with"
	      " a wrong 'kind' argument.\n");
      return;
    }
  str = malloc(sizeof(struct writeFunc_struct));
  if (!str)
    {
      allocationProblems();
      return;
    }
  str->writeFunc = writeFunc;
  if (kind == VISU_CONFIGFILE_RESOURCE)
    visuConfigFile_exportResourcesList = g_list_append(visuConfigFile_exportResourcesList,
						       (gpointer)str);
  else if (kind == VISU_CONFIGFILE_PARAMETER)
    visuConfigFile_exportParametersList = g_list_append(visuConfigFile_exportParametersList,
						       (gpointer)str);
}

void freeConfigEntry(gpointer entry)
{
  if (!entry)
    return;

  g_free(((VisuConfigFileEntry*)entry)->key);
  if (((VisuConfigFileEntry*)entry)->tag)
    g_free(((VisuConfigFileEntry*)entry)->tag);
  free(entry);
}

void visuConfigFileSet_tag(VisuConfigFileEntry *entry, gchar *tag)
{
  if (!entry)
    {
      fprintf(stderr, "WARNING! 'visuConfigFileSet_tag' has been called with"
	      " a null 'entry' argument, can't work.\n");
      return;
    }
  entry->tag = g_strdup(tag);
}

gboolean visuConfigFileLoad(int kind, const char* fileName, GString **message)
{
  GIOChannel *ioFile;
  gchar *fileUTF8;
  GError *error;
  GString *line, *errorMessage;
  GIOStatus status; 
  int nbLine, i;
  char *deuxPoints;
  gchar **tokens;
  gchar *key, *tag, *finTag, *finKey;
  VisuConfigFileEntry *entry;
  int withErrors;

  DBG_fprintf(stderr, "Visu ConfigFile : parsing '%s' file for"
	      " resources/parameters...\n", fileName);
  
  if (kind != VISU_CONFIGFILE_RESOURCE && kind != VISU_CONFIGFILE_PARAMETER)
    {
      fprintf(stderr, "WARNING! 'visuConfigFileLoad' has been called"
	      " with a wrong 'kind' argument.\n");
      *message = (GString*)0;
      return FALSE;
    }

  if (message)
    {
      *message = g_string_new("");
      fileUTF8 = getStringInUTF8(fileName);
      if (kind == VISU_CONFIGFILE_RESOURCE)
	g_string_append_printf(*message, _("Parsing '%s' file for resources...\n\n"), fileUTF8);
      else if (kind == VISU_CONFIGFILE_PARAMETER)
	g_string_append_printf(*message, _("Parsing '%s' file for parameters...\n\n"), fileUTF8);
      g_free(fileUTF8);
    }

  error = (GError*)0;
  ioFile = g_io_channel_new_file(fileName, "r", &error);
  if (error)
    {
      if (*message)
	g_string_append_printf(*message, _("Error : %s"), error->message);
      g_error_free(error);
      return FALSE;
    }

  line = g_string_new("");
  nbLine = 0;
  error = (GError*)0;
  status = g_io_channel_read_line_string(ioFile, line, NULL, &error);
  if (error)
    {
      if (*message)
	g_string_append_printf(*message, _("Error : %s"), error->message);
      g_error_free(error);
      return FALSE;
    }
  nbLine += 1;
  withErrors = 0;
  while (status == G_IO_STATUS_NORMAL)
    {
      if (line->str[0] != '#' && line->str[0] != '\n')
	{
	  deuxPoints = strchr(line->str, ':');
	  if (deuxPoints)
	    {
	      tokens = g_strsplit_set(line->str, ":", 2);
	      key = g_strdup(tokens[0]);
	      key = g_strstrip(key);
	      finKey = g_strdup(tokens[1]);
	      g_strfreev(tokens);
	      /* Look for the tag */
	      tag = strchr(key, '[');
	      if (tag)
		{
		  *tag = '\0';
		  tag = tag + 1;
		  finTag = strchr(tag, ']');
		  if (finTag)
		    *finTag = '\0';
		  else
		    {
		      if (*message)
			g_string_append_printf(*message, _("WARNING! Parse error at line %d,"
							   " the tag '%s' is not closed.\n"),
					       nbLine, tag);
		      withErrors = 1;
		    }
		  DBG_fprintf(stderr,"Visu ConfigFile : read a flag (tag): '%s' (%s).\n", key, tag);
		}
	      else
		  DBG_fprintf(stderr,"Visu ConfigFile : read a flag (tag): '%s' (none).\n", key);

	      if (tag && !g_hash_table_lookup(knownTags, (gpointer)tag))
		{
		  DBG_fprintf(stderr, "Visu ConfigFile : the entry '%s' has an unknown tag (%s),"
			      " it will be dismissed.\n", key, tag);
		}
	      else
		{
		  entry = (VisuConfigFileEntry*)g_hash_table_lookup(visuConfigFile_entryList,
								    (gpointer)key);
		  if (entry)
		    {
		      tokens = malloc(sizeof(gchar*) * (entry->nbLines + 1));
		      if (!tokens)
			{
			  allocationProblems();
			  exit(1);
			}
		      if (kind == VISU_CONFIGFILE_RESOURCE)
			for (i = 0; i < entry->nbLines; i++)
			  {
			    error= (GError*)0;
			    status = g_io_channel_read_line_string(ioFile, line, NULL, &error);
			    nbLine += 1;
			    if (status != G_IO_STATUS_NORMAL)
			      {
				if (*message)
				  {
				    g_string_append_printf(*message, _("Error at line %d :\n"), nbLine);
				    g_string_append_printf(*message, "%s", error->message);
				  }
				g_error_free(error);
				tokens[i] = (gchar*)0;
				g_strfreev(tokens);
				tokens = (gchar**)0;
				withErrors = 1;
			      }
			    tokens[i] = g_strdup(line->str);
			  }
		      else
			tokens[0] = finKey;
		      if (tokens)
			{
			  tokens[entry->nbLines] = (gchar*)0;
			  if (*message)
			    errorMessage = g_string_new("");
			  else
			    errorMessage = (GString*)0;
			  if (entry->read && !entry->read(tokens,
							  entry->nbLines,
							  nbLine,
							  errorMessage))
			    {
			      if (*message)
				g_string_append_printf(*message, "%s", errorMessage->str);
			      withErrors = 1;
			    }
			  if (*message)
			    g_string_free(errorMessage, TRUE);
			  g_strfreev(tokens);
			}
		    }
		  else
		    {
		      if (*message)
			g_string_append_printf(*message, _("WARNING! Parse error at line %d,"
							   " '%s' is an unknown markup.\n"),
					       nbLine, key);
		      withErrors = 1;
		    }
		}
	      g_free(key);
	    }
	}

      error = (GError*)0;
      status = g_io_channel_read_line_string(ioFile, line, NULL, &error);
      if (error)
	{
	  if (*message)
	    g_string_append_printf(*message, _("Error : %s"), error->message);
	  g_error_free(error);
	  return FALSE;
	}
      nbLine += 1;
    }
  if (status == G_IO_STATUS_ERROR)
    {
      if (*message)
	g_string_append_printf(*message, _("Error : %s"), error->message);
      g_error_free(error);
      withErrors = 1;
    }
  g_string_free(line, TRUE);

  error = (GError*)0;
  g_io_channel_shutdown(ioFile, FALSE, &error);
  if (error)
    {
      if (*message)
	g_string_append_printf(*message, _("Error : %s"), error->message);
      g_error_free(error);
      return FALSE;
    }

  if (kind == VISU_CONFIGFILE_RESOURCE)
    {
      DBG_fprintf(stderr, "Visu ConfigFile : emitting 'resourcesLoaded' signal.\n");
      g_signal_emit(visu, VISU_GET_CLASS(visu)->resourcesLoaded_signal_id,
		    0, NULL);
    }

  if (withErrors)
    return FALSE;
  else
    return TRUE;
}

/* Routine to export the resources (color and
   material of elements ...) to file. */
gboolean visuConfigFileSave(int kind, const char* fileName, GString **message, int *lines)
{
  gchar *fileUTF8;
  GString *exportString, *data;
  int nbLine, nb;
  GList *pos;
  gboolean ok;
  int withErrors;
  FILE *file;

  DBG_fprintf(stderr, "Visu ConfigFile : exporting '%s' file for"
	      " resources/parameters...\n", fileName);
  
  if (kind != VISU_CONFIGFILE_RESOURCE && kind != VISU_CONFIGFILE_PARAMETER)
    {
      fprintf(stderr, "WARNING! 'visuConfigFileSave' has been called"
	      " with a wrong 'kind' argument.\n");
      *message = (GString*)0;
      return FALSE;
    }

  if (message)
    {
      *message = g_string_new("");
      fileUTF8 = getStringInUTF8(fileName);
      if (kind == VISU_CONFIGFILE_RESOURCE)
	g_string_append_printf(*message, _("Writing '%s' file for resources...\n\n"), fileUTF8);
      else if (kind == VISU_CONFIGFILE_PARAMETER)
	g_string_append_printf(*message, _("Writing '%s' file for parameters...\n\n"), fileUTF8);
      g_free(fileUTF8);
    }

  withErrors = 0;
  nbLine = 0;
  exportString = g_string_new("");
  if (kind == VISU_CONFIGFILE_RESOURCE)
    g_string_append_printf(exportString, 
			   RESOURCE_HEADER);
  else if (kind == VISU_CONFIGFILE_PARAMETER)
    g_string_append_printf(exportString, 
			   PARAMETER_HEADER);
  g_string_append_printf(exportString, 
	  VERSION_HEADER
	  "\n"
	  "#====================\n"
	  "\n"
	  "#WARNING: this file format is DIFFERENT from that for\n"
	  "#standard v_sim version <= 2.x\n"
	  "\n");
  nbLine += 6;
  g_string_append_printf(exportString, 
	  "#Line beginning with a # are not parsed.\n"
	  "\n");
  nbLine += 2;
  pos = (GList*)0;
  if (kind == VISU_CONFIGFILE_RESOURCE)
    {
      g_string_append_printf(exportString, 
			     "#The only \"useful\" lines must have the following contents\n"
			     "#several two or more lines patterns:\n"
			     "#resource_name:\n"
			     "#values separeted by blank characters\n"
			     "\n");
      nbLine += 5;
      g_string_append_printf(exportString, 
			     "#The following resource names are valid :\n");
      nbLine += 1;
      pos = registeredResources;
    }
  else if (kind == VISU_CONFIGFILE_PARAMETER)
    {
      g_string_append_printf(exportString, 
			     "#The only \"useful\" lines must have the following pattern:\n"
			     "#parameter_name: value\n"
			     "\n");
      nbLine += 3;
      g_string_append_printf(exportString, 
			     "#The following parameter names are valid :\n");
      nbLine += 1;
      pos = registeredParameters;
    }
  while(pos)
    {
      g_string_append_printf(exportString, "# %s\n",
			     ((VisuConfigFileEntry*)(pos->data))->key);
      nbLine += 1;
      pos = g_list_next(pos);
    }
  g_string_append_printf(exportString, "\n");
  nbLine += 1;
  pos = (GList*)0;
  if (kind == VISU_CONFIGFILE_RESOURCE)
    pos = visuConfigFile_exportResourcesList;
  else if (kind == VISU_CONFIGFILE_PARAMETER)
    pos = visuConfigFile_exportParametersList;
  while(pos)
    {
      data = g_string_new("");
      ok = ((struct writeFunc_struct*)(pos->data))->writeFunc(data, &nb);
      if (!ok && message)
	g_string_append_printf(*message, _("Error on line %d.\n"), nbLine);
      if (ok)
	{
	  g_string_append_printf(exportString, "%s", data->str);
	  nbLine += nb;
	}
      else
	withErrors = 1;
      g_string_free(data, TRUE);
      pos = g_list_next(pos);
    }

  file = fopen(fileName, "w");
  if (!file)
    {
      if (message)
	g_string_append_printf(*message, _("WARNING! Unable to create the requested"
					   " file. Check that you have enough"
					   " permissions to write it.\n"));
      g_string_free(exportString, TRUE);
      return FALSE;
    }
  fprintf(file, "%s", exportString->str);
  fclose(file);
  g_string_free(exportString, TRUE);

  if (message)
    g_string_append_printf(*message, _(" %d line(s) written.\n\n"), nbLine);
  if (lines)
    *lines = nbLine;
  
  if (withErrors)
    return FALSE;
  else
    return TRUE;
}

int visuConfigFileSet_floatValue(float *variable, float value, float min, float max)
{
  int outOfBounds;

  outOfBounds = 0;
  if (max > min && value > max)
    {
      *variable = max;
      outOfBounds = 1;
    }
  if (min < max && value < min)
    {
      *variable = min;
      outOfBounds = 1;
    }
  if (!outOfBounds)
    *variable = value;

  return outOfBounds;
}

gchar* getValidFileWithHeader(int mode, char* filename, char* header, GList **list)
{
  gchar *res;
  FILE *file;
  char *msg;
  char line[MAX_LINE_LENGTH];
  float version;
  
  /* Look for a valid file.
     If it is for writing, a valid file is just given by a valid path.
     If it is for reading, a valid file is a valid path AND has a valid header. */
  while (*list)
    {
      /* We get the next valid path. */
      res = getValidPath(list, filename, mode);
      if (!res)
	{
	  DBG_fprintf(stderr, "Visu ConfigFile : no file available.\n");
	  return (gchar*)0;
	}

      /* if we are in reading mode, we test the header. */
      if (mode & R_OK)
	{
	  DBG_fprintf(stderr, "Visu ConfigFile : looking for header of \n  '%s' ... ", res);
	  file = fopen(res, "r");
	  if (!file)
	    {
	      fprintf(stderr, _("INTERNAL ERROR! The file '%s' should be readable"
				" but something goes nasty when one wants to open it.\n"), res);
	      free(res);
	      return (gchar*)0;
	    }
	  version = 0.;
	  msg = fgets(line, MAX_LINE_LENGTH, file);
	  fclose(file);
	  if (msg && !strncmp(line, header, strlen(header))
	      && sscanf(line + strlen(header), "%f", &version))
	    if (version >= 3.)
	      {
		DBG_fprintf(stderr, "ok.\n");
		return res;
	      }
	  DBG_fprintf(stderr, "wrong.\n");
	}
      /* We are in writing mode so the valid path is ok. */
      else
	return res;
      *list = g_list_next(*list);
    }
  DBG_fprintf(stderr, "Visu ConfigFile : no file available.\n");
  return (gchar*)0;
}

gchar* visuConfigFileGet_validPath(int kind, int mode, int utf8)
{
  GList *list;
  gchar* file;
  gchar* fileUTF8;

  if (kind != VISU_CONFIGFILE_RESOURCE && kind != VISU_CONFIGFILE_PARAMETER)
    {
      fprintf(stderr, "WARNING! 'visuConfigFileGet_validPath' has been called"
	      " with a wrong 'kind' argument.\n");
      return (gchar*)0;
    }

  if (kind == VISU_CONFIGFILE_RESOURCE)
    {
      list = resourcesPath;
      file = getValidFileWithHeader(mode, RESOURCES_FILE_NAME,
				    RESOURCE_HEADER, &list);
    }
  else
    {
      list = parametersPath;
      file = getValidFileWithHeader(mode, PARAMETERS_FILE_NAME,
				    PARAMETER_HEADER, &list);
    }

  if (!file)
    return file;

  if (utf8)
    {
      fileUTF8 = getStringInUTF8(file);
      g_free(file);
      return fileUTF8;
    }
  else
    return file;
}
gchar* visuConfigFileGet_nextValidPath(int kind, int accessMode, GList **list, int utf8)
{
  gchar* file;
  gchar* fileUTF8;

  if (kind != VISU_CONFIGFILE_RESOURCE && kind != VISU_CONFIGFILE_PARAMETER)
    {
      fprintf(stderr, "WARNING! 'visuConfigFileGet_nextValidPath' has been called"
	      " with a wrong 'kind' argument.\n");
      return (gchar*)0;
    }

  if (!list)
    {
      fprintf(stderr, "WARNING! 'visuConfigFileGet_nextValidPath' has been called"
	      " with a wrong 'list' argument.\n");
      return (gchar*)0;
    }
  if (!*list)
    return (gchar*)0;

  if (kind == VISU_CONFIGFILE_RESOURCE)
    file = getValidFileWithHeader(accessMode, RESOURCES_FILE_NAME,
				  RESOURCE_HEADER, list);
  else
    file = getValidFileWithHeader(accessMode, PARAMETERS_FILE_NAME,
				  PARAMETER_HEADER, list);

  if (*list)
    *list = g_list_next(*list);

  if (!file)
    return file;

  if (utf8)
    {
      fileUTF8 = getStringInUTF8(file);
      g_free(file);
      return fileUTF8;
    }
  else
    return file;
}
gchar* visuConfigFileGet_defaultFileName(int kind)
{
  if (kind != VISU_CONFIGFILE_RESOURCE && kind != VISU_CONFIGFILE_PARAMETER)
    {
      fprintf(stderr, "WARNING! 'visuConfigFileGet_defaultFileName' has been called"
	      " with a wrong 'kind' argument.\n");
      return (gchar*)0;
    }

  if (kind == VISU_CONFIGFILE_RESOURCE)
    return (gchar*)RESOURCES_FILE_NAME;
  else
    return (gchar*)PARAMETERS_FILE_NAME;
}

GList* visuConfigFileGet_pathList(int kind)
{
  if (kind != VISU_CONFIGFILE_RESOURCE && kind != VISU_CONFIGFILE_PARAMETER)
    {
      fprintf(stderr, "WARNING! 'visuConfigFileGet_nextValidPath' has been called"
	      " with a wrong 'kind' argument.\n");
      return (GList*)0;
    }

  if (kind == VISU_CONFIGFILE_RESOURCE)
    return resourcesPath;
  else
    return parametersPath;
}
GList* visuConfigFileAdd_resourcesPath(char* dir)
{
  GList *element;

  if (!dir || !dir[0])
    return (GList*)0;

  element = g_list_find_custom(resourcesPath, (gconstpointer)dir,
			       compareStringsInGList);
  if (!element)
    {
      DBG_fprintf(stderr, "Visu ConfigFile : add a new resource directory"
		  " to the path :\n '%s'\n", dir);
      resourcesPath = g_list_insert(resourcesPath, (gpointer)dir, 1);
      return resourcesPath->next;
    }
  else
    return (GList*)element;
}


int visuConfigFile_init()
{
  gchar *homeCfgDir, *currentDir;
  VisuConfigFileEntry *resourceEntry;

  DBG_fprintf(stderr, "Visu ConfigFile : initialization process ...");
  visuConfigFile_entryList = g_hash_table_new_full(g_str_hash, g_str_equal, NULL, freeConfigEntry);
  if (!visuConfigFile_entryList)
    {
      allocationProblems();
      return 0;
    }
  registeredResources = (GList*)0;
  registeredParameters = (GList*)0;
  visuConfigFile_exportResourcesList = (GList*)0;
  visuConfigFile_exportParametersList = (GList*)0;
  knownTags = g_hash_table_new_full(g_str_hash, g_str_equal, NULL, NULL);
  if (!knownTags)
    {
      allocationProblems();
      return 0;
    }
  resourcesPath = (GList*)0;
  parametersPath = (GList*)0;
  resourcesPath = g_list_prepend(resourcesPath, (gpointer)v_sim_data_dir);
  parametersPath = g_list_prepend(parametersPath, (gpointer)v_sim_conf_dir);

  resourcesPath = g_list_prepend(resourcesPath, (gpointer)v_sim_local_conf_dir);
  parametersPath = g_list_prepend(parametersPath, (gpointer)v_sim_local_conf_dir);

  currentDir = g_get_current_dir();
  resourcesPath = g_list_prepend(resourcesPath, (gpointer)currentDir);
  parametersPath = g_list_prepend(parametersPath, (gpointer)currentDir);

  DBG_fprintf(stderr, " OK\n");

  resourceEntry = visuConfigFileAdd_entry(VISU_CONFIGFILE_PARAMETER,
					  FLAG_RESOURCES_PATH,
					  DESC_RESOURCES_PATH,
					  1, readResourcesPaths);
  visuConfigFileAdd_exportFunction(VISU_CONFIGFILE_PARAMETER,
				   exportResourcesPaths);

  return 1;
}

gboolean readResourcesPaths(gchar **lines, int nbLines,
			    int position, GString *errorMessage)
{
  int i;
  gchar **tokens;
  gchar *key;

  tokens = g_strsplit_set(lines[0], ":", -1);
  for (i = 0; tokens[i]; i++)
    {
      key = g_strdup(tokens[i]);
      key = g_strstrip(key);
      visuConfigFileAdd_resourcesPath(key);
    }
  g_strfreev(tokens);
  return TRUE;
}
gboolean exportResourcesPaths(GString *data, int *nbLinesWritten)
{
  GList *pnt;
  
  g_string_append_printf(data, "# %s\n", DESC_RESOURCES_PATH);
  g_string_append_printf(data, "%s: ", FLAG_RESOURCES_PATH);
  pnt = resourcesPath;
  while(pnt)
    {
      /* We cancel the first and the last because it's the current working dir
	 and the install dir. */
      if (pnt->prev && pnt->next && pnt->next->next)
	g_string_append_printf(data, "%s", (char*)pnt->data);
      if (pnt->prev && pnt->next && pnt->next->next && pnt->next->next->next)
	g_string_append_printf(data, ":");
      pnt = g_list_next(pnt);
    }
  g_string_append_printf(data, "\n\n");
  *nbLinesWritten = 3;

  return TRUE;
}
