#ifndef __GRAPE_HMESH_C__
#define __GRAPE_HMESH_C__

#include "geldesc.hh"

/*****************************************************************************
* Globale defines                  *                     **
*****************************************************************************/

static const double EPSILON  = 1.0e-2;
#define STA(el) ((STACKENTRY *) (el))
static const double INFTY = 999999.;
#define FVAL_ON_NODE(b) (jump_data[b])

#define MINIMUM(a,b) (((a) > (b)) ? (b) : (a))
#define MAXIMUM(a,b) (((a) < (b)) ? (b) : (a))

GENMESHnD *genmesh3d_switch_part_light_model_on_off();
GENMESHnD *genmesh3d_switch_part_displaybar_on_off();
GENMESHnD *genmesh3d_partition_disp();

/*****************************************************************************
* Verwendete Strukturen                *                     **
*****************************************************************************/
typedef struct stackentry
{ 
  HELEMENT hel;
  
  int ref_flag ;
  
  double hmax;
  
  // default constructor 
  stackentry () : hel()
                , ref_flag(0), hmax(-1.0) {}
} STACKENTRY;

/* definition of dune_dat in g_eldesc.h */
/* stored as user_data in the mesh pointer */

namespace FctSelector {

/* function list management */
#define FCT_NONE "none"
#define FCT_ZERO "zero"
#define SLT_DEFAULT "default"

#define SYMBOL_LENGTH 8

typedef enum {
  fmtNone,
  fmtLog,
  fmtT_Fun
} function_modifier_index;

typedef struct function_modifier {
  function_modifier_index type;
  char name[MAX_STRLEN];
  GENMESH_FDATA *orig_f_data, *new_f_data;
  int new_f_size;
  void (*origfun)(void *, int, double *, double *, void *);
  void (*origbounds)(void *, double *, double *, void *);
  int number_of_functions;
  struct {
    GENMESH_FDATA *fdata;
    char name[MAX_STRLEN], symbol[SYMBOL_LENGTH];
    void (*fun)(void *, int, double *, double *, void *);
    int active;
  } *functions;
  ITEM *item;
  void *data;
  void (*modfun)(void *, int, double *, double *, void *);
  void (*modbounds)(void *, double *, double *, void *);
  GENMESH_FDATA *(*init) (struct function_modifier*);
  char *(*info) (struct function_modifier*);
  bool_t (*xdr) (XDR *, struct function_modifier*);
  void (*deleteFct) (struct function_modifier*);
} function_modifier;

/* function list management */
typedef struct {
  char *slot, *name;
  function_modifier modifier;
} chosen_function;

typedef ::std::pair< const char * , const char * > DataFunctionName_t;

// returns slot and name of selected function 
inline DataFunctionName_t getCurrentFunctionName(GRAPEMESH * mesh)
{
  DataFunctionName_t fctName( (const char *)0, (const char *)0 );

  chosen_function * current = (chosen_function *)
    g_list_current (mesh->current_function);
  if (current)
  {
    GENMESH_FDATA* fun = (GENMESH_FDATA *)
      GRAPE_CALL(mesh, "get-function")(NULL, current->slot,NULL);
    fctName.first  = current->slot;
    fctName.second = fun->name;
  }
  return fctName;
}

#undef FCT_NONE 
#undef FCT_ZERO 
#undef SLT_DEFAULT 
#undef SYMBOL_LENGTH 

} // end namespace fct selector 

/**************************************************************************
 *
 * froward declarations
 *  
 * ************************************************************************/

/* switch from leaf to level iteration for mesh */
int switchMethods( GENMESHnD *actHmesh);

/*****************************************************************************
******************************************************************************
**                      **
**  Memory Management Routinen              **
**                      **
******************************************************************************
*****************************************************************************/
inline static void gFreeElement(ELEMENT *el) 
{
  assert( el );
  assert( el->mesh );
  DUNE_DAT * dat = (DUNE_DAT *) el->mesh->user_data;
  assert(dat);
  dat->free_stackentry(dat,(void *)el);
  return ;
}

/* complete element does nothing at the moment */
inline static ELEMENT * complete_element(ELEMENT *el, MESH_ELEMENT_FLAGS flags) 
{
  return el;
}

/*****************************************************************************
 * little help routines 
 *****************************************************************************/
inline static double dist(const double *x,  const double *y)
{
  double dist=0.0;
  int i;
    
  for(i=0; i<GRAPE_DIMWORLD; i++)
  {
    dist += (x[i]-y[i])*(x[i]-y[i]);
  }
  return (sqrt(dist));
}

inline static double calc_hmax(HELEMENT *el)
{
  return ( dist(el->vertex[0], el->vertex[1]) );
}

/*****************************************************************************
******************************************************************************
**                      
**  The functions to which each HMesh has a pointer, i.e. first_macro 
**  here first_macro, next_macro, first_child, next_child
**                      
******************************************************************************
*****************************************************************************/
// update helement pointers  
inline static void helementUpdate( DUNE_ELEM *elem, HELEMENT *grapeEl )
{
  // set pointers 
  grapeEl->vertex       = elem->vpointer; 
  grapeEl->vindex       = elem->vindex ;
  grapeEl->eindex       = elem->eindex ;
  grapeEl->level        = elem->level;
  grapeEl->has_children = elem->has_children;
  grapeEl->user_data    = (void *)elem ;

  // select appropriate element description 
  grapeEl->descr = (ELEMENT_DESCRIPTION *) getElementDescription(elem->type);
  return ;
}

