/*******************************************************************************
 * ALBERTA:  an Adaptive multi Level finite element toolbox using           
 *           Bisectioning refinement and Error control by Residual          
 *           Techniques for scientific Applications                         
 *                                                                          
 * file:     traverse_nr.c                                                  
 *                                                                          
 * description:                                                             
 *           nonrecursive mesh traversal, ?d common routines                
 *                                                                          
 *******************************************************************************
 *                                                                          
 *  authors:   Alfred Schmidt                                               
 *             Zentrum fuer Technomathematik                                
 *             Fachbereich 3 Mathematik/Informatik                          
 *             Univesitaet Bremen                                           
 *             Bibliothekstr. 2                                             
 *             D-28359 Bremen, Germany                                      
 *                                                                          
 *             Kunibert G. Siebert                                          
 *             Institut fuer Mathematik                                     
 *             Universitaet Augsburg                                        
 *             Universitaetsstr. 14                                         
 *             D-86159 Augsburg, Germany                                    
 *                                                                          
 *  http://www.mathematik.uni-freiburg.de/IAM/ALBERTA                       
 *                                                                          
 *  (c) by A. Schmidt and K.G. Siebert (1996-2003)                          
 *                                                                          
 ******************************************************************************/

#include "alberta_intern.h"
#include "alberta.h"

/*******************************************************************************
 *   List of static variables for stack-based traversal                     
 *******************************************************************************
 *   traverse_mesh:       saved pointer to current mesh                     
 *   traverse_level:      saved level from traverse_first() call            
 *   traverse_flags:      saved traverse flags for traversal                
 *   fill_flag:          saved fill flags for traversal                    
 *   traverse_mel:        current macro element during traversal            
 *   stack_size:          current stack size                                
 *   stack_used:          current level of hierarchy recursion              
 *   elinfo_stack:        el_info hierarchy                                 
 *   info_stack:          describe path through hierarchy tree              
 *                        =0: leaf of current hierarchy                     
 *                        =1: next element is child[0] of this one          
 *                        =2: next element is child[1] of this one          
 *   save_elinfo_stack:   backup for elinfo_stack during traverse_neighbour 
 *   save_info_stack:     backup for info_stack during traverse_neighbour   
 ******************************************************************************/

static TRAVERSE_STACK *free_stack = NULL;

TRAVERSE_STACK *get_traverse_stack(void)
{
  FUNCNAME("get_traverse_stack");
  TRAVERSE_STACK *stack;

  if (!free_stack)
    stack = MEM_CALLOC(1, TRAVERSE_STACK);
  else
  {
    stack = free_stack;
    free_stack = free_stack->next;
    stack->next = NULL;
  }
  stack->marker.pos = -1;

  return stack;
}


void free_traverse_stack(TRAVERSE_STACK *stack)
{
  FUNCNAME("free_traverse_stack");

  if (!stack) {
    ERROR("stack==NULL ???\n");
    return;
  }

  stack->next = free_stack;
  free_stack = stack;

  return;
}

/******************************************************************************/

void __AI_enlarge_traverse_stack(TRAVERSE_STACK *stack)
{
  FUNCNAME("__AI_enlarge_traverse_stack");
  int     i;
  int     new_stack_size = stack->stack_size + 10;

  stack->elinfo_stack = MEM_REALLOC(stack->elinfo_stack, stack->stack_size,
                                    new_stack_size, EL_INFO);
  if (stack->stack_size > 0)
    for (i=stack->stack_size; i<new_stack_size; i++)
      stack->elinfo_stack[i].fill_flag = stack->elinfo_stack[0].fill_flag;

  stack->info_stack = MEM_REALLOC(stack->info_stack, stack->stack_size,
                                  new_stack_size, U_CHAR);
  stack->save_elinfo_stack = MEM_REALLOC(stack->save_elinfo_stack,
                                         stack->stack_size,
                                         new_stack_size, EL_INFO);
  stack->save_info_stack   = MEM_REALLOC(stack->save_info_stack,
                                         stack->stack_size,
                                         new_stack_size, U_CHAR);

#if 0
  MSG("increase stack at %p from %d to %d\n", stack,
      stack->stack_size, new_stack_size);
  MSG("elinfo_stack      = %p\n", stack->elinfo_stack);
  MSG("info_stack        = %p\n", stack->info_stack);
  MSG("save_elinfo_stack = %p\n", stack->save_elinfo_stack);
  MSG("save_info_stack   = %p\n", stack->save_info_stack);
#endif

  stack->stack_size = new_stack_size;   
}

