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

#include <visu_object.h>
#include <visu_tools.h>
#include <openGLFunctions/objectList.h>
#include <renderingBackend/visu_windowInterface.h>

struct DataFile_struct
{
  /* Set to TRUE to colorize. */
  gboolean used;

  /* Transformation vectors. */
  float vectA[3], vectB[3];

  /* Columns to be used. */
  int colUsed[3];

  /* RGB or HSV. */
  DataFileColorModeId colorType;

  /* Scheme to scale : manual or auto. */
  DataFileInputScaleId scaleType;

  /* Min and max values for manual scale. */
  float minMaxValues[2];

  /* Number of read columns. */
  int nbColumns;

  /* Values min and max read for each column. */
  float *readMinMax;

  /* File where data has been read. */
  gchar *file;
};
typedef struct DataFile_struct DataFile;

/* Cache pointers for data from currentVisuData.
   This cache is usefull to avoid too much visuDataGet_property().
   This cache is refresh as soon as currentVisuData is changed. */
DataFile *cacheDataFile;
gboolean dataFile_shadeListIsBuilt;

/* Default values */
#define DATAFILE_NB_COLUMN_DEFAULT  -1
#define DATAFILE_SCALE_TYPE_DEFAULT dataFile_normalize
#define DATAFILE_MIN_NORM_DEFAULT   -1.
#define DATAFILE_MAX_NORM_DEFAULT   +1.
#define DATAFILE_COLOR_TYPE_DEFAULT dataFile_hsv

void dataFileFree(gpointer data);
DataFile* dataFileNew(VisuData *visuData);
void colorFromUserData(VisuData *visuData, float rgba[4], VisuElement *ele, VisuNode* node);
float dataFileGet_valuesFromData(VisuData *visuData, int column, float fromVal);

int initDataFileModule()
{
  int i;

  cacheDataFile = (DataFile*)0;
  dataFile_shadeListIsBuilt = FALSE;

  return 1;
}

void dataFileReDraw(VisuData *data)
{
  visuData_createAllNodes(data);
  g_signal_emit(visu, VISU_GET_CLASS(visu)->OpenGLAskForReDraw_signal_id,
		0 , NULL);
}


DataFile* dataFileNew(VisuData *visuData)
{
  int i;
  DataFile *dataFile;

  DBG_fprintf(stderr, "Visu dataFile : allocate data informations for"
	      " given VisuData object %p.\n", (gpointer)visuData);
  g_return_val_if_fail(visuData, (DataFile*)0);

  dataFile = g_malloc(sizeof(DataFile));
  dataFile->used            = TRUE;
  dataFile->file            = (gchar*)0;
  dataFile->readMinMax      = (float*)0;
  dataFile->nbColumns       = DATAFILE_NB_COLUMN_DEFAULT;
  dataFile->scaleType       = DATAFILE_SCALE_TYPE_DEFAULT;
  dataFile->colorType       = DATAFILE_COLOR_TYPE_DEFAULT;
  dataFile->minMaxValues[0] = DATAFILE_MIN_NORM_DEFAULT;
  dataFile->minMaxValues[1] = DATAFILE_MAX_NORM_DEFAULT;
  for (i = 0; i < 3; i++)
    {
      dataFile->vectA[i]    = 1.;
      dataFile->vectB[i]    = 0.;
      dataFile->colUsed[i]  = -1;
    }
  visuDataSet_propertyWithDestroyFunc(visuData, "dataColor_parameters",
				      (gpointer)dataFile, dataFileFree);
  return dataFile;
}

void dataFileFree(gpointer data)
{
  DataFile *dataFile;

  DBG_fprintf(stderr, "Data File : freeing dataFile.\n");
  dataFile = (DataFile*)data;

  if (dataFile->readMinMax)
    g_free(dataFile->readMinMax);
  if (dataFile->file)
    g_free(dataFile->file);
  g_free(dataFile);
}

void dataFileActivate(VisuData *visuData, gboolean status)
{
  g_return_if_fail(visuData);

  if (status)
    {
      visuElementSet_updateNodesOnMaterialChange();
      visuDataSet_ColorFunc(visuData, colorFromUserData);
    }
  else
    {
      visuElementUnset_updateNodesOnMaterialChange();
      visuDataSet_ColorFunc(visuData, (setColorFunc)0);
    }
}