inline static HELEMENT * first_macro (GENMESHnD *mesh, MESH_ELEMENT_FLAGS flag) 
{
  assert(mesh);
  DUNE_DAT * dat = (DUNE_DAT *) mesh->user_data; 
  assert( dat );

  HELEMENT * el = (HELEMENT *) dat->get_stackentry(dat);
  DUNE_ELEM * elem = (DUNE_ELEM *) el->user_data;
 
  assert(el);
  assert(elem);

  // set iterator type depending on value of button 
  GRAPE_CALL(iteratorButton,      "get-value")(&(dat->iteratorType));
  GRAPE_CALL(partitionTypeButton, "get-value")(&(dat->partitionIteratorType));

  F_DATA * f_data = (F_DATA*)GRAPE_CALL(mesh,"get-function")
                    ("scalar","scalar","vector","default", NULL);
  
  assert( dat->setIterationModus );
  DUNE_FDATA * func = 0;
  if(f_data) 
  {
    DUNE_FDATA * data = (DUNE_FDATA *) f_data->function_data;
    if( DUNE_FDATA::dataList().find(data) !=
        DUNE_FDATA::dataList().end() )
    {
      func = data; 
    }
  }
  dat->setIterationModus(dat,func);

  // note this pointer can be NULL
  elem->gridPart = dat->gridPart;
    
  /* store level of interest for LeafIterator */
  if(maxlevelButton->on_off == OFF) /* dont know why wrong, but it works */
    elem->level_of_interest = -1;
  else 
    elem->level_of_interest = mesh->level_of_interest;
  
  el->present = hefAll;
  el->parent = NULL;

  elem->display = dat->all->display;
  elem->hiter = NULL;

  {
    /* call first macro and check for first element */
    int test = dat->first_macro(elem) ;
    // means no element exits at all 
    if(!test) return NULL;
  }
 
  el->level = 0;
  el->mesh  = (GENMESHnD *)mesh ;

  helementUpdate(elem,el);
  ((STACKENTRY *)el)->hmax = calc_hmax(el);

  el->vinh    = NULL ;
  ((STACKENTRY *)el)->ref_flag   = -1;
  
  /***************************************************************/
  // is this assertion is thrown then something with the geometry types is
  // wrong 
  assert( el->descr != 0 );
  
  return(el);
}

/* go next macro element */
inline static HELEMENT * next_macro(HELEMENT * el, MESH_ELEMENT_FLAGS flag) 
{
  int mflag=0;
  assert(el) ;

  el->present = (MESH_ELEMENT_FLAGS) (hefAll & ! hefVinh);
  mflag = (*(((struct dune_dat *)(el->mesh->user_data))->next_macro))((DUNE_ELEM *)el->user_data); 
  if(mflag)
  {
    helementUpdate( ((DUNE_ELEM *)el->user_data) , el);
    ((STACKENTRY *)el)->hmax = calc_hmax(el);
    return(el) ;
  } 
  else 
  { 
    /*printf("next macro: bin draussen flag = %i \n",mflag);*/ 
    gFreeElement((ELEMENT *)el) ; 
    return NULL ; 
  }
}

/***********************************************************/
/* first_child, go to first child of current element */
/************************************************************/
inline static HELEMENT * first_child (HELEMENT * ael, MESH_ELEMENT_FLAGS flag) 
{
  int actlevel = ael->level;
  
  DUNE_DAT * dat = (DUNE_DAT *) ael->mesh->user_data;
  assert( dat );

  // if pointer is zero then no child iteration
  if(dat->first_child) 
  {
    if ( actlevel < ((HMESH *)ael->mesh)->level_of_interest )
    {
      HELEMENT * el = (HELEMENT *) dat->get_stackentry(dat);
      assert(el);
      // set mesh, needed for removal 
      el->mesh = ael->mesh;
      
      DUNE_ELEM * elem = (DUNE_ELEM *)el->user_data;
      assert(elem);

      el->present = (MESH_ELEMENT_FLAGS) (hefAll & !hefVinh);

      DUNE_ELEM * aelem = (DUNE_ELEM *)ael->user_data;

      elem->display = aelem->display;
      elem->liter   = aelem->liter;
      elem->hiter   = aelem->hiter;

      /* call the dune method */
      if(dat->first_child(elem)) 
      {
        el->level = actlevel+1;
        el->mesh  = ael->mesh ;

        helementUpdate(elem,el);
        
        el->parent    = ael;  
        ((STACKENTRY *)el)->hmax = ((STACKENTRY *)ael)->hmax * 0.5;

        el->vinh  = NULL ;
        ((STACKENTRY *)el)->ref_flag   = -1;
        /****************************************************/
        // is this assertion is thrown then something with the geometry types is
        // wrong 
        assert( el->descr != 0 );
        return(el);
      }
      else 
      { 
        gFreeElement((ELEMENT *)el) ; 
        return NULL ; 
      }  
    }
  }
  return NULL ; 
}

/* go to next child of the current element */
inline static HELEMENT * next_child(HELEMENT * el, MESH_ELEMENT_FLAGS flag) 
{
  assert(el) ;
  el->present = (MESH_ELEMENT_FLAGS) (hefAll & !hefVinh);
  DUNE_ELEM * elem = ((DUNE_ELEM *)el->user_data);
  assert( elem );

  DUNE_DAT * dat = (DUNE_DAT *) el->mesh->user_data;
  assert( dat );

  if(dat->next_child)
  {
    if(dat->next_child(elem))
    {
      DUNE_ELEM * elem = ((DUNE_ELEM *)el->user_data);
      ((STACKENTRY *)el)->ref_flag++;
      helementUpdate(elem,el);
          
      // only implemented on triangles
      if(elem->type != gr_triangle) 
      {
        el->vinh = NULL;
      }
      
      return(el) ;
    }
    else 
    { 
      gFreeElement((ELEMENT *)el) ; 
      return NULL ; 
    }
  }

  return NULL;
}

/* first_child, go to first child of current element */
inline static HELEMENT * select_child (HELEMENT * ael, double *parent_coord, 
            double *child_coord, MESH_ELEMENT_FLAGS flag) 
{
  HELEMENT *child = NULL;
  HMESH *mesh = (HMESH *) ael->mesh;
  const ELEMENT_DESCRIPTION *descr = ael->descr;
  double coord [GRAPE_DIMWORLD];
  int inside = 0;

  /* in child_ccord the local coordinates of the point in child can be
   * stored */
  descr->coord_to_world(ael,parent_coord,(double *) &coord);
  
  if( mesh->first_child )
    child = mesh->first_child(ael, flag); 
  if( !child ) return NULL;
  
  /* tranform to local coords of child */
  descr->world_to_coord(child, (double *) &coord, child_coord);
    
  while ( inside != -1 )
  { 
    inside = descr->check_inside( child , child_coord );
    if( inside == -1) 
    {
      return child;
    }
 
    child = mesh->next_child( child , flag);
    if ( ! child ) return NULL;
    descr->world_to_coord(child, (double *) &coord, child_coord);
  }
  return NULL;
}

inline static ELEMENT * first_element (GRAPEMESH *mesh, MESH_ELEMENT_FLAGS flag) 
{
  return first_macro((GENMESHnD * )mesh,flag);
}

/* go next macro element */
inline static ELEMENT * next_element(ELEMENT * el, MESH_ELEMENT_FLAGS flag) 
{
  return next_macro(el,flag);
}
/***************************************************************************
 *
 *  f_data function
 *
 ***************************************************************************/