#include "traverse_nr_1d.c"
#if DIM_MAX > 1
#include "traverse_nr_2d.c"
#if DIM_MAX > 2
#include "traverse_nr_3d.c"
#endif
#endif

void clear_traverse_mark(TRAVERSE_STACK *stack)
{
  FUNCNAME("clear_traverse_mark");

  if (stack->marker.pos < 0) {
    return; /* no mark set */
  }

  stack->stack_used     = stack->marker.pos;
  stack->traverse_level = stack->marker.traverse_level;
  stack->traverse_flags = stack->marker.traverse_flags;
  stack->fill_flag      = stack->elinfo_stack[0].fill_flag;

  stack->marker.pos = -1; /* actually unmark */
}

/*******************************************************************************
 *                                                                          
 *   return next element in tree traversal, starting from current one       
 *                                                                          
 ******************************************************************************/

/* First the ancestor, then its children.
 *
 * Meaning of stack->info_stack[stack->stack_used]:
 *
 * It is just the number of the child to traverse next, or 2 if both
 * childs have already been traversed.
 */

static EL_INFO *traverse_every_el_preorder(TRAVERSE_STACK *stack)
{
  FUNCNAME("traverse_every_el_preorder");
  EL *el;
  int i;
 
  if (stack->stack_used == 0)   /* first call */
  {
    if (stack->traverse_mesh->n_macro_el == 0)  return NULL;
    stack->traverse_mel = stack->traverse_mesh->macro_els;

    stack->stack_used = 1;
    fill_macro_info(stack->traverse_mesh,
                    stack->traverse_mesh->macro_els,
                    stack->elinfo_stack+stack->stack_used);
    stack->info_stack[stack->stack_used] = 0;

    return stack->elinfo_stack+stack->stack_used;
  }
 
  el = stack->elinfo_stack[stack->stack_used].el;

  /* go up in tree until we can go down again */
  while ((stack->stack_used > 0) &&
	 ((stack->info_stack[stack->stack_used] >= 2) || (el->child[0]==NULL)))
  {
    stack->stack_used--;
    if (stack->marker.pos >= 0 && stack->marker.pos == stack->stack_used) {
      clear_traverse_mark(stack);
      return NULL;
    }
    el = stack->elinfo_stack[stack->stack_used].el;
  }


  /* goto next macro element */
  if (stack->stack_used < 1) {
    if (stack->traverse_mel == stack->traverse_mesh->macro_els +
        stack->traverse_mesh->n_macro_el - 1)
      return NULL;
    else
      stack->traverse_mel += 1;

    stack->stack_used = 1;
    fill_macro_info(stack->traverse_mesh,
                    stack->traverse_mel,
                    stack->elinfo_stack+stack->stack_used);
    stack->info_stack[stack->stack_used] = 0;

    return stack->elinfo_stack+stack->stack_used;
  }


  /* go down tree */

  if (stack->stack_used >= stack->stack_size-1)
    __AI_enlarge_traverse_stack(stack);

  i = stack->info_stack[stack->stack_used];
  stack->info_stack[stack->stack_used]++;
  fill_elinfo(i, stack->fill_flag, stack->elinfo_stack+stack->stack_used,
              stack->elinfo_stack+stack->stack_used+1);
  stack->stack_used++;

  DEBUG_TEST_EXIT(stack->stack_used < stack->stack_size,
		  "stack_size=%d too small, level=%d\n",
		  stack->stack_size, stack->elinfo_stack[stack->stack_used].level);

  stack->info_stack[stack->stack_used] = 0;
 
  return stack->elinfo_stack+stack->stack_used;
}

