/*--------------------------------------------------------------------------*/
/* ALBERTA:  an Adaptive multi Level finite element toolbox using           */
/*           Bisectioning refinement and Error control by Residual          */
/*           Techniques for scientific Applications                         */
/*                                                                          */
/* file:     traverse_r_common.c                                            */
/*                                                                          */
/*                                                                          */
/* description:                                                             */
/*           recursive mesh traversal routines - common 2d/3d part          */
/*                                                                          */
/*--------------------------------------------------------------------------*/
/*                                                                          */
/*  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.alberta-fem.de/                                              */
/*                                                                          */
/*--------------------------------------------------------------------------*/
/*  (c) by A. Schmidt and K.G. Siebert (1996-2004)                          */
/*                                                                          */
/*     This program is free software; you can redistribute it and/or modify */
/*     it under the terms of the GNU General Public License as published by */
/*     the Free Software Foundation; either version 2 of the License, or    */
/*     any later version.                                                   */
/*                                                                          */
/*     This program is distributed in the hope that it will be useful,      */
/*     but WITHOUT ANY WARRANTY; without even the implied warranty of       */
/*     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the        */
/*     GNU General Public License for more details.                         */
/*--------------------------------------------------------------------------*/
/*--------------------------------------------------------------------------*/
/* common (static) traversal routines for 2d and 3d                         */
/*--------------------------------------------------------------------------*/
// .cc von thilo moshagen. mesh traversal 
//it could be just a function instead of a class.
//can traverse mesh applying all classes derived from do_on_el.
//  in order to enable applying member functions of classes.

#ifndef __traverse_h
#define __traverse_h

#include <alberta.h>
#if (defined(ALBERTA_VER) && (ALBERTA_VER==2))
# include <alberta_inlines.h>
//#include <alberta_util_inlines.h>
# include "alberta1_wrapper.h"
#endif
#include "do_on_el.hh"

struct traverse_info 
{
  MESH     *mesh;
//  FLAGS    flag; 
  FLAGS	   trav_flags;
  FLAGS    fill_flags;
  U_CHAR   level;
};

typedef struct traverse_info TRAVERSE_INFO;

//class  mesh_class_traverse 
//{
//public:
/*--------------------------------------------------------------------------*/
/*   mesh_traverse:                                            		    */
/*   --------------                                     		    */
/*   run through all macro elements and start mesh traversal      	    */
/*   call recursive_traverse() for each macro element's element		    */
/*--------------------------------------------------------------------------*/
//jetzt:	void fill_elinfo(int ichild, FLAGS mask, const EL_INFO *parent_info, EL_INFO *elinfo)
static  void recursive_traverse(EL_INFO *elinfo, TRAVERSE_INFO *trinfo, do_on_el* class_ptr)
//			  void (T::*el_fct)(const EL_INFO *) )
  { 
    EL *el = elinfo->el;
    EL_INFO elinfo_new;
    int mg_level;
    // clear cache to make valgrind happy
    elinfo_new.el_geom_cache.current_el = NULL;   
    if (trinfo->trav_flags & CALL_LEAF_EL) 
    {
      if (el->child[0]) 
      {
	fill_elinfo(0, trinfo->fill_flags, elinfo, &elinfo_new);
	recursive_traverse(&elinfo_new, trinfo, class_ptr);
	fill_elinfo(1, trinfo->fill_flags, elinfo, &elinfo_new);
	recursive_traverse(&elinfo_new, trinfo, class_ptr);
      }
      else (class_ptr->el_fct)(elinfo); 
      
      return;
    }
    
    if (trinfo->trav_flags & CALL_LEAF_EL_LEVEL) 
    {
      if (el->child[0]) 
      {
	if ((elinfo->level >= trinfo->level))  return;
	fill_elinfo(0, trinfo->fill_flags, elinfo, &elinfo_new);
	recursive_traverse(&elinfo_new, trinfo, class_ptr);
	fill_elinfo(1, trinfo->fill_flags, elinfo, &elinfo_new);
	recursive_traverse(&elinfo_new, trinfo, class_ptr);
      }
      else 
      {
	if (elinfo->level == trinfo->level) (class_ptr->el_fct)(elinfo);
      }
      return;
    }

    if (trinfo->trav_flags & CALL_EL_LEVEL) 
    {
      if (elinfo->level == trinfo->level) (class_ptr->el_fct)(elinfo);
      else 
      {
	if (elinfo->level > trinfo->level) return;
	else
	{
	  if (el->child[0]) 
	  {
	    fill_elinfo(0, trinfo->fill_flags, elinfo, &elinfo_new);
	    recursive_traverse(&elinfo_new, trinfo, class_ptr);
	    fill_elinfo(1, trinfo->fill_flags, elinfo, &elinfo_new);
	    recursive_traverse(&elinfo_new, trinfo, class_ptr);
	  }
	}
      }
      return;
    }

    if (trinfo->trav_flags & CALL_MG_LEVEL) 
    {
      mg_level = ((int)elinfo->level + DIM-1) / DIM;

      if (mg_level > (int)trinfo->level) return;

      if (!(el->child[0])) 
      {
	(class_ptr->el_fct)(elinfo);
	return;
      }
    
      if ((mg_level == trinfo->level) && ((elinfo->level % DIM) == 0))
      {
	(class_ptr->el_fct)(elinfo);
	return;
      }

      fill_elinfo(0, trinfo->fill_flags, elinfo, &elinfo_new);
      recursive_traverse(&elinfo_new, trinfo, class_ptr);

      fill_elinfo(1, trinfo->fill_flags, elinfo, &elinfo_new);
      recursive_traverse(&elinfo_new, trinfo, class_ptr);

      return;
    }

    if (trinfo->trav_flags & CALL_EVERY_EL_PREORDER) (class_ptr->el_fct)(elinfo);

    if (el->child[0]) 
    {
      fill_elinfo(0, trinfo->fill_flags, elinfo, &elinfo_new);
      recursive_traverse(&elinfo_new, trinfo, class_ptr);

      if (trinfo->trav_flags & CALL_EVERY_EL_INORDER) (class_ptr->el_fct)(elinfo);

      fill_elinfo(1, trinfo->fill_flags, elinfo, &elinfo_new);
      recursive_traverse(&elinfo_new, trinfo, class_ptr);
    }
    else 
    {
      if (trinfo->trav_flags & CALL_EVERY_EL_INORDER) (class_ptr->el_fct)(elinfo);
    }

    if (trinfo->trav_flags & CALL_EVERY_EL_POSTORDER) (class_ptr->el_fct)(elinfo);

    return;
  }