inline void f_bounds(HELEMENT *el, double* min, double* max,
                       void *function_data)
{
  (*min) =  1.0E+308;
  (*max) = -1.0E+308;                   
  return;
}
/****************************************************************************/
inline void grape_get_vertex_estimate(HELEMENT *el, double *value,
                                      void *function_data)
{
  *value = 1.0E+308;
  return;
}

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

inline double grape_get_element_estimate(HELEMENT *el, void *function_data)
{
  return 1.0E+308;
}

/***************************************************************************/
inline static void dune_function_info(HELEMENT *el, F_EL_INFO *f_el_info,
       void *function_data)
{     
  assert( function_data );
  
  DUNE_FDATA * df = (DUNE_FDATA *) function_data;
  assert( df );

  // at the moment f_el_info only contains polynomial_degree 
  f_el_info->polynomial_degree = df->polyOrd; 
  return;
} 

inline static void level_function_info(HELEMENT *el, F_EL_INFO *f_el_info,
       void *function_data)
{     
  // the level function has polynomial order 0 
  f_el_info->polynomial_degree = 0; 
  return;
} 

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

/* print DUNE_FDATA STRUCT */
inline void printfFdata(DUNE_FDATA *fem)
{
  printf("Dune Fdata %p \n",fem);
  printf("comp %d      | DiscFunc   %p \n",fem->comp[0],fem->discFunc);
  printf("-------------------------------------------\n");
}
inline void printDuneFunc(DUNE_FDATA *df)
{
  printf("DUNE_FDATA %p \n",df);
  printf("discFunc %p \n",df->discFunc);
  //printf("lf       %p \n",df->lf);
  printf("comp     %d \n",df->comp[0]);
}

/* call the function to evaluate, depending on index of local vertex or
 * local coordinate */
static inline void evaluateFunction(DUNE_ELEM * elem, DUNE_FDATA * fem, int ind,
    double G_CONST *coord, double * val)
{
  assert(elem);
  assert(fem);
  
  if(coord) 
  {
    fem->evalCoord(elem,fem,coord,val);
  }
  else 
  {
    fem->evalDof(elem,fem,ind,val);
  }
} 

/* default function calling function to evaluate */
static inline void f_real(HELEMENT *el, int ind, double G_CONST *coord,
       double *val, void *function_data)
{
  assert(el);
  DUNE_ELEM * elem = (DUNE_ELEM *)el->user_data;
  assert(elem != NULL); 
  DUNE_FDATA *fem = (DUNE_FDATA *) function_data;
  
  assert(fem != NULL);
  assert(fem->discFunc != NULL);

  evaluateFunction(elem,fem,ind,coord,val);
  return;
}

/* function calling data to evaluate for picewise constant data */
static inline void f_real_polOrd_zero(HELEMENT *el, int ind, double G_CONST *coord,
       double *val, void *function_data)
{
  assert(el);
  DUNE_ELEM * elem = (DUNE_ELEM *)el->user_data;
  assert(elem != NULL); 
  DUNE_FDATA *fem = (DUNE_FDATA *) function_data;
  
  assert(fem != NULL);
  assert(fem->discFunc != NULL);

  // if polynomial order zero
  // then only evaluate for ind = 0 
  if(ind == 0) 
  { 
    evaluateFunction(elem,fem,ind,coord,val);
    // cache function value 
    fem->valCache = val[0];
  }
  else 
  {
    // use cached value 
    val[0] = fem->valCache;
  }
  return;
}

/* function displaying the level of the element */
inline void f_level(HELEMENT *el, int ind, double G_CONST *coord,
       double *val, void *function_data)
{
  assert(el);
  val[0] = (double) el->level; 
  return;
}

/***************************************************************************/
inline void grapeInitScalarData(GRAPEMESH *grape_mesh, DUNE_FDATA * dfunc)
{
  assert( grape_mesh );

  if(dfunc)
  {
    F_DATA * f_data = (F_DATA *) dfunc->f_data;
    if (f_data)
    {
      f_data->next = 0;
      f_data->last = 0;
  
      int length = 2*strlen(dfunc->name.c_str());
      f_data->name = (char *) malloc(length*sizeof(char));
      sprintf(f_data->name,"%s",dfunc->name.c_str());
      printf("generate data for discrete function '%s'!\n",f_data->name);

      f_data->dimension_of_value = dfunc->dimVal;

      f_data->continuous_data = dfunc->continuous;

      f_data->f                   = (dfunc->polyOrd == 0) ? f_real_polOrd_zero : f_real;
      f_data->f_el_info           = dune_function_info;
     
      f_data->function_data = (void *) dfunc;

      f_data->get_bounds      = f_bounds;
      f_data->get_vertex_estimate   = grape_get_vertex_estimate;
      f_data->get_element_estimate  = grape_get_element_estimate;
      f_data->threshold     = 0.0;
#if GRAPE_DIM == 3
      f_data->geometry_threshold     = 0.0;
#else 
      // if pointer 0, nothing done with this functions
      f_data->get_element_p_estimates = 0;
      f_data->get_edge_p_estimates    = 0; 
#endif
      f_data->hp_threshold    = 0.0;
      f_data->hp_maxlevel     = grape_mesh->max_level;

      grape_mesh = (GRAPEMESH *) GRAPE_CALL(grape_mesh,"add-function")(f_data);
    }
    else if (grape_mesh->f_data != (GENMESH_FDATA *)f_data)
    {
      printf("select f_data for \n");
      grape_mesh->f_data = (GENMESH_FDATA *)f_data;
    }
  }
  else
  {
    printf("no dfunc, or no vec\n");
  }
  
  return;
}

/* generates the function to display the level of an element */
inline void grapeAddLevelFunction(GRAPEMESH *grape_mesh)
{
  assert( grape_mesh );

  /* function info for level display */
  /* the variables are only needed once, therefore static */

  static std::string level_name("level"); 
  static F_DATA levelData; 

  static F_DATA * f_data = 0; 

  if (!f_data)
  {
    f_data = &levelData;
    assert( f_data );

    f_data->name = (char *) level_name.c_str();
    f_data->dimension_of_value = 1;
    f_data->continuous_data    = 0;

    f_data->f                   = f_level;
    f_data->f_el_info           = &level_function_info;
  
    // no function data here 
    f_data->function_data = 0;

    f_data->get_bounds      = f_bounds;
    f_data->get_vertex_estimate   = grape_get_vertex_estimate;
    f_data->get_element_estimate  = grape_get_element_estimate;
    f_data->threshold     = 0.0;
#if GRAPE_DIM == 3
    f_data->geometry_threshold     = 0.0;
#else 
    f_data->get_element_p_estimates = 0;
    f_data->get_edge_p_estimates    = 0; 
#endif
    f_data->hp_threshold    = 0.0;
    f_data->hp_maxlevel     = grape_mesh->max_level;
  }
  
  assert( f_data );
  grape_mesh = (GRAPEMESH *) GRAPE_CALL(grape_mesh,"add-function")(f_data);
  return;
}

