/*   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.
*/
#include "visu_nodes.h"

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

#include "visu_tools.h"
#include "coreTools/toolMatrix.h"

/**
 * SECTION:visu_nodes
 * @short_description: Defines the elementary structure to store
 * informations about an element in a box.
 *
 * <para>In V_Sim, elements are drawn in a box. The #VisuNode
 * structure is used to represent an instance of an element position
 * somewhere in the box. This element can have several characteristics
 * such as its translation or its visibility.</para>
 *
 * <para>All nodes are stored in a #VisuData object in a two
 * dimensional array. The first dimension is indexed by the
 * #VisuElement of the node and the second corresponds to the number
 * of this node for this element. When a node is own by a #VisuData,
 * the two integers, that control the indexes in this array, are not
 * negative. See the #VisuNode structure for further
 * explanations.</para>
 *
 * <para>The only basic informations own by the #VisuNode structure is
 * basicaly its position. To add further informations (such as
 * orientation for the spin), define a node property using
 * visu_node_array_property_newPointer().</para>
 */

/**
 * VisuNode:
 * @xyz: (in) (array fixed-size=3): an array of three floating point values that positions the node in (x, y, z) ;
 * @translation: (in) (array fixed-size=3): an array of three floating point values that translates the
 *               node to its drawn position from (x, y, z) ;
 * @number: an integer that corresponds to its position in the entry file, it references
 *          also the node itself in the array 'fromNumberToVisuNode' of the #VisuData
 *          that contains the node ;
 * @posElement: an integer that is the position of the #VisuElement of the node
 *              in the array 'fromIntToVisuElement' of the #VisuData object that
 *              contains the node ;
 * @posNode: an integer that is the position of the node itself in the array
 *           'nodes' of the #VisuData object that contains the node ;
 * @rendered: a boolean to store if the node is drwn or not.
 *
 * Structure to store primary data of a node.
 */

/* Local routines. */
static void freeNodePropStruct(gpointer data);
static void removeNodeProperty(gpointer key, gpointer value, gpointer data);
static void removeNodePropertyForElement(gpointer key, gpointer value, gpointer data);
static void reallocNodeProperty(gpointer key, gpointer value, gpointer data);
static void allocateNodeProp(gpointer key, gpointer value, gpointer data);
static void createNodeproperty(gpointer key, gpointer value, gpointer data);
static VisuNode* newOrCopyNode(VisuNodeArray *nodeArray, int iEle, int oldNodeId);
static void freeElePropStruct(gpointer data);

/* The number of nodes to be reallocated each time the visu_node_array_getNewNode()
   is called. */
#define REALLOCATION_STEP 100

/* The key of the original node property. */
#define ORIGINAL_ID       "originalId"

struct twoNodes
{
  VisuNode *oldNode;
  VisuNode *newNode;
};

typedef struct _VisuNodeArrayPrivate VisuNodeArrayPrivate;
struct _VisuNodeProperty
{
  /* A label to define the property. */
  gchar *name;

  /* A pointer to the array of nodes these properties are related to. */
  VisuNodeArray *array;

  /* The type of the property. */
  GType gtype;

  /* This table has the same size and structure
     than the node array object it is related to.
     Only one of the following data array is allocated. */
  gpointer **data_pointer;
  int **data_int;

  /* In the case of pointer data, one can give the new, copy and free routine. */
  /* This method is called for each stored token,
     if not NULL when the table is freed. */
  GFunc freeTokenFunc;
  /* This method is used to create/copy a token of the data array. */
  GCopyFunc newOrCopyTokenFunc;
  /* This value stores a pointer on a user data given when
     the object is created. This pointer is given to the copy
     or the free function. */
  gpointer user_data;
};
struct _ElementProperty
{
  VisuNodeArrayElementPropertyInit init;
  GArray *array;
};

/* static gpointer node_copy(gpointer boxed) */
/* { */
/*   VisuNode *node; */

/*   node = g_malloc(sizeof(VisuNode)); */
/*   DBG_fprintf(stderr, "Visu Node: copying node %p to %p.\n", boxed, (gpointer)node); */
/*   *node = *(VisuNode*)boxed; */

/*   return (gpointer)node; */
/* } */
static gpointer node_no_copy(gpointer boxed)
{
  return boxed;
}
static void node_no_free(gpointer boxed _U_)
{
}
GType visu_node_get_type(void)
{
  static GType g_define_type_id = 0;

  if (g_define_type_id == 0)
    g_define_type_id = g_boxed_type_register_static("VisuNode", node_no_copy, node_no_free);
  return g_define_type_id;
}

/**
 * visu_node_setCoordinates:
 * @node: a #VisuNode object ;
 * @xyz: (array fixed-size=3): new cartesian coordinates.
 *
 * This method is used to change coordinates of @node.
 *
 * Since: 3.7
 *
 * Returns: TRUE if the calling method should emit
 * #VisuNodeArray::position-changed signal.
 */
gboolean visu_node_setCoordinates(VisuNode* node, float xyz[3])
{
  g_return_val_if_fail(node, FALSE);

  if (node->xyz[0] == xyz[0] && node->xyz[1] == xyz[1] && node->xyz[2] == xyz[2])
    return FALSE;
  node->xyz[0] = xyz[0];
  node->xyz[1] = xyz[1];
  node->xyz[2] = xyz[2];
  return TRUE;
}

/**
 * visu_node_setVisibility:
 * @node: a #VisuNode object ;
 * @visibility: a boolean.
 *
 * This method is used to turn on or off the drawing of the specified node.
 *
 * Returns: %TRUE if the visibility has changed.
 */
gboolean visu_node_setVisibility(VisuNode* node, gboolean visibility)
{
  g_return_val_if_fail(node, FALSE);

  if (node->rendered == visibility)
    return FALSE;
  node->rendered = visibility;
  return TRUE;
}

/**
 * visu_node_getVisibility:
 * @node: a #VisuNode object.
 *
 * This method is used get the status of the drawing state of a node.
 *
 * Returns: true if the node is rendered, false otherwise.
 */
gboolean visu_node_getVisibility(VisuNode* node)
{
  g_return_val_if_fail(node, FALSE);

  return node->rendered;
}

/**
 * visu_node_newValues:
 * @node: an allocated #VisuNode object ;
 * @xyz: (in) (array fixed-size=3): the coordinates to set.
 * 
 * Set the coordinates and set all other values to default.
 */
void visu_node_newValues(VisuNode *node, float xyz[3])
{
  g_return_if_fail(node);

  DBG_fprintf(stderr, "Visu Node: set new position for node %d (%g;%g;%g).\n",
              node->number, xyz[0], xyz[1], xyz[2]);
  node->xyz[0]         = xyz[0];
  node->xyz[1]         = xyz[1];
  node->xyz[2]         = xyz[2];
  node->translation[0] = 0.;
  node->translation[1] = 0.;
  node->translation[2] = 0.;
  node->rendered       = TRUE;
}


/***************/
/* Node Arrays */
/***************/

typedef struct _eleArr
{
  VisuElement *ele;
  /* Listeners on VisuElement signals. */
  gulong rendered, maskable;
  /* Number of nodes allocated (size of the nodes array) and number of
     nodes physically present in the array for this element. */
  guint nNodes, nStoredNodes;
  /* Allocated space for nodes of this element. */
  VisuNode *nodes;
} EleArr;

typedef struct _nodeTable
{
  /* A counter. */
  guint idCounter;
  /* This array gives access to the good VisuNode
     when one has its number. This number is an integer ranging in
     [0;idCounter[. This value is readable in the #VisuNode structure
     as the number attribute. The current allocated size is stored in
     @nNodes. */
  /* GArray *array. */
  VisuNode **array;
  /* The total of allocated VisuNodes. */
  guint nNodes;
  /* The total of stored VisuNodes. */
  guint nStoredNodes;

  GArray *popIncIds, *posChgIds;
} NodeTable;

/* Local methods. */
static void onElementRenderChanged(VisuNodeArray *data, GParamSpec *pspec, VisuElement *element);
static void onElementPlaneChanged(VisuNodeArray *data, GParamSpec *pspec, VisuElement *element);
static void _freeNodes(VisuNodeArray *nodeArray);
#define _getEleArr(priv, i) (&g_array_index(priv->elements, EleArr, i))
#define _getElement(priv, i) _getEleArr(priv, i)->ele
static void allocateEleProp(gpointer key, gpointer value, gpointer data);
/* static void freeEleProp(gpointer key, gpointer value, gpointer data); */

/**
 * VisuNodeArray:
 *
 * Opaque structure representing array of nodes object.
 */
struct _VisuNodeArrayPrivate
{
  gboolean dispose_has_run;

  /****************/
  /* The elements */
  /****************/
  /* Stores for each element some related informations (see EleArr). */
  GArray *elements;

  /*************/
  /* The nodes */
  /*************/
  NodeTable nodeTable;

  /***********************/
  /* The property arrays */
  /***********************/
  /* Properties of elements. */
  GHashTable *eleProp;
  /* This is a table to store data, reachable with string keys.
     It should be accessed via visu_node_setproperty()
     and visu_node_array_getProperty(). */
  GHashTable *nodeProp;

  /* A convenient pointer on the original node property. */
  VisuNodeProperty *origProp;
  /* Total of original nodes. */
  guint nOrigNodes;
};

enum {
  POPULATION_INCREASE_SIGNAL,
  POPULATION_DECREASE_SIGNAL,
  POSITION_CHANGED_SIGNAL,
  ELEMENT_VISIBILITY_CHANGED_SIGNAL,
  ELEMENT_PLANE_CHANGED_SIGNAL,
  LAST_SIGNAL
};
static guint visu_node_array_signals[LAST_SIGNAL] = { 0 };

enum
  {
    PROP_0,
    NNODES_PROP,
    NORIGS_PROP,
    ELES_PROP,
    N_PROP
  };
static GParamSpec *properties[N_PROP];

static void visu_node_array_dispose     (GObject* obj);
static void visu_node_array_finalize    (GObject* obj);
static void visu_node_array_get_property(GObject* obj, guint property_id,
                                         GValue *value, GParamSpec *pspec);
static void visu_maskable_interface_init(VisuMaskableInterface *iface);

G_DEFINE_TYPE_WITH_CODE(VisuNodeArray, visu_node_array, VISU_TYPE_OBJECT,
                        G_ADD_PRIVATE(VisuNodeArray)
                        G_IMPLEMENT_INTERFACE(VISU_TYPE_MASKABLE,
                                              visu_maskable_interface_init))

static gboolean _resetVisibility(VisuMaskable *self);
static GArray* _getMasked(const VisuMaskable *self);

static void visu_node_array_class_init(VisuNodeArrayClass *klass)
{
  DBG_fprintf(stderr, "Visu NodeArray: creating the class of the object.\n");

  /* Connect the overloading methods. */
  G_OBJECT_CLASS(klass)->dispose  = visu_node_array_dispose;
  G_OBJECT_CLASS(klass)->finalize = visu_node_array_finalize;
  G_OBJECT_CLASS(klass)->get_property = visu_node_array_get_property;

  DBG_fprintf(stderr, "                - adding new signals ;\n");
  /**
   * VisuNodeArray::PopulationDecrease:
   * @nodes: the object which received the signal ;
   * @ids: (element-type guint) (array): an array of #VisuNode ids.
   *
   * Gets emitted when the number of nodes has changed,
   * decreasing. @ids contains all removed ids.
   * When emitted, nodes have already been removed, so no external
   * routines should keep pointers on these nodes.
   *
   * Since: 3.4
   */
  visu_node_array_signals[POPULATION_DECREASE_SIGNAL] =
    g_signal_new("PopulationDecrease", G_TYPE_FROM_CLASS (klass),
                 G_SIGNAL_RUN_LAST | G_SIGNAL_NO_RECURSE | G_SIGNAL_NO_HOOKS,
                 0, NULL, NULL, g_cclosure_marshal_VOID__BOXED,
                 G_TYPE_NONE, 1, G_TYPE_ARRAY);
  /**
   * VisuNodeArray::PopulationIncrease:
   * @nodes: the object which received the signal ;
   * @ids: (element-type guint) (array): an array of #VisuNode ids.
   *
   * Gets emitted when the number of nodes has changed,
   * increasing. @ids contains all new ids.
   *
   * Since: 3.4
   */
  visu_node_array_signals[POPULATION_INCREASE_SIGNAL] =
    g_signal_new("PopulationIncrease", G_TYPE_FROM_CLASS (klass),
                 G_SIGNAL_RUN_LAST | G_SIGNAL_NO_RECURSE | G_SIGNAL_NO_HOOKS,
                 0, NULL, NULL, g_cclosure_marshal_VOID__BOXED,
                 G_TYPE_NONE, 1, G_TYPE_ARRAY);
  /**
   * VisuNodeArray::position-changed:
   * @nodes: the object which received the signal ;
   * @ids: (allow-none) (element-type guint): ids of moved nodes.
   *
   * Gets emitted when one or more nodes have moved, because of
   * translations or because the user has moved them manually.
   *
   * Since: 3.2
   */
  visu_node_array_signals[POSITION_CHANGED_SIGNAL] =
    g_signal_new("position-changed", G_TYPE_FROM_CLASS (klass),
                 G_SIGNAL_RUN_LAST | G_SIGNAL_NO_RECURSE | G_SIGNAL_NO_HOOKS,
                 0, NULL, NULL, g_cclosure_marshal_VOID__BOXED,
                 G_TYPE_NONE, 1, G_TYPE_ARRAY, NULL);

  /**
   * VisuNodeArray::ElementVisibilityChanged:
   * @nodes: the object which received the signal ;
   * @ele: the #VisuElement that has its visibility changed
   *
   * Gets emitted when the visibility characteristic of one element changes.
   *
   * Since: 3.8
   */
  visu_node_array_signals[ELEMENT_VISIBILITY_CHANGED_SIGNAL] =
    g_signal_new("ElementVisibilityChanged", G_TYPE_FROM_CLASS(klass),
                 G_SIGNAL_RUN_LAST | G_SIGNAL_NO_RECURSE | G_SIGNAL_NO_HOOKS,
                 0, NULL, NULL, g_cclosure_marshal_VOID__OBJECT,
                 G_TYPE_NONE, 1, VISU_TYPE_ELEMENT, NULL);
  /**
   * VisuNodeArray::ElementMaskableChanged:
   * @nodes: the object which received the signal ;
   * @ele: the #VisuElement that has its visibility changed
   *
   * Gets emitted when the maskable characteristic of one element changes.
   *
   * Since: 3.8
   */
  visu_node_array_signals[ELEMENT_PLANE_CHANGED_SIGNAL] =
    g_signal_new("ElementMaskableChanged", G_TYPE_FROM_CLASS(klass),
                 G_SIGNAL_RUN_LAST | G_SIGNAL_NO_RECURSE | G_SIGNAL_NO_HOOKS,
                 0, NULL, NULL, g_cclosure_marshal_VOID__OBJECT,
                 G_TYPE_NONE, 1, VISU_TYPE_ELEMENT, NULL);

  /**
   * VisuNodeArray::n-nodes:
   *
   * Total number of nodes.
   *
   * Since: 3.8
   */
  properties[NNODES_PROP] = g_param_spec_uint("n-nodes", "# nodes", "total number of nodes",
                                              0, G_MAXUINT, 0, G_PARAM_READABLE);
  /**
   * VisuNodeArray::n-original-nodes:
   *
   * Total number of original nodes.
   *
   * Since: 3.8
   */
  properties[NORIGS_PROP] = g_param_spec_uint("n-original-nodes", "# original nodes",
                                              "total number of original nodes",
                                              0, G_MAXUINT, 0, G_PARAM_READABLE);
  /**
   * VisuNodeArray::elements:
   *
   * An array with the elements.
   *
   * Since: 3.8
   */
  properties[ELES_PROP] = g_param_spec_boxed("elements", "Elements", "all elements",
                                             G_TYPE_ARRAY, G_PARAM_READABLE);

  g_object_class_install_properties(G_OBJECT_CLASS(klass), N_PROP, properties);

  /* Create the boxed type of nodes. */
  visu_node_get_type();
}
static void visu_maskable_interface_init(VisuMaskableInterface *iface)
{
  iface->reset_visibility = _resetVisibility;
  iface->get_masked = _getMasked;
}

