#ifndef __GRAPE_HMESH_H__
#define __GRAPE_HMESH_H__

//- system includes 
#include <cstdlib>
#include <cassert>
#include <cstring>
#include <iostream>
#include <stack>
#include <set>
#include <list>

//- Grape includes 
#include "grapecommon.hh"

#if HAVE_GRAPE

enum { MAX_NAME_LENGTH = 32 };

typedef struct dune_elem  DUNE_ELEM;
typedef struct dune_fdata DUNE_FDATA;
typedef struct dune_dat  DUNE_DAT;

typedef void evalDof_t  (DUNE_ELEM *, DUNE_FDATA *, int , double *);
typedef void evalCoord_t(DUNE_ELEM *, DUNE_FDATA *, const double *, double * );

/* interface element */
struct dune_elem 
{

  // default constructor 
  dune_elem() 
    : type(127) 
    , eindex(-1)
    , level(-1)
    , level_of_interest(-1)
    , has_children(0) 
    , liter(0)
    , enditer(0) 
    , hiter(0) 
    , actElement(0) 
    , gridPart(0) 
    , display(0) 
    , mesh(0) 
  {
    // default set all coordinates to zero
    for(int i=0; i<MAX_EL_DOF; ++i)
    {
      vindex [i] = -1;
      vpointer[i] = (double *) coordinates[i];
      for(int j=0; j<3; ++j)
      {
        vpointer[i][j] = 0.0;
      }
    }
    for(int i=0; i<MAX_EL_FACE; ++i)
    {
      bnd [i] = -1;
    }
  }
  
  /* 
   *  see g_eldesc.h for ElementType 
   */
  int       type; 

  double *        vpointer [MAX_EL_DOF];
  double          coordinates [MAX_EL_DOF][3];
  int             vindex [MAX_EL_DOF] ;
  int             bnd [MAX_EL_FACE] ;
  int             eindex;
  int             level;
  int             level_of_interest;
  int             has_children;
  
  /* is the pointer to LevelIterator or to LeafIterator */
  void          * liter;
  void          * enditer;

  // pointer fo hierarchic iterator */
  void          * hiter;

  /* points to actual iterator to compare an get type */
  /* down cast to EntityPointer */
  void          * actElement;

  /* actual choosen gridPart */
  void          * gridPart; 

  // pointer to my display class 
  void          * display;

  // pointer to mesh 
  void          * mesh; 
};

struct dune_fdata 
{
  static std::set<DUNE_FDATA*>& dataList () 
  {
    static std::set<DUNE_FDATA*> dList;
    return dList;
  }
  
  // default constructor 
  dune_fdata() 
    : mynum (-1) 
    , name() 
    , evalCoord(0) 
    , evalDof(0)
    , discFunc(0) 
    , indexSet(0)
    , allLevels(0)
    , dimVal(0)
    , dimRange(0) 
    , comp(0) 
    , polyOrd(0)
    , continuous(0)
    , compName(0)
    , gridPart(0) 
    , setGridPartIterators(0)
    , f_data (0)
    , minValue(0.0)
    , maxValue(1.0)
    , valuesSet(false)
    , valCache(0.0)
    , getMinMaxValues(0)
  {
    // add this data to list of dune data funcs 
    dataList().insert(this);
  }
  
  // default destructor  
  ~dune_fdata() 
  { 
    dataList().erase(this);
  }
  
  /* my number in the data vector */
  int mynum; 

  /* name of data */
  std::string name; 
  
  // functions to evaluate 
  evalCoord_t * evalCoord; 
  evalDof_t   * evalDof; 
  
  /* pointer to object of discrete function or vector */
  const void *discFunc;

  /* pointer to index set of underlying datas */
  const void *indexSet;

  /* are all Levels occupied? */
  int allLevels; 

  /* dimension of value, i.e. the length of the vector  */
  int dimVal;

  /* dimension of data, when vectorial data is interpreted as scalar data */
  int dimRange; 
  