/* First the child 0, then the parent, then child 1
 *
 * Meaning of stack->info_stack[stack->stack_used]:
 *
 * 0: go further down
 * 1: child 0 has been handled
 * 2: parent has been handled
 * 3: child 1 has been handled
 */

static EL_INFO *traverse_every_el_inorder(TRAVERSE_STACK *stack)
{
  /* FUNCNAME("traverse_every_el_inorder"); */
  EL *el;
  int i;

  /*ERROR_EXIT("not yet implemented\n"); */
 
  if (stack->stack_used == 0)   /* first call */
  {
    if (stack->traverse_mesh->n_macro_el == 0)  return NULL;
    stack->traverse_mel = stack->traverse_mesh->macro_els;

    stack->stack_used = 1;
    fill_macro_info(stack->traverse_mesh,
                    stack->traverse_mesh->macro_els,
                    stack->elinfo_stack+stack->stack_used);
    stack->info_stack[stack->stack_used] = 0;
  }
 
  el = stack->elinfo_stack[stack->stack_used].el;

  /* go up in tree until we can go down again -- inorder !!! */
  while((stack->stack_used > 0) &&
        ((stack->info_stack[stack->stack_used] >= 3) || (el->child[0]==NULL)))
  {
    stack->stack_used--;
    if (stack->marker.pos >= 0&& stack->stack_used == stack->marker.pos) {
      clear_traverse_mark(stack);
      return NULL;
    }
    el = stack->elinfo_stack[stack->stack_used].el;
  }


  /* goto next macro element */
  if (stack->stack_used < 1) {
    if (stack->traverse_mel == stack->traverse_mesh->macro_els +
        stack->traverse_mesh->n_macro_el - 1)
      return NULL;
    else
      stack->traverse_mel += 1;

    stack->stack_used = 1;
    fill_macro_info(stack->traverse_mesh,
                    stack->traverse_mel,
                    stack->elinfo_stack+stack->stack_used);
    stack->info_stack[stack->stack_used] = 0;
  }

  /* go down tree */
  while((stack->elinfo_stack+stack->stack_used)->el->child[0]
        && (stack->info_stack[stack->stack_used] != 1)) {

    if (stack->stack_used >= stack->stack_size-1)
      __AI_enlarge_traverse_stack(stack);

    i = stack->info_stack[stack->stack_used] ? 1 : 0;
    stack->info_stack[stack->stack_used]++;
    fill_elinfo(i, stack->fill_flag, stack->elinfo_stack+stack->stack_used,
                stack->elinfo_stack+stack->stack_used+1);
    stack->stack_used++;
    stack->info_stack[stack->stack_used] = 0;
  }
 
  stack->info_stack[stack->stack_used]++; /* flag for in-order operation */

  return stack->elinfo_stack+stack->stack_used;
}

/* First the children, then their ancestor
 *
 * Meaning of stack->info_stack[stack->stack_used]:
 *
 * It is just the number of the child to traverse next, or 2 if both
 * childs have already been traversed, or 3 if both childs and the
 * parent have already been traversed.
 */
 