static void visu_node_array_init(VisuNodeArray *array)
{
  VisuNodeArrayPrivate *priv = visu_node_array_get_instance_private(array);
  DBG_fprintf(stderr, "Visu NodeArray: initializing a new object (%p).\n",
	      (gpointer)array);

  priv->dispose_has_run = FALSE;

  priv->elements      = g_array_new(FALSE, FALSE, sizeof(EleArr));

  priv->nodeTable.idCounter    = 0;
  priv->nodeTable.nNodes       = 0;
  priv->nodeTable.nStoredNodes = 0;
  priv->nodeTable.array        = (VisuNode**)0;
  priv->nodeTable.popIncIds    = (GArray*)0;
  priv->nodeTable.posChgIds    = (GArray*)0;

  priv->eleProp       = g_hash_table_new_full(g_str_hash, g_str_equal,
                                              NULL, freeElePropStruct);
  priv->nodeProp      = g_hash_table_new_full(g_str_hash, g_str_equal,
                                              NULL, freeNodePropStruct);

  /* We add a node property that is > 0 if the node is a duplicate
     node and negative if not. The value is the node id that the
     duplicate refers to. */
  DBG_fprintf(stderr, " | create the original node property.\n");
  priv->origProp = visu_node_array_property_newInteger(array, ORIGINAL_ID);
  priv->nOrigNodes = 0;
}

/* This method can be called several times.
   It should unref all of its reference to
   GObjects. */
static void visu_node_array_dispose(GObject* obj)
{
  VisuNodeArrayPrivate *priv = visu_node_array_get_instance_private(VISU_NODE_ARRAY(obj));
  guint i;
  EleArr *ele;

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

  g_return_if_fail(priv);
  if (priv->dispose_has_run)
    return;
  priv->dispose_has_run = TRUE;

  for (i = 0; i < priv->elements->len; i++)
    {
      ele = _getEleArr(priv, i);
      g_signal_handler_disconnect(ele->ele, ele->rendered);
      g_signal_handler_disconnect(ele->ele, ele->maskable);
      g_object_unref(ele->ele);
    }

  /* Chain up to the parent class */
  G_OBJECT_CLASS(visu_node_array_parent_class)->dispose(obj);
}
/* This method is called once only. */
static void visu_node_array_finalize(GObject* obj)
{
  VisuNodeArrayPrivate *priv = visu_node_array_get_instance_private(VISU_NODE_ARRAY(obj));

  g_return_if_fail(priv);

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

  /* We first remove the properties, before the node description because
     these descriptions may be relevant. */
  if (priv->nodeProp)
    g_hash_table_destroy(priv->nodeProp);
  if (priv->eleProp)
    g_hash_table_destroy(priv->eleProp);
  _freeNodes(VISU_NODE_ARRAY(obj));
  g_array_free(priv->elements, TRUE);

  /* Chain up to the parent class */
  DBG_fprintf(stderr, "Visu NodeArray: chain to parent.\n");
  G_OBJECT_CLASS(visu_node_array_parent_class)->finalize(obj);
  DBG_fprintf(stderr, "Visu NodeArray: freeing ... OK.\n");
}
static void visu_node_array_get_property(GObject* obj, guint property_id,
                                         GValue *value, GParamSpec *pspec)
{
  VisuNodeArrayPrivate *priv = visu_node_array_get_instance_private(VISU_NODE_ARRAY(obj));
  GArray *eles;
  guint i;
  EleArr *arr;

  DBG_fprintf(stderr, "Visu NodeArray: get property '%s' -> ",
	      g_param_spec_get_name(pspec));
  switch (property_id)
    {
    case NNODES_PROP:
      g_value_set_uint(value, priv->nodeTable.nStoredNodes);
      DBG_fprintf(stderr, "%d.\n", priv->nodeTable.nStoredNodes);
      break;
    case NORIGS_PROP:
      g_value_set_uint(value, priv->nOrigNodes);
      DBG_fprintf(stderr, "%d.\n", priv->nOrigNodes);
      break;
    case ELES_PROP:
      eles = g_array_sized_new(FALSE, FALSE, sizeof(VisuElement*),
                               priv->elements->len);
      for (i = 0; i < priv->elements->len; i++)
        {
          arr = _getEleArr(priv, i);
          g_array_append_val(eles, arr->ele);
        }
      g_value_take_boxed(value, eles);
      DBG_fprintf(stderr, "%p.\n", g_value_get_boxed(value));
      break;
    default:
      /* We don't have any other property... */
      G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, property_id, pspec);
      break;
    }
}

#if DEBUG == 1
static void _checkNodeTable(NodeTable *table)
{
  guint j;

  for (j = 0; j < table->idCounter; j++)
    if (table->array[j] && table->array[j]->number != j)
      g_warning("inconsistency on node number %d.", j);
}
#endif
static gboolean _validNodeTableId(NodeTable *table, guint id)
{
  g_return_val_if_fail(table, FALSE);

  return id < table->idCounter;
}
static void _increaseNodeTable(NodeTable *table, guint delta)
{
  table->nNodes += delta;
  table->array = g_realloc(table->array, sizeof(VisuNode*) * table->nNodes);
  memset(table->array + table->nNodes - delta, '\0', sizeof(VisuNode*) * delta);
}
static void _compactNodeTable(NodeTable *table)
{
  DBG_fprintf(stderr, "Visu NodeArray: compaction required (%d %d).\n",
              table->idCounter, table->nNodes);
  g_return_if_fail(table && table->idCounter <= table->nNodes);

  /* We get the last non NULL node pointer in the array array to make the
     idCounter having this value to avoid to much reallocation of the array
     array. */
  for (; table->idCounter > 0 && !table->array[table->idCounter - 1];
       table->idCounter -= 1);
  DBG_fprintf(stderr, "Visu NodeArray: idCounter is set to %d.\n", table->idCounter);
}
static VisuNode* _getFromId(NodeTable *table, guint number)
{
  g_return_val_if_fail(table && number < table->nNodes, (VisuNode*)0);

  return table->array[number];
}
static void _setAtId(NodeTable *table, guint number, VisuNode *node)
{
  g_return_if_fail(table && number < table->nNodes);

  if (node && !table->array[number])
    table->nStoredNodes += 1;
  else if (!node && table->array[number])
    table->nStoredNodes -= 1;
  table->array[number] = node;
}
static void _addNodeTable(NodeTable *table, VisuNode *node)
{
  g_return_if_fail(table && node);

  if (table->idCounter == table->nNodes)
    _increaseNodeTable(table, REALLOCATION_STEP);

  node->number = table->idCounter;
  _setAtId(table, node->number, node);
  table->idCounter += 1;
}

/**
 * visu_node_array_allocate:
 * @array: a #VisuNodeArray object.
 * @elements: (in) (element-type VisuElement*):the size of nNodes.
 * @nNodes: (in) (element-type guint): an array giving the number of nodes per element.
 *
 * Reallocate the internal arrays to match @elements and @nNodes.
 */
void visu_node_array_allocate(VisuNodeArray *array,
                              GArray *elements, GArray *nNodes)
{
  guint i, j;
  EleArr ele;
  VisuElement *element;
  VisuNodeArrayPrivate *priv = visu_node_array_get_instance_private(array);

  g_return_if_fail(priv);
  g_return_if_fail(nNodes && nNodes->len > 0);
  g_return_if_fail(elements && elements->len > 0);
  g_return_if_fail(nNodes->len == elements->len);

  DBG_fprintf(stderr, "Visu NodeArray: allocating VisuElement data (+%d elements).\n",
              elements->len);

  for(i = 0; i < elements->len; i++)
    {
      element = g_array_index(elements, VisuElement*, i);
      if (visu_node_array_getElementId(array, element) < 0)
        {
          /* Create new element. */
          ele.ele = g_object_ref(element);
          ele.rendered =
            g_signal_connect_swapped(G_OBJECT(element), "notify::rendered",
                                     G_CALLBACK(onElementRenderChanged), array);
          ele.maskable =
            g_signal_connect_swapped(G_OBJECT(element), "notify::maskable",
                                     G_CALLBACK(onElementPlaneChanged), array);
          ele.nNodes = g_array_index(nNodes, guint, i);
          ele.nStoredNodes = 0;
          ele.nodes = g_malloc(sizeof(VisuNode) * ele.nNodes);
          for (j = 0; j < ele.nNodes; j++)
            {
              ele.nodes[j].posElement = priv->elements->len;
              ele.nodes[j].posNode    = j;
            }

          priv->elements = g_array_append_val(priv->elements, ele);

          /* Increase the node table. */
          _increaseNodeTable(&priv->nodeTable, ele.nNodes);

          /* Expand element properties for new element. */
          g_hash_table_foreach(priv->eleProp, allocateEleProp, (gpointer)ele.ele);
          /* Expand node properties for new element. */
          g_hash_table_foreach(priv->nodeProp, allocateNodeProp, (gpointer)0);

          DBG_fprintf(stderr, " | add VisuElement '%p' -> '%s' (%ld) at %p.\n",
                      (gpointer)element, element->name, ele.rendered,
                      (gpointer)_getEleArr(priv, priv->elements->len - 1));
          DBG_fprintf(stderr, " | %d nodes allocated.\n", ele.nNodes);
        }
      else
        /* Reallocate existing element. */
        visu_node_array_allocateNodesForElement(array, i, g_array_index(nNodes, guint, i));
    }
  DBG_fprintf(stderr, " | has now %d elements.\n", priv->elements->len);
  DBG_fprintf(stderr, " | total number of allocated nodes %d.\n",
	      priv->nodeTable.nNodes);

  DBG_fprintf(stderr, " | size = %do\n",
	      (int)(priv->elements->len * sizeof(EleArr) + sizeof(GArray) +
                    sizeof(VisuNode) * priv->nodeTable.nNodes +
		    sizeof(VisuNode*) * priv->nodeTable.nNodes + sizeof(VisuNodeArray)));

  g_object_notify_by_pspec(G_OBJECT(array), properties[ELES_PROP]);
}
/**
 * visu_node_array_allocateByNames:
 * @array: a #VisuNodeArray object;
 * @nNodesPerElement: (in) (element-type guint): number of #VisuNode per VisuElement;
 * @elementNames: (in) (element-type utf8): names of elements;
 *
 * This method allocates the storing part of the given #VisuNodeArray structure and
 * store all the #VisuNodes.
 */
void visu_node_array_allocateByNames(VisuNodeArray *array,
                                     GArray *nNodesPerElement,
                                     GArray *elementNames)
{
  GArray *elements;
  guint i;
  VisuElement *ele;

  DBG_fprintf(stderr, "Visu NodeArray: allocating %p from names.\n", (gpointer)array);

  elements = g_array_sized_new(FALSE, FALSE, sizeof(VisuElement*), elementNames->len);
  for (i = 0; i < elementNames->len; i++)
    {
      ele = visu_element_retrieveFromName(g_array_index(elementNames, gchar*, i),
                                          (gboolean*)0);
      g_array_append_val(elements, ele);
    }
  visu_node_array_allocate(array, elements, nNodesPerElement);
  g_array_free(elements, TRUE);
}
static void _freeNodes(VisuNodeArray *nodeArray)
{
  guint i;
  EleArr *ele;
  VisuNodeArrayPrivate *priv = visu_node_array_get_instance_private(nodeArray);

  DBG_fprintf(stderr, "Visu NodeArray: free storages of %p.\n", (gpointer)nodeArray);

  g_return_if_fail(priv);
  if (priv->elements)
    {
      for (i = 0; i < priv->elements->len; i++)
        {
          ele = _getEleArr(priv, i);
          if (!priv->dispose_has_run)
            {
              g_signal_handler_disconnect(G_OBJECT(ele->ele), ele->rendered);
              g_signal_handler_disconnect(G_OBJECT(ele->ele), ele->maskable);
              g_object_unref(ele->ele);
            }
          g_free(ele->nodes);
        }
      g_array_set_size(priv->elements, 0);
    }

  g_free(priv->nodeTable.array);
  if (priv->nodeTable.popIncIds)
    g_array_unref(priv->nodeTable.popIncIds);
  if (priv->nodeTable.posChgIds)
    g_array_unref(priv->nodeTable.posChgIds);
  priv->nodeTable.array = (VisuNode**)0;
  priv->nodeTable.idCounter      = 0;
  priv->nodeTable.nNodes         = 0;
  priv->nodeTable.nStoredNodes   = 0;
  priv->nodeTable.popIncIds      = (GArray*)0;
  priv->nodeTable.posChgIds      = (GArray*)0;
  DBG_fprintf(stderr, "Visu NodeArray: freeing node array ... OK.\n");
}

/**
 * visu_node_array_freeNodes:
 * @nodeArray: a #VisuNodeArray object.
 *
 * Deallocate all nodes of the object and related properties but keep
 * the object alive.
 **/
void visu_node_array_freeNodes(VisuNodeArray *nodeArray)
{
  guint i;
  VisuNodeArrayPrivate *priv = visu_node_array_get_instance_private(nodeArray);

  /* We first remove the properties, before the node description because
     these descriptions may be relevant. */
  g_return_if_fail(priv);
  if (priv->nodeProp)
    for (i = 0; i < priv->elements->len; i++)
      g_hash_table_foreach(priv->nodeProp,
                           removeNodePropertyForElement, GINT_TO_POINTER(i));
  if (priv->eleProp)
    g_hash_table_remove_all(priv->eleProp);

  _freeNodes(nodeArray);
  g_object_notify_by_pspec(G_OBJECT(nodeArray), properties[NNODES_PROP]);
  g_object_notify_by_pspec(G_OBJECT(nodeArray), properties[ELES_PROP]);

  priv->origProp = visu_node_array_property_newInteger(nodeArray, ORIGINAL_ID);
  priv->nOrigNodes = 0;
}

/**
 * visu_node_array_removeNodes:
 * @nodeArray: a #VisuNodeArray object.
 * @nodeNumbers: (element-type guint): an array of integers (negative terminated).
 *
 * Remove the given #VisuNode from the @nodeArray. The properties
 * are also updated.
 */
