/*!\file DofIndexing.c
 * \brief: implementation of the DofIndexing object
 */

#ifdef HAVE_CONFIG_H
	#include <config.h>
#else
#error "Cannot compile with HAVE_CONFIG_H symbol! run configure first!"
#endif

#include <stdio.h>
#include <string.h>
#include "./classes.h"
#include "../EnumDefinitions/EnumDefinitions.h"
#include "../shared/shared.h"
#include "../Container/Container.h"
#include "../include/include.h"

/*DofIndexing constructors and destructor*/
/*FUNCTION DofIndexing::DofIndexing(){{{*/
DofIndexing::DofIndexing(){

	this->gsize    = UNDEF;
	this->fsize    = UNDEF;
	this->ssize    = UNDEF;
	this->clone    = false;
	this->f_set    = NULL;
	this->s_set    = NULL;
	this->svalues  = NULL;
	this->doftype  = NULL;
	this->gdoflist = NULL;
	this->fdoflist = NULL;
	this->sdoflist = NULL;

}
/*}}}*/
/*FUNCTION DofIndexing::DofIndexing(int gsize){{{*/
DofIndexing::DofIndexing(int in_gsize){
	this->Init(in_gsize,NULL);
}
/*}}}*/
/*FUNCTION DofIndexing::DofIndexing(DofIndexing* in)  -> copy{{{*/
DofIndexing::DofIndexing(DofIndexing* in){ //copy constructor

	this->gsize = in->gsize;
	this->fsize = in->fsize;
	this->ssize = in->ssize;
	this->clone = in->clone;

	if(this->gsize>0){
		this->f_set=xNew<bool>(this->gsize);
		this->s_set=xNew<bool>(this->gsize);
		this->svalues=xNew<IssmDouble>(this->gsize);
		if(in->doftype)this->doftype=xNew<int>(this->gsize); 
		this->gdoflist=xNew<int>(this->gsize); 
	}
	else{
		this->f_set    = NULL;
		this->s_set    = NULL;
		this->svalues  = NULL;
		this->doftype  = NULL;
		this->gdoflist = NULL;
	}
	if(this->fsize>0 && this->fsize!=UNDEF)this->fdoflist=xNew<int>(this->fsize); else this->fdoflist=NULL;
	if(this->ssize>0 && this->ssize!=UNDEF)this->sdoflist=xNew<int>(this->ssize); else this->sdoflist=NULL;

	if(this->gsize>0){
		memcpy(this->f_set,in->f_set,this->gsize*sizeof(bool));
		memcpy(this->s_set,in->s_set,this->gsize*sizeof(bool));
		xMemCpy<IssmDouble>(this->svalues,in->svalues,this->gsize);
		if(this->doftype)memcpy(this->doftype,in->doftype,this->gsize*sizeof(int));
		memcpy(this->gdoflist,in->gdoflist,this->gsize*sizeof(int));
	}
	if(this->fsize>0 && this->fsize!=UNDEF)memcpy(this->fdoflist,in->fdoflist,this->fsize*sizeof(int));
	if(this->ssize>0 && this->ssize!=UNDEF)memcpy(this->sdoflist,in->sdoflist,this->ssize*sizeof(int));

}
/*}}}*/
/*FUNCTION DofIndexing::~DofIndexing() {{{*/
DofIndexing::~DofIndexing(){ //destructor

	xDelete<bool>(f_set); 
	xDelete<bool>(s_set); 
	xDelete<IssmDouble>(svalues);
	xDelete<int>(doftype); 
	xDelete<int>(gdoflist);
	xDelete<int>(fdoflist);
	xDelete<int>(sdoflist);

}
/*}}}*/
/*FUNCTION DofIndexing::Init{{{*/
void DofIndexing::Init(int in_gsize,int* in_doftype){

	this->gsize=in_gsize;
	this->clone=false;

	/*allocate: */
	if(this->gsize>0){
		this->f_set=xNew<bool>(this->gsize);
		this->s_set=xNew<bool>(this->gsize);
		this->svalues=xNew<IssmDouble>(this->gsize);
		if(in_doftype)this->doftype=xNew<int>(this->gsize);
		this->gdoflist=xNew<int>(this->gsize);
	}

	for(int i=0;i<this->gsize;i++){
		/*assume dof is free, no constraints, no rigid body constraint: */
		this->f_set[i]=true;
		this->s_set[i]=false;
		if(this->doftype)this->doftype[i]=in_doftype[i];
		this->svalues[i]=0; //0 constraint is the default value
		this->gdoflist[i]=UNDEF;
	}
}
/*}}}*/
/*FUNCTION DofIndexing::InitSet{{{*/
void DofIndexing::InitSet(int setenum){

	int i;
	int size=0;

	/*go through sets, and figure out how many dofs belong to this set, except for g-set, 
	 * which has already been initialized: */
	if(setenum==FsetEnum){
		size=0;
		for(i=0;i<this->gsize;i++) if(f_set[i])size++;
		this->fsize=size;
		xDelete<int>(this->fdoflist);
		if(this->fsize)this->fdoflist=xNew<int>(size);
		else this->fdoflist=NULL;
	}
	else if(setenum==SsetEnum){
		size=0;
		for(i=0;i<this->gsize;i++) if(s_set[i])size++;
		this->ssize=size;
		xDelete<int>(this->sdoflist);
		if(this->ssize)this->sdoflist=xNew<int>(size);
		else this->sdoflist=NULL;
	}
	else _error_("set of enum type " << EnumToStringx(setenum) << " not supported yet!");
}
/*}}}*/

/*Some of the Object functionality: */
/*FUNCTION DofIndexing::Echo{{{*/
void DofIndexing::Echo(void){

	_printLine_("DofIndexing:");
	_printLine_("   gsize: " << gsize);
	_printLine_("   clone: " << clone);
}
/*}}}*/
/*FUNCTION DofIndexing::DeepEcho{{{*/
void DofIndexing::DeepEcho(void){

	int i;

	_printLine_("DofIndexing:");
	_printLine_("   gsize: " << gsize);
	_printLine_("   fsize: " << fsize);
	_printLine_("   ssize: " << ssize);
	_printLine_("   clone: " << clone);

	_printLine_("   set membership: f,s sets ");
	for(i=0;i<gsize;i++){
		_printLine_("      dof " << i << ": " <<(f_set[i]?"true":"false")<< " " <<(s_set[i]?"true":"false"));
	}

	_printString_("   svalues (" << this->ssize << "): |");
	for(i=0;i<this->gsize;i++){
		if(this->s_set[i])_printString_(" " << svalues[i] << " |");
	}
	_printLine_("");

	if(doftype){
		_printString_("   doftype: |");
		for(i=0;i<gsize;i++){
			_printString_(" " << doftype[i] << " |");
		}
		_printLine_("");
	}
	else _printLine_("   doftype: NULL");

	_printString_("   g_doflist (" << this->gsize << "): |");
	for(i=0;i<this->gsize;i++){
		_printString_(" " << gdoflist[i] << " |");
	}
	_printLine_("");

	_printString_("   f_doflist (" << this->fsize << "): |");
	for(i=0;i<this->fsize;i++){
		_printString_(" " << fdoflist[i] << " |");
	}
	_printLine_("");

	_printString_("   s_doflist (" << this->ssize << "): |");
	for(i=0;i<this->ssize;i++){
		_printString_(" " << sdoflist[i] << " |");
	}
	_printLine_("");
}		
/*}}}*/