/* add data to Hmesh  */
inline void addDataToHmesh(void  *hmesh, DUNE_FDATA * data)
{
  GRAPEMESH *mesh = (GRAPEMESH *) hmesh;
  assert(mesh);
 
  if(data)
  {
    assert( data->f_data );
    assert( data->discFunc );
      
    /* setup dune data */
    grapeInitScalarData (mesh, data );
  }
  else 
  {
    fprintf(stderr,"ERROR: no function data for setup in addDataToHmesh! \n");
  }
}

/*****************************************************************************
******************************************************************************
**                      **
**  Die MESH Routinen "copy_element"                              **  
**                      **
******************************************************************************
*****************************************************************************/

inline static ELEMENT * copy_element(ELEMENT *el, MESH_ELEMENT_FLAGS flag) 
{
  DUNE_DAT * dat = (DUNE_DAT *) el->mesh->user_data;
  HELEMENT * cel = (HELEMENT *) dat->get_stackentry(dat);

  assert(el) ;
  assert(cel) ;
  
  DUNE_ELEM * hexa_elem = 0, * chexa_elem = 0;

  hexa_elem  = (DUNE_ELEM *) el->user_data;
  chexa_elem = (DUNE_ELEM *) dat->copy(hexa_elem) ;

  assert(chexa_elem) ;
  cel->mesh              = el->mesh ;
  cel->vertex            = chexa_elem->vpointer;
  cel->vindex            = el->vindex ;
  cel->eindex            = el->eindex ;
  cel->descr             = el->descr ;
  cel->parent             = ((HELEMENT *)el)->parent ;
  cel->user_data         = (void *)chexa_elem ;
  cel->level = el->level;

  return ( (ELEMENT *)cel );
}

inline static void get_geometry_vertex_estimate(HELEMENT* helement, double* results)
{
  /* planar mesh -> all geometry-estimates 0*/
  int i;
  for(i=0;i<3;i++)
    results[i] = 1e5;
  return;
}


inline static double get_geometry_element_estimate(HELEMENT* helement)
{
  /*planar mesh -> estimators 0*/
  return(1e5);
}

/* method to get partition number from mesh */
inline HMESH * get_partition_number (int * partition)
{
  HMESH * hmesh = (HMESH *) START_METHOD (G_INSTANCE);
  assert(hmesh != 0);
  DUNE_DAT * dunedata = (DUNE_DAT *) hmesh->user_data;
  assert(dunedata != 0);
  *partition = dunedata->partition;
  
  END_METHOD(hmesh);
}

inline GRAPEMESH *getMesh ( const char *meshName = "Dune Mesh" )
{
  return (GRAPEMESH *)GRAPE_CALL( GrapeMesh, "new-instance" )( meshName );
}

// if parameter is not 0 ,then mesh is freed (i.e. pushed to stack)
inline GRAPEMESH * getAndFreeMesh( GRAPEMESH * mesh = 0 )  
{
  static std::stack< GRAPEMESH * > meshStack;

  if(mesh) 
  {
    // free mesh 
    meshStack.push(mesh);
    return 0;
  }
  else 
  {
    // get mesh 
    //if(meshStack.empty())
    {
      return getMesh();
    }
    /*
    // not working yet 
    else 
    {
      GRAPEMESH * m = meshStack.top();
      meshStack.pop();
      return m;
    }
    */
  }
}

/*****************************************************************************
******************************************************************************
**                      **
**  Die Hautroutine zum Initialisieren und Aufrufen eines HMESH"      **
**                      **
**  --setupHmesh 
**  --hmesh 
**
******************************************************************************
*****************************************************************************/
inline void * setupHmesh(const int noe, const int nov, 
    const int maxlev, DUNE_DAT * dune,
    const char *meshName )
{
  GRAPEMESH *mesh = getMesh( meshName );
  
  assert(mesh != NULL);
  
  mesh->first_macro = first_macro ;
  mesh->next_macro  = next_macro ;
  
  mesh->first_child = first_child ;
  mesh->next_child  = next_child ;

  mesh->select_child  = select_child;
  
  mesh->copy_element  = copy_element ;
  mesh->free_element  = gFreeElement ;
  mesh->complete_element = complete_element;

  mesh->max_number_of_vertices = MAX_EL_DOF ;
  mesh->max_eindex = noe ;
  mesh->max_vindex = nov ;
  
#if GRAPE_DIM==2
  mesh->dimension_of_world = GRAPE_DIMWORLD;
#endif
  mesh->max_dimension_of_coord = GRAPE_DIMWORLD;
  mesh->max_dindex = 20;

  mesh->max_level = maxlev;
  mesh->level_of_interest = maxlev;

  mesh->get_geometry_vertex_estimate  = get_geometry_vertex_estimate;  
  mesh->get_geometry_element_estimate = get_geometry_element_estimate;
  mesh->get_lens_element_estimate = 0;

  mesh->threshold              = 1.0;
  
  mesh->user_data = (void *) dune;

  mesh->set_time = 0;
  mesh->get_time = 0;
  mesh->f_data   = 0;

  grapeAddLevelFunction(mesh);
 
  return ((void *) mesh);
}

// delete Hmesh , not really working yet 
inline void deleteHmesh( void * hmesh ) 
{
  getAndFreeMesh( (GRAPEMESH *) hmesh);
}
  
// delete Hmesh , not really working yet 
inline void deleteFunctions( void * hmesh ) 
{
  //assert( hmesh );
  //GRAPEMESH * mesh = (GRAPEMESH *) hmesh; 

  /*
  GENMESH_FDATA * f_data = mesh->f_data; 
  while( f_data )
  {
    char * name = f_data->name;
    if(name) 
    {
      std::cout << "Got " << name << " func \n";
      mesh = (GRAPEMESH *) GRAPE_CALL(mesh,"remove-function")(name);
    }
    f_data = mesh->f_data;
  }
  */

  //mesh->f_data = 0;
  //mesh->user_data = 0;
}
  