void visu_node_array_removeNodes(VisuNodeArray *nodeArray, GArray *nodeNumbers)
{
  VisuNode *node;
  guint i, iEle, iNode, number;
  EleArr *ele;
  VisuNodeArrayPrivate *priv = visu_node_array_get_instance_private(nodeArray);

  g_return_if_fail(priv && nodeNumbers);

  if (nodeNumbers->len == 0)
    return;

  /* For each element in the given node array, we take the last node
     of the same element and it takes it position. */
  DBG_fprintf(stderr, "Visu Node: removing nodes from array %p (%d).\n",
	      (gpointer)nodeArray, nodeNumbers->len);
  for (i = 0; i < nodeNumbers->len; i++)
    {
      number = g_array_index(nodeNumbers, guint, i);
      node = _getFromId(&priv->nodeTable, number);
      if (!node)
        continue;
      g_return_if_fail(node->number == number);

      iEle  = node->posElement;
      iNode = node->posNode;

      ele = _getEleArr(priv, iEle);
      ele->nStoredNodes -= 1;
      if (priv->origProp->data_int[iEle][iNode] < 0)
        priv->nOrigNodes -= 1;

      if (ele->nStoredNodes > 0)
	{
	  /* First, we copy the properties following the same scheme,
	     the last node of the given element is copy instead of
	     the given one. */
	  g_hash_table_foreach(priv->nodeProp, removeNodeProperty,
                               ele->nodes + iNode);

	  /* Then, we copy the node values themselves. */
          ele->nodes[iNode] = ele->nodes[ele->nStoredNodes];
	  /* We update the index values. */
	  ele->nodes[iNode].posNode = iNode;
	  ele->nodes[iNode].number  = ele->nodes[ele->nStoredNodes].number;
          _setAtId(&priv->nodeTable, ele->nodes[iNode].number, ele->nodes + iNode);
	}
      /* Nullify the removed node. */
      _setAtId(&priv->nodeTable, number, (VisuNode*)0);

      DBG_fprintf(stderr, "Visu NodeArray: %d removed, population for element %d is now:",
                  number, iEle);
      DBG_fprintf(stderr, " %d/%d # %d/%d\n", priv->nodeTable.nStoredNodes,
		  priv->nodeTable.nNodes, ele->nStoredNodes, ele->nNodes);
    }
  _compactNodeTable(&priv->nodeTable);
  DBG_fprintf(stderr, " | size = %do\n",
	      (int)(priv->elements->len * sizeof(EleArr) + sizeof(GArray) +
                    sizeof(VisuNode) * priv->nodeTable.nNodes +
		    sizeof(VisuNode*) * priv->nodeTable.nNodes +
                    sizeof(VisuNodeArray)));

  DBG_fprintf(stderr, "Visu NodeArray: emit a 'NodePopulationDecrease' signal.\n");
  g_object_notify_by_pspec(G_OBJECT(nodeArray), properties[NNODES_PROP]);
  g_signal_emit(G_OBJECT(nodeArray), visu_node_array_signals[POPULATION_DECREASE_SIGNAL],
		0, (gpointer)nodeNumbers, NULL);
}

/**
 * visu_node_array_removeNodesOfElement:
 * @nodeArray: a #VisuNodeArray object.
 * @element: a #VisuElement object.
 *
 * Remove all the #VisuNode from the element @element. The properties
 * are also updated.
 *
 * Since: 3.7
 */
void visu_node_array_removeNodesOfElement(VisuNodeArray *nodeArray, VisuElement *element)
{
  guint i;
  gint iEle;
  EleArr *ele;
  GArray *nodeNumbers;
  VisuNodeArrayPrivate *priv = visu_node_array_get_instance_private(nodeArray);

  g_return_if_fail(priv && element);

  iEle = visu_node_array_getElementId(nodeArray, element);
  if (iEle < 0)
    return;

  /* We keep the allocation to avoid deallocating, reallocating. */

  /* Begin by removing the the node properties. */
  g_hash_table_foreach(priv->nodeProp,
                       removeNodePropertyForElement, GINT_TO_POINTER(iEle));

  ele = _getEleArr(priv, iEle);
  if (ele->nStoredNodes == 0)
    return;

  /* We update the node table. */
  nodeNumbers = g_array_new(FALSE, FALSE, sizeof(guint));
  for (i = 0; i < ele->nStoredNodes; i++)
    {
      g_array_append_val(nodeNumbers, ele->nodes[i].number);
      if (priv->origProp->data_int[ele->nodes[i].posElement][ele->nodes[i].posNode] < 0)
        priv->nOrigNodes -= 1;
      _setAtId(&priv->nodeTable, ele->nodes[i].number, (VisuNode*)0);
    }
  ele->nStoredNodes = 0;
  _compactNodeTable(&priv->nodeTable);

  DBG_fprintf(stderr, "Visu NodeArray: emit a 'NodePopulationDecrease' signal.\n");
  g_object_notify_by_pspec(G_OBJECT(nodeArray), properties[NNODES_PROP]);
  g_signal_emit(G_OBJECT(nodeArray), visu_node_array_signals[POPULATION_DECREASE_SIGNAL],
		0, (gpointer)nodeNumbers, NULL);
  g_array_unref(nodeNumbers);
}

/**
 * visu_node_array_removeAllDuplicateNodes:
 * @nodeArray: a #VisuNodeArray object.
 *
 * Remove all nodes that are not original in the box.
 *
 * Returns: TRUE if some nodes have been removed.
 */
gboolean visu_node_array_removeAllDuplicateNodes(VisuNodeArray *nodeArray)
{
  GArray *tmp;
  guint i, j;
  EleArr *ele;
  VisuNodeArrayPrivate *priv = visu_node_array_get_instance_private(nodeArray);

  g_return_val_if_fail(priv, FALSE);

  tmp = g_array_new(FALSE, FALSE, sizeof(int));
  for (i = 0; i < priv->elements->len; i++)
    {
      ele = _getEleArr(priv, i);
      for (j = 0; j < ele->nStoredNodes; j++)
        if (priv->origProp->data_int[i][j] >= 0)
          tmp = g_array_append_val(tmp, ele->nodes[j].number);
    }

  if (tmp->len > 0)
    {
      visu_node_array_removeNodes(nodeArray, tmp);
      g_array_unref(tmp);
      return TRUE;
    }

  g_array_free(tmp, TRUE);
  return FALSE;
}

/**
 * visu_node_array_getFromId:
 * @array: a #VisuNodeArray structure which stores the nodes.
 * @number: an integer.
 *
 * This methods retrieves the #VisuNode identified by the integer @number.
 * The number must be strictly positive. No error is raised if no node corresponds
 * to the given number.
 *
 * Returns: (transfer none): the found #VisuNode or NULL if none corresponds to number.
 */
VisuNode* visu_node_array_getFromId(VisuNodeArray *array, guint number)
{
  VisuNodeArrayPrivate *priv = visu_node_array_get_instance_private(array);
  g_return_val_if_fail(priv, (VisuNode*)0);

  /* DBG_fprintf(stderr, "Visu NodeArray: get VisuNode from number %d.\n", number); */
  if (_validNodeTableId(&priv->nodeTable, number))
    return _getFromId(&priv->nodeTable, number);
  else
    return (VisuNode*)0;
}

/**
 * visu_node_array_getOriginal:
 * @nodeArray: a #VisuNodeArray object.
 * @nodeId: a node id.
 *
 * Test if the given @nodeId is an original or a replica for the
 * periodisation.
 *
 * Returns: the original node index or -1 if @nodeId is original.
 */
gint visu_node_array_getOriginal(VisuNodeArray *nodeArray, guint nodeId)
{
  VisuNode *node;
  gint orig;
  VisuNodeArrayPrivate *priv = visu_node_array_get_instance_private(nodeArray);

  g_return_val_if_fail(priv && priv->origProp, -1);
  g_return_val_if_fail(_validNodeTableId(&priv->nodeTable, nodeId), -1);

  orig = (gint)nodeId;
  do
    {
      node = _getFromId(&priv->nodeTable, orig);
      orig = priv->origProp->data_int[node->posElement][node->posNode];
    }
  while (orig >= 0);
/*   DBG_fprintf(stderr, "Visu Node: get original from %d: %d (%d).\n", */
/* 	      nodeId, node->number, */
/* 	      nodeArray->priv->origProp->data_int[node->posElement][node->posNode]); */
  return (node->number == nodeId)?-1:(gint)node->number;
}

/**
 * visu_node_array_setOriginal:
 * @nodeArray: a #VisuNodeArray object.
 * @nodeId: a node id.
 *
 * Make @nodeId an original node.
 *
 * Returns: TRUE if @nodeId was not original.
 */
gboolean visu_node_array_setOriginal(VisuNodeArray *nodeArray, guint nodeId)
{
  VisuNode *node;
  gint orig;
  VisuNodeArrayPrivate *priv = visu_node_array_get_instance_private(nodeArray);

  g_return_val_if_fail(priv && priv->origProp, -1);
  g_return_val_if_fail(_validNodeTableId(&priv->nodeTable, nodeId), -1);

  node = _getFromId(&priv->nodeTable, nodeId);
  g_return_val_if_fail(node, FALSE);

  orig = priv->origProp->data_int[node->posElement][node->posNode];
  priv->origProp->data_int[node->posElement][node->posNode] = -1;
  if (orig != -1)
    priv->nOrigNodes += 1;

  DBG_fprintf(stderr, "Visu Node: set original for %d (%d).\n",
	      nodeId, orig);
  return (orig != -1);
}

/**
 * visu_node_array_switchNumber:
 * @nodeArray: a #VisuNodeArray object.
 * @from: a node id.
 * @to: another node id.
 *
 * Two nodes of @nodeArray switches their number.
 *
 * Since: 3.6
 *
 * Returns: TRUE if number is switched.
 */
gboolean visu_node_array_switchNumber(VisuNodeArray *nodeArray, guint from, guint to)
{
  VisuNode *nodeFrom, *nodeTo;
  VisuNodeArrayPrivate *priv = visu_node_array_get_instance_private(nodeArray);

  if (from == to)
    return FALSE;

  g_return_val_if_fail(priv, FALSE);
  nodeFrom = _getFromId(&priv->nodeTable, from);
  nodeTo   = _getFromId(&priv->nodeTable, to);
  _setAtId(&priv->nodeTable, from, nodeTo);
  _setAtId(&priv->nodeTable, to, nodeFrom);
  nodeFrom->number = to;
  nodeTo->number   = from;
  return TRUE;
}

/**
 * visu_node_array_compareElements:
 * @data1: a #VisuData object ;
 * @data2: an other #VisuData object.
 *
 * This method is used to compare the composition of the given two #VisuData objects.
 * The test is only done on #VisuElement lists.
 *
 * Returns: TRUE if the two objects contains exactly the same #VisuElement objects (not
 *          one more or one less or one different), FALSE otherwise.
 */
gboolean visu_node_array_compareElements(VisuNodeArray *data1, VisuNodeArray *data2)
{
  guint i, j;
  gboolean found;
  VisuNodeArrayPrivate *priv1 = visu_node_array_get_instance_private(data1);
  VisuNodeArrayPrivate *priv2 = visu_node_array_get_instance_private(data2);

  g_return_val_if_fail(priv1 && priv2, FALSE);

  DBG_fprintf(stderr, "Visu NodeArray: comparing composition of '%p' and '%p'.\n",
	      (gpointer)data1, (gpointer)data2);
  if (data1 == data2)
    return TRUE;

  if (priv1->elements->len != priv2->elements->len)
    return FALSE;

  for (i = 0; i < priv1->elements->len; i++)
    {
      found = FALSE;
      for (j = 0; !found && j < priv2->elements->len; j++)
        found = (_getElement(priv1, i) == _getElement(priv2, j));
      if (!found)
        return FALSE;
    }

  return TRUE;
}
static gint _appendElement(VisuNodeArray *nodeArray, const VisuElement *element)
{
  GArray *ele, *nEle;
  guint one = 1;
  VisuNodeArrayPrivate *priv = visu_node_array_get_instance_private(nodeArray);

  g_return_val_if_fail(VISU_IS_ELEMENT(element), -1);

  ele = g_array_sized_new(FALSE, FALSE, sizeof(VisuElement*), 1);
  g_array_append_val(ele, element);
  nEle = g_array_sized_new(FALSE, FALSE, sizeof(guint), 1);
  g_array_append_val(nEle, one);
  visu_node_array_allocate(nodeArray, ele, nEle);
  g_array_free(ele, TRUE);
  g_array_free(nEle, TRUE);

  return priv->elements->len - 1;
}
/**
 * visu_node_array_getElement:
 * @data: a #VisuNodeArray object ;
 * @node: a #VisuNode of this array.
 *
 * This routine gets the #VisuElement the @node belongs to.
 *
 * Since: 3.7
 *
 * Returns: (transfer none): a #VisuElement, owned by V_Sim.
 */
VisuElement* visu_node_array_getElement(const VisuNodeArray *data, const VisuNode *node)
{
  VisuNodeArrayPrivate *priv = visu_node_array_get_instance_private((VisuNodeArray*)data);
  g_return_val_if_fail(priv && node, (VisuElement*)0);

  return _getElement(priv, node->posElement);
}
/**
 * visu_node_array_setElement:
 * @data: a #VisuNodeArray object.
 * @node: a #VisuNode pointer.
 * @element: a #VisuElement object.
 *
 * Change the nature of the #VisuElement of @node to be @element.
 *
 * Since: 3.8
 *
 * Returns: (transfer none): the new location of the #VisuNode.
 **/
VisuNode* visu_node_array_setElement(VisuNodeArray *data, VisuNode *node,
                                     const VisuElement *element)
{
  VisuNode* out;
  gint iEle;
  GArray *arr;
  VisuNodeArrayPrivate *priv = visu_node_array_get_instance_private(data);

  g_return_val_if_fail(priv && node, (VisuNode*)0);

  iEle = visu_node_array_getElementId(data, element);
  if ((gint)node->posElement == iEle)
    return node;

  if (iEle < 0)
    iEle = _appendElement(data, element);
  DBG_fprintf(stderr, "Visu Node: copy a new node from node %d (%d-%d).\n",
	      node->number, iEle, node->posNode);
  visu_node_array_startAdding(data);

  out = newOrCopyNode(data, iEle, node->number);
  _setAtId(&priv->nodeTable, out->number, (VisuNode*)0);
  out->number = node->number;

  arr = g_array_sized_new(FALSE, FALSE, sizeof(guint), 1);
  g_array_append_val(arr, node->number);
  visu_node_array_removeNodes(data, arr);
  g_array_free(arr, TRUE);

  _setAtId(&priv->nodeTable, out->number, out);
  priv->origProp->data_int[out->posElement][out->posNode] = -1;
  priv->nOrigNodes += 1;

  g_array_insert_val(priv->nodeTable.popIncIds, 0, out->number);
  visu_node_array_completeAdding(data);

  DBG_fprintf(stderr, "Visu Node: copy a new node from node -> %d.\n", out->number);
  return out;
  
}
/**
 * visu_node_array_containsElement:
 * @array: a #VisuNodeArray object.
 * @element: a #VisuElement object.
 *
 * Tests if @element is contained in @array. @element may be part of
 * @array but without nodes.
 *
 * Since: 3.8
 *
 * Returns: TRUE, if @array contains @element.
 **/
gboolean visu_node_array_containsElement(const VisuNodeArray *array,
                                         const VisuElement *element)
{
  guint i;
  const VisuNodeArrayPrivate *priv = visu_node_array_get_instance_private((VisuNodeArray*)array);

  g_return_val_if_fail(priv, FALSE);

  for (i = 0; i < priv->elements->len; i++)
    if (_getElement(priv, i) == element)
      return TRUE;
  return FALSE;
}
/**
 * visu_node_array_getElementId:
 * @array: a #VisuNodeArray object ;
 * @element: a #VisuElement object.
 *
 * This routines returns the internal id used to represent @element,
 * or -1 if not found.
 *
 * Since: 3.7
 *
 * Returns: a positive number or -1 if not found.
 */
gint visu_node_array_getElementId(const VisuNodeArray *array, const VisuElement *element)
{
  guint i;
  VisuNodeArrayPrivate *priv = visu_node_array_get_instance_private((VisuNodeArray*)array);

  g_return_val_if_fail(priv, -1);

  for (i = 0; i < priv->elements->len; i++)
    if (_getElement(priv, i) == element)
      return i;
  return -1;
}
/**
 * visu_node_array_getNNodes:
 * @array: a #VisuNodeArray object.
 *
 * This routines returns the number of #VisuNode stored in @array.
 * 
 * Since: 3.7
 *
 * Returns: a positive number.
 */
guint visu_node_array_getNNodes(const VisuNodeArray *array)
{
  VisuNodeArrayPrivate *priv = visu_node_array_get_instance_private((VisuNodeArray*)array);
  g_return_val_if_fail(priv, 0);
  
  return priv->nodeTable.nStoredNodes;
}
/**
 * visu_node_array_getNOriginalNodes:
 * @array: a #VisuNodeArray object.
 *
 * This routines returns the number of original #VisuNode stored in @array.
 * 
 * Since: 3.7
 *
 * Returns: a positive number.
 */
