#include <ctype.h>
#include <alberta.h>
#if (defined(ALBERTA_VER) && (ALBERTA_VER==2))
//# include "alberta1_wrapper.h" keine Kompatibilitaet, schon lang nich mehr.
#endif
#include "newalberta.hh"
#include "graphics.hh"

ADAPT_INSTAT   *adapt_master = nil;
const FE_SPACE* const_fe_space;
DOF_INT_VEC* subdoms=nil;
#if 0
void init_subdom_dof_admin(MESH *mesh)
{
  FUNCNAME("init_err_dof_admin");
  const BAS_FCTS  *lagrange= get_lagrange(0);
  const_fe_space = get_fe_space(mesh, lagrange->name, nil, lagrange);
  return;
}
#endif
void init_subdom_dof_admin(MESH *mesh)
{
  FUNCNAME("init_subdom_dof_admin");
  FLAGS periodic = 0U, flag = 0U;
  GET_PARAMETER(2, "periodic", "%d", &periodic);
  if (periodic) 	{flag = ADM_PERIODIC ;}
	else 				{flag = 0U;}
flag = 0U;//wegen bug ueberbuegelt
  const BAS_FCTS  *lagrange= get_lagrange(mesh->dim,0);
  TEST_EXIT(lagrange,"no lagrange BAS_FCTS\n");
  const_fe_space = get_fe_space(mesh, lagrange->name, nil, lagrange, flag);
//Punkte auf dem Bazyzentrum sind von Periodizitaet nicht betroffen. Oder vielleicht daher der
//FEhler beim Coarsening?
  return;
}


//const DOF    *(*get_subdomdof)(const EL *, const DOF_ADMIN *, DOF *);//??
int get_subdom(const EL *el)
{
//Baustelle!!!!!!!!
int subdom;
//  if (IS_LEAF_EL(el))
 //  {
	(const_fe_space->bas_fcts->get_int_vec)(el, subdoms, &subdom);
   	return(subdom);
//	}
//  else
//    return(-1);
}
REAL get_plot_subdom( EL *el)
{
//dasselbe, nur fuers schwule plot...
int subdom;
//  if (IS_LEAF_EL(el))
 //  {
	(const_fe_space->bas_fcts->get_int_vec)(el, subdoms, &subdom);
   	return((REAL) subdom);
//	}
//  else
//    return(-1);
}


// gem. S. 194
#if 0
static void  const_int_refine_interpol(DOF_INT_VEC* drv, RC_LIST_EL *list, int n)
{
  FUNCNAME("const_int_refine_interpol");
	TEST_EXIT(drv->fe_space == const_fe_space,"no const_fe_space\n");
  int*  vec=nil;
	DOF dof0, dof_new1, dof_new2;
  EL* el= list->el;
 static const int n0 = const_fe_space->admin->n0_dof[VERTEX];// riskant, koennte falsch sein
	MSG("n: %d\n", n );	//if (n<1) return;				//Nicht-
	GET_DOF_VEC(vec, drv);
	dof0=el->dof[0][n0]; //hoffentlich richtig indiziert
	dof_new1=el->child[0]->dof[0][n0];
	MSG("dof0: %d ,vec[dof0]: %d", dof0, vec[dof0]);
	dof_new2=el->child[1]->dof[0][n0];
	vec[dof_new1]=	vec[dof_new2]	=vec[dof0];
	MSG("dof_new1: %d ,vec[dof_new1]: %d\n", dof_new1, vec[dof_new1]);
	MSG("dof_new2: %d ,vec[dof_new2]: %d\n", dof_new2, vec[dof_new2]);
return;
}
#endif

void dof_set(int alpha, DOF_INT_VEC *x)
{
  FUNCNAME("dof_set(int)");
  const DOF_ADMIN *admin = NULL;

  TEST_EXIT(x && x->fe_space && (admin = x->fe_space->admin),
	    "pointer is NULL: %p, %p\n", x, admin);
  TEST_EXIT(x->size >= admin->size_used,
	    "x->size = %d too small: admin->size_used = %d\n", x->size,
	    admin->size_used);

  FOR_ALL_DOFS(admin, x->vec[dof] = alpha );
}

