/*!\file SpcTransient.c
 * \brief: implementation of the SpcTransient 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 "../../include/include.h"
#include "../../shared/shared.h"
#include "../../EnumDefinitions/EnumDefinitions.h"
#include "../../Container/Container.h"
#include "../objects.h"

/*SpcTransient constructors and destructor*/
/*FUNCTION SpcTransient::SpcTransient(){{{1*/
SpcTransient::SpcTransient(){
	sid=-1;
	nodeid=-1;
	dof=-1;
	values=NULL;
	times=NULL;
	nsteps=-1;
	analysis_type=-1;
	return;
}
/*}}}1*/
/*FUNCTION SpcTransient::SpcTransient(int spc_sid,int spc_nodeid,...){{{1*/
SpcTransient::SpcTransient(int spc_sid,int spc_nodeid, int spc_dof,int spc_nsteps, double* spc_times, double* spc_values,int spc_analysis_type){

	sid=spc_sid;
	nodeid=spc_nodeid;
	dof=spc_dof;
	nsteps=spc_nsteps;
	if(spc_nsteps){
		values=(double*)xmalloc(spc_nsteps*sizeof(double));
		times=(double*)xmalloc(spc_nsteps*sizeof(double));
		memcpy(values,spc_values,nsteps*sizeof(double));
		memcpy(times,spc_times,nsteps*sizeof(double));
	}
	analysis_type=spc_analysis_type;
	return;
}
/*}}}1*/
/*FUNCTION SpcTransient::~SpcTransient{{{1*/
SpcTransient::~SpcTransient(){
	xfree((void**)&times);
	xfree((void**)&values);
	return;
}
/*}}}1*/
		
/*Object virtual functions definitions:*/
/*FUNCTION SpcTransient::Echo {{{1*/
void SpcTransient::Echo(void){

	int i;
	printf("SpcTransient:\n");
	printf("   sid: %i\n",sid);
	printf("   nodeid: %i\n",nodeid);
	printf("   dof: %i\n",dof);
	printf("   nsteps: %i\n",nsteps);
	printf("   analysis_type: %s\n",EnumToStringx(analysis_type));
	printf("   steps|times|values\n");
	for(i=0;i<nsteps;i++){
		printf("%i-%g:%g\n",i,times[i],values[i]);
	}
	return;
}
/*}}}1*/
/*FUNCTION SpcTransient::DeepEcho {{{1*/
void SpcTransient::DeepEcho(void){
	this->Echo();
}		
/*}}}1*/
/*FUNCTION SpcTransient::Id {{{1*/
int    SpcTransient::Id(void){ return sid; }
/*}}}1*/
/*FUNCTION SpcTransient::MyRank {{{1*/
int    SpcTransient::MyRank(void){ 
	extern int my_rank;
	return my_rank; 
}
/*}}}1*/
/*FUNCTION SpcTransient::ObjectEnum{{{1*/
int SpcTransient::ObjectEnum(void){

	return SpcTransientEnum;

}
/*}}}1*/
/*FUNCTION SpcTransient::copy {{{1*/
Object* SpcTransient::copy() {
	return new SpcTransient(sid,nodeid,dof,nsteps,times,values,analysis_type);
}
/*}}}1*/

/*Constraint virtual functions definitions:*/
/*FUNCTION SpcTransient::InAnalysis{{{1*/
bool SpcTransient::InAnalysis(int in_analysis_type){
	
	if (in_analysis_type==this->analysis_type) return true;
	else return false;
}
/*}}}*/
/*FUNCTION SpcTransient::ConstrainNode{{{1*/
void SpcTransient::ConstrainNode(Nodes* nodes,Parameters* parameters){

	Node* node=NULL;
	double time=0;
	int    i;
	double alpha=-1;
	double value;
	bool   found=false;

	/*Chase through nodes and find the node to which this SpcTransient applys: */
	node=(Node*)nodes->GetObjectById(NULL,nodeid);
	
	if(node){ //in case the spc is dealing with a node on another cpu

		/*Retrieve time in parameters: */
		parameters->FindParam(&time,TimeEnum);

		/*Now, go fetch value for this time: */
		if (time<=times[0]){
			value=values[0];
			found=true;
		}
		else if (time>=times[nsteps-1]){
			value=values[nsteps-1];
			found=true;
		}
		else{
			for(i=0;i<nsteps-1;i++){
				if (times[i]<=time && time<times[i+1]){
					alpha=(time-times[i])/(times[i+1]-times[i]);
					value=(1-alpha)*values[i]+alpha*values[i+1];
					found=true;
					break;
				}
			}
		}

		if(!found)_error_("could not find time segment for constraint");

		/*Apply or relax constraint: */
		if(isnan(value)){
			node->RelaxConstraint(dof);
		}
		else node->ApplyConstraint(dof,value);
	}
}
/*}}}*/

/*SpcTransient functions*/
/*FUNCTION SpcTransient::GetDof {{{1*/
int SpcTransient::GetDof(){
	return dof;
}
/*}}}1*/
/*FUNCTION SpcTransient::GetNodeId {{{1*/
int   SpcTransient::GetNodeId(){
	
	return nodeid;
}
/*}}}1*/
/*FUNCTION SpcTransient::GetValue {{{1*/
double SpcTransient::GetValue(){
	return values[0];
}
/*}}}1*/