guint visu_node_array_getNOriginalNodes(const VisuNodeArray *array)
{
  VisuNodeArrayPrivate *priv = visu_node_array_get_instance_private((VisuNodeArray*)array);
  g_return_val_if_fail(priv, 0);
  
  return priv->nOrigNodes;
}
/**
 * visu_node_array_getNElements:
 * @array: a #VisuNodeArray object ;
 * @physical: a boolean.
 *
 * The parameter @array stores several #VisuNode of #VisuElement. This
 * routine is used to get the number of #VisuElement that are used by
 * this @array. Depending on @physical value, the number of
 * #VisuElement representing physical element or not is retrieved. The
 * actual returned number of #VisuElement take into account only
 * elements with a positive number of nodes.
 *
 * Since: 3.7
 *
 * Returns: a positive number.
 */
guint visu_node_array_getNElements(const VisuNodeArray *array, gboolean physical)
{
  guint nEle, i;
  VisuNodeArrayPrivate *priv = visu_node_array_get_instance_private((VisuNodeArray*)array);

  g_return_val_if_fail(priv, 0);

  nEle = 0;
  for (i = 0; i < priv->elements->len; i++)
    if (_getEleArr(priv, i)->nStoredNodes > 0)
      {
        if (physical && visu_element_getPhysical(_getElement(priv, i)))
          nEle += 1;
        else if (!physical)
          nEle += 1;
      }
  
  return nEle;
}

/**
 * visu_node_array_allocateNodesForElement:
 * @array: a #VisuNodeArray object ;
 * @eleId: an internal #VisuElement id ;
 * @nNodes: a positive number of nodes.
 *
 * This routine is used to allocate space for @nNodes of a
 * #VisuElement. This #VisuElement is identified by its internal id,
 * see visu_node_array_getElementId(). If this #VisuElement has
 * already enough space in this @array, nothing is done, otherwise
 * space is reallocated.
 *
 * Since: 3.7
 */
void visu_node_array_allocateNodesForElement(VisuNodeArray *array, guint eleId, guint nNodes)
{
  guint j, delta;
  VisuNode *oldNodeList;
  EleArr *ele;
  VisuNodeArrayPrivate *priv = visu_node_array_get_instance_private(array);

  g_return_if_fail(priv && eleId < priv->elements->len);

  ele = _getEleArr(priv, eleId);
  if (ele->nNodes >= nNodes)
    return;

  delta = nNodes - ele->nNodes;
  oldNodeList = ele->nodes;
  DBG_fprintf(stderr, "Visu Node: reallocation needed for element "
	      "%d with %d nodes.\n", eleId, delta);
  ele->nNodes = nNodes;
  ele->nodes  = g_realloc(ele->nodes, sizeof(VisuNode) * ele->nNodes);
  _increaseNodeTable(&priv->nodeTable, delta);
  DBG_fprintf(stderr, " | (all)%d/%d # (%d)%d/%d\n",
	      priv->nodeTable.nStoredNodes, priv->nodeTable.nNodes,
              eleId, ele->nStoredNodes, ele->nNodes);
  /* We set the default values for the new nodes. */
  for (j = ele->nStoredNodes; j < ele->nNodes; j++)
    {
      ele->nodes[j].posElement = eleId;
      ele->nodes[j].posNode    = j;
    }
  /* If the node list has been moved, we need to reassign pointers
     of array nodeTable. */
  if (oldNodeList != ele->nodes)
    for (j = 0; j < ele->nStoredNodes; j++)
      _setAtId(&priv->nodeTable, ele->nodes[j].number, ele->nodes + j);
  /* We reallocate the table properties. */
  g_hash_table_foreach(priv->nodeProp, reallocNodeProperty,
		       GINT_TO_POINTER(eleId));

  /* Test part for the nodeTable array. */
#if DEBUG == 1
  _checkNodeTable(&priv->nodeTable);
#endif
  DBG_fprintf(stderr, "Visu Node: reallocation OK.\n");
  DBG_fprintf(stderr, " | size = %do\n",
	      (int)(priv->elements->len * sizeof(EleArr) + sizeof(GArray) +
                    sizeof(VisuNode) * priv->nodeTable.nNodes +
		    sizeof(VisuNode*) * priv->nodeTable.nNodes + sizeof(VisuNodeArray)));
}

/**
 * visu_node_array_getNewNode:
 * @nodeArray: a #VisuNodeArray object ;
 * @element: a #VisuElement object.
 *
 * Return the location of an unstored node for the given #VisuElement.
 * The returned node is then added in the list of used nodes.
 *
 * Since: 3.8
 *
 * Returns: (transfer none): the location of a newly used node.
 */
VisuNode* visu_node_array_getNewNode(VisuNodeArray *nodeArray, const VisuElement *element)
{
  gint iEle;

  iEle = visu_node_array_getElementId(nodeArray, element);
  if (iEle < 0)
    iEle = _appendElement(nodeArray, element);
  DBG_fprintf(stderr, "Visu Node: create a new node of element %d.\n", iEle);
  return newOrCopyNode(nodeArray, iEle, -1);
}

/**
 * visu_node_array_getNewNodeForId:
 * @nodeArray: a #VisuNodeArray object ;
 * @iEle: the id used in @nodeArray to index a #VisuElement.
 *
 * Return the location of an unstored node for the given #VisuElement.
 * The returned node is then added in the list of used nodes.
 *
 * Returns: (transfer none): the location of a newly used node.
 */
VisuNode* visu_node_array_getNewNodeForId(VisuNodeArray *nodeArray, guint iEle)
{
  DBG_fprintf(stderr, "Visu Node: create a new node of element %d.\n", iEle);
  return newOrCopyNode(nodeArray, iEle, -1);
}

/**
 * visu_node_array_copyNode:
 * @nodeArray: a #VisuNodeArray object ;
 * @node: a node of the given #VisuNodeArray.
 *
 * Return the location of an unstored node that is the deep copy of the given node.
 * The returned node is then added in the list of used nodes.
 *
 * Returns: (transfer none): the location of a newly used node.
 */
VisuNode* visu_node_array_copyNode(VisuNodeArray *nodeArray, VisuNode *node)
{
  VisuNode* out;

  DBG_fprintf(stderr, "Visu Node: copy a new node from node %d (%d-%d).\n",
	      node->number, node->posElement, node->posNode);
  out = newOrCopyNode(nodeArray, node->posElement, node->number);
  DBG_fprintf(stderr, "Visu Node: copy a new node from node -> %d.\n", out->number);
  return out;
}
static gboolean _emitPopInc(gpointer data)
{
  visu_node_array_completeAdding(VISU_NODE_ARRAY(data));
  g_object_unref(G_OBJECT(data));
  return FALSE;
}
static VisuNode* newOrCopyNode(VisuNodeArray *nodeArray, int iEle,
			       int oldNodeId)
{
  EleArr *ele;
  VisuNode *node, *oldNode;
  struct twoNodes nodes;
  VisuNodeArrayPrivate *priv = visu_node_array_get_instance_private(nodeArray);

  g_return_val_if_fail(priv, (VisuNode*)0);
  g_return_val_if_fail((oldNodeId >= 0 &&
                        _validNodeTableId(&priv->nodeTable, (guint)oldNodeId)) ||
		       (iEle >= 0 && iEle < (int)priv->elements->len),
		       (VisuNode*)0);

  ele = _getEleArr(priv, iEle);
  if (ele->nStoredNodes == ele->nNodes)
    /* We need to realloc... */
    visu_node_array_allocateNodesForElement(nodeArray, iEle,
                                            ele->nNodes + REALLOCATION_STEP);

  /* Get the new node. */
  node = ele->nodes + ele->nStoredNodes;
  _addNodeTable(&priv->nodeTable, node);
  /* Update the node internal values. */
  ele->nStoredNodes += 1;

  /* Set default values. */
  node->xyz[0] = 0.f;
  node->xyz[1] = 0.f;
  node->xyz[2] = 0.f;
  node->translation[0] = 0.f;
  node->translation[1] = 0.f;
  node->translation[2] = 0.f;
  node->rendered = FALSE;

  /* We copy the values from oldNode. */
  oldNode = (VisuNode*)0;
  if (oldNodeId >= 0 && (oldNode = _getFromId(&priv->nodeTable, oldNodeId)))
    {
      node->xyz[0]         = oldNode->xyz[0];
      node->xyz[1]         = oldNode->xyz[1];
      node->xyz[2]         = oldNode->xyz[2];
      node->translation[0] = oldNode->translation[0];
      node->translation[1] = oldNode->translation[1];
      node->translation[2] = oldNode->translation[2];
      node->rendered       = oldNode->rendered;
    }

  /* Create new properties for the node. */
  nodes.newNode = node;
  nodes.oldNode = oldNode;
  g_hash_table_foreach(priv->nodeProp, createNodeproperty, (gpointer)&nodes);

  /* If we have an old node, we use it as original node id, or we put
     -1 if not. */
  priv->origProp->data_int[node->posElement][node->posNode] = oldNodeId;
  if (oldNodeId < 0)
    priv->nOrigNodes += 1;

  if (!priv->nodeTable.popIncIds)
    {
      visu_node_array_startAdding(nodeArray);
      g_array_append_val(priv->nodeTable.popIncIds, node->number);
      g_idle_add(_emitPopInc, g_object_ref(nodeArray));
    }
  else
    {
      g_array_append_val(priv->nodeTable.popIncIds, node->number);
    }

  return node;
}
/**
 * visu_node_array_startAdding:
 * @array: a #VisuNodeArray object.
 *
 * Begin to accumulate the node ids that are added to the
 * structure. When addition is finished, call
 * visu_node_array_completeAdding() to ensure completion and emit signals.
 *
 * Since: 3.8
 **/
void visu_node_array_startAdding(VisuNodeArray *array)
{
  VisuNodeArrayPrivate *priv = visu_node_array_get_instance_private(array);
  g_return_if_fail(priv && !priv->nodeTable.popIncIds);

  priv->nodeTable.popIncIds = g_array_new(FALSE, FALSE, sizeof(guint));
}
/**
 * visu_node_array_completeAdding:
 * @array: a #VisuNodeArray object.
 * 
 * After new nodes have been added, call this routine to ensure that
 * proper signals are emitted. See visu_node_array_startAdding() to
 * start a bunch addition of new nodes.
 *
 * Since: 3.8
 **/
void visu_node_array_completeAdding(VisuNodeArray *array)
{
  VisuNodeArrayPrivate *priv = visu_node_array_get_instance_private(array);
  g_return_if_fail(priv && priv->nodeTable.popIncIds);

  if (priv->nodeTable.popIncIds->len > 0)
    {
      g_object_notify_by_pspec(G_OBJECT(array), properties[NNODES_PROP]);
      DBG_fprintf(stderr, "Visu NodeArray: emit a 'PopulationIncrease' signal.\n");
      g_signal_emit(G_OBJECT(array),
                    visu_node_array_signals[POPULATION_INCREASE_SIGNAL],
                    0, priv->nodeTable.popIncIds, NULL);
    }

  g_array_unref(priv->nodeTable.popIncIds);
  priv->nodeTable.popIncIds = (GArray*)0;
}
static gboolean _resetVisibility(VisuMaskable *self)
{
  gboolean redraw;
  guint i, j;
  EleArr *ele;
  VisuNodeArrayPrivate *priv = visu_node_array_get_instance_private(VISU_NODE_ARRAY(self));

  g_return_val_if_fail(priv, FALSE);
  redraw = FALSE;
  for (i = 0; i < priv->elements->len; i++)
    for(ele = _getEleArr(priv, i), j = 0; j < ele->nStoredNodes; j++)
      redraw = visu_node_setVisibility(ele->nodes + j, TRUE) || redraw;
  return redraw;
}
static GArray* _getMasked(const VisuMaskable *self)
{
  GArray *masked;
  guint i, j;
  EleArr *ele;
  const VisuNodeArrayPrivate *priv = visu_node_array_get_instance_private((VisuNodeArray*)self);

  g_return_val_if_fail(priv, FALSE);
  
  masked = g_array_sized_new(FALSE, FALSE, sizeof(guint), priv->nodeTable.nStoredNodes / 10);
  for (i = 0; i < priv->elements->len; i++)
    for(ele = _getEleArr(priv, i), j = 0; j < ele->nStoredNodes; j++)
      if (!visu_node_getVisibility(ele->nodes + j))
        g_array_append_val(masked, ele->nodes[j].number);
  return masked;
}
/**
 * visu_node_array_setNodeVisibility:
 * @nodeArray: a #VisuNodeArray object.
 * @id: a node id.
 * @status: a boolean.
 *
 * Change the visibility of node @id in @nodeArray. If @id is out of
 * bound, nothing is done and no error raised. If visibility is indeed
 * changed, then #VisuNodeArray::VisibilityChanged signal is emitted.
 *
 * Since: 3.8
 *
 * Returns: TRUE if visibility of node @id is indeed changed.
 **/
gboolean visu_node_array_setNodeVisibility(VisuNodeArray *nodeArray, guint id,
                                           gboolean status)
{
  VisuNode *node;

  g_return_val_if_fail(VISU_IS_NODE_ARRAY(nodeArray), FALSE);
  
  node = visu_node_array_getFromId(nodeArray, id);
  if (!node)
    return FALSE;

  if (!visu_node_setVisibility(node, status))
    return FALSE;

  visu_maskable_visibilityChanged(VISU_MASKABLE(nodeArray));

  return TRUE;
}
/**
 * visu_node_array_startMoving:
 * @array: a #VisuNodeArray object.
 *
 * Begin to accumulate the node ids that are moved in the
 * structure. When moving is finished, call
 * visu_node_array_completeMoving() to ensure completion and emit signals.
 *
 * Since: 3.8
 **/
void visu_node_array_startMoving(VisuNodeArray *array)
{
  VisuNodeArrayPrivate *priv = visu_node_array_get_instance_private(array);
  g_return_if_fail(priv && !priv->nodeTable.posChgIds);

  DBG_fprintf(stderr, "Visu Nodes: starting moving nodes.\n");
  priv->nodeTable.posChgIds = g_array_new(FALSE, FALSE, sizeof(guint));
}
/**
 * visu_node_array_completeMoving:
 * @array: a #VisuNodeArray object.
 * 
 * After new nodes have been moved, call this routine to ensure that
 * proper signals are emitted. See visu_node_array_startMoving() to
 * start a bunch movements of new nodes.
 *
 * Since: 3.8
 **/
void visu_node_array_completeMoving(VisuNodeArray *array)
{
  VisuNodeArrayPrivate *priv = visu_node_array_get_instance_private(array);
  g_return_if_fail(priv && priv->nodeTable.posChgIds);

  if (priv->nodeTable.posChgIds->len > 0)
    {
      DBG_fprintf(stderr, "Visu NodeArray: emit a 'position-changed' signal.\n");
      g_signal_emit(G_OBJECT(array),
                    visu_node_array_signals[POSITION_CHANGED_SIGNAL],
                    0, priv->nodeTable.posChgIds, NULL);
    }

  DBG_fprintf(stderr, "Visu Nodes: complete moving nodes.\n");
  g_array_unref(priv->nodeTable.posChgIds);
  priv->nodeTable.posChgIds = (GArray*)0;
}
static gboolean _emitPosChg(gpointer data)
{
  visu_node_array_completeMoving(VISU_NODE_ARRAY(data));
  g_object_unref(G_OBJECT(data));
  return FALSE;
}
/**
 * visu_node_array_shiftNode:
 * @array: a #VisuNodeArray object.
 * @id: a node id.
 * @delta: (array fixed-size=3): a shift in cartesian coordinates.
 *
 * Move the node @id of the quantity @delta given in cartesian
 * coordinates. If several nodes should be shifted, consider using
 * visu_node_array_shiftNodes() or encapsulate the calls within
 * visu_node_array_startMoving() and visu_node_array_completeMoving().
 *
 * Since: 3.8
 **/