int dataFileSet_file(VisuData *attachedVisuData, char* filename, GString *message, int *errors)
{
  int i, j, res, err, nb;
  FILE *file;
  char line[MAX_LINE_LENGTH];
  char *msg;
  int nAtome;
  float *data;
  gchar **dataRead;
  gchar *fileUTF8, *storedFilename;
  DataFile *dataFile;

  DBG_fprintf(stderr, "Visu dataFile : set data file to '%s'.\n", filename);
  g_return_val_if_fail(attachedVisuData && filename && message, 0);

  /* Test if this VisuData has already been colorized by testing
     the existence of the 'dataColor_used' property. If not, all required
     memory is allocated. */
  dataFile = visuDataGet_property(attachedVisuData, "dataColor_parameters");
  if (!dataFile)
    dataFile = dataFileNew(attachedVisuData);
  g_return_val_if_fail(dataFile, 0);

  if (!errors)
    errors = &err;
  *errors = 0;

  /* erase previously stored dataFile informations. */
  dataFile->nbColumns = DATAFILE_NB_COLUMN_DEFAULT;
  for (i = 0; i < 3; i++)
    dataFile->colUsed[i] = -1;
  if (dataFile->file)
    {
      g_free(dataFile->file);
      dataFile->file = (gchar*)0;
    }
  if (dataFile->readMinMax)
    {
      g_free(dataFile->readMinMax);
      dataFile->readMinMax = (float*)0;
    }

  /* We clear previously stored user data from the current
     visuData structure. */
  if (attachedVisuData->nodes)
    visuDataRemove_nodeProperty(attachedVisuData, "dataColor_data");

  file = fopen(filename, "r");
  if (!file)
    {
      fileUTF8 = getStringInUTF8(filename);
      g_string_append_printf(message, _("WARNING! Can't find the '%s' data file.\n"),
			     fileUTF8);
      g_free(fileUTF8);
      *errors = 1;
      return 0;
    }
  nAtome = 0;
  visuDataAdd_nodeProperty(attachedVisuData, "dataColor_data", freeFloat);
  while (!feof(file))
    {
      msg = fgets(line, MAX_LINE_LENGTH, file);
      if (!msg)
	continue;
      if (line[0] == '#' || line[0] == '!' || line[0] == '\n')
	continue;
      /* Test the number of columns. */
      if (dataFile->nbColumns == DATAFILE_NB_COLUMN_DEFAULT)
	{
	  dataRead = g_strsplit_set(msg, " \t;:\n", MAX_LINE_LENGTH);
	  DBG_fprintf(stderr, "Visu dataFile : looking for number of columns.\n");
	  dataFile->nbColumns = 0;
	  for (i = 0; dataRead[i]; i++)
	    if (dataRead[i][0])
	      {
		DBG_fprintf(stderr, "                 | one token : '%s'\n", dataRead[i]);
		dataFile->nbColumns += 1;
	      }
	  g_strfreev(dataRead);
	  DBG_fprintf(stderr, "Visu dataFile : detected number of columns : %d\n",
		      dataFile->nbColumns);
	  if (dataFile->nbColumns <= 0)
	    {
	      g_string_append_printf(message, _("WARNING! Can't find any column of"
						" data in the given file.\n"));
	      *errors = 1;
	      dataFileActivate(attachedVisuData, FALSE);
	      dataFile->used = FALSE;
	      return 0;
	    }
	  dataFile->readMinMax = g_malloc(sizeof(float) * 2 * (dataFile->nbColumns));
	}
      if (nAtome >= attachedVisuData->nbOfAllStoredNodes)
	{
	  g_string_append_printf(message, _("WARNING! There are more data than nodes.\n"));
	  *errors = 1;
	  break;
	}
      data = g_malloc(sizeof(float) * dataFile->nbColumns);
      dataRead = g_strsplit_set(msg, " \t;:\n", MAX_LINE_LENGTH);
      res = 1;
      nb = 0;
      for (i = 0; dataRead[i]; i++)
	{
	  if (dataRead[i][0])
	    {
	      res = res && (1 == sscanf(dataRead[i], "%f", data + nb));
	      DBG_fprintf(stderr, "                 | one value : '%s' -> '%f'\n",
			  dataRead[i], data[nb]);
	      nb += 1;
	    }
	}
      res = res && (nb == dataFile->nbColumns);
      g_strfreev(dataRead);
      if (res)
	{
	  /* Associates the values to the node. */
	  visuDataSet_nodeProperty(attachedVisuData, attachedVisuData->fromNumberToVisuNode[nAtome],
				   "dataColor_data", (gpointer)data);
	  /* Check for minMax values for each column. */
	  for (i = 0; i < dataFile->nbColumns; i++)
	    {
	      if (nAtome == 0)
		{
		  dataFile->readMinMax[i * 2 + 0] = data[i];
		  dataFile->readMinMax[i * 2 + 1] = data[i];
		}
	      else
		{
		  if (data[i] < dataFile->readMinMax[i * 2 + 0])
		    dataFile->readMinMax[i * 2 + 0] = data[i];
		  if (data[i] > dataFile->readMinMax[i * 2 + 1])
		    dataFile->readMinMax[i * 2 + 1] = data[i];
		}
	    }
	  nAtome++;
	}
      else
	free(data);
    }
  fclose(file);
  if (nAtome < attachedVisuData->nbOfAllStoredNodes)
    {
      g_string_append_printf(message, _("WARNING! There are less data than nodes.\n"));
      /* Padding with min values for other nodes. */
      for (i = nAtome; i < attachedVisuData->nbOfAllStoredNodes; i++)
	{
	  data = g_malloc(sizeof(float) * dataFile->nbColumns);
	  for (j = 0; j < dataFile->nbColumns; j++)
	    data[j] = dataFile->readMinMax[j * 2];
	  visuDataSet_nodeProperty(attachedVisuData, attachedVisuData->fromNumberToVisuNode[i],
				   "dataColor_data", (gpointer)data);
	}
      *errors = 1;
    }
  dataFile->file = g_strdup(filename);

  if (dataFile->nbColumns < 0)
    {
      g_string_append_printf(message, _("WARNING! Can't find any columns with numbers.\n"
					"Valid format are as much numbers as desired, separated"
					" by any of the following characters : [ ;:\\t].\n"));
      dataFile->used = FALSE;
      return 0;
    }

  if (DEBUG)
    {
      DBG_fprintf(stderr, "Visu dataFile : min/max values :\n");
      for (i = 0; i < dataFile->nbColumns; i++)
	DBG_fprintf(stderr, "Visu dataFile :  col %d -> %f (min) and %f (max).\n",
		    i, dataFile->readMinMax[i * 2 + 0], dataFile->readMinMax[i * 2 + 1]);
    }

  dataFileActivate(attachedVisuData, dataFile->used);
  cacheDataFile = dataFile;

  return 1;
}
gchar* dataFileGet_file(VisuData *visuData)
{
  DataFile *dataFile;

  dataFile = (DataFile*)visuDataGet_property(visuData, "dataColor_parameters");
  if (dataFile)
    return dataFile->file;
  else
    return (gchar*)0;
}
gboolean dataFileGet_fileMinMaxFromColumn(VisuData *visuData, float minMax[2], int column)
{
  DataFile *dataFile;

  g_return_val_if_fail(visuData && minMax, FALSE);

  dataFile = (DataFile*)visuDataGet_property(visuData, "dataColor_parameters");
  g_return_val_if_fail(dataFile, FALSE);
  g_return_val_if_fail(column >= 0 && column < dataFile->nbColumns, FALSE);

  minMax[0] = dataFile->readMinMax[column * 2 + 0];
  minMax[1] = dataFile->readMinMax[column * 2 + 1];
  return TRUE;
}