void traverse(MESH* mesh, int level, FLAGS flags, do_on_el* class_ptr)
//		void (T::*el_fct)(const EL_INFO *))
  {
    FUNCNAME("traverse");
    MACRO_EL*     mel;
    EL_INFO       elinfo = {0};
    TRAVERSE_INFO traverse_info= {0};
 
    if (mesh==nil) return;
//    mesh_class_traverse::classptr = classptr;
  if (!mesh->is_periodic) {
    flags &= ~(FILL_NON_PERIODIC|FILL_WALL_TRAFOS);
  } else if (flags & FILL_OPP_COORDS) {
    flags |= FILL_WALL_TRAFOS;
  }


    traverse_info.mesh  = mesh;
    traverse_info.level = level;
//    traverse_info.flag  = flag;
    traverse_info.trav_flags = flags & ~FILL_ANY;
    traverse_info.fill_flags = flags & FILL_ANY;
    elinfo.mesh = mesh;
  elinfo.fill_flag = traverse_info.fill_flags;

    if (flags & (CALL_LEAF_EL_LEVEL | CALL_EL_LEVEL | CALL_MG_LEVEL))
    {
      TEST_EXIT(level >= 0,"invalid level: %d\n",level);
    }
#if (defined(ALBERTA_VER) && (ALBERTA_VER==2))
    mel = mesh->macro_els;
    for (int n=0; n < mesh->n_macro_el; n++)
    { 
    	fill_macro_info(mesh, &mel[n], &elinfo);
	recursive_traverse(&elinfo, &traverse_info, class_ptr);
    } 
#else
    for (mel = mesh->first_macro_el; mel; mel = mel->next) 
    { 
      fill_macro_info(mesh, mel, &elinfo);
      recursive_traverse(&elinfo, &traverse_info, class_ptr);
    }
#endif
  };

//private:
/*--------------------------------------------------------------------------*/
/*   recursive_traverse:                                		    */
/*   -------------------                                		    */
/*   recursively traverse the mesh hierarchy tree       		    */
/*   call the routine traverse_info->el_fct(el_info) with    		    */
/*    - all tree leaves                                 		    */
/*    - all tree leaves at a special level              		    */
/*    - all tree elements in pre-/in-/post-order        		    */
/*   depending on the traverse_info->level variable     		    */
/*--------------------------------------------------------------------------*/

#endif