void visu_node_array_shiftNode(VisuNodeArray *array, guint id, const gfloat delta[3])
{
  VisuNode *node;
  VisuNodeArrayPrivate *priv = visu_node_array_get_instance_private(array);

  g_return_if_fail(priv);
  
  node = visu_node_array_getFromId(array, id);
  if (node)
    {
      node->xyz[0] += delta[0];
      node->xyz[1] += delta[1];
      node->xyz[2] += delta[2];
    }
  if (!priv->nodeTable.posChgIds)
    {
      visu_node_array_startMoving(array);
      g_array_append_val(priv->nodeTable.posChgIds, node->number);
      g_idle_add(_emitPosChg, g_object_ref(array));
    }
  else
    {
      g_array_append_val(priv->nodeTable.posChgIds, node->number);
    }
}
/**
 * visu_node_array_shiftNodes:
 * @array: a #VisuNodeArray object.
 * @ids: (element-type uint): a set of #VisuNode ids.
 * @delta: (array fixed-size=3): a shift in cartesian coordinates.
 *
 * Apply @delta on the coordinates of every nodes in @ids.
 *
 * Since: 3.8
 **/
void visu_node_array_shiftNodes(VisuNodeArray *array, const GArray *ids,
                                const float delta[3])
{
  guint i;
  gboolean inside;
  VisuNodeArrayPrivate *priv = visu_node_array_get_instance_private(array);

  g_return_if_fail(priv);

  inside = (priv->nodeTable.posChgIds != (GArray*)0);
  if (!inside)
    visu_node_array_startMoving(array);
  for (i = 0; i < ids->len; i++)
    visu_node_array_shiftNode(array, g_array_index(ids, guint, i), delta);
  if (!inside)
    visu_node_array_completeMoving(array);
}
/**
 * visu_node_array_moveNode:
 * @array: a #VisuNodeArray object.
 * @id: a node id.
 * @at: (array fixed-size=3): a position in cartesian coordinates.
 *
 * Move the node @id at the posityion @at given in cartesian
 * coordinates. If several nodes should be moved, consider using
 * visu_node_array_moveNodes() or encapsulate the calls within
 * visu_node_array_startMoving() and visu_node_array_completeMoving().
 *
 * Since: 3.8
 **/
void visu_node_array_moveNode(VisuNodeArray *array, guint id, const float at[3])
{
  VisuNode *node;
  VisuNodeArrayPrivate *priv = visu_node_array_get_instance_private(array);

  g_return_if_fail(priv);

  node = visu_node_array_getFromId(array, id);
  if (node)
    {
      node->xyz[0] = at[0];
      node->xyz[1] = at[1];
      node->xyz[2] = at[2];
    }
  if (!priv->nodeTable.posChgIds)
    {
      visu_node_array_startMoving(array);
      g_array_append_val(priv->nodeTable.posChgIds, node->number);
      g_idle_add(_emitPosChg, g_object_ref(array));
    }
  else
    {
      g_array_append_val(priv->nodeTable.posChgIds, node->number);
    }
}
/**
 * visu_node_array_moveNodes:
 * @array: a #VisuNodeArray object.
 * @ids: (element-type uint): a set of #VisuNode ids.
 * @xyz: (element-type float): a set of cartesian displacements.
 *
 * Apply translations on all nodes defined by @ids. Displacements are
 * read from @xyz which is an array containing as many float triplets
 * as nodes in ids.
 *
 * Since: 3.8
 **/
void visu_node_array_moveNodes(VisuNodeArray *array, const GArray *ids,
                               const GArray *xyz)
{
  guint i;
  gboolean inside;
  VisuNodeArrayPrivate *priv = visu_node_array_get_instance_private(array);

  g_return_if_fail(priv && ids && xyz && ids->len * 3 == xyz->len);

  inside = (priv->nodeTable.posChgIds != (GArray*)0);
  if (!inside)
    visu_node_array_startMoving(array);
  for (i = 0; i < ids->len; i++)
    visu_node_array_moveNode(array, g_array_index(ids, guint, i),
                             &g_array_index(xyz, float, 3 * i));
  if (!inside)
    visu_node_array_completeMoving(array);
}
/**
 * visu_node_array_rotateNodes:
 * @array: a #VisuNodeArray object.
 * @ids: (element-type uint): a set of #VisuNode ids.
 * @axis: (array fixed-size=3): an axis orientation.
 * @center: (array fixed-size=3): point coordinates.
 * @angle: an angle in degrees.
 *
 * Apply the rotation defined by @angle along @axis passing by @center
 * to all nodes referenced in @ids.
 *
 * Since: 3.8
 **/
void visu_node_array_rotateNodes(VisuNodeArray *array, const GArray *ids,
                                 const float axis[3], const float center[3],
                                 float angle)
{
  VisuNode *node;
  guint i;
  float sph[3], mat[3][3], work[3];
  VisuNodeArrayPrivate *priv = visu_node_array_get_instance_private(array);

  g_return_if_fail(priv);
  g_return_if_fail(axis[0] != 0.f || axis[1] != 0.f || axis[2] != 0.f);

  tool_matrix_cartesianToSpherical(sph, axis);
  DBG_fprintf(stderr, "Visu Nodes: rotation along %g %g.\n",
              sph[TOOL_MATRIX_SPHERICAL_THETA], sph[TOOL_MATRIX_SPHERICAL_PHI]);
  tool_matrix_setIdentity(mat);
  tool_matrix_rotate(mat, -sph[TOOL_MATRIX_SPHERICAL_PHI], TOOL_XYZ_Z);
  tool_matrix_rotate(mat, -sph[TOOL_MATRIX_SPHERICAL_THETA], TOOL_XYZ_Y);
  tool_matrix_rotate(mat, angle, TOOL_XYZ_Z);
  tool_matrix_rotate(mat, sph[TOOL_MATRIX_SPHERICAL_THETA], TOOL_XYZ_Y);
  tool_matrix_rotate(mat, sph[TOOL_MATRIX_SPHERICAL_PHI], TOOL_XYZ_Z);
  
  for (i = 0; i < ids->len; i++)
    {
      node = visu_node_array_getFromId(array, g_array_index(ids, guint, i));
      if (node)
        {
          node->xyz[0] -= center[0];
          node->xyz[1] -= center[1];
          node->xyz[2] -= center[2];
          tool_matrix_productVector(work, mat, node->xyz);
          node->xyz[0] = work[0] + center[0];
          node->xyz[1] = work[1] + center[1];
          node->xyz[2] = work[2] + center[2];
        }
    }
  if (priv->nodeTable.posChgIds)
    g_array_append_vals(priv->nodeTable.posChgIds, ids->data, ids->len);
  else
    g_signal_emit(array, visu_node_array_signals[POSITION_CHANGED_SIGNAL], 0, ids);
}
/**
 * visu_node_array_join:
 * @array: a #VisuNodeArray object.
 * @frag: another #VisuNodeArray object.
 * @at: (array fixed-size=3): a position in cartesian coordinates.
 *
 * Add all nodes from @frag to @array and position them centred at @at.
 *
 * Since: 3.8
 *
 * Returns: (transfer full) (element-type guint): the ids of the added
 * nodes in @array.
 **/
GArray* visu_node_array_join(VisuNodeArray *array,
                          const VisuNodeArray *frag, const gfloat at[3])
{
  GArray *ids;
  guint i;
  GArray *elements, *nElements;
  VisuNodeArrayIter iter;
  gfloat centre[3], xyz[3];
  VisuNodeArrayPrivate *priv = visu_node_array_get_instance_private(array);
  VisuNodeArrayPrivate *fpriv = visu_node_array_get_instance_private((VisuNodeArray*)frag);
  
  g_return_val_if_fail(priv && fpriv, NULL);

  elements = g_array_sized_new(FALSE, FALSE, sizeof(VisuElement*),
                               fpriv->elements->len);
  nElements = g_array_sized_new(FALSE, FALSE, sizeof(guint),
                                fpriv->elements->len);
  for (i = 0; i < fpriv->elements->len; i++)
    {
      EleArr *ele = _getEleArr(fpriv, i);;
      g_array_append_val(elements, ele->ele);
      g_array_append_val(nElements, ele->nStoredNodes);
    }
  visu_node_array_allocate(array, elements, nElements);
  g_array_unref(elements);
  g_array_unref(nElements);

  visu_node_array_iter_new(VISU_NODE_ARRAY((VisuNodeArray*)frag), &iter);
  centre[0] = 0.f;
  centre[1] = 0.f;
  centre[2] = 0.f;
  for (visu_node_array_iterStart(VISU_NODE_ARRAY((VisuNodeArray*)frag), &iter); iter.node;
       visu_node_array_iterNext(VISU_NODE_ARRAY((VisuNodeArray*)frag), &iter))
    {
      centre[0] += iter.node->xyz[0];
      centre[1] += iter.node->xyz[1];
      centre[2] += iter.node->xyz[2];
    }
  centre[0] = at[0] - centre[0] / (float)fpriv->nodeTable.nStoredNodes;
  centre[1] = at[1] - centre[1] / (float)fpriv->nodeTable.nStoredNodes;
  centre[2] = at[2] - centre[2] / (float)fpriv->nodeTable.nStoredNodes;

  visu_node_array_startAdding(array);
  for (visu_node_array_iterStart(VISU_NODE_ARRAY((VisuNodeArray*)frag), &iter); iter.node;
       visu_node_array_iterNext(VISU_NODE_ARRAY((VisuNodeArray*)frag), &iter))
    {
      VisuNode *node = visu_node_array_getNewNode(array, iter.element);
      if (node)
        {
          xyz[0] = iter.node->xyz[0] + centre[0];
          xyz[1] = iter.node->xyz[1] + centre[1];
          xyz[2] = iter.node->xyz[2] + centre[2];
          visu_node_setCoordinates(node, xyz);
        }
    }
  ids = g_array_ref(priv->nodeTable.popIncIds);
  visu_node_array_completeAdding(array);

  return ids;
}

/*******************/
/* Local routines. */
/*******************/
static void onElementRenderChanged(VisuNodeArray *data, GParamSpec *pspec _U_, VisuElement *element)
{
  DBG_fprintf(stderr, "Visu NodeArray: caught the 'ElementVisibilityChanged' signal,"
	      " emitting node render signal.\n");
  g_signal_emit(G_OBJECT(data), visu_node_array_signals[ELEMENT_VISIBILITY_CHANGED_SIGNAL],
		0, element);
  visu_maskable_visibilityChanged(VISU_MASKABLE(data));
}
static void onElementPlaneChanged(VisuNodeArray *data, GParamSpec *pspec _U_, VisuElement *element)
{
  DBG_fprintf(stderr, "Visu NodeArray: caught the 'ElementMaskableChanged' signal,"
	      " emitting node render signal.\n");
  g_signal_emit(G_OBJECT(data), visu_node_array_signals[ELEMENT_PLANE_CHANGED_SIGNAL],
		0, element);
}



/**************************/
/* The property routines. */
/**************************/
static void freeNodePropStruct(gpointer data)
{
  VisuNodeProperty *prop;
  guint i, j;
  EleArr *ele;
  VisuNodeArrayPrivate *priv;

  prop = (VisuNodeProperty*)data;
  DBG_fprintf(stderr, "Visu Node: freeing node property '%s'.\n", prop->name);

  g_free(prop->name);
  priv = visu_node_array_get_instance_private(prop->array);
  /* The pointer case. */
  if (priv && prop->data_pointer)
    {
      for (i = 0; i < priv->elements->len; i++)
	{
	  for (ele = _getEleArr(priv, i), j = 0; j < ele->nNodes; j++)
            if (prop->data_pointer[i][j])
              {
                if (prop->freeTokenFunc)
                  prop->freeTokenFunc(prop->data_pointer[i][j], prop->user_data);
                else
                  g_free(prop->data_pointer[i][j]);
              }
	  g_free(prop->data_pointer[i]);
	}
      g_free(prop->data_pointer);
    }
  /* The integer case */
  if (priv && prop->data_int)
    {
      for (i = 0; i < priv->elements->len; i++)
	g_free(prop->data_int[i]);
      g_free(prop->data_int);
    }
  g_free(prop);
  DBG_fprintf(stderr, "Visu Node: freeing property ... OK.\n");
}

/* Remove the property of all nodes of the element given in data. */
static void removeNodePropertyForElement(gpointer key, gpointer value, gpointer data)
{
  guint iEle;
  guint j;
  EleArr *ele;
  VisuNodeProperty *prop;
  VisuNodeArrayPrivate *priv;
  
  prop = (VisuNodeProperty*)value;
  iEle= GPOINTER_TO_INT(data);
  priv = visu_node_array_get_instance_private(prop->array);
  g_return_if_fail(priv && iEle < priv->elements->len);
  ele = _getEleArr(priv, iEle);

  DBG_fprintf(stderr, "Visu Node: remove node property '%s' for all nodes of element '%s'.\n",
	      (gchar*)key, ele->ele->name);
  /* We first remove the property tokens. */
  switch (prop->gtype)
    {
    case G_TYPE_POINTER:
      for (j = 0; j < ele->nNodes; j++)
        if (prop->data_pointer[iEle][j])
          {
            if (prop->freeTokenFunc)
              prop->freeTokenFunc(prop->data_pointer[iEle][j], prop->user_data);
            else
              g_free(prop->data_pointer[iEle][j]);
            prop->data_pointer[iEle][j] = (gpointer)0;
          }
      break;
    case G_TYPE_INT:
      for (j = 0; j < ele->nNodes; j++)
        prop->data_int[iEle][j] = 0;
      break;
    default:
      g_warning("Unsupported GValue type for property '%s'.", prop->name);
    }
}

/* Remove the property of the node given in data and move the
   last property of this element at the place of the removed node. */
static void removeNodeProperty(gpointer key, gpointer value, gpointer data)
{
  EleArr *ele;
  VisuNode *node;
  VisuNodeProperty *prop;
  VisuNodeArrayPrivate *priv;
  
  node = (VisuNode*)data;
  prop = (VisuNodeProperty*)value;
  priv = visu_node_array_get_instance_private(prop->array);
  g_return_if_fail(priv);
  ele = _getEleArr(priv, node->posElement);
  g_return_if_fail(ele->nStoredNodes > 0);

  DBG_fprintf(stderr, "Visu Node: remove node property '%s' from %d %d.\n",
	      (gchar*)key, node->posElement, node->posNode);
  /* We first remove the property token. */
  switch (prop->gtype)
    {
    case G_TYPE_POINTER:
      if (prop->data_pointer[node->posElement][node->posNode])
        {
          if (prop->freeTokenFunc)
            prop->freeTokenFunc(prop->data_pointer[node->posElement][node->posNode],
                                prop->user_data);
          else
            g_free(prop->data_pointer[node->posElement][node->posNode]);
        }
      break;
    case G_TYPE_INT:
      prop->data_int[node->posElement][node->posNode] = 0;
      break;
    default:
      g_warning("Unsupported GValue type for property '%s'.", prop->name);
    }

  /* Then we copy the pointer from the last position to the given one.
     The last position is given by nStoredNodesPerEle since this counter
     has already been lowered. */
  switch (prop->gtype)
    {
    case G_TYPE_POINTER:
      prop->data_pointer[node->posElement][node->posNode] =
	prop->data_pointer[node->posElement][ele->nStoredNodes];
      prop->data_pointer[node->posElement][ele->nStoredNodes] = (gpointer)0;
      break;
    case G_TYPE_INT:
      prop->data_int[node->posElement][node->posNode] =
	prop->data_int[node->posElement][ele->nStoredNodes];
      prop->data_int[node->posElement][ele->nStoredNodes] = 0;
      break;
    default:
      g_warning("Unsupported GValue type for property '%s'.", prop->name);
    }
}