static inline void addProjectUIF ()
{
#if 0
  // only call this once because GraPE cannot be run twice within the same program
  static bool firstCall = true;
  if( firstCall )
  {
    char p_name[ 32 ];
    sprintf( p_name, "uif-m%d", GRAPE_DIM );
    g_project_add( p_name );
    firstCall = false;
  }
#endif
}

extern "C" {
  extern MESH2D   * mesh2d_isoline_disp();
  extern MESH2D   * mesh2d_isoline_select_disp(); 
  extern HPMESH2D * hpmesh2d_isoline_disp();
  extern GENMESH2D* genmesh2d_isoline_disp();
  extern GENMESH2D* genmesh2d_isoline_select_disp();
  extern GENMESH2D* genmesh2d_geometry_graph_disp();
  extern MESH2D *mesh2d_isoline_disp();
  extern MESH2D *mesh2d_isoline_select_disp();
  extern MESH2D *mesh2d_vect_disp();
  extern HPMESH2D* hpmesh2d_pdegfine_disp();
  extern GENMESH2D* genmesh2d_chess_disp();
  extern MESH2D *mesh2d_flic_disp();
  
  extern GENMESH3D* genmesh3d_bnd_isoline_disp();
  extern GENMESH3D* genmesh3d_bnd_isoline_select_disp();
  extern GENMESH3D* genmesh3d_clip_isoline_multi_disp ();
  extern GENMESH3D* genmesh3d_volume_disp ();
  extern MESH3D* mesh3d_bnd_isoline_select_disp();
  extern MESH3D* mesh3d_bnd_isoline_disp();
}

// methodName is set by scene set_min_max_value
static std::string grapeMethodName;

static inline void setMinMaxValuesToColorbars(const char* meshName, 
                                              const double min, 
                                              const double max) 
{
  typedef std::list< COLORBAR * > ColorBarListType; 
  static bool firstCall = true; 
  static ColorBarListType colorBarList; 
  
  if( firstCall )
  {
    ///////////////////////////////
    // all functions from mesh2d 
    ///////////////////////////////
    {
      COLORBAR * colorBar = (COLORBAR *) GRAPE_CALL(Colorbar,"get-stdcolorbar")(genmesh2d_isoline_disp,"isoline-disp"); 
      if ( colorBar ) colorBarList.push_back( colorBar );
    }
    {
      COLORBAR * colorBar = (COLORBAR *) GRAPE_CALL(Colorbar,"get-stdcolorbar")(genmesh2d_isoline_select_disp,"isoline-select-disp"); 
      if ( colorBar ) colorBarList.push_back( colorBar );
    }
    {
      COLORBAR * colorBar = (COLORBAR *) GRAPE_CALL(Colorbar,"get-stdcolorbar")(hpmesh2d_isoline_disp,"isoline-disp"); 
      if ( colorBar ) colorBarList.push_back( colorBar );
    }
    {
      COLORBAR * colorBar = (COLORBAR *) GRAPE_CALL(Colorbar,"get-stdcolorbar")(genmesh2d_geometry_graph_disp,"geometry-graph-disp"); 
      if ( colorBar ) colorBarList.push_back( colorBar );
    }
    {
      COLORBAR * colorBar = (COLORBAR *) GRAPE_CALL(Colorbar,"get-stdcolorbar")(mesh2d_isoline_select_disp,"mesh2d-isoline-select"); 
      if ( colorBar ) colorBarList.push_back( colorBar );
    }
    {
      COLORBAR * colorBar = (COLORBAR *) GRAPE_CALL(Colorbar,"get-stdcolorbar")(mesh2d_isoline_disp,"mesh2d-isoline"); 
      if ( colorBar ) colorBarList.push_back( colorBar );
    }
    {
      COLORBAR * colorBar = (COLORBAR *) GRAPE_CALL(Colorbar,"get-stdcolorbar")(mesh2d_vect_disp,"mesh2d-vect"); 
      if ( colorBar ) colorBarList.push_back( colorBar );
    }
    {
      COLORBAR * colorBar = (COLORBAR *) GRAPE_CALL(Colorbar,"get-stdcolorbar")(hpmesh2d_pdegfine_disp,"pdegfine-disp"); 
      if ( colorBar ) colorBarList.push_back( colorBar );
    }
    {
      COLORBAR * colorBar = (COLORBAR *) GRAPE_CALL(Colorbar,"get-stdcolorbar")(genmesh2d_chess_disp, "GenMesh2d::chess-disp"); 
      if ( colorBar ) colorBarList.push_back( colorBar );
    }
    //{
    //  COLORBAR * colorBar = (COLORBAR *) GRAPE_CALL(Colorbar,"get-stdcolorbar")(mesh2d_flic_disp,"flic"); 
    //  if ( colorBar ) colorBarList.push_back( colorBar );
    //}
    ///////////////////////////////
    // all functions from mesh3d 
    ///////////////////////////////
    {
      COLORBAR * colorBar = (COLORBAR *) GRAPE_CALL(Colorbar,"get-stdcolorbar")(genmesh3d_bnd_isoline_disp,"bnd-isoline-disp");
      if ( colorBar ) colorBarList.push_back( colorBar );
    }
    {
      COLORBAR * colorBar = (COLORBAR *) GRAPE_CALL(Colorbar,"get-stdcolorbar")(genmesh3d_bnd_isoline_select_disp,"bnd-isoline-select-disp");
      if ( colorBar ) colorBarList.push_back( colorBar );
    }
    {
      COLORBAR * colorBar = (COLORBAR *) GRAPE_CALL(Colorbar,"get-stdcolorbar")(genmesh3d_clip_isoline_multi_disp,"genmesh3d-clip-isoline-multi-disp");
      if ( colorBar ) colorBarList.push_back( colorBar );
    }
    {
      COLORBAR * colorBar = (COLORBAR *) GRAPE_CALL(Colorbar,"get-stdcolorbar")(genmesh3d_volume_disp, "GenMesh3d-volume");
      if ( colorBar ) colorBarList.push_back( colorBar );
    }
    {
      COLORBAR * colorBar = (COLORBAR *) GRAPE_CALL(Colorbar,"get-stdcolorbar")(mesh3d_bnd_isoline_select_disp,"bnd-isoline-select-disp");
      if ( colorBar ) colorBarList.push_back( colorBar );
    }
    {
      COLORBAR * colorBar = (COLORBAR *) GRAPE_CALL(Colorbar,"get-stdcolorbar")(mesh3d_bnd_isoline_disp,"bnd-isoline-disp");
      if ( colorBar ) colorBarList.push_back( colorBar );
    }
    {
      COLORBAR * colorBar = (COLORBAR *) GRAPE_CALL(Colorbar,"get-stdcolorbar")(genmesh3d_bnd_isoline_disp,"bnd-isoline-disp");
      if ( colorBar ) colorBarList.push_back( colorBar );
    }
    //////////////////////////////
    //////////////////////////////
    firstCall = false;
  }

#ifdef GRAPE_GENMESH_WITH_DIFFERENT_COLORBARS
  if ( meshName ) 
  {
    COLORBAR * cb = get_colorbar_from_handle( meshName );
    if( cb )
    {
      cb->min = min; 
      cb->max = max;
    }
  }
#endif

  typedef ColorBarListType :: iterator iterator; 

  const iterator end = colorBarList.end();
  for(iterator it = colorBarList.begin(); it != end; ++it)
  {
    COLORBAR * cb = (*it);
    cb->min = min; 
    cb->max = max;
  }
}

