/*   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.
*/
#ifndef VISU_ELEMENTS_H
#define VISU_ELEMENTS_H

#include <glib.h>

#include "visu_tools.h"

/**
 * NMAX_TP:
 *
 * We suppose that we have at most %NMAX_TP element. If the
 * actual number of elements must be greater than %NMAX_TP then
 * one should recompile with a greater value.
 */
#define NMAX_TP 500

enum materialName
  {
    amb,
    dif,
    shi,
    spe,
    emi
  };

/* Structure to store the description of an element. */
struct Element_struct
{
  /* Name of the key used in the hashtable to find
     this element. The int variable is the number
     of this type. */
  char* name;
  /* An integer unique for each VisuElement, it is
     used as a name for the opengl material associated
     with it. */
  int typeNumber;

  /* OpenGl part */
  /* main color of the element  in [r, g, b, a] format*/
  float rgb[4];
  /* lighting effects for material in [amb, dif, shi, spe, emi] format. */
  float material[5];
  /* the identifier that stores the glObjectList that draw this VisuElement. */
  int openGLIdentifier;

  /* A flag that is TRUE when the OpenGL list of the material is up to date. */
  gboolean materialIsUpToDate;
  /* A flag to store if all nodes of this element are rendered or not.
     Its default value is TRUE. */
  gboolean rendered;