static void reallocNodeProperty(gpointer key, gpointer value, gpointer data)
{
  EleArr *ele;
  VisuNodeProperty *prop;
  guint iEle, j;
  VisuNodeArrayPrivate *priv;

  iEle = (guint)GPOINTER_TO_INT(data);
  prop = (VisuNodeProperty*)value;
  DBG_fprintf(stderr, "Visu Node: realloc node property '%s' for element %d.\n",
	      (gchar*)key, iEle);

  priv = visu_node_array_get_instance_private(prop->array);
  g_return_if_fail(priv && iEle < priv->elements->len);

  ele = _getEleArr(priv, iEle);
  switch (prop->gtype)
    {
    case G_TYPE_POINTER:
      prop->data_pointer[iEle] = g_realloc(prop->data_pointer[iEle],
					   sizeof(gpointer) * ele->nNodes);
      /* We nullify the newly created properties. */
      for (j = ele->nStoredNodes; j < ele->nNodes; j++)
	prop->data_pointer[iEle][j] = (gpointer)0;
      break;
    case G_TYPE_INT:
      prop->data_int[iEle] = g_realloc(prop->data_int[iEle],
				       sizeof(int) * ele->nNodes);
      /* We nullify the newly created properties. */
      for (j = ele->nStoredNodes; j < ele->nNodes; j++)
	prop->data_int[iEle][j] = 0;
      break;
    default:
      g_warning("Unsupported GValue type for property '%s'.", prop->name);
    }
}

static void allocateNodeProp(gpointer key, gpointer value, gpointer data _U_)
{
  guint i;
  VisuNodeProperty *prop;
  VisuNodeArrayPrivate *priv;

  prop = (VisuNodeProperty*)value;
  DBG_fprintf(stderr, "Visu Node: realloc node property '%s' for 1 new element.\n",
	      (gchar*)key);

  priv = visu_node_array_get_instance_private(prop->array);
  g_return_if_fail(priv);
  switch (prop->gtype)
    {
    case G_TYPE_POINTER:
      prop->data_pointer =
        g_realloc(prop->data_pointer, sizeof(gpointer*) * priv->elements->len);
      i = priv->elements->len - 1;
      prop->data_pointer[i] = g_malloc0(sizeof(gpointer) * _getEleArr(priv, i)->nNodes);
      break;
    case G_TYPE_INT:
      prop->data_int =
        g_realloc(prop->data_int, sizeof(int*) * priv->elements->len);
      i = priv->elements->len - 1;
      prop->data_int[i] = g_malloc0(sizeof(int) * _getEleArr(priv, i)->nNodes);
      break;
    default:
      g_warning("Unsupported GValue type for property '%s'.", prop->name);
    }
}

static void createNodeproperty(gpointer key, gpointer value, gpointer data)
{
  VisuNodeProperty *prop;
  struct twoNodes *nodes;

  prop = (VisuNodeProperty*)value;
  nodes = (struct twoNodes*)data;
  DBG_fprintf(stderr, "Visu Node: create/copy node property '%s' for node %d-%d.\n",
	      (gchar*)key, nodes->newNode->posElement, nodes->newNode->posNode);

  switch (prop->gtype)
    {
    case G_TYPE_POINTER:
      if (nodes->oldNode)
	prop->data_pointer[nodes->newNode->posElement][nodes->newNode->posNode] =
	  prop->newOrCopyTokenFunc((gconstpointer)prop->data_pointer[nodes->oldNode->posElement][nodes->oldNode->posNode], prop->user_data);
      else
	prop->data_pointer[nodes->newNode->posElement][nodes->newNode->posNode] =
          (gpointer)0;
      break;
    case G_TYPE_INT:
      if (nodes->oldNode)
	prop->data_int[nodes->newNode->posElement][nodes->newNode->posNode] =
	  prop->data_int[nodes->oldNode->posElement][nodes->oldNode->posNode];
      else
	prop->data_int[nodes->newNode->posElement][nodes->newNode->posNode] = 0;
      break;
    default:
      g_warning("Unsupported GValue type for property '%s'.", prop->name);
    }
}
/*****************************/
/* Public property routines. */
/*****************************/

/**
 * visu_node_property_getArray:
 * @nodeProp: a #VisuNodeProperty structure.
 *
 * Retrieve the #VisuNodeArray @nodeProp is attached to.
 *
 * Since: 3.8
 *
 * Returns: (transfer none): the #VisuNodeArray @nodeProp is attached to.
 **/
VisuNodeArray* visu_node_property_getArray(const VisuNodeProperty* nodeProp)
{
  g_return_val_if_fail(nodeProp, (VisuNodeArray*)0);
  return nodeProp->array;
}
/**
 * visu_node_property_setValue:
 * @nodeProp: a #VisuNodeProperty object ;
 * @node: a #VisuNode object ;
 * @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 can be retrieved with the visu_node_property_getValue() method.
 *
 * See visu_node_array_getProperty() to get a property by its name.
 */
void visu_node_property_setValue(VisuNodeProperty* nodeProp,
                                 const VisuNode* node, const GValue *value)
{
  float fval;
  VisuNodeArrayPrivate *priv;

  g_return_if_fail(nodeProp && value);
  priv = visu_node_array_get_instance_private(nodeProp->array);
  g_return_if_fail(priv && node && node->posElement < priv->elements->len &&
		   node->posNode < _getEleArr(priv, node->posElement)->nStoredNodes);

  switch (nodeProp->gtype)
    {
    case G_TYPE_POINTER:
      /* Quick return if in place. */
      if (G_VALUE_HOLDS_BOXED(value) && g_value_get_boxed(value) ==
          nodeProp->data_pointer[node->posElement][node->posNode])
        return;
      if (G_VALUE_HOLDS_POINTER(value) && g_value_get_pointer(value) ==
          nodeProp->data_pointer[node->posElement][node->posNode])
        return;
      /* We free previous pointer. */
      if (nodeProp->freeTokenFunc && nodeProp->data_pointer[node->posElement][node->posNode])
	nodeProp->freeTokenFunc(nodeProp->data_pointer[node->posElement][node->posNode],
				nodeProp->user_data);
      else
	g_free(nodeProp->data_pointer[node->posElement][node->posNode]);
      /* We set the value. */
      if (G_VALUE_HOLDS_STRING(value))
        nodeProp->data_pointer[node->posElement][node->posNode] =
          nodeProp->newOrCopyTokenFunc((gpointer)g_value_get_string(value), nodeProp->user_data);
      else if (G_VALUE_HOLDS_FLOAT(value))
        {
          fval = g_value_get_float(value);
          nodeProp->data_pointer[node->posElement][node->posNode] =
            nodeProp->newOrCopyTokenFunc(&fval, nodeProp->user_data);
        }
      else if (G_VALUE_HOLDS_BOXED(value))
        nodeProp->data_pointer[node->posElement][node->posNode] =
          nodeProp->newOrCopyTokenFunc(g_value_get_boxed(value), nodeProp->user_data);
      else
        nodeProp->data_pointer[node->posElement][node->posNode] =
          nodeProp->newOrCopyTokenFunc(g_value_get_pointer(value), nodeProp->user_data);
      break;
    case G_TYPE_INT:
      if (G_VALUE_HOLDS_BOOLEAN(value))
        nodeProp->data_int[node->posElement][node->posNode] =
          (int)g_value_get_boolean(value);
      else
        nodeProp->data_int[node->posElement][node->posNode] = g_value_get_int(value);
      break;
    default:
      g_warning("Unsupported GValue type for property '%s'.", nodeProp->name);
    }
}

/**
 * visu_node_property_getValue:
 * @nodeProp: a #VisuNodeArray object ;
 * @node: a #VisuNode object ;
 * @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.
 */
GValue* visu_node_property_getValue(const VisuNodeProperty* nodeProp,
                                    const VisuNode* node,
                                    GValue *value)
{
  VisuNodeArrayPrivate *priv = visu_node_array_get_instance_private(nodeProp->array);
  g_return_val_if_fail(priv, value);
  g_return_val_if_fail(nodeProp && value, value);
  g_return_val_if_fail(node &&
                       node->posElement < priv->elements->len &&
		       node->posNode < _getEleArr(priv, node->posElement)->nStoredNodes, value);

  switch (nodeProp->gtype)
    {
    case G_TYPE_POINTER:
      if (G_VALUE_HOLDS_STRING(value))
        g_value_set_string(value, (gchar*)nodeProp->data_pointer[node->posElement][node->posNode]);
      else if (G_VALUE_HOLDS_BOXED(value))
        g_value_set_static_boxed(value, nodeProp->data_pointer[node->posElement][node->posNode]);
      else
        {
          DBG_fprintf(stderr, "Visu Node: get '%s' for node %d(%d,%d) as pointer %p.\n",
                      nodeProp->name, node->number, node->posElement, node->posNode,
                      (gpointer)nodeProp->data_pointer[node->posElement][node->posNode]);
          g_value_set_pointer(value, nodeProp->data_pointer[node->posElement][node->posNode]);
        }
      return value;
    case G_TYPE_INT:
      if (G_VALUE_HOLDS_POINTER(value))
        {
          DBG_fprintf(stderr, "Visu Node: get property '%s' for node %d as pointer %d.\n",
                      nodeProp->name, node->number,
                      nodeProp->data_int[node->posElement][node->posNode]);
          g_value_set_pointer(value, &nodeProp->data_int[node->posElement][node->posNode]);
        }
      else if (G_VALUE_HOLDS_BOOLEAN(value))
        g_value_set_boolean(value, (gboolean)nodeProp->data_int[node->posElement][node->posNode]);
      else
        {
          DBG_fprintf(stderr, "Visu Node: get property '%s' for node %d as integer %d.\n",
                      nodeProp->name, node->number,
                      nodeProp->data_int[node->posElement][node->posNode]);
          g_value_set_int(value, nodeProp->data_int[node->posElement][node->posNode]);
        }
      return value;
      break;
    default:
      g_warning("Unsupported GValue type for property '%s'.", nodeProp->name);
    }
  return value;
}

/**
 * visu_node_array_getProperty:
 * @nodeArray: a #VisuNodeArray object ;
 * @key: a string.
 *
 * This method is used to retrieve the node property associated to the given @key.
 *
 * Returns: (transfer none): a #VisuNodeProperty.
 */
VisuNodeProperty* visu_node_array_getProperty(VisuNodeArray* nodeArray, const char* key)
{
  VisuNodeProperty *prop;
  VisuNodeArrayPrivate *priv = visu_node_array_get_instance_private(nodeArray);

  g_return_val_if_fail(priv && key, (VisuNodeProperty*)0);

  prop = (VisuNodeProperty*)g_hash_table_lookup(priv->nodeProp, (gpointer)key);
  return prop;
}

/**
 * visu_node_array_freeProperty:
 * @nodeArray: a #VisuNodeArray object.
 * @key: the name of the property to be removed.
 * 
 * This method free the given property and all associated data.
 */
void visu_node_array_freeProperty(VisuNodeArray* nodeArray, const char* key)
{
  VisuNodeArrayPrivate *priv = visu_node_array_get_instance_private(nodeArray);
  g_return_if_fail(priv && key);

  g_hash_table_remove(priv->nodeProp, key);
  DBG_fprintf(stderr, "Visu Node: removing the property called '%s'.\n", key);
}

/**
 * visu_node_array_property_newPointer:
 * @nodeArray: a #VisuNodeArray object ;
 * @key: a string ;
 * @freeFunc: (allow-none) (scope call): a method to free each token (can be NULL).
 * @newAndCopyFunc: (scope call): a method to create or copy each token.
 * @user_data: (closure): a user defined pointer that will be given to
 * the free and copy routine.
 * 
 * This method creates and allocates a new area to store nodes associated data that
 * can be retrieve with the @key. These data are pointers on allocated memory
 * locations. When the property is removed with the #visu_node_freePropertry (or the
 * associated #VisuNodeArray is free) the area is free and @freeFunc is called for
 * each token (or g_free() if @freeFunc is NULL).
 *
 * The method @newAndCopyFunc is used when the number of nodes is increased,
 * if the const gpointer of the GCopyFunc is not NULL, then we require a copy,
 * if it is NULL, then the routine must create a new token with
 * default values.
 *
 * If the property already exists, it is returned.
 *
 * Returns: (transfer none): the newly created #VisuNodeProperty
 * object or the existing one.
 */
VisuNodeProperty* visu_node_array_property_newPointer(VisuNodeArray* nodeArray,
					      const char* key, 
					      GFunc freeFunc,
					      GCopyFunc newAndCopyFunc,
					      gpointer user_data)
{
  VisuNodeProperty *prop;
  EleArr *ele;
  VisuNodeArrayPrivate *priv = visu_node_array_get_instance_private(nodeArray);
  guint i;
  
  g_return_val_if_fail(priv && key && newAndCopyFunc, (VisuNodeProperty*)0);

  prop = (VisuNodeProperty*)g_hash_table_lookup(priv->nodeProp, key);
  if (prop)
    return prop;

  DBG_fprintf(stderr, "Visu Node: adding a new pointer"
	      " property, called '%s'.\n", key);
  prop                = g_malloc(sizeof(VisuNodeProperty));
  prop->gtype         = G_TYPE_POINTER;
  prop->name          = g_strdup(key);
  prop->array         = nodeArray;
  prop->data_pointer  = (gpointer**)0;
  prop->data_int      = (int**)0;
  if (priv->elements->len > 0)
    prop->data_pointer  = g_malloc(sizeof(gpointer*) * priv->elements->len);
  for (i = 0; i < priv->elements->len; i++)
    {
      ele = _getEleArr(priv, i);
      DBG_fprintf(stderr, " | allocate (%d,%d)\n", i, ele->nNodes);
      prop->data_pointer[i] = g_malloc0(sizeof(gpointer) * ele->nNodes);
    }
  prop->freeTokenFunc      = freeFunc;
  prop->newOrCopyTokenFunc = newAndCopyFunc;
  prop->user_data          = user_data;
  g_hash_table_insert(priv->nodeProp, (gpointer)key, (gpointer)prop);
  
  return prop;
}

static void freeFloatArray(gpointer obj, gpointer data)
{
#if GLIB_MINOR_VERSION > 9
  g_slice_free1(sizeof(float) * GPOINTER_TO_INT(data), obj);
#else
  if (GPOINTER_TO_INT(data) > 0)
    g_free(obj);
#endif
}
static gpointer newAndCopyFloatArray(gconstpointer orig, gpointer user_data)
{
  float *data;
  int nb;

  if (!orig)
    return (gpointer)0;
  
  nb = GPOINTER_TO_INT(user_data);
#if GLIB_MINOR_VERSION > 9
  data = g_slice_alloc(sizeof(float) * nb);
#else
  data = g_malloc(sizeof(float) * nb);
#endif
  if (orig)
    memcpy(data, orig, sizeof(float) * nb);
  else
    memset(data, 0, sizeof(float) * nb);

  return (gpointer)data;
}

/**
 * visu_node_array_property_newFloatArray:
 * @nodeArray: a #VisuNodeArray object ;
 * @key: a string ;
 * @len: the number of floats to be stored per node.
 * 
 * This method creates and allocates a new area to store nodes associated data that
 * can be retrieve with the @key. These data are constant float arrays
 * of length @len.
 *
 * If the property already exists, it is returned.
 *
 * Since: 3.8
 *
 * Returns: (transfer none): the newly created #VisuNodeProperty
 * object or the existing one.
 */