static void  const_int_refine_interpol(DOF_INT_VEC* drv, RC_LIST_EL *list, int n)
{
  FUNCNAME("const_int_refine_interpol");
  TEST_EXIT(drv->fe_space == const_fe_space,"no const_fe_space\n");
  int*  vec= nil;//GET_DOF_VEC(vec, drv);
	int i;
	GET_DOF_VEC(vec, drv);
  	EL* el;
  const DOF    *(*get_dof_indices)(const EL *, const DOF_ADMIN *, DOF *
				   DEF_BFCTS_THIS(thisptr));
	get_dof_indices	= const_fe_space->bas_fcts->get_dof_indices;
for  (i=0;i<n; i++) 
	{
#if (defined(ALBERTA_VER) && (ALBERTA_VER==2))
	el = list[i].el_info.el;
#else
	el = list[i].el;
#endif	
	//if (el->child)
	//	{
   	DOF      dof0, dof_new1, dof_new2;
	get_dof_indices(el, const_fe_space->admin, &dof0);
	//(const_fe_space->bas_fcts->get_int_vec)(el, subdoms, &subdom);
	get_dof_indices(el->child[0], const_fe_space->admin,&dof_new1);
	get_dof_indices(el->child[1], const_fe_space->admin,&dof_new2);
	vec[dof_new1]=	vec[dof_new2]	=vec[dof0];
//	MSG("dof_new1: %d ,vec[dof_new1]: %d\n", dof_new1, vec[dof_new1]);
//	MSG("dof_new2: %d ,vec[dof_new2]: %d\n", dof_new2, vec[dof_new2]);
	}
return;
}

#if 0

static void const_int_coarsen_interpol(DOF_INT_VEC* drv, RC_LIST_EL *list, int n)
{
  FUNCNAME("const_int_coarsen_interpol");
  TEST_EXIT(drv->fe_space == const_fe_space,"no const_fe_space\n");
  int*  vec=nil;
	DOF dof0, dof_new1, dof_new2;
  EL* el= list->el;
 static const int n0 = const_fe_space->admin->n0_dof[/*VERTEX*/CENTER];// riskant, koennte falsch sein
	//if (n<1) return;				//Nicht-
	GET_DOF_VEC(vec, drv);
	dof0=el->dof[0][n0]; //hoffentlich richtig indiziert
	dof_new1=el->child[0]->dof[0][n0];
	dof_new2=el->child[1]->dof[0][n0];
//	TEST_EXIT(vec[dof_new1]==vec[dof_new2],"Elements of different subdoms coarsened to one");
	vec[dof0]=vec[dof_new1];
return;
}
#endif
static void  const_int_coarsen_interpol(DOF_INT_VEC* drv, RC_LIST_EL *list, int n)
{
  FUNCNAME("const_int_coarsen_interpol");
  TEST_EXIT(drv->fe_space == const_fe_space,"no const_fe_space\n");
  int*  vec= nil;//GET_DOF_VEC(vec, drv);
	int i;
	GET_DOF_VEC(vec, drv);
  	EL* el;
	const DOF*  (*get_dof_indices)(const EL *,const DOF_ADMIN *, DOF *);
				get_dof_indices	= const_fe_space->bas_fcts->get_dof_indices;
for  (i=0;i<n; i++) 
	{
#if (defined(ALBERTA_VER) && (ALBERTA_VER==2))
	el = list[i].el_info.el;
#else
	el = list[i].el;
#endif	
	//if (el->child)
	//	{
   	DOF      dof0, dof_new1, dof_new2;
	get_dof_indices(el, const_fe_space->admin, &dof0);
	get_dof_indices(el->child[0], const_fe_space->admin,&dof_new1);
	get_dof_indices(el->child[1], const_fe_space->admin,&dof_new2);
//	TEST_EXIT(vec[dof_new1]==vec[dof_new2],"%s:Elements of different subdoms coarsened to one",drv->name);
//dies geht nicht fuer symm. FE-Raum. Warum versteh ich nicht.
	vec[dof0]=vec[dof_new1];
//	MSG("dof_new1: %d ,vec[dof_new1]: %d\n", dof_new1, vec[dof_new1]);
//	MSG("dof_new2: %d ,vec[dof_new2]: %d\n", dof_new2, vec[dof_new2]);
	}
return;
}

