/*--------------------------------------------------------------------------*/
/* ALBERTA:  an Adaptive multi Level finite element toolbox using           */
/*           Bisectioning refinement and Error control by Residual          */
/*           Techniques for scientific Applications                         */
/*                                                                          */
/* file:     traverse_nr_1d.c                                               */
/*                                                                          */
/* description:                                                             */
/*           nonrecursive mesh traversal, 1d routines                       */
/*                                                                          */
/*--------------------------------------------------------------------------*/
/*                                                                          */
/*  authors:   Alfred Schmidt                                               */
/*             Zentrum fuer Technomathematik                                */
/*             Fachbereich 3 Mathematik/Informatik                          */
/*             Universitaet 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)                          */
/*                                                                          */
/*--------------------------------------------------------------------------*/

static int coarse_nb_1d[3][2] = {{-2,-2}, {-1,1}, {0,-1}};
                    /* father.neigh[coarse_nb[i][j]] == child[i-1].neigh[j] */

/*--------------------------------------------------------------------------*/
/*   traverse_neighbour_1d:                           		            */
/*   -------------------                                		    */
/*   walk through hierarchy tree and look for a neighbour		    */
/*--------------------------------------------------------------------------*/


static const EL_INFO *traverse_neighbour_1d(TRAVERSE_STACK *stack,
					    const EL_INFO *elinfo_old,
					    int neighbour)
{
  FUNCNAME("traverse_neighbour_1d");
  EL      *el, *sav_el;
  EL_INFO *old_elinfo, *elinfo;
  int     i, nb, opp_vertex;

  int     sav_index, sav_neighbour = neighbour;

  DEBUG_TEST_EXIT(stack->stack_used > 0, "no current element");
  DEBUG_TEST_EXIT(stack->traverse_flags & CALL_LEAF_EL,
	      "invalid traverse_fill_flag=%d", stack->traverse_flags);

  DEBUG_TEST_EXIT(IS_LEAF_EL(elinfo_old->el), "invalid old elinfo");

  DEBUG_TEST_EXIT(elinfo_old == stack->elinfo_stack+stack->stack_used,
	      "invalid old elinfo");

  DEBUG_TEST_FLAG(FILL_NEIGH, stack->elinfo_stack+stack->stack_used);
  el = stack->elinfo_stack[stack->stack_used].el;
  sav_index = INDEX(el);
  sav_el    = el;

  /* save information about current element and its position in the tree */
  stack->save_traverse_mel = stack->traverse_mel;
  stack->save_stack_used   = stack->stack_used;
  for (i=0; i<=stack->stack_used; i++)
    stack->save_info_stack[i]   = stack->info_stack[i];
  for (i=0; i<=stack->stack_used; i++)
    stack->save_elinfo_stack[i] = stack->elinfo_stack[i];
  old_elinfo = stack->save_elinfo_stack+stack->stack_used;
  opp_vertex = old_elinfo->opp_vertex[neighbour];


/*--------------------------------------------------------------------------*/
/* First phase: go up in tree until we can go down again.                   */
/*                                                                          */
/* During this first phase, nb is the neighbour index which points from an  */
/* element of the OLD hierarchy branch to the NEW branch                    */
/*--------------------------------------------------------------------------*/

  nb = neighbour;

  while (stack->stack_used > 1)
  {
    stack->stack_used--;
    nb = coarse_nb_1d[stack->info_stack[stack->stack_used]][nb];
    if (nb == -1) break;
    DEBUG_TEST_EXIT(nb >= 0, "invalid coarse_nb_1d %d\n",nb);
  }

/*--------------------------------------------------------------------------*/
/* Now, goto neighbouring element at the local hierarchy entry              */
/* This is either a macro element neighbour or the other child of parent.   */
/* initialize nb for second phase (see below)                               */
/*--------------------------------------------------------------------------*/

  if (nb >= 0) {                        /* go to macro element neighbour */

    i = stack->traverse_mel->opp_vertex[nb];
    stack->traverse_mel = stack->traverse_mel->neigh[nb];
    if (stack->traverse_mel == NULL)  return NULL;
    nb = i;
    
    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;
    
  } else {                                               /* goto other child */

    if (stack->stack_used >= stack->stack_size-1)
      __AI_enlarge_traverse_stack(stack);
    i = 2 - stack->info_stack[stack->stack_used];
    stack->info_stack[stack->stack_used] = i+1;
    fill_elinfo(i, stack->fill_flag, stack->elinfo_stack+stack->stack_used,
		stack->elinfo_stack+stack->stack_used+1);
    stack->stack_used++;
    nb = i;                                 /* different to 2d/3d-case!! */
  }

/*--------------------------------------------------------------------------*/
/* Second phase: go down in a new hierarchy branch until leaf level.        */
/* Now, nb is the neighbour index which points from an element of the       */
/* NEW hierarchy branch to the OLD branch.                                  */
/*--------------------------------------------------------------------------*/

  elinfo = stack->elinfo_stack+stack->stack_used;
  el = elinfo->el;

  while(el->child[0]) {

    /* go down one level in hierarchy */
    if (stack->stack_used >= stack->stack_size-1)
      __AI_enlarge_traverse_stack(stack);
    fill_elinfo(1-nb, stack->fill_flag, stack->elinfo_stack+stack->stack_used, 
		stack->elinfo_stack+stack->stack_used+1);
    stack->info_stack[stack->stack_used] = 2-nb;
    stack->stack_used++;

    elinfo = stack->elinfo_stack+stack->stack_used;
    el = elinfo->el;
  }


  if (elinfo->neigh[opp_vertex] != old_elinfo->el) {
    MSG(" looking for neighbour %d of element %d at %p\n",
	neighbour, INDEX(old_elinfo->el), old_elinfo->el);
    MSG(" originally: neighbour %d of element %d at %p\n",
	sav_neighbour, sav_index, sav_el);
    MSG(" got element %d at %p with opp_vertex %d neigh %d\n",
	INDEX(elinfo->el), elinfo->el, opp_vertex,
	INDEX(elinfo->neigh[opp_vertex]));
    DEBUG_TEST_EXIT(elinfo->neigh[opp_vertex] == old_elinfo->el,
		"didn't succeed !?!?!?");
  }
  if (elinfo->el->child[0])
  {
    MSG(" looking for neighbour %d of element %d at %p\n",
	neighbour, INDEX(old_elinfo->el), old_elinfo->el);
    MSG(" originally: neighbour %d of element %d at %p\n",
	sav_neighbour, sav_index, sav_el);
    MSG(" got element %d at %p with opp_vertex %d neigh %d\n",
	INDEX(elinfo->el), elinfo->el, opp_vertex,
	INDEX(elinfo->neigh[opp_vertex]));
    MSG("got no leaf element\n");
    WAIT_REALLY;
  }

  elinfo->el_geom_cache.current_el = NULL;

  return elinfo;
}

