/*   EXTRAITS DE LA LICENCE
	Copyright CEA, contributeurs : Luc BILLARD et Damien
	CALISTE, laboratoire L_Sim, (2001-2005)
  
	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-2005)

	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_NODES_H
#define VISU_NODES_H

#include <glib.h>
#include <glib-object.h>

#include "visu_elements.h"
#include "iface_maskable.h"

G_BEGIN_DECLS

typedef struct _VisuNode VisuNode;

struct _VisuNode
{
  /* coordinates of the node in cartesian coordinates. */
  float xyz[3];

  /* translation */
  float translation[3];

  /* Number of this element in the input file. */
  guint number;
  /* Position in the #VisuData structure. */
  guint posElement, posNode;

  /* A boolean to specify if this node is rendered or not. */
  gboolean rendered;
};

/**
 * VisuNodeProperty:
 *
 * This structure defines a storage for one property for each node of a given
 * #VisuNodeArray. Use visu_node_array_property_newPointer() or
 * visu_node_array_property_newInteger() to create one property.
 */
typedef struct _VisuNodeProperty VisuNodeProperty;

GType visu_node_get_type(void);
#define VISU_TYPE_NODE (visu_node_get_type())
void visu_node_newValues(VisuNode *node, float xyz[3]);

gboolean visu_node_setVisibility(VisuNode* node, gboolean visibility);
gboolean visu_node_getVisibility(VisuNode* node);
gboolean visu_node_setCoordinates(VisuNode* node, float xyz[3]);



/**
 * VISU_TYPE_NODE_ARRAY:
 *
 * return the type of #VisuNodeArray.
 */
#define VISU_TYPE_NODE_ARRAY	     (visu_node_array_get_type ())
G_DECLARE_DERIVABLE_TYPE(VisuNodeArray, visu_node_array, VISU, NODE_ARRAY, VisuObject)
VISU_DECLARE_CONST(VisuNodeArray, visu_node_array, VISU, NODE_ARRAY)

/**
 * VisuNodeArrayElementPropertyInit:
 * @element: a #VisuElement object ;
 * @value: a #GValue.
 *
 * Prototype of routine used to initialise an element property.
 *
 * Since: 3.7
 */
typedef void (*VisuNodeArrayElementPropertyInit)(VisuElement *element, GValue *value);

/**
 * VisuNodeArrayClass:
 * @parent: private.
 *
 * Class structure of #VisuNodeArray objects.
 */
struct _VisuNodeArrayClass
{
  VisuObjectClass parent;
};

void visu_node_array_allocate(VisuNodeArray *array,
                              GArray *elements, GArray *nNodes);
void visu_node_array_allocateByNames(VisuNodeArray *array,
                                     GArray *nNodesPerElement,
                                     GArray *elementNames);
void visu_node_array_freeNodes(VisuNodeArray *nodeArray);
void visu_node_array_allocateNodesForElement(VisuNodeArray *array, guint eleId, guint nNodes);

void visu_node_array_startAdding(VisuNodeArray *array);
void visu_node_array_completeAdding(VisuNodeArray *array);
void visu_node_array_startMoving(VisuNodeArray *array);
void visu_node_array_completeMoving(VisuNodeArray *array);

void visu_node_array_removeNodes(VisuNodeArray *nodeArray, GArray *nodeNumbers);
void visu_node_array_removeNodesOfElement(VisuNodeArray *nodeArray, VisuElement *element);
gboolean visu_node_array_removeAllDuplicateNodes(VisuNodeArray *nodeArray);

gint visu_node_array_getOriginal(VisuNodeArray *nodeArray,
                                 guint nodeId);
gboolean visu_node_array_setOriginal(VisuNodeArray *nodeArray,
                                     guint nodeId);
gboolean visu_node_array_compareElements(VisuNodeArray *data1, VisuNodeArray *data2);
VisuElement* visu_node_array_getElement(const VisuNodeArray *data, const VisuNode *node);
VisuNode* visu_node_array_setElement(VisuNodeArray *data, VisuNode *node,
                                     const VisuElement *element);
gboolean visu_node_array_containsElement(const VisuNodeArray *array,
                                         const VisuElement *element);
gint visu_node_array_getElementId(const VisuNodeArray *array, const VisuElement *element);
guint visu_node_array_getNNodes(const VisuNodeArray *array);
guint visu_node_array_getNOriginalNodes(const VisuNodeArray *array);
guint visu_node_array_getNElements(const VisuNodeArray *array, gboolean physical);
GArray* visu_node_array_setElementProperty(VisuNodeArray *data, const gchar *name,
                                           VisuNodeArrayElementPropertyInit init);
GArray* visu_node_array_getElementProperty(VisuNodeArray *data, const gchar *name);