static EL_INFO *traverse_every_el_postorder(TRAVERSE_STACK *stack)
{
  FUNCNAME("traverse_every_el_postorder");
  EL *el;
  int i;

  INFO(0,2,"\n");

  if (stack->stack_used == 0) /* first call */
  {
    if (stack->traverse_mesh->n_macro_el == 0)  return NULL;
    stack->traverse_mel = stack->traverse_mesh->macro_els;

    stack->stack_used = 1;
    fill_macro_info(stack->traverse_mesh,
                    stack->traverse_mesh->macro_els,
                    stack->elinfo_stack+stack->stack_used);
    stack->info_stack[stack->stack_used] = 0;
  }
 
  el = stack->elinfo_stack[stack->stack_used].el;

  /* go up in tree until we can go down again -- postorder!!! */
  while((stack->stack_used > 0) &&
        ((stack->info_stack[stack->stack_used] >= 3) || (el->child[0]==NULL)))
  {
    stack->stack_used--;
    if (stack->marker.pos >= 0&& stack->stack_used == stack->marker.pos) {
      clear_traverse_mark(stack);
      return NULL;
    }
    el = stack->elinfo_stack[stack->stack_used].el;
  }


  /* goto next macro element */
  if (stack->stack_used < 1) {
    if (stack->traverse_mel == stack->traverse_mesh->macro_els +
        stack->traverse_mesh->n_macro_el - 1)
      return NULL;
    else
      stack->traverse_mel += 1;

    stack->stack_used = 1;
    fill_macro_info(stack->traverse_mesh,
                    stack->traverse_mel,
                    stack->elinfo_stack+stack->stack_used);
    stack->info_stack[stack->stack_used] = 0;
  }


  /* go down tree */

  while((stack->elinfo_stack+stack->stack_used)->el->child[0]
        && (stack->info_stack[stack->stack_used] < 2)) {

    if (stack->stack_used >= stack->stack_size-1)
      __AI_enlarge_traverse_stack(stack);

    i = stack->info_stack[stack->stack_used];
    stack->info_stack[stack->stack_used]++;
    fill_elinfo(i, stack->fill_flag, stack->elinfo_stack+stack->stack_used,
                stack->elinfo_stack+stack->stack_used+1);
    stack->stack_used++;
    stack->info_stack[stack->stack_used] = 0;
  }
 
  stack->info_stack[stack->stack_used]++; /* postorder!!! */

  return stack->elinfo_stack+stack->stack_used;
}

/* Traverse the leaf-elements.
 *
 * Meaning of stack->info_stack[stack->stack_used]:
 *
 * It is just the number of the child to traverse next, or 2 if both
 * childs have already been traversed.
 */
 
static EL_INFO *traverse_leaf_el(TRAVERSE_STACK *stack)
{
  FUNCNAME("traverse_leaf_el");
  EL *el;
  int i;
 
  if (stack->stack_used == 0) /* first call */
  {
    if (stack->traverse_mesh->n_macro_el == 0)  return NULL;
    stack->traverse_mel = stack->traverse_mesh->macro_els;

    stack->stack_used = 1;
    fill_macro_info(stack->traverse_mesh,
                    stack->traverse_mesh->macro_els,
                    stack->elinfo_stack+stack->stack_used);
    stack->info_stack[stack->stack_used] = 0;

    el = stack->elinfo_stack[stack->stack_used].el;
    if ((el == NULL) || (el->child[0] == NULL)) {
      return stack->elinfo_stack+stack->stack_used;
    }
  }
  else
  {
    el = stack->elinfo_stack[stack->stack_used].el;

    /* go up in tree until we can go down again */
    while ((stack->stack_used > 0) &&
	   ((stack->info_stack[stack->stack_used] >= 2) || (el->child[0] == NULL)))
    {
      stack->stack_used--;
      if (stack->marker.pos >= 0 && stack->stack_used == stack->marker.pos) {
	clear_traverse_mark(stack);
        return NULL;
      }
      el = stack->elinfo_stack[stack->stack_used].el;
    }

    /* goto next macro element */
    if (stack->stack_used < 1) {
      if (stack->traverse_mel == stack->traverse_mesh->macro_els +
          stack->traverse_mesh->n_macro_el - 1)
        return NULL;
      else
        stack->traverse_mel += 1;

      stack->stack_used = 1;
      fill_macro_info(stack->traverse_mesh,
                      stack->traverse_mel,
                      stack->elinfo_stack+stack->stack_used);
      stack->info_stack[stack->stack_used] = 0;

      el = stack->elinfo_stack[stack->stack_used].el;
      if ((el == NULL) || (el->child[0] == NULL)) {
        return stack->elinfo_stack+stack->stack_used;
      }
    }
  }

  /* go down tree until leaf */
  while (el->child[0])
  {
    if (stack->stack_used >= stack->stack_size-1)
      __AI_enlarge_traverse_stack(stack);
    i = stack->info_stack[stack->stack_used];
    el = el->child[i];
    stack->info_stack[stack->stack_used]++;
    fill_elinfo(i, stack->fill_flag, stack->elinfo_stack+stack->stack_used,
                stack->elinfo_stack+stack->stack_used+1);
    stack->stack_used++;
   

    DEBUG_TEST_EXIT(stack->stack_used < stack->stack_size,
		    "stack_size=%d too small, level=(%d,%d)\n",
		    stack->stack_size,
		    stack->elinfo_stack[stack->stack_used].level);

    stack->info_stack[stack->stack_used] = 0;
  }

  return stack->elinfo_stack+stack->stack_used;

}