  /* 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;
};
typedef struct Element_struct VisuElement;


/**
 * initVisuElements:
 *
 * This is an initialization method, it should not be used.
 *
 * Returns: 1 if everything goes right.
 */
int initVisuElements();

/**
 * visuElementNewWithName:
 * @key: the name of the new element to create.
 *
 * Allocate a new visuElement with the specified name. Remember
 * that names must be unique since they identify the element.
 *
 * Returns: the newly created VisuElement or 0 if something goes
 * wrong in the process (if the name already exist for example).
 */
VisuElement *visuElementNewWithName(char *key);
   
/**
 * visuElementAdd:
 * @element: the element to add.
 *
 * Add a VisuElement to the hashtable of the already available elements.
 *
 * Returns : 0 if the element has been added or if it already exists.
 */
int visuElementAdd(VisuElement* element);

/**
 * VISU_ELEMENT_EMPTY_LINE
 *
 * Error code for the #visuElementGet_fromValueLine method. The given line is empty.
 */
#define VISU_ELEMENT_EMPTY_LINE 0
/**
 * VISU_ELEMENT_BAD_NAME
 *
 * Error code for the #visuElementGet_fromValueLine method. The given name contains a
 * carriage return or a nnull caracter ('\0').
 */
#define VISU_ELEMENT_BAD_NAME   1
/**
 * VISU_ELEMENT_MAX_REACHED
 *
 * Error code for the #visuElementGet_fromValueLine method. The maximum number of element
 * has been reached (#NMAX_TP) and the element one the line can't be added.
 */
#define VISU_ELEMENT_MAX_REACHED 2
/**
 * VISU_ELEMENT_CREATE_ERROR
 *
 * Error code for the #visuElementGet_fromValueLine method. The element read is
 * new but can't be created (mostly for bad allocation).
 */
#define VISU_ELEMENT_CREATE_ERROR 3
/**
 * visuElementGet_fromValueLine:
 * @line: the line to scan.
 * @sizeMax: number of characters read, at most.
 * @errorFlag: a pointer to an integer to store a identifier of error if the
 *             function return a NULL pointer (otherwise, errorFlag is not set).
 *
 * This method is a unified way to retrieve the
 * element at the beginning of line of value. It is really
 * useful when reading lines of resource file. Note that the
 * position of pointer line is modified to point to the character
 * immediatly after the last found character of an element name.
 * At most sizeMax character are read from line.
 *
 * Returns: the VisuElement structure corresponding to the
 * name read or NULL if the element is unknown or its name
 * unreadable.
 */
VisuElement* visuElementGet_fromValueLine(char **line, int sizeMax, int *errorFlag);
/**
 * visuElementPrint_errorFromValueLine:
 * @dest : an already allocated string buffer to append the message.
 * @line : the number of the line read.
 * @flag : the identifier of the error.
 *
 * This function print an error message corresponding to the @flag to the
 * string buffer desgned by @dest.
 */
void visuElementPrint_errorFromValueLine(GString *dest, int line, int flag);

/**
 * visuElementGet_allElements:
 *
 * This method returns a list of all the registered #VisuElement.
 * The returned list is read-only.
 *
 * Returns: the list of all known #VisuElement.
 */
GList* visuElementGet_allElements();
/**
 * visuElementGet_fromName:
 * @name: a string.
 *
 * This method returns the #VisuElement corresponding
 * to the given name.
 *
 * Returns: a #VisuElement or NULL.
 */
VisuElement* visuElementGet_fromName(char* name);

/**
 * visuElementSet_allColorValues:
 * @ele: the element of which the color must be changed ;
 * @rgb: the new color given by a {red, green, blue} array ;
 * @material: the new values to define the lighting.
 *
 * This method is used to set all the values that define the color
 * and the lighting of the given element.
 *
 * Returns: > 0 if visuData_createNodes() should be called and then
 *          redraw is need if the value is not null.
 */
int visuElementSet_allColorValues(VisuElement* ele, float rgb[4], float material[5]);
/**
 * visuElementSet_allRGBValues:
 * @ele: the element of which the color must be changed,
 * @rgb: the new color given by a {red, green, blue} array.
 *
 * It saves the values of rgb in the specified VisuElement.
 *
 * Returns: > 0 if visuData_createNodes() should be called and then
 *          redraw is need if the value is not null.
 */
int visuElementSet_allRGBValues(VisuElement* ele, float rgb[4]);
/**
 * visuElementSet_RGBValue:
 * @ele: the element of which the color must be changed,
 * @rgb: the component to change, 0 for red, 1 for green and 2
 * for blue,
 * @value: the value for one of the red, green or blue component.
 *
 * It saves the specific value of rgb (0 for red, 1 for green and 2
 * for bluein the specified VisuElement.
 *
 * Returns: > 0 if visuData_createNodes() should be called and then
 *          redraw is need if the value is not null.
 */
int visuElementSet_RGBValue(VisuElement* ele, int rgb, float value);
/**
 * visuElementSet_allMaterialValues:
 * @ele: the element of which the color must be changed,
 * @material: the new values to define the lighting.
 *
 * It saves the values of material in the specified VisuElement.
 *
 * Returns: > 0 if visuData_createNodes() should be called and then
 *          redraw is need if the value is not null.
 */
int visuElementSet_allMaterialValues(VisuElement* ele, float material[5]);
/**
 * visuElementSet_materialValue:
 * @ele: the element of which the color must be changed,
 * @material: the component to change,
 * @value: the new value of the specified component.
 *
 * It saves the specific value of material (use the enum as the parameter
 * material) in the specified VisuElement.
 *
 * Returns: > 0 if visuData_createNodes() should be called and then
 *          redraw is need if the value is not null.
 */
int visuElementSet_materialValue(VisuElement* ele, int material, float value);
/**
 * visuElement_createMaterial:
 * @ele: a pointer to a valid %VisuElement.
 *
 * Create a list whose number is defined by #identifierMaterials + @ele->typeNumber
 * that stores the definition of light and color for this #VisuElement. The previous
 * OpenGL object list with the same identifier is deleted.
 */
void visuElement_createMaterial(VisuElement *ele);
/**
 * visuElementGet_identifierMaterial:
 * @ele: an element.
 *
 * This method is useful for the rendering method to get the
 * OpenGl identifier of the material of the specified element.
 *
 * Returns: the OpenGL identifier of the specified VisuElement.
 */
int visuElementGet_identifierMaterial(const VisuElement *ele);
/**
 * visuElementSet_property:
 * @element: a #VisuElement object ;
 * @key: a string ;
 * @value: an allocated area to store data.
 *
 * This method is used to store some values associated with
 * the given @element. These values are anything allocated and will be
 * freed (with free()) when the @element is deleted. These values
 * are described by the @key, and can be retrieved with the
 * #visuElementGet_property() method. The @key is used by the #VisuElement
 * and should not be freed. Moreover it is not freed when the node
 * is destroyed.
 */
void visuElementSet_property(VisuElement* element, char* key, gpointer value);
/**
 * visuElementGet_property:
 * @element: a #VisuElement object ;
 * @key: a string.
 *
 * This method is used to retrieve some data associated to
 * the specified @element. These return data should not be freed after used.
 *
 * Returns: some data associated to the key.
 */
gpointer visuElementGet_property(const VisuElement* element, char* key);
/**
 * visuElementRemove_property:
 * @element: a #VisuElement object ;
 * @key: a string.
 * 
 * This method remove the data associated with the string @key.
 * They are freed.
 */
void visuElementRemove_property(VisuElement* element, char* key);

/**
 * visuElementSet_rendered:
 * @element: a #VisuElement object ;
 * @rendered: TRUE or FALSE.
 *
 * This method set the private attribute 'rendered' to TRUE or FALSE
 * for the specified #visuElement. If FALSE, all the nodes of that #VisuElement
 * are not included in the nodes OpenGL list.
 *
 * Returns: 1 if the calling method should call visuData_createNodes() for the given
 *          #VisuElement and then should emit the 'OpenGLAskForReDraw' signal.
 */
int visuElementSet_rendered(VisuElement *element, gboolean rendered);
/**
 * visuElementGet_rendered:
 * @element: a #VisuElement object.
 *
 * This gets the value of the private attribute 'rendered' for
 * the specified #VisuElement.
 *
 * Returns: the value of attribute 'rendered'.
 */
gboolean visuElementGet_rendered(VisuElement *element);
/**
 * visuElementSet_updateNodesOnMaterialChange:
 *
 * If this method is called, whenever a change occurs to a #VisuElement material
 * description (color and light) the corresponding OpenGl list of nodes of the
 * currentVisuData is rebuilt. This is usefull if the nodes can't use the list material
 * because the color is node dependant for example. Use
 * visuElementUnset_updateNodesOnMaterialChange() to return to the normal behavior.
 */
void visuElementSet_updateNodesOnMaterialChange();
/**
 * visuElementUnset_updateNodesOnMaterialChange:
 *
 * If this method is called (and no other method has used
 * visuElementSet_updateNodesOnMaterialChange(), a changement
 * in the material description only change the list of the material.
 */
void visuElementUnset_updateNodesOnMaterialChange();



/* Debug : print all informations about all the stored VisuElements. */
void debug_AllVisuElements();
/* Debug : print all informations about the specified VisuElement. */
void debug_VisuElement(gpointer key, gpointer value, gpointer data);


#endif