inline GRAPEMESH * setMinMaxValue()  
{
  GRAPEMESH * mesh = 0;
  mesh = (GRAPEMESH *) START_METHOD(G_INSTANCE);
  ASSURE (mesh, "No HMESH in setMinMaxValue! \n", END_METHOD (0));

  F_DATA * f_data = (F_DATA*)GRAPE_CALL(mesh,"get-function")
                    ("scalar","scalar","vector","default", 0);
  DUNE_FDATA * func = 0;
  if(f_data) 
  {
    DUNE_FDATA * data = (DUNE_FDATA *) f_data->function_data;
    if( DUNE_FDATA::dataList().find(data) !=
        DUNE_FDATA::dataList().end() )
    {
      func = data; 
    }
  }

  double min=0.0, max=1.0;
  if(func) 
  {
    assert(func->getMinMaxValues);
    func->getMinMaxValues(func,&min,&max);
  }

  setMinMaxValuesToColorbars(mesh->name,min,max);

  END_METHOD(mesh);
}

inline void colorBarMinMax(const double min, const double max)
{
  GRAPE_CALL(Colorbar,"set-default-min-max")(min,max);
}
    
/* forward declaration */
static void grape_add_remove_methods(void);

inline void handleMesh( void *hmesh, bool gridMode )
{
    GRAPEMESH *mesh = (GRAPEMESH *)hmesh;
    assert( mesh );

    // remember last selected function 
    static std::string lastFunctionName("zero");
    static std::string lastSlotName("default");

    MANAGER * mgr = (MANAGER *)GRAPE_CALL( Manager, "get-stdmgr" )();
    SCENE *scene = (SCENE *)GRAPE_CALL( Scene, "new-instance" )( "DUNE Grid" );
    assert( scene );

    addProjectUIF();
    
#ifdef GRID_MODE
    if(gridMode)
    {
      /* if no data then switch to grid mode */
      GRAPHICDEVICE *grdev;

      grdev = (GRAPHICDEVICE *)GRAPE_CALL(GraphicDevice,"get-stddev")();
      grdev->clear();
      if (grdev && (grdev->grid_patch != G_GRID)) {
        GRAPE_CALL(grdev,"grid-patch")(G_GRID);
      }
    }
#endif

    scene->object = (TREEOBJECT *)mesh;

    if( !maxlevelButton)
      setupLeafButton( mgr, scene, 0 );
    
    grape_add_remove_methods();
    
    // if function name exists, this function is selected again 
    if( (lastFunctionName != "") && (lastSlotName != "") )
    {
      GRAPE_CALL(mesh,"select-function")(lastSlotName.c_str(),lastFunctionName.c_str());
    }

    GRAPE_CALL( mgr, "handle" )(scene); // grape display call 

    removeLeafButton(mgr,scene);

    FctSelector::DataFunctionName_t fctName = FctSelector::getCurrentFunctionName( mesh );
    
    // remember last selected function 
    lastSlotName     = fctName.first;
    lastFunctionName = fctName.second;

    // remove obj 
    scene->object = 0;
    GRAPE_CALL( scene, "delete" )();
}

/*
 * setup TimeScene Tree  */
inline void addHmeshToTimeScene(void * timescene, double time, void  *hmesh, int proc)
{
  TIMESCENE *tsc = (TIMESCENE *) timescene;
  GRAPEMESH *mesh = (GRAPEMESH *) hmesh;
  int i=0;
  assert(tsc != NULL); assert ( mesh != NULL);

  for(i=0; i<proc; i++)
  {
    tsc = (TIMESCENE *) tsc->next_scene;
  }
  assert(tsc);
  
  if(tsc->dynamic)
  { 
    tsc->dynamic = (G_SCENE_OBJECT *)GRAPE_CALL(tsc->dynamic,"put") (mesh, mesh, time);
  }
  else
    tsc->dynamic = (G_SCENE_OBJECT *)GRAPE_CALL(TimeStep,"put") (mesh, mesh, time);
 
  return;
}

/*
 * setup TimeScene Tree  */
inline void addHmeshToGlobalTimeScene(double time, void  *hmesh, int proc)
{
  TIMESCENE *tsc = globalTsc;
  GRAPEMESH *mesh = (GRAPEMESH *) hmesh;
  assert(tsc  != NULL); 
  assert(mesh != NULL);

  if(tsc->dynamic)
  { 
    tsc->dynamic = (G_SCENE_OBJECT *)GRAPE_CALL(tsc->dynamic,"put") (mesh, mesh, time);
  }
  else
    tsc->dynamic = (G_SCENE_OBJECT *)GRAPE_CALL(TimeStep,"put") (mesh, mesh, time);
 
  return;
}

inline DUNE_FDATA * extractData ( void * hmesh , int num )
{
  HMESH *mesh = (HMESH *) hmesh;
  int count = 0;
  assert ( mesh != NULL );

  printf("actual mesh %p \n",mesh);
  
  GENMESH_FDATA *next_data = mesh->f_data;
  while ( (count < num) && (next_data != NULL) ) 
  {
    next_data = next_data->next;
    count++;
  }

  if( next_data )
  {
    DUNE_FDATA * df = (DUNE_FDATA *) next_data->function_data;
    std::cout << "df->name = " << df->name << std::endl;
    return df;
  }
  
  return NULL;
}