/*Uhr: verwendet z.B. in PE_graphics.c zum Speichern
und (nicht mehr) zwischendurch in estimator*/
double get_time()
	{return(adapt_master->time);
	}

//standard set_time. sollte bei allen adapt_instats angewendet werde, da man dort oftmals
//adapt_instat->timestep u adapt_instat->time braucht. Sonst NaNs.
//machen wir erstmal per get_time u dann per Argumentliste
void set_time(MESH *mesh, ADAPT_INSTAT *adapt)
{
  FUNCNAME("set_time");
adapt->timestep = adapt_master->timestep;
adapt->time = adapt_master->time;
}


//must be called on macro grid. otherwise crash
static int get_subdoms(MESH *mesh,const char *filename)
{  FUNCNAME("get_subdoms");
  FILE       *file;
  MACRO_EL *mac = nil;
  int        dom, index, i, doms[mesh->n_macro_el], *domvec;
  char       name[128], line[256],key[100];
  char         *k = key;
  char         *l ;
  int        line_no,counter;
  const DOF*  (*get_dof_indices)(const EL *,const DOF_ADMIN *, DOF *);
	get_dof_indices	= const_fe_space->bas_fcts->get_dof_indices;
  DOF 	subdomdof;

//        doms=MEM_ALLOC(mesh->n_macro_el,int);
        index=0;
  TEST_EXIT(filename,"no file specified; filename nil pointer\n");
  TEST_EXIT(strlen(filename) < (unsigned int) 127,
    "can only handle filenames up to 127 characters\n");

  TEST_EXIT((file=fopen(filename,"r")),"cannot open file %s\n",filename);
  strncpy(name, filename, 127);

/*--------------------------------------------------------------------------*/
/*  looking for all keys in the macro file ...                              */
/*--------------------------------------------------------------------------*/

  line_no = 0;
  while (fgets(line, 255, file))
        {
        line_no++;
        l=&line[0];
        k=&key[0];
        if (!strchr(line, ':'))  continue;
        while(isspace(*l)) l++;
        while((*k++ = *l++) != ':');
                        {*--k = '\0';
                        } /*key enthaelt nun das Schluesselwort*/
        if (!strcmp(key,"element subdoms")) break;
        }
  counter=0;
  while (fgets(line, 255, file))
        { TEST_EXIT(counter <= mesh->n_macro_el,
                        "more subdomain marks than macro elements(%d)\n",mesh->n_macro_el);
        if (strchr(line, ':'))  break;
        if (sscanf(line,"%d",&dom)!=1)
                {
                MSG("error in subdom information, more or less than one number per line?\n");
                }
        else
                {TEST_EXIT(dom>0,"Domains must be numbered from 1 onward. Number was %d\n",&dom);
                doms[counter]=dom;
		MSG("%d",doms[counter]);
                counter++;
                }
        }
  i=0;
//  const int n0 = const_fe_space->admin->n0_dof[/*VERTEX*/CENTER];// riskant, koennte falsch sein
  GET_DOF_VEC(domvec,subdoms);
#if (defined(ALBERTA_VER) && (ALBERTA_VER==2))
  mac=mesh->macro_els;
  for(int n=0; n<mesh->n_macro_el; n++)
  {
   TEST_EXIT(i<counter,"more macro elements (>%d) than subdomain marks (%d) \n",i,counter);
   get_dof_indices(mac[n].el, const_fe_space->admin, &subdomdof);
   domvec[subdomdof] = doms[i];
   i++;
  }
#else  
  for (mac=(mesh->first_macro_el); mac!=nil; mac=(mac->next))
        {
        TEST_EXIT(i<counter,"more macro elements (>%d) than subdomain marks (%d) \n",i,counter);
//		subdomdof=mac->el->dof[0][n0]; //hoffentlich richtig indiziert
		get_dof_indices(mac->el, const_fe_space->admin, &subdomdof);
	
       domvec[subdomdof] = doms[i];
                i++;
        }
#endif	
  print_dof_int_vec(subdoms);
  return(0);
}
#if !(defined(ALBERTA_VER) && (ALBERTA_VER==2))
//noch nicht der Weisheit letzter Schluss, sehe aber nich, warum man universelleres braeuchte
static const BOUNDARY *init_boundary(MESH *mesh, int ibdry)
{
  FUNCNAME("init_boundary_4");
  static const BOUNDARY robin_1   = {nil, -1};
  static const BOUNDARY robin_2   = {nil, -2};
  static const BOUNDARY robin_3   = {nil, -3};
  static const BOUNDARY robin_4   = {nil, -4};
  static const BOUNDARY robin_5   = {nil, -5};
  static const BOUNDARY robin_6   = {nil, -6};
  static const BOUNDARY robin_7   = {nil, -7};
  static const BOUNDARY robin_8   = {nil, -8};
  static const BOUNDARY robin_9   = {nil, -9};
  static const BOUNDARY robin_10   = {nil, -10};
  static const BOUNDARY dirichlet = {nil, 1};

  if      (ibdry == -1) return(&robin_1);
  else if (ibdry == -2) return(&robin_2);
  else if (ibdry == -3) return(&robin_3);
  else if (ibdry == -4) return(&robin_4);
  else if (ibdry == -5) return(&robin_5);
  else if (ibdry == -6) return(&robin_6);
  else if (ibdry == -7) return(&robin_7);
  else if (ibdry == -8) return(&robin_8);
  else if (ibdry == -9) return(&robin_9);
  else if (ibdry == -10) return(&robin_10);
  else if (ibdry == 1)  return(&dirichlet);
  else ERROR_EXIT("unknown ibdry %d\n", ibdry);
  return(nil);
}
#endif