int dataFileSet_used(VisuData *data, int val)
{
  DataFile *dataFile;

  DBG_fprintf(stderr, "Visu dataFile : set using flag for dataFile module to %d .\n", val);

  dataFile = (DataFile*)visuDataGet_property(data, "dataColor_parameters");
  if (!dataFile)
    return 0;

  if (val == dataFile->used)
    return 0;

  dataFile->used = val;

  dataFileActivate(data, dataFile->used && dataFile->file);
  if (dataFile->file)
    return 1;
  else
    return 0;
}
int dataFileGet_used(VisuData *data)
{
  DataFile *dataFile;

  dataFile = (DataFile*)visuDataGet_property(data, "dataColor_parameters");
  
  if (!dataFile)
    return 0;
  else
    return (int)dataFile->used;
}

int dataFileSet_scaleType(VisuData *visuData, DataFileInputScaleId scale)
{
  DataFile *dataFile;

  g_return_val_if_fail(visuData, 0);
  dataFile = (DataFile*)visuDataGet_property(visuData, "dataColor_parameters");
  g_return_val_if_fail(dataFile, 0);

  DBG_fprintf(stderr, "Visu dataFile : set the scale type to %d (previuosly %d).\n",
	      scale, dataFile->scaleType);
  if (scale == dataFile->scaleType)
    return 0;
  dataFile->scaleType = scale;

  return dataFile->used && dataFile->file;
}
DataFileInputScaleId dataFileGet_scaleType(VisuData *visuData)
{
  DataFile *dataFile;

  g_return_val_if_fail(visuData, DATAFILE_SCALE_TYPE_DEFAULT);
  dataFile = (DataFile*)visuDataGet_property(visuData, "dataColor_parameters");

  if (!dataFile)
    return DATAFILE_SCALE_TYPE_DEFAULT;
  else
    return dataFile->scaleType;
}
int dataFileSet_min(VisuData *visuData, float min)
{
  DataFile *dataFile;

  g_return_val_if_fail(visuData, 0);
  dataFile = (DataFile*)visuDataGet_property(visuData, "dataColor_parameters");
  g_return_val_if_fail(dataFile, 0);

  if (min >= dataFile->minMaxValues[1])
    {
      fprintf(stderr, "WARNING! Can't put a minimum value equal or greater than"
			" the maximum value.\n");
      return 0;
    }
  DBG_fprintf(stderr, "Visu dataFile : set the min value to %f (previuosly %f).\n",
	      min, dataFile->minMaxValues[0]);
  if (dataFile->minMaxValues[0] == min)
    return 0;
  dataFile->minMaxValues[0] = min;

  return dataFile->used && dataFile->file;
}
int dataFileSet_max(VisuData *visuData, float max)
{
  DataFile *dataFile;

  g_return_val_if_fail(visuData, 0);
  dataFile = (DataFile*)visuDataGet_property(visuData, "dataColor_parameters");
  g_return_val_if_fail(dataFile, 0);

  if (max <= dataFile->minMaxValues[0])
    {
      fprintf(stderr, "WARNING! Can't put a maximum value equal or smaller than"
	      " the minimum value.\n");
      return 0;
    }
  DBG_fprintf(stderr, "Visu dataFile : set the max value to %f (previuosly %f).\n",
	      max, dataFile->minMaxValues[1]);
  if (dataFile->minMaxValues[1] == max)
    return 0;
  dataFile->minMaxValues[1] = max;

  return dataFile->used && dataFile->file;
}
float dataFileGet_min(VisuData *visuData)
{
  DataFile *dataFile;

  g_return_val_if_fail(visuData, DATAFILE_MIN_NORM_DEFAULT);
  dataFile = (DataFile*)visuDataGet_property(visuData, "dataColor_parameters");

  if (!dataFile)
    return DATAFILE_MIN_NORM_DEFAULT;
  else
    return dataFile->minMaxValues[0];
}
float dataFileGet_max(VisuData *visuData)
{
  DataFile *dataFile;

  g_return_val_if_fail(visuData, DATAFILE_MAX_NORM_DEFAULT);
  dataFile = (DataFile*)visuDataGet_property(visuData, "dataColor_parameters");

  if (!dataFile)
    return DATAFILE_MAX_NORM_DEFAULT;
  else
    return dataFile->minMaxValues[1];
}