VisuNode* visu_node_array_getNewNode(VisuNodeArray *nodeArray, const VisuElement *element);
VisuNode* visu_node_array_getNewNodeForId(VisuNodeArray *nodeArray, guint iEle);
gboolean visu_node_array_switchNumber(VisuNodeArray *nodeArray, guint from, guint to);
VisuNode* visu_node_array_copyNode(VisuNodeArray *nodeArray, VisuNode *node);
VisuNode* visu_node_array_getFromId(VisuNodeArray *array, guint number);

gboolean visu_node_array_setNodeVisibility(VisuNodeArray *nodeArray, guint id,
                                           gboolean status);
void visu_node_array_shiftNode(VisuNodeArray *array, guint id, const gfloat delta[3]);
void visu_node_array_shiftNodes(VisuNodeArray *array, const GArray *ids,
                                const float delta[3]);
void visu_node_array_moveNode(VisuNodeArray *array, guint id, const float at[3]);
void visu_node_array_moveNodes(VisuNodeArray *array, const GArray *ids,
                               const GArray *xyz);
void visu_node_array_rotateNodes(VisuNodeArray *array, const GArray *ids,
                                 const float axis[3], const float center[3],
                                 float angle);
GArray* visu_node_array_join(VisuNodeArray *array,
                             const VisuNodeArray *frag, const gfloat at[3]);


/*************************/
/* The property methods. */
/*************************/
VisuNodeProperty* visu_node_array_property_newPointer(VisuNodeArray* nodeArray,
					      const char* key, 
					      GFunc freeFunc,
					      GCopyFunc newAndCopyFunc,
					      gpointer user_data);
VisuNodeProperty* visu_node_array_property_newFloatArray(VisuNodeArray* nodeArray,
                                                         const char* key, guint len);
VisuNodeProperty* visu_node_array_property_newInteger(VisuNodeArray* nodeArray,
                                                const char* key);

void visu_node_array_freeProperty(VisuNodeArray* nodeArray, const char* key);
void visu_node_array_traceProperty(VisuNodeArray *array, const gchar *id);

VisuNodeProperty* visu_node_array_getProperty(VisuNodeArray* nodeArray, const char* key);

/**
 * visu_node_setpropertyValue:
 * @nodeArray: a #VisuNodeArray object ;
 * @node: a #VisuNode object ;
 * @key: a string ;
 * @value: A GValue pointer this the value to be stored.
 *
 * This method is used to store some values associated with
 * the given @node of the given @nodeArray. These values can be pointers to
 * anything allocated (will be free automatically when the property is deleted) or
 * they can be static values. This depends on the construction of the node property.
 * These values are described by the @key, and can be retrieved with the
 * visu_node_array_getPropertyValue() method.
 *
 * See visu_node_property_setValue() to directly set a value associated to a node.
 */
#define visu_node_setpropertyValue(nodeArray, node, key, value)	\
  visu_node_property_setValue(visu_node_array_getProperty(nodeArray, key), node, value)

void visu_node_property_setValue(VisuNodeProperty* nodeProp,
                                 const VisuNode* node, const GValue *value);
/**
 * visu_node_array_getPropertyValue:
 * @nodeArray: a #VisuNodeArray object ;
 * @node: a #VisuNode object ;
 * @key: a string ;
 * @value: an initialise GValue location.
 *
 * This method is used to retrieve some data associated to
 * the specified @node, stored in the given @data. These return data
 * should not be freed after used. The read value is stored in the given
 * GValue pointer. This GValue must be of the right type, depending on the
 * creation of the #VisuNodeProperty.
 *
 * Returns: some data associated to the key, stored the given GValue location.
 */
#define visu_node_array_getPropertyValue(nodeArray, node, key, value)		\
  visu_node_property_getValue(visu_node_array_getProperty(nodeArray, key), node, value)

GValue* visu_node_property_getValue(const VisuNodeProperty* nodeProp,
                                    const VisuNode* node,
                                    GValue *value);
VisuNodeArray* visu_node_property_getArray(const VisuNodeProperty* nodeProp);
void visu_node_property_reset(VisuNodeProperty* prop);

/* Iterators. */
/**
 * VisuNodeArrayIterType:
 * @ITER_NODES_BY_TYPE: run on nodes, as V_Sim internal storage,
 * fastest.
 * @ITER_NODES_BY_NUMBER: run on nodes as entered in the input file.
 * @ITER_NODES_FROM_LIST: run on nodes as given in a #GList.
 * @ITER_NODES_FROM_ARRAY: run on nodes as given in a #GArray.
 * @ITER_NODES_VISIBLE: run on visible nodes only (internal sort).
 * @ITER_NODES_ORIGINAL: run on original nodes only (internal sort).
 * @ITER_NODES_FOR_ELEMENT: run on all nodes of a specific element.
 * @ITER_ELEMENTS: run on elements only.
 *
 * The kind of iterator to be used on #VisuData objects.
 *
 * Since: 3.6
 */