/* copy function data */
inline void copyFdata(F_DATA *copy, F_DATA *org)
{
  copy->name = org->name;
  copy->last = org->last;
  copy->next = org->next;
  
  copy->dimension_of_value  = org->dimension_of_value;
  copy->continuous_data = org->continuous_data;
  copy->function_data  = org->function_data;

  copy->f = org->f;
  copy->f_el_info = org->f_el_info;
  
  copy->get_bounds  = org->get_bounds;
  copy->get_vertex_estimate = org->get_vertex_estimate;
  copy->get_element_estimate  = org->get_element_estimate;
   
  copy->threshold = org->threshold;
#if GRAPE_DIM == 3
  copy->geometry_threshold = org->geometry_threshold;
#else 
  copy->get_element_p_estimates = org->get_element_p_estimates;
  copy->get_edge_p_estimates    = org->get_edge_p_estimates; 
#endif
  copy->hp_threshold = org->hp_threshold;
  copy->hp_maxlevel = org->hp_maxlevel;
}

inline static void copyHmeshes(GRAPEMESH *orgMesh, GRAPEMESH * self) 
{
  assert( self );
  assert( orgMesh );
  
  if( (!self->f_data) && (orgMesh->f_data) )
  {
    self->level_of_interest = orgMesh->level_of_interest;
    F_DATA *next_data = (F_DATA *) orgMesh->f_data;
    /* to keep the same order we have to go backward */
    while (next_data)
    {
      if(next_data->next) next_data = (F_DATA *) next_data->next;
      else break;
    }
    while (next_data)
    {
      F_DATA * f_data = (F_DATA *) malloc(sizeof(F_DATA));
      assert(f_data != NULL);
      copyFdata(f_data,next_data);

      self = (GRAPEMESH *) GRAPE_CALL(self,"add-function")(f_data);
      next_data = (F_DATA *) next_data->last;
    }
  }
 
  self->max_dimension_of_coord = orgMesh->max_dimension_of_coord;
  self->max_eindex = orgMesh->max_eindex;
  self->max_vindex = orgMesh->max_vindex;
  self->max_dindex = orgMesh->max_dindex;
  self->max_number_of_vertices = orgMesh->max_number_of_vertices;

  self->access_mode = orgMesh->access_mode;
  self->access_capability = orgMesh->access_capability;

  /* we have to do that, GRAPE sucks  */
  /* set other function_data pointers */
  if(orgMesh->f_data)
  {
    GENMESH_FDATA * sf = self->f_data;
    while(sf != NULL)
    {
      const char * sfname = sf->name;
      GENMESH_FDATA * nf = orgMesh->f_data;
      int length = strlen(sfname);
      while( (nf != NULL) ) 
      {
        /* compare the real function name, ha, not with me */
        const char * nfname = nf->name;
        if( strncmp(sfname,nfname,length) == 0 )
        {
          sf->function_data = nf->function_data;
          break;
        }

        /* GRAPE sucks, sucks, sucks 
         * Robert after debugin' for this shit more than one day */
        if( nf != nf->last )
          nf = nf->next;
        else 
          break; 
      }

      /* go next f_data */
      if( sf != sf->last )
        sf = sf->next;
    }
  }

  /* copy current function selections to orgMesh */
  self = (GRAPEMESH *) GRAPE_CALL(self, "copy-function-selector")(orgMesh);

  self->user_data = orgMesh->user_data;

  self->copy_element = orgMesh->copy_element;
  self->free_element = orgMesh->free_element;

  self->complete_element = orgMesh->complete_element;
  self->set_time = orgMesh->set_time;
  self->get_time = orgMesh->get_time;

  self->first_macro = orgMesh->first_macro;
  self->next_macro = orgMesh->next_macro;
  self->first_child = orgMesh->first_child;
  self->next_child = orgMesh->next_child;
  self->select_child = orgMesh->select_child;

  self->max_level = orgMesh->max_level;
  self->level_of_interest = orgMesh->level_of_interest;
  /* do not set level_of_interest, because is set by user during run time */
  
  self->get_geometry_vertex_estimate  = orgMesh->get_geometry_vertex_estimate;  
  self->get_geometry_element_estimate = orgMesh->get_geometry_element_estimate;
  self->get_lens_element_estimate     = orgMesh->get_lens_element_estimate;
  self->threshold                     = orgMesh->threshold;

#if GRAPE_DIM==2
  self->dimension_of_world = orgMesh->dimension_of_world;
#endif
}

/* interpol method for timescence, just constant interpolation */
inline static GRAPEMESH *grape_mesh_interpol(GRAPEMESH *mesh1, GRAPEMESH *mesh2,
               double factor)
{
  GRAPEMESH *self=NULL;
  GRAPEMESH *org =NULL;
  
  self = (GRAPEMESH *)START_METHOD(G_INSTANCE);
  ASSURE (self, "No HMESH in method interpol! \n", END_METHOD (NULL));

  if (factor < 0.5)
    org = mesh1;
  else
    org = mesh2;

  // copy meshes 
  copyHmeshes(org,self);

  END_METHOD(self);
}

/****************************************************************************/
/* handling of multiple functions (selection by next/last)                  */
/****************************************************************************/

inline static HMESH *next_f_data_send(void)
{
  HMESH *self;
  printf("next_f_data_send called! \n");
  
  self = (HMESH *)START_METHOD(G_INSTANCE);
  ASSURE(self, "", END_METHOD(NULL));

  if (self->f_data && self->f_data->next)
  {
    self->f_data->next->last = self->f_data;  /*only to be sure...*/
    self->f_data = self->f_data->next;
  }
  if (self->f_data)
    printf("new f_data is: %s\n", self->f_data->name);

  END_METHOD(self);
}

inline static HMESH *prev_f_data_send(void)
{
  HMESH *self;
  printf("prev_f_data_send called! \n");

  self = (HMESH *)START_METHOD(G_INSTANCE);
  ASSURE(self, "", END_METHOD(NULL));

  if (self->f_data && self->f_data->last)
  {
    self->f_data->last->next = self->f_data;  /*only to be sure...*/
    self->f_data = self->f_data->last;
  }
  if (self->f_data)
    printf("new f_data is: %s\n", self->f_data->name);

  END_METHOD(self);
}