int dataFileGet_nbColumns(VisuData *visuData)
{
  DataFile *dataFile;

  g_return_val_if_fail(visuData, DATAFILE_NB_COLUMN_DEFAULT);
  dataFile = (DataFile*)visuDataGet_property(visuData, "dataColor_parameters");

  if (!dataFile)
    return DATAFILE_NB_COLUMN_DEFAULT;
  else
    return dataFile->nbColumns;
}

int dataFileSet_vectA(VisuData *visuData, float val, int pos)
{
  DataFile *dataFile;

  g_return_val_if_fail(visuData && pos > DATAFILE_NB_COLUMN_DEFAULT && pos < 3, 0);
  dataFile = (DataFile*)visuDataGet_property(visuData, "dataColor_parameters");
  g_return_val_if_fail(dataFile, 0);

  DBG_fprintf(stderr, "Visu dataFile : set the %d value of vectA to %f (previuosly %f).\n",
	      pos, val, dataFile->vectA[pos]);
  if (dataFile->vectA[pos] == val)
    return 0;
  dataFile->vectA[pos] = val;

  return dataFile->used && dataFile->file;
}
int dataFileSet_vectB(VisuData *visuData, float val, int pos)
{
  DataFile *dataFile;

  g_return_val_if_fail(visuData && pos > DATAFILE_NB_COLUMN_DEFAULT && pos < 3, 0);
  dataFile = (DataFile*)visuDataGet_property(visuData, "dataColor_parameters");
  g_return_val_if_fail(dataFile, 0);

  DBG_fprintf(stderr, "Visu dataFile : set the %d value of vectB to %f (previuosly %f).\n",
	      pos, val, dataFile->vectB[pos]);
  if (dataFile->vectB[pos] == val)
    return 0;
  dataFile->vectB[pos] = val;

  return dataFile->used && dataFile->file;
}
float* dataFileGet_vectA(VisuData *visuData)
{
  DataFile *dataFile;

  g_return_val_if_fail(visuData, (float*)0);
  dataFile = (DataFile*)visuDataGet_property(visuData, "dataColor_parameters");

  if (!dataFile)
    return (float*)0;
  else
    return dataFile->vectA;
}
float* dataFileGet_vectB(VisuData *visuData)
{
  DataFile *dataFile;

  g_return_val_if_fail(visuData, (float*)0);
  dataFile = (DataFile*)visuDataGet_property(visuData, "dataColor_parameters");

  if (!dataFile)
    return (float*)0;
  else
    return dataFile->vectB;
}
int dataFileSet_colUsed(VisuData *visuData, int val, int pos)
{
  DataFile *dataFile;

  g_return_val_if_fail(visuData && pos > DATAFILE_NB_COLUMN_DEFAULT && pos < 3, 0);
  dataFile = (DataFile*)visuDataGet_property(visuData, "dataColor_parameters");
  g_return_val_if_fail(dataFile, 0);

  g_return_val_if_fail(val < dataFile->nbColumns || val == DATAFILE_NB_COLUMN_DEFAULT, 0);

  DBG_fprintf(stderr, "Visu dataFile : channel %d uses column %d (previuosly %d).\n",
	      pos, val, dataFile->colUsed[pos]);
  if (dataFile->colUsed[pos] == val)
    return 0;
  dataFile->colUsed[pos] = val;

  return dataFile->used && dataFile->file;
}
int* dataFileGet_colUsed(VisuData *visuData)
{
  DataFile *dataFile;

  g_return_val_if_fail(visuData, (int*)0);
  dataFile = (DataFile*)visuDataGet_property(visuData, "dataColor_parameters");

  if (!dataFile)
    return (int*)0;
  else
    return dataFile->colUsed;
}
int dataFileSet_colorType(VisuData *visuData, DataFileColorModeId color)
{
  DataFile *dataFile;

  g_return_val_if_fail(visuData, 0);
  dataFile = (DataFile*)visuDataGet_property(visuData, "dataColor_parameters");
  g_return_val_if_fail(dataFile, 0);

  DBG_fprintf(stderr, "Visu dataFile : set the color type to %d (previuosly %d).\n",
	      color, dataFile->colorType);
  if (color == dataFile->colorType)
    return 0;
  dataFile->colorType = color;

  return dataFile->used && dataFile->file;
}
DataFileColorModeId dataFileGet_colorType(VisuData *visuData)
{
  DataFile *dataFile;

  g_return_val_if_fail(visuData, DATAFILE_COLOR_TYPE_DEFAULT);
  dataFile = (DataFile*)visuDataGet_property(visuData, "dataColor_parameters");

  if (!dataFile)
    return DATAFILE_COLOR_TYPE_DEFAULT;
  else
    return dataFile->colorType;
}
int dataFileSet_shade(VisuData *visuData, Shade *shade)
{
  float *vectA, *vectB;
  gboolean *vectX, ok;
  int i, res;
  DataFile *dataFile;

  g_return_val_if_fail(visuData && shade, (int)0);

  res = dataFileSet_colorType(visuData, shadeGet_colorMode(shade));
  ok = shadeGet_colorTransformation(shade, &vectA, &vectB, &vectX);
  if (!ok)
    {
      g_warning("Can't get the color transformation.");
      return 0;
    }
  for (i = 0; i < 3; i++)
    {
      res = dataFileSet_vectA(visuData, vectA[i], i) || res;
      res = dataFileSet_vectB(visuData, vectB[i], i) || res;
      if (vectX[i])
	res = dataFileSet_colUsed(visuData, 0, i) || res;
      else
	res = dataFileSet_colUsed(visuData, DATAFILE_NB_COLUMN_DEFAULT, i) || res;
    }
  dataFile = (DataFile*)visuDataGet_property(visuData, "dataColor_parameters");
  g_return_val_if_fail(dataFile, 0);
  return dataFile->used && res;
}
gboolean dataFileApply_hideOnMinValue(VisuData *visuData, int column, float value)
{
  gboolean redraw;
  int *nbColumns, i;
  float *storedValues;
  DataFile *dataFile;

  g_return_val_if_fail(visuData, FALSE);

  if (column == -1)
    {
      DBG_fprintf(stderr, "Data File : unmask previously masked nodes.\n");
      return FALSE;
    }
  
  dataFile = (DataFile*)visuDataGet_property(visuData, "dataColor_parameters");
  if (!dataFile)
    return FALSE;
  if (dataFile->nbColumns == DATAFILE_NB_COLUMN_DEFAULT)
    return FALSE;

  g_return_val_if_fail(column > DATAFILE_NB_COLUMN_DEFAULT && column < dataFile->nbColumns, FALSE);
  
  redraw = FALSE;
  for (i = 0; i < visuData->nbOfAllStoredNodes; i++)
    {
      storedValues =
	(float*)visuDataGet_nodeProperty(visuData,
					 visuData->fromNumberToVisuNode[i],
					 "dataColor_data");
      if (storedValues[column] < value && -storedValues[column] < value)
	redraw = visuNodeSet_visibility(visuData->fromNumberToVisuNode[i], FALSE) || redraw;
    }

  return TRUE;
}