  /* index of current component */
  /* for scalar this vec has length 1 and contains the component number */ 
  /* for vector this contains the number of each component */
  int * comp;

  /* polynonial order of basis functions */
  int polyOrd; 
  
  /* continuous or not */
  int continuous;

  /* max number of components */
  int compName;

  /* the corresponding gridPart */
  void * gridPart; 

  /* function pointer to choose grid part iterators */
  void (*setGridPartIterators)(DUNE_DAT * , void * gridPart);

  /* pointer to f_data */
  void * f_data; 

  /* minValue of function, for colorbar */
  double minValue;
  /* maxValue of function, for colorbar */
  double maxValue;

  /* true if min and max values have been calculated */
  bool valuesSet;
  
  /* cache for polOrd zero functions */
  double valCache;

  /* returns min and max values of function */
  void (*getMinMaxValues)(DUNE_FDATA *, double * min, double * max );
};

/* dune_dat */
struct dune_dat
{
  // default constructor 
  dune_dat() 
    : first_macro(0)
    , next_macro(0) 
    , delete_iter(0) 
    , first_child(0) 
    , next_child(0)
    , copy(0)
    , check_inside(0)
    , wtoc(0) 
    , ctow(0)
    , setIterationModus(0)
    , partition(-1)
    , iteratorType(-1) // g_LeafIterator
    , partitionIteratorType(-1)
    , gridPart(0)
    , all (0) 
    , get_stackentry(0) 
    , free_stackentry(0) {}

  /* the actual first and next macro for Iteration  */
  int (* first_macro)(DUNE_ELEM *) ;
  int (* next_macro)(DUNE_ELEM *) ;

  /* method to delete iterators */
  void (* delete_iter)(DUNE_ELEM *) ;

  /* first and next child , if 0, then no child iteration */
  int (* first_child)(DUNE_ELEM *) ;
  int (* next_child)(DUNE_ELEM *) ;

  void * (* copy)(const void *) ;

  int  (* check_inside)(DUNE_ELEM *, const double * ) ;
  int  (* wtoc)(DUNE_ELEM *, const double *, double * ) ;
  void (* ctow)(DUNE_ELEM *, const double *, double * ) ;

  
  /* selects the iterators, like leaf iterator .. */
  void (* setIterationModus)(DUNE_DAT *, DUNE_FDATA *);  

  /* to which processor partition the element belongs */
  int partition;

  /* type of choosen iterator */
  int iteratorType; 

  /* type of partition to iterate */
  int partitionIteratorType; 

  /* actual gridPart */
  void * gridPart;

  DUNE_ELEM * all;

  /* get HELEMENT */
  void * (*get_stackentry)(DUNE_DAT * ); 
  /* free HELEMENT */
  void   (*free_stackentry)(DUNE_DAT * , void *); 
};

/* setup hmesh with given data */
extern void *setupHmesh(const int noe, const int nov, 
                        const int maxlev, DUNE_DAT * dune);

/* delete given hmesh pointer */
extern void deleteHmesh( void * hmesh ); 
extern void deleteFunctions( void * hmesh ); 

//extern void displayTimeScene(INFO * info, int procs);
extern void handleMesh (void *hmesh, bool gridMode );

extern DUNE_FDATA * extractData (void *hmesh , int num );

/* setup TimeScene Tree  */
extern void timeSceneInit(INFO *info, const int n_info, const int procs);
extern void addDataToHmesh(void  *hmesh, DUNE_FDATA * data);

extern void addHmeshToTimeScene(void * timescene, double time, void  *hmesh , int proc);

extern void addHmeshToGlobalTimeScene(double time, void  *hmesh , int proc);
extern void tsc_timebar(void *timescene, double t_start, double t_end);
extern void colorBarMinMax(const double min, const double max);

#endif // #if HAVE_GRAPE

#endif // #ifndef __GRAPE_HMESH_H__