typedef enum
  {
    ITER_NODES_BY_TYPE,
    ITER_NODES_BY_NUMBER,
    ITER_NODES_FROM_LIST,
    ITER_NODES_FROM_ARRAY,
    ITER_NODES_VISIBLE,
    ITER_NODES_ORIGINAL,
    ITER_NODES_FOR_ELEMENT,
    ITER_ELEMENTS
  } VisuNodeArrayIterType;

/**
 * VisuNodeArrayIter:
 * @array: a pointer the iterator is associated to ;
 * @idMax: current higher id used to identified nodes.
 * @nAllStoredNodes: the total number of stored nodes for the
 *                   associated #VisuData ;
 * @nElements: the number of #VisuElement for the associated #VisuData ;
 * @nStoredNodes: the number of stored nodes for the current @element ;
 * @iElement: the index corresponding to @element (or -1 if no set);
 * @node: a pointer on a current node ;
 * @element: a pointer on a current element.
 * @type: the kind of iterator, see #VisuNodeArrayIterType.
 * @init: an internal flag.
 * @itLst: an internal list iterator.
 * @arr: an iternal list of nodes to iterate on.
 * @itArr: an internal iterator on array.
 *
 * This structure is an iterator over the nodes of a #VisuData object.
 * Create it with visu_node_array_iter_new(). Then the numbers are allocated and
 * correspond to the value of the #VisuData object. Use visu_node_array_iterStart()
 * to initialise the iterator for a run over the nodes, visu_node_array_iterNext()
 * to associate @node and @element to the next node, or NULL if there is no
 * more node to run over.
 */
typedef struct _VisuNodeArrayIter VisuNodeArrayIter;
struct _VisuNodeArrayIter
{
  VisuNodeArray *array;

  guint idMax;
  guint nAllStoredNodes;
  guint nElements;


  guint iElement;
  guint nStoredNodes;
  VisuNode *node;
  VisuElement *element;

  VisuNodeArrayIterType type;
  gboolean init;
  GList *itLst;
  GArray *arr;
  guint itArr;
};

/**
 * VisuNodeArrayIterFunc:
 * @array: (transfer full): the #VisuNodeArray object the function deals with.
 * @iter: the #VisuNodeArrayIter object the function works on.
 * @data: (closure): some user data.
 *
 * Prototype of function that evaluates a boolean condition on a given
 * node in a node iteration.
 *
 * Since: 3.8
 */
typedef gboolean (*VisuNodeArrayIterFunc)(VisuNodeArray *array,
                                          const VisuNodeArrayIter *iter,
                                          gpointer data);

void visu_node_array_iter_new(VisuNodeArray *array, VisuNodeArrayIter *iter);

void visu_node_array_iterStart(VisuNodeArray *array, VisuNodeArrayIter *iter);
void visu_node_array_iterStartVisible(VisuNodeArray *array, VisuNodeArrayIter *iter);
void visu_node_array_iterStartNumber(VisuNodeArray *array, VisuNodeArrayIter *iter);
void visu_node_array_iterStartList(VisuNodeArray *array, VisuNodeArrayIter *iter, GList *lst);
void visu_node_array_iterStartArray(VisuNodeArray *array, VisuNodeArrayIter *iter, GArray *arr);
void visu_node_array_iterRestartNode(VisuNodeArray *array, VisuNodeArrayIter *iter);
void visu_node_array_iterWhere(VisuNodeArray *array, VisuNodeArrayIter *iter,
                               VisuNodeArrayIterFunc where, gpointer data);

void visu_node_array_iterNext(VisuNodeArray *array, VisuNodeArrayIter *iter);
void visu_node_array_iterNextNode(VisuNodeArray *array, VisuNodeArrayIter *iter);
void visu_node_array_iterNextNodeNumber(VisuNodeArray *array, VisuNodeArrayIter *iter);
void visu_node_array_iterNextNodeOriginal(VisuNodeArray *array, VisuNodeArrayIter *iter);
void visu_node_array_iterNextList(VisuNodeArray *array, VisuNodeArrayIter *iter);
void visu_node_array_iterNextArray(VisuNodeArray *array, VisuNodeArrayIter *iter);
void visu_node_array_iterNextElement(VisuNodeArray *array, VisuNodeArrayIter *iter,
                                     gboolean allowEmpty);
void visu_node_array_iterNextVisible(VisuNodeArray *array, VisuNodeArrayIter *iter);

gboolean visu_node_array_iter_next(VisuNodeArrayIter *iter);
gboolean visu_node_array_iter_next2(VisuNodeArrayIter *iter1, VisuNodeArrayIter *iter2);

G_END_DECLS

#endif