/*******************/
/* Drawing methods */
/*******************/
/* In these methods, vectA and vectB (and others) are not retrieve from the visuData object for
   speed reason. We use instead global pointers dataFile_vectA/B that are
   pointing to the right place in the visuData object that needs to be rendered. */

/* Normalization method */
float dataFileGet_valuesFromData(VisuData *visuData, int column, float fromVal)
{
  float res;

  g_return_val_if_fail(cacheDataFile, 0.);
  switch (cacheDataFile->scaleType)
    {
    case dataFile_normalize:
      g_return_val_if_fail(column >= 0 && column < cacheDataFile->nbColumns, 0.);
      res = ( (fromVal - cacheDataFile->readMinMax[column * 2 + 0]) /
	      (cacheDataFile->readMinMax[column * 2 + 1] -
	       cacheDataFile->readMinMax[column * 2 + 0]) );
      return res;
    case dataFile_minMax:
      res = ( (fromVal - cacheDataFile->minMaxValues[0]) /
	      (cacheDataFile->minMaxValues[1] - cacheDataFile->minMaxValues[0]) );
      if (res > 1.)
	res = 1.;
      else if (res < 0.)
	res = 0.;
      return res;
    }
  return 0.;
}
/* Colourization method */
void dataFileGet_valuesTransformedInRGB(VisuData *visuData,
					float* valuesTransformed, float* valuesFrom)
{
  int i;

  g_return_if_fail(visuData && valuesTransformed && valuesFrom);

  for (i = 0; i < 3; i++)
    {
      valuesTransformed[i] = cacheDataFile->vectA[i] * valuesFrom[i] + cacheDataFile->vectB[i];
      valuesTransformed[i] = (valuesTransformed[i] < 0.)?0.:valuesTransformed[i];
      valuesTransformed[i] = (valuesTransformed[i] > 1.)?1.:valuesTransformed[i];
    }
  switch(cacheDataFile->colorType)
    {
    case dataFile_rgb:
      return;
    case dataFile_hsv:
      HSVtoRGB(valuesTransformed, valuesTransformed);
      break;
    }
}