VisuNodeProperty* visu_node_array_property_newFloatArray(VisuNodeArray* nodeArray,
                                                         const char* key, guint len)
{
  VisuNodeProperty *prop;
  EleArr *ele;
  VisuNodeArrayPrivate *priv = visu_node_array_get_instance_private(nodeArray);
  guint i;
  
  g_return_val_if_fail(priv && key && len > 0, (VisuNodeProperty*)0);

  prop = (VisuNodeProperty*)g_hash_table_lookup(priv->nodeProp, key);
  if (prop)
    return prop;

  DBG_fprintf(stderr, "Visu Node: adding a new float array"
	      " property, called '%s'.\n", key);
  prop                = g_malloc(sizeof(VisuNodeProperty));
  prop->gtype         = G_TYPE_POINTER;
  prop->name          = g_strdup(key);
  prop->array         = nodeArray;
  prop->data_pointer  = (gpointer**)0;
  prop->data_int      = (int**)0;
  if (priv->elements->len > 0)
    prop->data_pointer  = g_malloc(sizeof(gpointer*) * priv->elements->len);
  for (i = 0; i < priv->elements->len; i++)
    {
      ele = _getEleArr(priv, i);
      DBG_fprintf(stderr, " | allocate (%d,%d)\n", i, ele->nNodes);
      prop->data_pointer[i] = g_malloc0(sizeof(gpointer) * ele->nNodes);
    }
  prop->freeTokenFunc      = freeFloatArray;
  prop->newOrCopyTokenFunc = newAndCopyFloatArray;
  prop->user_data          = GINT_TO_POINTER(len);
  g_hash_table_insert(priv->nodeProp, (gpointer)key, (gpointer)prop);
  
  return prop;
}

/**
 * visu_node_array_property_newInteger:
 * @nodeArray: a #VisuNodeArray object ;
 * @key: a string.
 * 
 * This method creates and allocates a new area to store nodes associated integer
 * values. This is the same than visu_node_array_property_newPointer() but for static
 * integers instead of pointers as data.
 *
 * Returns: (transfer none): the newly created #VisuNodeProperty object.
 */
VisuNodeProperty* visu_node_array_property_newInteger(VisuNodeArray* nodeArray,
					  const char* key)
{
  VisuNodeProperty *prop;
  EleArr *ele;
  VisuNodeArrayPrivate *priv = visu_node_array_get_instance_private(nodeArray);
  guint i;
  
  g_return_val_if_fail(priv && key, (VisuNodeProperty*)0);

  prop = (VisuNodeProperty*)g_hash_table_lookup(priv->nodeProp, key);
  if (prop)
    return prop;

  DBG_fprintf(stderr, "Visu Node: adding a new int property, called '%s'.\n", key);
  prop                = g_malloc(sizeof(VisuNodeProperty));
  prop->gtype         = G_TYPE_INT;
  prop->name          = g_strdup(key);
  prop->array         = nodeArray;
  prop->data_pointer  = (gpointer**)0;
  prop->data_int      = (int**)0;
  if (priv->elements->len > 0)
    prop->data_int      = g_malloc(sizeof(int*) * priv->elements->len);
  for (i = 0; i < priv->elements->len; i++)
    {
      ele = _getEleArr(priv, i);
      DBG_fprintf(stderr, " | allocate (%d,%d)\n", i, ele->nNodes);
      prop->data_int[i] = g_malloc0(sizeof(int) * ele->nNodes);
    }
  prop->freeTokenFunc      = (GFunc)0;
  prop->newOrCopyTokenFunc = (GCopyFunc)0;
  prop->user_data          = (gpointer)0;
  g_hash_table_insert(priv->nodeProp, (gpointer)key, (gpointer)prop);
  
  return prop;
}
/**
 * visu_node_property_reset:
 * @prop: A #VisuNodeProperty object.
 *
 * Reset to zero all values, deallocating allocated memory, if any.
 *
 * Since: 3.8
 **/
void visu_node_property_reset(VisuNodeProperty* prop)
{
  guint i, j;
  EleArr *ele;
  VisuNodeArrayPrivate *priv = visu_node_array_get_instance_private(prop->array);

  g_return_if_fail(prop && priv);

  switch (prop->gtype)
    {
    case G_TYPE_POINTER:
      for (i = 0; i < priv->elements->len; i++)
        {
          ele = _getEleArr(priv, i);      
          if (prop->freeTokenFunc)
            for (j = 0; j < ele->nNodes; j++)
              if (prop->data_pointer[i][j])
                prop->freeTokenFunc(prop->data_pointer[i][j], prop->user_data);
          memset(prop->data_pointer[i], '\0', sizeof(gpointer) * ele->nNodes);
        }
      break;
    case G_TYPE_INT:
      for (i = 0; i < priv->elements->len; i++)
        {
          ele = _getEleArr(priv, i);      
          memset(prop->data_int[i], '\0', sizeof(int) * ele->nNodes);
        }
      break;
    default:
      g_warning("Unsupported type for property '%s'.", prop->name);
    }
}

/**
 * visu_node_array_traceProperty:
 * @array: a #VisuNodeArray object ;
 * @id: a property name.
 *
 * This is a debug method. It outputs on stderr the values for all
 * nodes of the property @id.
 */
void visu_node_array_traceProperty(VisuNodeArray *array, const gchar *id)
{
  VisuNodeProperty* prop;
  EleArr *ele;
  guint i, j;
  VisuNodeArrayPrivate *priv = visu_node_array_get_instance_private(array);
  
  prop = visu_node_array_getProperty(array, id);
  
  fprintf(stderr, "Visu Node: output node property '%s'.\n", id);
  fprintf(stderr, " | type= %d\n", (int)prop->gtype);
  g_return_if_fail(priv);
  if (prop->data_int)
    {
      for (i = 0; i < priv->elements->len; i++)
	for (ele = _getEleArr(priv, i), j = 0; j < ele->nStoredNodes; j++)
	  fprintf(stderr, " | %7d %3d %7d -> %d\n", ele->nodes[j].number,
		  i, j, prop->data_int[i][j]);
    }
  if (prop->data_pointer)
    {
      for (i = 0; i < priv->elements->len; i++)
	for (ele = _getEleArr(priv, i), j = 0; j < ele->nStoredNodes; j++)
	  fprintf(stderr, " | %7d %3d %7d -> %p\n", ele->nodes[j].number,
		  i, j, prop->data_pointer[i][j]);
    }
}

/**********************/
/* Element properties */
/**********************/
static void allocateEleProp(gpointer key, gpointer value, gpointer data)
{
  struct _ElementProperty *prop = (struct _ElementProperty*)value;
  VisuElement *ele = VISU_ELEMENT(data);
  GValue val = G_VALUE_INIT;

  DBG_fprintf(stderr, "Visu Data: allocate element property '%s'.\n", (gchar*)key);
  prop->init(ele, &val);
  g_array_append_val(prop->array, val);
  DBG_fprintf(stderr, " | now has %d elements.\n", prop->array->len);
}
/* static void freeEleProp(gpointer key, gpointer value, gpointer data _U_) */
/* { */
/*   struct _ElementProperty *prop = (struct _ElementProperty*)value; */
/*   gint i; */

/*   DBG_fprintf(stderr, "Visu Data: free element property '%s'.\n", (gchar*)key); */
/*   for (i = prop->array->priv->n_values - 1; i >= 0; i--) */
/*     g_value_array_remove(prop->array, i); */
/* } */
static void freeElePropStruct(gpointer data)
{
  struct _ElementProperty *prop = (struct _ElementProperty*)data;

  g_array_free(prop->array, TRUE);
  g_free(data);
}
/**
 * visu_node_array_setElementProperty:
 * @data: a #VisuNodeArray object.
 * @name: a string to identify the property.
 * @init: (scope call): an init routine.
 *
 * Create a new array to stores properties related to elements. If the
 * property @name already exists the previous one is destroyed. The
 * @init routine is called for each #VisuElement of the @data.
 *
 * Since: 3.7
 *
 * Returns: (transfer none) (element-type GLib.Value): a newly allocated array.
 **/
GArray* visu_node_array_setElementProperty(VisuNodeArray *data, const gchar *name,
                                           VisuNodeArrayElementPropertyInit init)
{
  struct _ElementProperty *prop;
  guint i;
  GValue val = G_VALUE_INIT;
  VisuNodeArrayPrivate *priv = visu_node_array_get_instance_private(data);

  g_return_val_if_fail(priv, (GArray*)0);
  g_return_val_if_fail(name && name[0] && init, (GArray*)0);

  DBG_fprintf(stderr, "Visu Data: add a new element property '%s'.\n", name);
  prop        = g_malloc(sizeof(struct _ElementProperty));
  prop->init  = init;
  prop->array = g_array_sized_new(FALSE, FALSE, sizeof(GValue), priv->elements->len);
  g_hash_table_insert(priv->eleProp, (gpointer)name, (gpointer)prop);
  for (i = 0; i < priv->elements->len; i++)
    {
      memset(&val, '\0', sizeof(GValue));
      init(_getElement(priv, i), &val);
      g_array_insert_val(prop->array, i, val);
    }

  return prop->array;
}
/**
 * visu_node_array_getElementProperty:
 * @data: a #VisuNodeArray object ;
 * @name: an identifier string.
 *
 * This routine is used to retrieve an array of #GValue for each
 * element of the @data array.
 *
 * Since: 3.7
 *
 * Returns: (transfer none) (element-type GLib.Value): an array of #GValue, indexed by the id of
 * each #VisuElement of @data.
 */
GArray* visu_node_array_getElementProperty(VisuNodeArray *data, const gchar *name)
{
  struct _ElementProperty *prop;
  VisuNodeArrayPrivate *priv = visu_node_array_get_instance_private(data);

  g_return_val_if_fail(priv, (GArray*)0);

  DBG_fprintf(stderr, "Visu Data: get element property '%s'.\n", name);
  prop = (struct _ElementProperty*)g_hash_table_lookup(priv->eleProp, name);
  return prop ? prop->array : (GArray*)0;
}

/****************/
/* The iterator */
/****************/

/**
 * visu_node_array_iter_new:
 * @array: a #VisuNodeArray object ;
 * @iter: (out caller-allocates) (transfer full): an alocated iterator.
 *
 * Set values to a #VisuNodeArrayIter object to iterate over nodes.
 * Its contain is initialised with the array size (number of elements,
 * number of nodes per element...).
 */
void visu_node_array_iter_new(VisuNodeArray *array, VisuNodeArrayIter *iter)
{
  VisuNodeArrayPrivate *priv = visu_node_array_get_instance_private(array);
  g_return_if_fail(iter && priv);

  iter->nAllStoredNodes = 0;
  iter->nElements       = 0;
  iter->nStoredNodes    = 0;
  iter->node            = (VisuNode*)0;
  iter->element         = (VisuElement*)0;
  iter->type            = ITER_NODES_BY_TYPE;
  iter->init            = FALSE;

  g_return_if_fail(VISU_IS_NODE_ARRAY(array));

  iter->array           = array;
  iter->idMax           = priv->nodeTable.idCounter - 1;
  iter->nAllStoredNodes = priv->nodeTable.nStoredNodes;
  iter->nElements       = priv->elements->len;
  iter->iElement        = -1;
  iter->itLst           = (GList*)0;
  iter->arr             = (GArray*)0;

  g_return_if_fail(priv->nodeTable.idCounter >= priv->nodeTable.nStoredNodes);
}

/**
 * visu_node_array_iterStart:
 * @array: a #VisuNodeArray object ;
 * @iter: a #VisuNodeArrayIter object.
 *
 * Initialise the node and element internal pointers for a run over the nodes.
 */
void visu_node_array_iterStart(VisuNodeArray *array, VisuNodeArrayIter *iter)
{
  EleArr *ele;
  VisuNodeArrayPrivate *priv = visu_node_array_get_instance_private(array);

  g_return_if_fail(priv && iter && array == iter->array);

  iter->init = TRUE;

  iter->iElement = -1;
  iter->node     = (VisuNode*)0;
  iter->element  = (VisuElement*)0;
  if (priv->elements->len == 0)
    return;

  ele = _getEleArr(priv, 0);
  iter->iElement = 0;
  iter->element  = ele->ele;
  /* We look for an element with stored nodes. */
  while (ele->nStoredNodes == 0)
    {
      iter->iElement += 1;
      if (iter->iElement >= priv->elements->len)
	{
	  /* We found nothing. */
	  iter->iElement = -1;
	  iter->element  = (VisuElement*)0;
	  return;
	}
      ele = _getEleArr(priv, iter->iElement);
      iter->element      = ele->ele;
      iter->nStoredNodes = ele->nStoredNodes;
    }

  iter->node         = ele->nodes;
  iter->nStoredNodes = ele->nStoredNodes;
}

/**
 * visu_node_array_iterStartNumber:
 * @array: a #VisuNodeArray object ;
 * @iter: a #VisuNodeArrayIter object.
 *
 * Initialise the node and element internal pointers for a run
 * following the node oder.
 */
void visu_node_array_iterStartNumber(VisuNodeArray *array, VisuNodeArrayIter *iter)
{
  guint i;
  VisuNodeArrayPrivate *priv = visu_node_array_get_instance_private(array);

  g_return_if_fail(priv && iter && array == iter->array);

  iter->init = TRUE;

  iter->iElement = -1;
  iter->node     = (VisuNode*)0;
  iter->element  = (VisuElement*)0;
  if (priv->elements->len == 0)
    return;

  i = 0;
  iter->node = (VisuNode*)0;
  do
    {
      iter->node = visu_node_array_getFromId(VISU_NODE_ARRAY(array), i);
      i += 1;
    }
  while (!iter->node && i < priv->nodeTable.idCounter);
  if (!iter->node)
    return;
  iter->iElement     = iter->node->posElement;
  iter->element      = _getElement(priv, iter->iElement);
  iter->nStoredNodes = _getEleArr(priv, iter->iElement)->nStoredNodes;
}

/**
 * visu_node_array_iterStartVisible:
 * @array: a #VisuNodeArray object ;
 * @iter: a #VisuNodeArrayIter object.
 *
 * Initialise the node and element internal pointers for a run over the 
 * visible nodes (see visu_node_array_iterNextVisible).
 */
void visu_node_array_iterStartVisible(VisuNodeArray *array, VisuNodeArrayIter *iter)
{
  visu_node_array_iterStart(array, iter);
  if (iter->node && iter->node->rendered && visu_element_getRendered(iter->element))
    /* Ok, first is good. */
    return;

  /* First was not visible, we go next. */
  visu_node_array_iterNextVisible(array, iter);
}

/**
 * visu_node_array_iterStartList:
 * @array: a #VisuNodeArray object ;
 * @iter: (out caller-allocates) (transfer full): an alocated
 * iterator.
 * @lst: (element-type guint) (transfer none): a list of node ids to
 * iterate on.
 *
 * Set values to a #VisuNodeArrayIter object to iterate over nodes of
 * the given list.
 *
 * Since: 3.7
 */
void visu_node_array_iterStartList(VisuNodeArray *array, VisuNodeArrayIter *iter, GList *lst)
{
  GList init;

  g_return_if_fail(iter);

  iter->init = TRUE;
  iter->type = ITER_NODES_FROM_LIST;
  init.next = lst;
  iter->itLst = &init;
  visu_node_array_iterNextList(array, iter);
}
/**
 * visu_node_array_iterStartArray:
 * @array: a #VisuNodeArray object ;
 * @iter: (out caller-allocates) (transfer full): an alocated
 * iterator.
 * @arr: (element-type guint) (transfer full): an array of node ids to
 * iterate on.
 *
 * Set values to a #VisuNodeArrayIter object to iterate over nodes of
 * the given array.
 *
 * Since: 3.8
 */