static EL_INFO *traverse_leaf_el_level(TRAVERSE_STACK *stack)
{
  FUNCNAME("traverse_leaf_el_level");

  ERROR_EXIT("not yet");
  return NULL;
}

static EL_INFO *traverse_el_level(TRAVERSE_STACK *stack)
{
  FUNCNAME("traverse_el_level");
  ERROR_EXIT("not yet");
  return NULL;
}

static EL_INFO *traverse_mg_level(TRAVERSE_STACK *stack)
{
  FUNCNAME("traverse_mg_level");
  ERROR_EXIT("not yet");
  return NULL;
}

/******************************************************************************/

const EL_INFO *traverse_neighbour(TRAVERSE_STACK *stack,
                                  const EL_INFO *elinfo_old,
                                  int neighbour)
{
  FUNCNAME("traverse_neighbour");

  TEST_EXIT(stack,"No stack specified!\n");
  TEST_EXIT(stack->traverse_mesh,"No traverse_mesh specified in stack!\n");

  switch(stack->traverse_mesh->dim) {
  case 0:
  case 1:
    return traverse_neighbour_1d(stack, elinfo_old, neighbour);
    break;
#if DIM_MAX > 1
  case 2:
    return traverse_neighbour_2d(stack, elinfo_old, neighbour);
    break;
#if DIM_MAX > 2
  case 3:
    return traverse_neighbour_3d(stack, elinfo_old, neighbour);
    break;
#endif
#endif
  default:
    ERROR_EXIT("Illegal dim == %d!\n", stack->traverse_mesh->dim);
  }

  return NULL; /* Statement not reached. */
}

/******************************************************************************/

/* Lookup the ancestor of CHILD in the traverse-stack STACK. Return
 * the ancestor's EL_INFO structure or NULL if no ancestor could be
 * found in the traverse stack STACK.
 *
 * NOTE: the EL_INFO structure returned by this function might be
 * overwritten by subsequent calls to traverse_next() and so on.
 *
 * NOTE ALSO: this function does _NOT_ modify STACK, it simply looks
 * up the ancestor of CHILD.
 */
 
const EL_INFO *traverse_parent(const TRAVERSE_STACK *stack,
                               const EL_INFO *child)
{
  const EL *ancestor;
  int stack_pos;
  FUNCNAME("traverse_parent");

  TEST_EXIT(stack,"No stack specified!\n");
  TEST_EXIT(stack->traverse_mesh,"No traverse_mesh specified in stack!\n");

  /* The parent should live somewhere on the stack, so simply
   * pop-off elements from the stack until we reach the parent.
   */
   
  ancestor = child->parent->el;

  for (stack_pos = stack->stack_used; stack_pos; stack_pos--) {
    if (stack->elinfo_stack[stack_pos].el == ancestor)
      break;
  }

  TEST_EXIT (!ancestor || stack->stack_used > 0,
             "Parent not found in tree.\n");

  if (!stack_pos)
    return NULL; /* elinfo_old must be a macro element */

  return &stack->elinfo_stack[stack_pos];
}

/******************************************************************************/

/* Generate a traverse stack suitable for sub-tree traversal.  The
 * next element must be fetched via traverse_next(). DO NOT TRY TO USE
 * traverse_neighbour() with this stack!
 *
 * If local_root == NULL, we take the current position in stack as the
 * local root, otherwise stack is re-initialized.
 */
 