GList* dataFileBuild_presetShadeList()
{
  Shade *shade;
  float vectA[3], vectB[3];
  gboolean vectX[3];
  GList *list;

  if (dataFile_shadeListIsBuilt)
    return toolShadeListGet();

  dataFile_shadeListIsBuilt = TRUE;
  /* Create a blue to red color range. */
  vectA[0] = -0.66667;
  vectA[1] = 0.;
  vectA[2] = 0.;
  vectB[0] = 0.66667;
  vectB[1] = 1.;
  vectB[2] = 1.;
  vectX[0] = TRUE;
  vectX[1] = FALSE;
  vectX[2] = FALSE;
  shade = shadeNew(_("blue to red"), vectA, vectB, vectX, shade_colorModeHSV);
  shadeSet_pathToImage(shade, "stock-blue-to-red.png");
  list = toolShadeListAppend(shade);

  /* Create a black to white (through yellow and red) color range. */
  vectA[0] = 2.66667;
  vectA[1] = 2.66667;
  vectA[2] = 4.;
  vectB[0] = 0.;
  vectB[1] = -1.;
  vectB[2] = -3.;
  vectX[0] = TRUE;
  vectX[1] = TRUE;
  vectX[2] = TRUE;
  shade = shadeNew(_("hot color"), vectA, vectB, vectX, shade_colorModeRGB);
  shadeSet_pathToImage(shade, "stock-hot-color.png");
  list = toolShadeListAppend(shade);

  /* Create a blue to yellow (through dark purple) color range. */
  vectA[0] = 1.33333;
  vectA[1] = 2.;
  vectA[2] = -2;
  vectB[0] = 0.;
  vectB[1] = -1.;
  vectB[2] = 1.;
  vectX[0] = TRUE;
  vectX[1] = TRUE;
  vectX[2] = TRUE;
  shade = shadeNew(_("blue to yellow"), vectA, vectB, vectX, shade_colorModeRGB);
  shadeSet_pathToImage(shade, "stock-blue-to-yellow.png");
  list = toolShadeListAppend(shade);

  /* Create a green to red color range. */
  vectA[0] = -.3333;
  vectA[1] = 0.;
  vectA[2] = 0.;
  vectB[0] = 0.3333;
  vectB[1] = 1.;
  vectB[2] = 1.;
  vectX[0] = TRUE;
  vectX[1] = FALSE;
  vectX[2] = FALSE;
  shade = shadeNew(_("green to red"), vectA, vectB, vectX, shade_colorModeHSV);
  shadeSet_pathToImage(shade, "stock-green-to-red.png");
  list = toolShadeListAppend(shade);

  /* Create a white to red color range. */
  vectA[0] = -.3333;
  vectA[1] = 0.8;
  vectA[2] = 0.;
  vectB[0] = 0.3333;
  vectB[1] = 0.1;
  vectB[2] = 1.;
  vectX[0] = TRUE;
  vectX[1] = TRUE;
  vectX[2] = FALSE;
  shade = shadeNew(_("light green to red"), vectA, vectB, vectX, shade_colorModeHSV);
  shadeSet_pathToImage(shade, "stock-white-to-red.png");
  list = toolShadeListAppend(shade);

  /* Create a black to white color range. */
  vectA[0] = 0.;
  vectA[1] = 0.;
  vectA[2] = 1.;
  vectB[0] = 0.;
  vectB[1] = 0.;
  vectB[2] = 0.;
  vectX[0] = FALSE;
  vectX[1] = FALSE;
  vectX[2] = TRUE;
  shade = shadeNew(_("black to white"), vectA, vectB, vectX, shade_colorModeHSV);
  shadeSet_pathToImage(shade, "stock-black-to-white.png");
  list = toolShadeListAppend(shade);

  /* Create a black to white color range. */
  vectA[0] = 0.;
  vectA[1] = 0.;
  vectA[2] = -1.;
  vectB[0] = 0.;
  vectB[1] = 0.;
  vectB[2] = 1.;
  vectX[0] = FALSE;
  vectX[1] = FALSE;
  vectX[2] = TRUE;
  shade = shadeNew(_("white to black"), vectA, vectB, vectX, shade_colorModeHSV);
  shadeSet_pathToImage(shade, "stock-white-to-black.png");
  list = toolShadeListAppend(shade);
  
  return list;
}

/*******************/
/* Color functions */
/*******************/

void colorFromUserData(VisuData *visuData, float rgba[4], VisuElement *ele, VisuNode* node)
{
  float val[3];
  int i;
  float *storedValues;

  g_return_if_fail(visuData && node && ele && rgba);

  storedValues = (float*)visuDataGet_nodeProperty(visuData, node, "dataColor_data");
  if (!storedValues)
    return;

  for (i = 0; i < 3; i++)
    if (cacheDataFile->colUsed[i] == -1)
      val[i] = 1.;
    else
      val[i] = dataFileGet_valuesFromData(visuData, cacheDataFile->colUsed[i],
					  storedValues[cacheDataFile->colUsed[i]]);

  dataFileGet_valuesTransformedInRGB(visuData, rgba, val);
  rgba[3] = ele->rgb[3];
}
