#include <alberta.h>
#include <alberta_util.h>
#include "newalberta.hh"
#include "operator_parts.hh"
/*
Wenn wir die Gestaltung von c, Lb0 u LALT-Koeffunktionen nach *problem.cc
auslagern, brauchen wir erstmal nur wenig Lalts etc. deshalb werden diese nu hier definiert.*/

	constmat::constmat(REAL coeff)
		{
		mat[0][1]=mat[1][0]=0.0 ; 
		mat[0][0]=mat[1][1]=coeff ; 
#if DIM_OF_WORLD==3
		mat[2][2]=coeff;      // Ups -- waren falsche Indices (EP)
		mat[2][0]=mat[2][1]=mat[0][2]=mat[1][2]=0.0; 
#endif
		}

int vardiffmat::set_at_el(const EL_INFO * const el_info,
					REAL eval_time)
	{
	elfunc_ptr->set_at_el( el_info,  eval_time);
	return(0);
	}


int vardiffmat::set_at_bary(const REAL* const lambda)
	{
		mat[0][1]=mat[1][0]=0.0 ;
		mat[0][0]=mat[1][1]=
#if DIM_OF_WORLD==3
		mat[2][2]=
#endif
		elfunc_ptr->calc(lambda);
#if DIM_OF_WORLD==3
		mat[2][1]=mat[1][2]=mat[0][2]=mat[2][0]=0.0 ;
#endif
	return(0);
	}

vardiffmat::vardiffmat( elfunc* const  elfunc_ptr)
		: elfunc_ptr(elfunc_ptr)
{}





constfunc::constfunc(REAL coeff)
{fac=coeff;}

//Fuer die allemeisten Faelle hinreichende Funktionen zum anhaengen an OPERATOR_INFO. 
//Vielleicht nach Build_stat migrieren?
#if 0
Sehen inzwischen so aus, bei gelegenheit aendern:
static const REAL_B *LALt(const EL_INFO *el_info, const QUAD *quad, 
			  int iq, void *ud)
{
  struct op_info *info = (struct op_info *)ud;
  int            i, j, k, dim = el_info->mesh->dim;
  static REAL_BB LALt;

  for (i = 0; i <= dim; i++)
    for (j = i; j <= dim; j++)
    {
      for (LALt[i][j] = k = 0; k < DIM_OF_WORLD; k++)
	LALt[i][j] += info->Lambda[i][k]*info->Lambda[j][k];
      LALt[i][j] *= info->det;
      LALt[j][i] = LALt[i][j];
    }
  return (const REAL_B *)LALt;
}
#endif
const REAL (*LALt(const EL_INFO *el_info, const QUAD *quad,
                         int iq, void *ud))[DIM+1]
{
  OP_ARG_INFO *assem_el_info=(OP_ARG_INFO *)ud;
  		int            i, j, k;
  static REAL    	LALt[DIM+1][DIM+1];
  matfunc* 		diff_mat_ptr= assem_el_info->prob_data_ptr->diffmat;
 		
	diff_mat_ptr->set_at_bary( quad->lambda[iq]) ;


  for (i = 0; i <= DIM; i++)
    for (j = i; j <= DIM; j++)
    {
      for (LALt[i][j] = k = 0; k < DIM_OF_WORLD; k++)
        	LALt[i][j] +=
				el_info->el_geom_cache.Lambda[i][k]
				*el_info->el_geom_cache.Lambda[j][k];
//ist natuerlich auch LLALtdiag. Baustelle
      LALt[i][j] *= diff_mat_ptr->getcomp(0,0)* el_info->el_geom_cache.det;
/*(*A)[i][i]*/
 				
      LALt[j][i] = LALt[i][j];
    }
  return((const REAL (*)[DIM+1]) LALt);
}

/*Attention: if you change prob_data_ptr without changing the element, 
initialisation of new diff_mat...*/

const REAL (*LALtdiag(const EL_INFO *el_info, const QUAD *quad,
                         int iq, void *ud))[DIM+1]
{
  OP_ARG_INFO *assem_el_info=(OP_ARG_INFO *)ud;
  		int            i, j, k;
  static REAL    	LALt[DIM+1][DIM+1];
  matfunc* 		diff_mat_ptr= assem_el_info->prob_data_ptr->diffmat;
 		
	diff_mat_ptr->set_at_bary( quad->lambda[iq]) ;

  for (i = 0; i <= DIM; i++)
    for (j = i; j <= DIM; j++)
    {
      for (LALt[i][j] = k = 0; k < DIM_OF_WORLD; k++)
        	LALt[i][j] += el_info->el_geom_cache.Lambda[i][k]*el_info->el_geom_cache.Lambda[j][k];

      LALt[i][j] *= diff_mat_ptr->getcomp(i,i)* el_info->el_geom_cache.det;
/*(*A)[i][i]*/
 				
      LALt[j][i] = LALt[i][j];
    }
  return((const REAL (*)[DIM+1]) LALt);
}

const REAL (*LALtfull(const EL_INFO *el_info, const QUAD *quad,
                         int iq, void *ud))[DIM+1]
{
  OP_ARG_INFO *assem_el_info=(OP_ARG_INFO *)ud;
  		int            i, j, k;
  static REAL    	LALt[DIM+1][DIM+1];
  static REAL           ALt_t[DIM+1][DIM_OF_WORLD]; //schon transponiert
  matfunc* 		diff_mat_ptr= assem_el_info->prob_data_ptr->diffmat;
 		
	diff_mat_ptr->set_at_bary( quad->lambda[iq]) ;

  for (i = 0; i < DIM_OF_WORLD; i++)
    for (j = 0; j <= DIM; j++)
  	{
  	    for (ALt_t[j][i] = k = 0; k < DIM_OF_WORLD; k++)
	 		ALt_t[j][i] += diff_mat_ptr->getcomp(i,k)
				* el_info->el_geom_cache.Lambda[j][k];
      	ALt_t[j][i] *=  el_info->el_geom_cache.det;
  	}//ok
  for (i = 0; i <= DIM; i++)
    for (j = 0; j <= DIM; j++)
      LALt[i][j] = SCP_DOW(el_info->el_geom_cache.Lambda[i],ALt_t[j]);


 				
 //     LALt[j][i] = LALt[i][j];
  return((const REAL (*)[DIM+1]) LALt);
}


 REAL c_std(const EL_INFO *el_info, const QUAD *quad, int iq, void *ud)
{
  OP_ARG_INFO *assem_el_info=(OP_ARG_INFO *)ud;
  elfunc* elfunc_ptr = assem_el_info->prob_data_ptr->order0func;
  return(
		elfunc_ptr->calc( /*const REAL* const lambda*/ 	quad->lambda[iq])
				*(el_info->el_geom_cache.det) );		 /* Sachlich kontrolliert*/
}

//zum anhaengen an OPERATOR_INFO Buch S.231
//Lambda und det muessen vor aufruf gemacht werden.
 _Bool init_element(const EL_INFO* el_info,const QUAD* quad[3], void * ud )
{
  OP_ARG_INFO *assem_el_info=(OP_ARG_INFO *)ud;
  matfunc*	diff_mat_ptr; 
  elfunc* 	elfunc_ptr;
  	if ( (diff_mat_ptr = assem_el_info->prob_data_ptr->diffmat))
		{diff_mat_ptr->set_at_el(el_info, assem_el_info->eval_time);
		}
  	if ( (elfunc_ptr = assem_el_info->prob_data_ptr->order0func))
		{elfunc_ptr->set_at_el(el_info, assem_el_info->eval_time);
		}
	return(0);
}
