/*!\file DatasetInput2.c
 * \brief: implementation of the datasetinput object
 */
/*Headers*/
#ifdef HAVE_CONFIG_H
	#include <config.h>
#else
#error "Cannot compile with HAVE_CONFIG_H symbol! run configure first!"
#endif

#include "./DatasetInput2.h"
#include "./TriaInput2.h"
#include "./PentaInput2.h"
#include "./TransientInput2.h"

/*DatasetInput2 constructors and destructor*/
DatasetInput2::DatasetInput2(){/*{{{*/
	this->inputs    = NULL;
	this->numids    = 0;
	this->ids       = NULL;
	this->numberofelements_local = -1;
	this->numberofvertices_local = -1;
}
/*}}}*/
DatasetInput2::DatasetInput2(int nbe, int nbv){/*{{{*/
	this->inputs    = NULL;
	this->numids    = 0;
	this->ids       = NULL;
	this->numberofelements_local = nbe;
	this->numberofvertices_local = nbv;
}
/*}}}*/
DatasetInput2::~DatasetInput2(){/*{{{*/
	xDelete<int>(this->ids);
	for(int i=0;i<this->numids;i++){
		delete this->inputs[i];
	}
	xDelete<Input2*>(this->inputs);
}
/*}}}*/

/*Object virtual functions definitions:*/
Input2* DatasetInput2::copy() {/*{{{*/

	DatasetInput2* output=NULL;

	output = new DatasetInput2();
	output->numids=this->numids;
	if(this->numids>0){
		output->ids=xNew<int>(output->numids);
		xMemCpy(output->ids,this->ids,output->numids);
		output->inputs = xNew<Input2*>(this->numids);
		for(int i=0;i<this->numids;i++){
			output->inputs[i] = this->inputs[i]->copy();
		}
	}

	return output;
}
/*}}}*/
void DatasetInput2::Configure(Parameters* params){/*{{{*/
	for(int i=0;i<this->numids;i++){
		this->inputs[i]->Configure(params);
	}
}
/*}}}*/
void DatasetInput2::DeepEcho(void){/*{{{*/

	_printf_("DatasetInput2:\n");
	_printf_("   numids:"<< this->numids<< "\n");
	_printf_("      ids: ");
	for(int i=0;i<this->numids;i++) _printf_(this->ids[i]<<" ("<<EnumToStringx(this->ids[i])<<") ");
	_printf_("\n");
	//_printf_("   inputs: \n"); inputs->Echo();
}
/*}}}*/
void DatasetInput2::Echo(void){/*{{{*/
	this->DeepEcho();
}
/*}}}*/
int  DatasetInput2::Id(void){ return -1; }/*{{{*/
/*}}}*/
void DatasetInput2::Marshall(char** pmarshalled_data,int* pmarshalled_data_size, int marshall_direction){ /*{{{*/

	MARSHALLING_ENUM(DatasetInput2Enum);

	MARSHALLING(numids);
	MARSHALLING(this->numberofelements_local);
	MARSHALLING(this->numberofvertices_local);
	MARSHALLING_DYNAMIC(ids,int,numids);
	//if (marshall_direction == MARSHALLING_BACKWARD) inputs = new Inputs();
	//inputs->Marshall(pmarshalled_data,pmarshalled_data_size,marshall_direction);
	_error_("not implemented");

}
/*}}}*/
int  DatasetInput2::ObjectEnum(void){/*{{{*/
	return DatasetInput2Enum;
}/*}}}*/