const EL_INFO *subtree_traverse_first(TRAVERSE_STACK *stack,
                                      const EL_INFO *local_root,
                                      int level, FLAGS flags)
{
  FUNCNAME("subtree_traverse_first");
  MESH *mesh;

  if (!stack) {
    ERROR("no traverse stack\n");
    return NULL;
  }

  if (local_root != NULL) {

    mesh = local_root->mesh;

    stack->traverse_mesh  = mesh;

    if (stack->stack_size < 1) {
      __AI_enlarge_traverse_stack(stack);
    }

    if (flags & CALL_LEAF_EL_LEVEL) {
      TEST_EXIT(level >= 0, "invalid level: %d\n",level);
    }

    stack->stack_used = 1;
    stack->elinfo_stack[stack->stack_used] = *local_root;
    stack->traverse_mel = local_root->macro_el;
    stack->el_count = 1;

    stack->elinfo_stack[0].mesh = local_root->mesh;
    stack->elinfo_stack[0].fill_flag = stack->fill_flag;
  } else {
    mesh = stack->traverse_mesh;
  }  

  DEBUG_TEST_EXIT(stack->stack_used > 0, "Need a local root or a populated traverse stack");
  DEBUG_TEST_EXIT(stack->marker.pos < 0, "Stack already marked");

  stack->info_stack[stack->stack_used] = 0;
  stack->marker.pos            = stack->stack_used - 1;
  stack->marker.traverse_flags = stack->traverse_flags;
  stack->marker.traverse_level = stack->traverse_level;

  if (mesh->parametric && !mesh->parametric->use_reference_mesh) {
    flags &= ~(FILL_COORDS|FILL_OPP_COORDS);
  }
  
  if (!mesh->is_periodic) {
    flags &= ~(FILL_NON_PERIODIC|FILL_MACRO_WALLS);
  } else if (flags & FILL_OPP_COORDS) {
    flags |= FILL_MACRO_WALLS;
  }

  stack->traverse_level = level;
  stack->traverse_flags = flags & ~FILL_ANY;
  stack->fill_flag      = flags & FILL_ANY;

  /* hopefully, this will work. */
  return traverse_next(stack, &stack->elinfo_stack[stack->stack_used]);
}

/******************************************************************************/

const EL_INFO *traverse_next(TRAVERSE_STACK *stack, const EL_INFO *elinfo_old)
{
  FUNCNAME("traverse_next");
  EL_INFO       *elinfo=NULL;

  if (stack->stack_used) {
    TEST_EXIT(elinfo_old == stack->elinfo_stack+stack->stack_used,
	      "invalid old elinfo\n");
  }
  else {
    TEST_EXIT(elinfo_old == NULL,"invalid old elinfo != NULL\n");
  }

  if (stack->traverse_flags & CALL_LEAF_EL)
    elinfo = traverse_leaf_el(stack);
  else
    if (stack->traverse_flags & CALL_LEAF_EL_LEVEL)
      elinfo = traverse_leaf_el_level(stack);
    else if (stack->traverse_flags & CALL_EL_LEVEL)
      elinfo = traverse_el_level(stack);
    else if (stack->traverse_flags & CALL_MG_LEVEL)
      elinfo = traverse_mg_level(stack);
    else
      if (stack->traverse_flags & CALL_EVERY_EL_PREORDER)
        elinfo = traverse_every_el_preorder(stack);
      else if (stack->traverse_flags & CALL_EVERY_EL_INORDER)
        elinfo = traverse_every_el_inorder(stack);
      else if (stack->traverse_flags & CALL_EVERY_EL_POSTORDER)
        elinfo = traverse_every_el_postorder(stack);
      else
        ERROR_EXIT("invalid traverse_flag: %8x\n", stack->traverse_flags);

  if (elinfo) {
    stack->el_count++;
    elinfo->el_geom_cache.current_el = NULL;
  } else {
    /* MSG("total element count:%d\n",stack->el_count); */
  }

  return elinfo;
}