void visu_node_array_iterStartArray(VisuNodeArray *array, VisuNodeArrayIter *iter,
                                    GArray *arr)
{
  g_return_if_fail(iter);

  iter->init = TRUE;
  iter->type = ITER_NODES_FROM_ARRAY;
  iter->arr = arr;
  iter->itArr = 0;
  visu_node_array_iterNextArray(array, iter);
}
/**
 * visu_node_array_iterWhere:
 * @array: a #VisuNodeArray object ;
 * @iter: (out caller-allocates) (transfer full): an alocated
 * iterator.
 * @where: (closure data) (scope call): the function to evaluate on
 * each node.
 * @data: (closure) (allow-none): user data.
 *
 * Starts @iter to iterate on nodes of @array, when the condition
 * defined by @where evaluates to TRUE. @iter is then to be used with
 * visu_node_array_iterNextArray().
 *
 * Since: 3.8
 **/
void visu_node_array_iterWhere(VisuNodeArray *array, VisuNodeArrayIter *iter,
                               VisuNodeArrayIterFunc where, gpointer data)
{
  GArray *arr;
  VisuNodeArrayIter it;

  g_return_if_fail(where);

  arr = g_array_new(FALSE, FALSE, sizeof(guint));

  visu_node_array_iter_new(array, &it);
  for (visu_node_array_iterStart(array, &it);
       it.node;
       visu_node_array_iterNext(array, &it))
    if (where(array, &it, data))
      g_array_append_val(arr, it.node->number);

  visu_node_array_iter_new(array, iter);
  visu_node_array_iterStartArray(array, iter, arr);
}

/**
 * visu_node_array_iterRestartNode:
 * @array: a #VisuNodeArray object ;
 * @iter: a #VisuNodeArrayIter object.
 *
 * The element internal pointer must be associated. Then, it returns the
 * node pointer to the first node for this element.
 */
void visu_node_array_iterRestartNode(VisuNodeArray *array, VisuNodeArrayIter *iter)
{
  gint iEle;
  EleArr *ele;
  VisuNodeArrayPrivate *priv = visu_node_array_get_instance_private(array);

  g_return_if_fail(priv && iter && array == iter->array);

  iEle = visu_node_array_getElementId(array, iter->element);
  g_return_if_fail(iEle >= 0);

  iter->init = TRUE;
  iter->iElement = (guint)iEle;
  ele = _getEleArr(priv, iEle);
  if (ele->nStoredNodes)
    iter->node = ele->nodes;
  else
    iter->node = (VisuNode*)0;
  iter->nStoredNodes = ele->nStoredNodes;
}

/**
 * visu_node_array_iterNext:
 * @array: a #VisuNodeArray object ;
 * @iter: a #VisuNodeArrayIter object.
 *
 * Modify node and element internal pointers to the next node, or NULL if
 * none remains.
 */
void visu_node_array_iterNext(VisuNodeArray *array, VisuNodeArrayIter *iter)
{
  guint iNode;
  EleArr *ele;
  VisuNodeArrayPrivate *priv = visu_node_array_get_instance_private(array);

  g_return_if_fail(priv && iter && array == iter->array);
  g_return_if_fail(iter->init && iter->node && iter->iElement == iter->node->posElement);

  ele = _getEleArr(priv, iter->iElement);
  iNode = iter->node->posNode + 1;
  if (iNode < ele->nStoredNodes)
    iter->node = ele->nodes + iNode;
  else
    {
      iter->iElement += 1;
      if (iter->iElement >= priv->elements->len)
        {
          iter->node     = (VisuNode*)0;
          iter->iElement = -1;
          iter->element  = (VisuElement*)0;
          iter->nStoredNodes = 0;
        }
      else
        {
          ele = _getEleArr(priv, iter->iElement);
          iter->node     = ele->nodes;
          iter->element  = ele->ele;
          iter->nStoredNodes = ele->nStoredNodes;
        }
    }
}

/**
 * visu_node_array_iterNextList:
 * @array: a #VisuNodeArray object ;
 * @iter: a #VisuNodeArrayIter object.
 *
 * Modify node and element internal pointers to the next node from the
 * starting list, or NULL if none remains.
 *
 * Since: 3.7
 */
void visu_node_array_iterNextList(VisuNodeArray *array, VisuNodeArrayIter *iter)
{
  EleArr *ele;
  VisuNodeArrayPrivate *priv = visu_node_array_get_instance_private(array);

  g_return_if_fail(priv && iter && array == iter->array);
  g_return_if_fail(iter->init && iter->type == ITER_NODES_FROM_LIST);
  g_return_if_fail(iter->itLst);

  do
    {
      iter->itLst = g_list_next(iter->itLst);
      iter->node = (iter->itLst)?visu_node_array_getFromId(array, GPOINTER_TO_INT(iter->itLst->data)):(VisuNode*)0;
    }
  while (iter->itLst && !iter->node);
  if (!iter->itLst)
    {
      iter->itLst = (GList*)0;
      iter->node = (VisuNode*)0;
    }
  /* We set additional elements. */
  if (!iter->node)
    {
      iter->iElement = -1;
      iter->element  = (VisuElement*)0;
      iter->nStoredNodes = 0;
    }
  else
    {
      ele = _getEleArr(priv, iter->node->posElement);
      iter->iElement = iter->node->posElement;
      iter->element  = ele->ele;
      iter->nStoredNodes = ele->nStoredNodes;
    }
}

/**
 * visu_node_array_iterNextArray:
 * @array: a #VisuNodeArray object ;
 * @iter: a #VisuNodeArrayIter object.
 *
 * Modify node and element internal pointers to the next node from the
 * starting array, or NULL if none remains.
 *
 * Since: 3.8
 */
void visu_node_array_iterNextArray(VisuNodeArray *array, VisuNodeArrayIter *iter)
{
  EleArr *ele;
  VisuNodeArrayPrivate *priv = visu_node_array_get_instance_private(array);

  g_return_if_fail(priv && iter && array == iter->array);
  g_return_if_fail(iter->init && iter->type == ITER_NODES_FROM_ARRAY);

  if (iter->itArr < iter->arr->len)
    iter->node = visu_node_array_getFromId(array, g_array_index(iter->arr, guint, iter->itArr));
  else
    {
      iter->node = (VisuNode*)0;
      g_array_unref(iter->arr);
    }
  iter->itArr += 1;
  /* We set additional elements. */
  if (!iter->node)
    {
      iter->iElement = -1;
      iter->element  = (VisuElement*)0;
      iter->nStoredNodes = 0;
    }
  else
    {
      ele = _getEleArr(priv, iter->node->posElement);
      iter->iElement = iter->node->posElement;
      iter->element  = ele->ele;
      iter->nStoredNodes = ele->nStoredNodes;
    }
}

/**
 * visu_node_array_iterNextVisible:
 * @array: a #VisuNodeArray object ;
 * @iter: a #VisuNodeArrayIter object.
 *
 * Go to the next rendered node (changing element if required).
 */
void visu_node_array_iterNextVisible(VisuNodeArray *array, VisuNodeArrayIter *iter)
{
  g_return_if_fail(VISU_IS_NODE_ARRAY(array) && iter && array == iter->array);

  /* Get the next node, and test if it is rendered. */
  visu_node_array_iterNext(array, iter);
  if (!iter->node || (visu_element_getRendered(iter->element) && iter->node->rendered))
    return;

  /* From the current node, we go next to find one that is rendred. */
  for (; iter->element; visu_node_array_iterNextElement(array, iter, FALSE))
    if (visu_element_getRendered(iter->element))
      for (; iter->node; visu_node_array_iterNextNode(array, iter))
	if (iter->node->rendered)
	  return;
}

/**
 * visu_node_array_iterNextNode:
 * @array: a #VisuNodeArray object ;
 * @iter: a #VisuNodeArrayIter object.
 *
 * Modify node internal pointer to the next node, or NULL if
 * none remains. Contrary to visu_node_array_iterNext() it does not go to the
 * next element if one exists.
 */
void visu_node_array_iterNextNode(VisuNodeArray *array, VisuNodeArrayIter *iter)
{
  EleArr *ele;
  VisuNodeArrayPrivate *priv = visu_node_array_get_instance_private(array);

  g_return_if_fail(priv && iter && array == iter->array);
  g_return_if_fail(iter->init && iter->node);

  ele = _getEleArr(priv, iter->node->posElement);
  if (iter->node->posNode + 1 < ele->nStoredNodes)
    iter->node = iter->node + 1;
  else
    iter->node = (VisuNode*)0;
}
/**
 * visu_node_array_iterNextNodeOriginal:
 * @array: a #VisuNodeArray object ;
 * @iter: a #VisuNodeArrayIter object.
 *
 * Modify node internal pointer to the next original node, or NULL if
 * none remains. Contrary to visu_node_array_iterNext() it does not go to the
 * next element if one exists.
 *
 * Since: 3.6
 */
void visu_node_array_iterNextNodeOriginal(VisuNodeArray *array, VisuNodeArrayIter *iter)
{
  EleArr *ele;
  VisuNodeArrayPrivate *priv = visu_node_array_get_instance_private(array);

  g_return_if_fail(priv && iter && array == iter->array);
  g_return_if_fail(iter->init && iter->node);

  do
    {
      ele = _getEleArr(priv, iter->node->posElement);
      if (iter->node->posNode + 1 < ele->nStoredNodes)
	iter->node = iter->node + 1;
      else
	iter->node = (VisuNode*)0;
    }
  while (iter->node && visu_node_array_getOriginal(array, iter->node->number) >= 0);
}

/**
 * visu_node_array_iterNextNodeNumber:
 * @array: a #VisuNodeArray object ;
 * @iter: a #VisuNodeArrayIter object.
 *
 * Modify node internal pointer to the next node, increasing the id of
 * the current node. The element internal pointer is also updated
 * accordingly. If no more nodes exist after the given one, node and
 * element internal pointers are set to NULL.
 */
void visu_node_array_iterNextNodeNumber(VisuNodeArray *array, VisuNodeArrayIter *iter)
{
  guint i;
  EleArr *ele;
  VisuNodeArrayPrivate *priv = visu_node_array_get_instance_private(array);

  g_return_if_fail(priv && iter && array == iter->array);
  g_return_if_fail(iter->init && iter->node);

  for (i = iter->node->number + 1;
       !(iter->node = visu_node_array_getFromId(VISU_NODE_ARRAY(array), i)) &&
	 (i < priv->nodeTable.idCounter) ; i++);

  if (iter->node)
    {
      ele = _getEleArr(priv, iter->node->posElement);
      iter->iElement = iter->node->posElement;
      iter->element  = ele->ele;
      iter->nStoredNodes = ele->nStoredNodes;
    }
  else
    {
      iter->element = (VisuElement*)0;
      iter->nStoredNodes = 0;
    }
}

/**
 * visu_node_array_iterNextElement:
 * @array: a #VisuNodeArray object ;
 * @iter: a #VisuNodeArrayIter object ;
 * @allowEmpty: a boolean.
 *
 * Modify element internal pointer to the next element and set node
 * to the first one, or NULL if none remains. If @allowEmpty is TRUE,
 * this iterator may return an element with no nodes, otherwise, it
 * skips elements with no nodes.
 */
void visu_node_array_iterNextElement(VisuNodeArray *array, VisuNodeArrayIter *iter,
                                     gboolean allowEmpty)
{
  EleArr *ele;
  VisuNodeArrayPrivate *priv = visu_node_array_get_instance_private(array);

  g_return_if_fail(priv && iter && array == iter->array);
  g_return_if_fail(iter->init && iter->iElement < priv->elements->len);

  do
    iter->iElement += 1;
  while(iter->iElement < priv->elements->len &&
	(!allowEmpty && _getEleArr(priv, iter->iElement)->nStoredNodes == 0));

  if (iter->iElement == priv->elements->len)
    {
      iter->iElement = -1;
      iter->node     = (VisuNode*)0;
      iter->element  = (VisuElement*)0;
      iter->nStoredNodes = 0;
    }
  else
    {
      ele = _getEleArr(priv, iter->iElement);
      iter->node     = ele->nodes;
      iter->element  = ele->ele;
      iter->nStoredNodes = ele->nStoredNodes;
    }
}


/*************************************/
/* Additionnal routines for bindings */
/*************************************/

/**
 * visu_node_array_iter_next:
 * @iter: a #VisuNodeArrayIter object.
 *
 * Run the iterator to go to next item.
 *
 * Since: 3.6
 * 
 * Returns: TRUE if any item is found, FALSE otherwise.
 */
gboolean visu_node_array_iter_next(VisuNodeArrayIter *iter)
{
  if (!iter->init)
    switch (iter->type)
      {
      case ITER_NODES_BY_TYPE:
      case ITER_ELEMENTS:
	visu_node_array_iterStart(iter->array, iter);
	break;
      case ITER_NODES_BY_NUMBER:
      case ITER_NODES_ORIGINAL:
	visu_node_array_iterStartNumber(iter->array, iter);
	break;
      case ITER_NODES_VISIBLE:
	visu_node_array_iterStartVisible(iter->array, iter);
	break;
      case ITER_NODES_FOR_ELEMENT:
        visu_node_array_iterRestartNode(iter->array, iter);
        break;
      case ITER_NODES_FROM_LIST:
      case ITER_NODES_FROM_ARRAY:
        g_warning("nodes from list or array not handled.");
        break;
      }
  else
    switch (iter->type)
      {
      case ITER_NODES_BY_TYPE:
	visu_node_array_iterNext(iter->array, iter);
	break;
      case ITER_NODES_BY_NUMBER:
	visu_node_array_iterNextNodeNumber(iter->array, iter);
	break;
      case ITER_NODES_VISIBLE:
	visu_node_array_iterNextVisible(iter->array, iter);
	break;
      case ITER_NODES_ORIGINAL:
	visu_node_array_iterNextNodeOriginal(iter->array, iter);
	break;
      case ITER_NODES_FOR_ELEMENT:
        visu_node_array_iterNextNode(iter->array, iter);
        break;
      case ITER_NODES_FROM_LIST:
	visu_node_array_iterNextList(iter->array, iter);
	break;
      case ITER_NODES_FROM_ARRAY:
	visu_node_array_iterNextArray(iter->array, iter);
	break;
      case ITER_ELEMENTS:
	visu_node_array_iterNextElement(iter->array, iter, FALSE);
	break;
      }
  
  if (iter->node)
    return TRUE;
  else
    return FALSE;
}
/**
 * visu_node_array_iter_next2:
 * @iter1: a #VisuNodeArrayIter object.
 * @iter2: a #VisuNodeArrayIter object.
 *
 * Iterator to run on a pair of different nodes.
 *
 * Returns: TRUE if any item is found, FALSE otherwise.
 *
 * Since: 3.6
 */
gboolean visu_node_array_iter_next2(VisuNodeArrayIter *iter1, VisuNodeArrayIter *iter2)
{
  if (!iter1->init)
    {
      visu_node_array_iterStart(iter1->array, iter1);
      visu_node_array_iterStart(iter1->array, iter2);
    }
  else
    {
      if (!iter1->node)
        return FALSE;

      /* DBG_fprintf(stderr, "go next %p-%p ->", (gpointer)iter1->node, (gpointer)iter2->node); */
      visu_node_array_iterNext(iter1->array, iter2);
      if (!iter2->node ||
	  iter2->node->posElement > iter1->node->posElement ||
	  (iter2->node->posElement == iter1->node->posElement &&
	   iter2->node->posNode    >= iter1->node->posNode))
	{
	  visu_node_array_iterNext(iter1->array, iter1);
	  if (iter1->node)
	    visu_node_array_iterStart(iter1->array, iter2);
	  else
	    iter2->node = (VisuNode*)0;
	}
      /* DBG_fprintf(stderr, " %p-%p\n", (gpointer)iter1->node, (gpointer)iter2->node); */
    }

  if (!iter1->node && !iter2->node)
    return FALSE;
  else
    return TRUE;
}