void DatasetInput2::SetTriaInput(int id,int interp_in,int numinds,int* rows,IssmDouble* values_in){ /*{{{*/

	int  index = -1;
	for(int i=0;i<this->numids;i++){
		if(this->ids[i] == id) index = i;
	}

	/*Create new input if not found*/
	if(index == -1){
		int* new_ids = xNew<int>(this->numids+1);
		if(this->numids) xMemCpy(new_ids,this->ids,this->numids);
		new_ids[this->numids] = id;

		Input2** new_inputs = xNew<Input2*>(this->numids+1);
		if(this->numids) xMemCpy(new_inputs,this->inputs,this->numids);
		new_inputs[this->numids] = new TriaInput2(this->numberofelements_local,this->numberofvertices_local,interp_in);
		index = this->numids;

		xDelete<int>(this->ids);
		this->ids = new_ids;
		xDelete<Input2*>(this->inputs);
		this->inputs = new_inputs;

		this->numids ++;
	}

	/*Set input*/
	if(this->inputs[index]->ObjectEnum()!=TriaInput2Enum) _error_("cannot add Element values to a "<<EnumToStringx(this->inputs[index]->ObjectEnum()));
	TriaInput2* input = xDynamicCast<TriaInput2*>(this->inputs[index]);
	input->SetInput(interp_in,numinds,rows,values_in);

}
/*}}}*/
void DatasetInput2::SetPentaInput(int id,int interp_in,int numinds,int* rows,IssmDouble* values_in){ /*{{{*/

	int  index = -1;
	for(int i=0;i<this->numids;i++){
		if(this->ids[i] == id) index = i;
	}

	/*Create new input if not found*/
	if(index == -1){
		int* new_ids = xNew<int>(this->numids+1);
		if(this->numids) xMemCpy(new_ids,this->ids,this->numids);
		new_ids[this->numids] = id;

		Input2** new_inputs = xNew<Input2*>(this->numids+1);
		if(this->numids) xMemCpy(new_inputs,this->inputs,this->numids);
		new_inputs[this->numids] = new PentaInput2(this->numberofelements_local,this->numberofvertices_local,interp_in);
		index = this->numids;

		xDelete<int>(this->ids);
		this->ids = new_ids;
		xDelete<Input2*>(this->inputs);
		this->inputs = new_inputs;

		this->numids ++;
	}

	/*Set input*/
	if(this->inputs[index]->ObjectEnum()!=PentaInput2Enum) _error_("cannot add Element values to a "<<EnumToStringx(this->inputs[index]->ObjectEnum()));
	PentaInput2* input = xDynamicCast<PentaInput2*>(this->inputs[index]);
	input->SetInput(interp_in,numinds,rows,values_in);

}
/*}}}*/
TransientInput2* DatasetInput2::SetTransientInput(int id,IssmDouble* times,int numtimes){ /*{{{*/

	int  index = -1;
	for(int i=0;i<this->numids;i++){
		if(this->ids[i] == id) index = i;
	}

	/*Create new input if not found*/
	if(index == -1){
		int* new_ids = xNew<int>(this->numids+1);
		if(this->numids) xMemCpy(new_ids,this->ids,this->numids);
		new_ids[this->numids] = id;

		Input2** new_inputs = xNew<Input2*>(this->numids+1);
		if(this->numids) xMemCpy(new_inputs,this->inputs,this->numids);
		new_inputs[this->numids] = new TransientInput2(NoneEnum,this->numberofelements_local,this->numberofvertices_local,times,numtimes);
		index = this->numids;

		xDelete<int>(this->ids);
		this->ids = new_ids;
		xDelete<Input2*>(this->inputs);
		this->inputs = new_inputs;

		this->numids ++;
	}

	/*Set input*/
	if(this->inputs[index]->ObjectEnum()!=TransientInput2Enum) _error_("cannot add values to a "<<EnumToStringx(this->inputs[index]->ObjectEnum()));
	TransientInput2* input = xDynamicCast<TransientInput2*>(this->inputs[index]);
	return input;
}
/*}}}*/
void DatasetInput2::GetInputValue(IssmDouble* pvalue,Gauss* gauss,int id){ /*{{{*/

	int  index = -1;
	for(int i=0;i<this->numids;i++){
		if(this->ids[i] == id) index = i;
	}

	/*Create new input if not found*/
	if(index == -1){
		this->Echo();
		_error_("Could not find input "<<id<<" ("<<EnumToStringx(id)<<"?) in DatasetInput");
	}

	Input2* input = this->inputs[index];

	if(this->inputs[index]->ObjectEnum()==TransientInput2Enum){
		input = xDynamicCast<TransientInput2*>(this->inputs[index])->current_input;
	}

	input->GetInputValue(pvalue,gauss);

}
/*}}}*/
TriaInput2* DatasetInput2::GetTriaInputByOffset(int offset){/*{{{*/

	_assert_(offset>=0 && offset<this->numids);
	_assert_(this->inputs[offset]);

	/*Cast and return*/
	if(this->inputs[offset]->ObjectEnum()==TransientInput2Enum){
		return xDynamicCast<TransientInput2*>(this->inputs[offset])->GetTriaInput();
	}
	if(this->inputs[offset]->ObjectEnum()!=TriaInput2Enum){
		_error_("Cannot return a TriaInput2");
	}
	return xDynamicCast<TriaInput2*>(this->inputs[offset]);

}/*}}}*/
PentaInput2* DatasetInput2::GetPentaInputByOffset(int offset){/*{{{*/

	_assert_(offset>=0 && offset<this->numids);
	_assert_(this->inputs[offset]);

	/*Cast and return*/
	if(this->inputs[offset]->ObjectEnum()==TransientInput2Enum){
		return xDynamicCast<TransientInput2*>(this->inputs[offset])->GetPentaInput();
	}
	if(this->inputs[offset]->ObjectEnum()!=PentaInput2Enum){
		_error_("Cannot return a PentaInput2");
	}
	return xDynamicCast<PentaInput2*>(this->inputs[offset]);

}/*}}}*/