int init_master(MESH *mesh/*,const char *filename*/, ADAPT_INSTAT *adapt_masterptr)
{
  FUNCNAME("init_master");
  char  filename[156],filename2[156];
  int     n_refine;
  
  TEST_EXIT(adapt_masterptr,"No adapt_instat passed to here");
  TEST_EXIT(mesh,"No mesh passed to here");
  GET_PARAMETER(1, "global refinements", "%d", &n_refine);
//  GET_PARAMETER(1, "macro file name", "%s", filename);
  GET_PARAMETER(1, "subdomains file name", "%s", filename2);
#if (defined(ALBERTA_VER) && (ALBERTA_VER==2))
//   MACRO_DATA * macro_data=read_macro(filename);
//   macro_data2mesh(mesh,macro_data,nil, nil);
//   free_macro_data(macro_data);
//void macro_data2mesh(MESH*, const MACRO_DATA*
//		, NODE_PROJECTION* (*)(MESH*, MACRO_EL*, int), AFF_TRAFO* (*)(MESH*, MACRO_EL*, int))
#else	
	mesh->preserve_coarse_dofs = 0;
    	read_macro(mesh, 	filename,	init_boundary);
#endif
	subdoms  = get_dof_int_vec("subdoms", const_fe_space);
	subdoms->refine_interpol = const_int_refine_interpol;
	subdoms->coarse_restrict = const_int_coarsen_interpol;
 	get_subdoms(mesh, filename2);
//	graphics(mesh,   get_plot_subdom, nil, 		nil,	2);	
//	print_dof_int_vec(subdoms);
    	global_refine(mesh, n_refine*DIM);
	dof_compress(mesh);
//	print_dof_int_vec(subdoms);
   adapt_master = adapt_masterptr; 
	MSG("Master adapt instat and Grid initialized\n");
	return(0);
}