/*******************************************************************************
 *   traverse_first:                                                        
 *   ---------------                                                        
 *   initiate traversal and return first el_info                            
 ******************************************************************************/

const EL_INFO *traverse_first(TRAVERSE_STACK *stack,
                              MESH *mesh, int level, FLAGS flags)
{
  FUNCNAME("traverse_first");

  if (!stack)
  {
    ERROR("no traverse stack\n");
    return NULL;
  }

  if (mesh->parametric && !mesh->parametric->use_reference_mesh) {
    flags &= ~(FILL_COORDS|FILL_OPP_COORDS);
  }

  if (!mesh->is_periodic) {
    flags &= ~FILL_NON_PERIODIC;
  } else if (flags & FILL_OPP_COORDS) {
    flags |= FILL_MACRO_WALLS;
  }

  stack->traverse_mesh  = mesh;
  stack->traverse_level = level;
  stack->traverse_flags = flags & ~FILL_ANY;
  stack->fill_flag      = flags & FILL_ANY;

  if (stack->stack_size < 1) {
    __AI_enlarge_traverse_stack(stack);
  }

  stack->elinfo_stack[0].mesh =
    stack->elinfo_stack[1].mesh = mesh;
  stack->elinfo_stack[0].fill_flag =
    stack->elinfo_stack[1].fill_flag = stack->fill_flag;

  if (flags & CALL_LEAF_EL_LEVEL) {
    TEST_EXIT(level >= 0,"invalid level: %d\n",level);
  }

  stack->traverse_mel = NULL;
  stack->stack_used   = 0;
  stack->el_count     = 0;

  return traverse_next(stack, NULL);
}


/*******************************************************************************
 *   test_traverse_nr_fct:                                                  
 *   ---------------------
 *   display information about an element from EL and EL_INFO structures    
 ******************************************************************************/

static void test_traverse_nr_fct(const EL_INFO *elinfo)
{
  FUNCNAME("test_traverse_nr_fct");
  EL      *el = elinfo->el;

  MSG("\n");
  MSG("traversing element %d: at %p --------------------\n",
      INDEX(el), el);

  print_msg("level:        %3d\n",elinfo->level);

}

/*******************************************************************************
 *   AI_test_traverse_nr:                                                   
 *   --------------------                                                   
 *   display information about all elements from EL and EL_INFO structures  
 *   by calling traverse with test_traverse_fct().                          
 ******************************************************************************/

void AI_test_traverse_nr(MESH *mesh, int level, FLAGS fill_flag)
{
  FUNCNAME("AI_test_traverse_nr");
  const EL_INFO *elinfo;
  TRAVERSE_STACK *stack;

  MSG("with level    : %3d\n", level);
  MSG("with fill_flag:");
  if (fill_flag & FILL_ANY) {
    if (fill_flag & FILL_COORDS)       print_msg(" FILL_COORDS");
    if (fill_flag & FILL_BOUND)        print_msg(" FILL_BOUND");
    if (fill_flag & FILL_NEIGH)        print_msg(" FILL_NEIGH");
    if (fill_flag & FILL_OPP_COORDS)   print_msg(" FILL_OPP_COORDS");
    if (fill_flag & FILL_ORIENTATION)  print_msg(" FILL_ORIENTATION");
    if (fill_flag & FILL_PROJECTION)   print_msg(" FILL_PROJECTION");
    if (fill_flag & FILL_MACRO_WALLS)     print_msg(" FILL_MACRO_WALLS");
    if (fill_flag & FILL_NON_PERIODIC) print_msg(" FILL_NON_PERIODIC");
  }
  else print_msg(" none");
  print_msg("\n");


  stack = get_traverse_stack();

  elinfo = traverse_first(stack, mesh, level, fill_flag);
  while (elinfo)
  {
    test_traverse_nr_fct(elinfo);

    elinfo = traverse_next(stack, elinfo);
  }

  free_traverse_stack(stack);

  MSG("done.\n");
}