inline SCENE* scene_maxlevel_on_off ()
{
  SCENE* sc = (SCENE*) START_METHOD (G_INSTANCE);
  GRAPE_ALERT(sc,"maxlevel-on-off: No hmesh!",END_METHOD(NULL));

  if( maxlevelButton->on_off == ON )
  { 
    GRAPE_CALL(maxlevelButton,"set-state")(UNPRESSED);
    maxlevelButton->on_off = OFF;
  }
  else
  { 
    GRAPE_CALL(maxlevelButton,"set-state")(PRESSED);
    maxlevelButton->on_off = ON;
  }
  END_METHOD (sc);
}

inline SCENE* scene_set_min_max_values ()
{
  SCENE* sc = (SCENE*) START_METHOD (G_INSTANCE);
  GRAPE_ALERT( sc, "set-min-max-values: No hmesh!", END_METHOD(NULL));
  
  // only if method different from display
  if(sc->method_name) 
  {
    // remember method name 
    grapeMethodName = sc->method_name;
    GRAPE_CALL(sc, "universal")("value-min-max");
  }
  END_METHOD (sc);
}

GENMESH3D * genmesh3d_switch_iterateLeafs_on_off();
 
static int ruler_bnd_id = 0;
inline static HELEMENT * bnd_next_macro (HELEMENT * prevEl, MESH_ELEMENT_FLAGS flag) 
{
  HELEMENT * el = next_macro(prevEl,flag);
  if(el) 
  {
    DUNE_ELEM* elem = (DUNE_ELEM*) el->user_data;
    assert( elem );
    for(int i=0; i<MAX_EL_FACE; ++i)
     if(ruler_bnd_id == elem->bnd[i]) return el; 
  }
  else 
  { 
    return 0;
  }
  return bnd_next_macro(el,flag); 
}
  
inline static HELEMENT * bnd_first_macro (GENMESHnD *mesh, MESH_ELEMENT_FLAGS flag) 
{
  HELEMENT * el = first_macro(mesh,flag);
  
  if(el) 
  {
    DUNE_ELEM* elem = (DUNE_ELEM*) el->user_data;
    assert( elem );
    for(int i=0; i<MAX_EL_FACE; ++i)
     if(ruler_bnd_id == elem->bnd[i]) return el; 
  }
  else 
  {
    return 0;
  }
  return bnd_next_macro(el,flag); 
}
  
inline HMESH* genmesh_boundary_disp ()
{  
  HMESH * hmesh = (HMESH*) START_METHOD (G_INSTANCE);
  GRAPE_ALERT(hmesh, "genmesh-boundary-id: No hmesh!", END_METHOD(NULL));

  MANAGER* mgr = (MANAGER *) GRAPE_CALL(Manager,"get-stdmgr") ();
  assert( mgr );
  
  hmesh->first_macro = bnd_first_macro ;
  hmesh->next_macro  = bnd_next_macro ;
 
  static RULER * bndIdRuler = 0; 
  
  if(!bndIdRuler) 
  { 
    bndIdRuler = (RULER *) 
      new_item(Ruler, I_Name, "boundary id",
          I_Instance, hmesh,
          I_Var, &ruler_bnd_id, dfINT,
          I_ColorRGB,0.42,0.42,0.0,
          I_End);
  }
 
  // if called first time, add ruler 
  if(GRAPE_CALL(mgr,"new-handle") (genmesh_boundary_disp,1)) 
  {
    GRAPE_CALL(mgr,"add-inter")(bndIdRuler);
  }
  
  GRAPE_CALL(hmesh,"display")();
  
  hmesh->first_macro = first_macro ;
  hmesh->next_macro  = next_macro ;
  
  END_METHOD (hmesh);
}

// make hard copy of hmesh, i.e. create new object and copy data 
inline HMESH* newHmeshHardCopy() 
{  
  HMESH * hmesh = (HMESH*) START_METHOD (G_INSTANCE);
  GRAPE_ALERT(hmesh, "hmesh-hardcopy: No hmesh!", END_METHOD(NULL));

  std::string newName("H: ");
  newName += hmesh->name;

  // get new hmesh 
  HMESH* copy = (HMESH *) GRAPE_CALL(HMesh,"new-instance")(newName.c_str());
  GRAPE_ALERT(copy, "hmesh_hardcopy: No new instance!", END_METHOD(NULL));

  // copy mesh
  copyHmeshes(hmesh,copy);

  END_METHOD (copy);
}

/* add some usefull methods */
inline static void grape_add_remove_methods(void)
{
  // if true returned, then grape was already initialized 
  if( GRAPE_CALL(HMesh,"find-method")("next-f-data-send") ) return ;
  
  if( (GRAPE_CALL(Scene,"find-method")("set-min-max-values")) )
  {
    GRAPE_CALL(Scene,"delete-method")("set-min-max-values");
  }
  GRAPE_CALL(Scene,"add-method")("set-min-max-values",scene_set_min_max_values);

  printf("add-method 'next-f-data-send' on HMesh%dd!\n",GRAPE_DIM);
  GRAPE_CALL(HMesh,"add-method")("next-f-data-send",&next_f_data_send);
  printf("add-method 'prev-f-data-send' on HMesh%dd!\n",GRAPE_DIM);
  GRAPE_CALL(HMesh,"add-method")("prev-f-data-send",&prev_f_data_send);
  GRAPE_CALL(GrapeMesh,"add-method")("interpol", &grape_mesh_interpol);
  
  printf("add-method 'value-min-max' on HMesh%dd!\n",GRAPE_DIM);
  
  GRAPE_CALL(HMesh,"add-method")("value-min-max", &setMinMaxValue);

  // overload hardcopy 
  printf("add-method 'hardcopy' on HMesh%dd!\n",GRAPE_DIM);
  GRAPE_CALL(HMesh,"add-method")("hardcopy",&newHmeshHardCopy);

#if GRAPE_DIM == 3 
  GRAPE_CALL(GenMesh3d,"add-method")("get-partition-number",get_partition_number);
  GRAPE_CALL(HMesh,"add-method")("boundary-id-disp",genmesh_boundary_disp);
#endif

  if( ! (GRAPE_CALL(Scene,"find-method")("maxlevel-on-off")) )
    GRAPE_CALL(Scene,"add-method")("maxlevel-on-off",scene_maxlevel_on_off);

  {
    char p_name[32];
    sprintf(p_name,"uif-m%d",GRAPE_DIM);
    g_project_add(p_name);
  }
}

#endif // #ifndef __GRAPE_HMESH_C__
