/*
 * \file Parameters.c
 * \brief: implementation of the Parameters class, derived from DataSet class
 */

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

#include <vector>
#include <functional>
#include <algorithm>
#include <iostream>

#include "./DataSet.h"
#include "../shared/shared.h"
#include "../include/include.h"
#include "../EnumDefinitions/EnumDefinitions.h"

using namespace std;
/*}}}*/

/*Object constructors and destructor*/
/*FUNCTION Parameters::Parameters(){{{*/
Parameters::Parameters(){
	enum_type=ParametersEnum;
	return;
}
/*}}}*/
/*FUNCTION Parameters::~Parameters(){{{*/
Parameters::~Parameters(){
	return;
}
/*}}}*/

/*Object management*/
/*FUNCTION Parameters::Exist{{{*/
bool Parameters::Exist(int enum_type){

	vector<Object*>::iterator object;
	Param* param=NULL;

	for ( object=objects.begin() ; object < objects.end(); object++ ){
		param=dynamic_cast<Param*>(*object);
		if(param->InstanceEnum()==enum_type) return true;
	}
	return false;
}
/*}}}*/
/*FUNCTION Parameters::FindParam(bool* pbool,int enum_type){{{*/
void Parameters::FindParam(bool* pbool,int enum_type){ _assert_(this);

	vector<Object*>::iterator object;
	Param* param=NULL;

	for ( object=objects.begin() ; object < objects.end(); object++ ){

		param=dynamic_cast<Param*>(*object);
		if(param->InstanceEnum()==enum_type){
			param->GetParameterValue(pbool);
			return;
		}
	}
	_error_("could not find parameter " << EnumToStringx(enum_type));
}
/*}}}*/
/*FUNCTION Parameters::FindParam(int* pinteger,int enum_type){{{*/
void Parameters::FindParam(int* pinteger,int enum_type){ _assert_(this);

	vector<Object*>::iterator object;
	Param* param=NULL;

	for ( object=objects.begin() ; object < objects.end(); object++ ){

		param=dynamic_cast<Param*>(*object);
		if(param->InstanceEnum()==enum_type){
			param->GetParameterValue(pinteger);
			return;
		}
	}
	_error_("could not find parameter " << EnumToStringx(enum_type));
}
/*}}}*/
/*FUNCTION Parameters::FindParam(IssmDouble* pscalar, int enum_type){{{*/
void Parameters::FindParam(IssmDouble* pscalar, int enum_type){ _assert_(this);

	vector<Object*>::iterator object;
	Param* param=NULL;

	for ( object=objects.begin() ; object < objects.end(); object++ ){

		param=dynamic_cast<Param*>(*object);
		if(param->InstanceEnum()==enum_type){
			param->GetParameterValue(pscalar);
			return;
		}
	}
	_error_("could not find parameter " << EnumToStringx(enum_type));
}
/*}}}*/
/*FUNCTION Parameters::FindParam(IssmDouble* pscalar, int enum_type,IssmDouble time){{{*/
void Parameters::FindParam(IssmDouble* pscalar, int enum_type,IssmDouble time){ _assert_(this);

	vector<Object*>::iterator object;
	Param* param=NULL;

	for ( object=objects.begin() ; object < objects.end(); object++ ){

		param=dynamic_cast<Param*>(*object);
		if(param->InstanceEnum()==enum_type){
			param->GetParameterValue(pscalar,time);
			return;
		}
	}
	_error_("could not find parameter " << EnumToStringx(enum_type));
}
/*}}}*/
/*FUNCTION Parameters::FindParam(char** pstring,int enum_type){{{*/
void Parameters::FindParam(char** pstring,int enum_type){ _assert_(this);

	vector<Object*>::iterator object;
	Param* param=NULL;

	for ( object=objects.begin() ; object < objects.end(); object++ ){

		param=dynamic_cast<Param*>(*object);
		if(param->InstanceEnum()==enum_type){
			param->GetParameterValue(pstring);
			return;
		}
	}
	_error_("could not find parameter " << EnumToStringx(enum_type));

}
/*}}}*/
/*FUNCTION Parameters::FindParam(char*** pstringarray,int* pM,int enum_type){{{*/
void Parameters::FindParam(char*** pstringarray,int* pM,int enum_type){ _assert_(this);

	vector<Object*>::iterator object;
	Param* param=NULL;

	for ( object=objects.begin() ; object < objects.end(); object++ ){

		param=dynamic_cast<Param*>(*object);
		if(param->InstanceEnum()==enum_type){
			param->GetParameterValue(pstringarray,pM);
			return;
		}
	}
	_error_("could not find parameter " << EnumToStringx(enum_type));

}
/*}}}*/
/*FUNCTION Parameters::FindParam(int** pintarray,int* pM,int enum_type){{{*/
void Parameters::FindParam(int** pintarray,int* pM, int enum_type){ _assert_(this);

	vector<Object*>::iterator object;
	Param* param=NULL;

	for ( object=objects.begin() ; object < objects.end(); object++ ){

		param=dynamic_cast<Param*>(*object);
		if(param->InstanceEnum()==enum_type){
			param->GetParameterValue(pintarray,pM);
			return;
		}
	}
	_error_("could not find parameter " << EnumToStringx(enum_type));

}
/*}}}*/
/*FUNCTION Parameters::FindParam(int** pintarray,int* pM,int* pN,int enum_type){{{*/
void Parameters::FindParam(int** pintarray,int* pM,int *pN,int enum_type){ _assert_(this);

	vector<Object*>::iterator object;
	Param* param=NULL;

	for ( object=objects.begin() ; object < objects.end(); object++ ){

		param=dynamic_cast<Param*>(*object);
		if(param->InstanceEnum()==enum_type){
			param->GetParameterValue(pintarray,pM,pN);
			return;
		}
	}
	_error_("could not find parameter " << EnumToStringx(enum_type));

}
/*}}}*/
/*FUNCTION Parameters::FindParam(IssmDouble** pIssmDoublearray,int* pM,int enum_type){{{*/
void Parameters::FindParam(IssmDouble** pIssmDoublearray,int* pM, int enum_type){ _assert_(this);

	vector<Object*>::iterator object;
	Param* param=NULL;

	for ( object=objects.begin() ; object < objects.end(); object++ ){

		param=dynamic_cast<Param*>(*object);
		if(param->InstanceEnum()==enum_type){
			param->GetParameterValue(pIssmDoublearray,pM);
			return;
		}
	}
	_error_("could not find parameter " << EnumToStringx(enum_type));

}
/*}}}*/
/*FUNCTION Parameters::FindParam(IssmDouble** pIssmDoublearray,int* pM, int* pN,int enum_type){{{*/
void Parameters::FindParam(IssmDouble** pIssmDoublearray,int* pM, int* pN,int enum_type){ _assert_(this);

	vector<Object*>::iterator object;
	Param* param=NULL;

	for ( object=objects.begin() ; object < objects.end(); object++ ){

		param=dynamic_cast<Param*>(*object);
		if(param->InstanceEnum()==enum_type){
			param->GetParameterValue(pIssmDoublearray,pM,pN);
			return;
		}
	}
	_error_("could not find parameter " << EnumToStringx(enum_type));

}
/*}}}*/
/*FUNCTION Parameters::FindParam(IssmDouble*** parray,int* pM,int** pmdims_array,int** pndims_array,int enum_type){{{*/
void Parameters::FindParam(IssmDouble*** parray,int* pM,int** pmdims_array,int** pndims_array,int enum_type){ _assert_(this);

	vector<Object*>::iterator object;
	Param* param=NULL;

	for ( object=objects.begin() ; object < objects.end(); object++ ){

		param=dynamic_cast<Param*>(*object);
		if(param->InstanceEnum()==enum_type){
			param->GetParameterValue(parray,pM,pmdims_array,pndims_array);
			return;
		}
	}
	_error_("could not find parameter " << EnumToStringx(enum_type));
}
/*}}}*/
/*FUNCTION Parameters::FindParam(Vector<IssmDouble>** pvec,int enum_type){{{*/
void Parameters::FindParam(Vector<IssmDouble>** pvec,int enum_type){ _assert_(this);

	vector<Object*>::iterator object;
	Param* param=NULL;

	for ( object=objects.begin() ; object < objects.end(); object++ ){

		param=dynamic_cast<Param*>(*object);
		if(param->InstanceEnum()==enum_type){
			param->GetParameterValue(pvec);
			return;
		}
	}
	_error_("could not find parameter " << EnumToStringx(enum_type));

}
/*}}}*/
/*FUNCTION Parameters::FindParam(Matrix<IssmDouble>** pmat,int enum_type){{{*/
void Parameters::FindParam(Matrix<IssmDouble>** pmat,int enum_type){ _assert_(this);

	vector<Object*>::iterator object;
	Param* param=NULL;

	for ( object=objects.begin() ; object < objects.end(); object++ ){

		param=dynamic_cast<Param*>(*object);
		if(param->InstanceEnum()==enum_type){
			param->GetParameterValue(pmat);
			return;
		}
	}
	_error_("could not find parameter " << EnumToStringx(enum_type));

}
/*}}}*/
/*FUNCTION Parameters::FindParam(FILE** pfid,int enum_type){{{*/
void Parameters::FindParam(FILE** pfid,int enum_type){ _assert_(this);

	vector<Object*>::iterator object;
	Param* param=NULL;

	for ( object=objects.begin() ; object < objects.end(); object++ ){

		param=dynamic_cast<Param*>(*object);
		if(param->InstanceEnum()==enum_type){
			param->GetParameterValue(pfid);
			return;
		}
	}
	_error_("could not find parameter " << EnumToStringx(enum_type));
}
/*}}}*/
/*FUNCTION Parameters::FindParam(DataSet** pdataset,int enum_type){{{*/
void Parameters::FindParam(DataSet** pdataset,int enum_type){ 
	_assert_(this);

	vector<Object*>::iterator object;
	Param* param=NULL;

	for ( object=objects.begin() ; object < objects.end(); object++ ){

		param=dynamic_cast<Param*>(*object);
		if(param->InstanceEnum()==enum_type){
			param->GetParameterValue(pdataset);
			return;
		}
	}
	_error_("could not find parameter " << EnumToStringx(enum_type));
}
/*}}}*/

/*FUNCTION Parameters::SetParam(bool boolean,int enum_type);{{{*/
void   Parameters::SetParam(bool boolean,int enum_type){

	Param* param=NULL;

	/*first, figure out if the param has already been created: */
	param=dynamic_cast<Param*>(this->FindParamObject(enum_type));

	if(param) param->SetValue(boolean); //already exists, just set it.
	else this->AddObject(new BoolParam(enum_type,boolean)); //just add the new parameter.
}
/*}}}*/
/*FUNCTION Parameters::SetParam(int integer,int enum_type);{{{*/
void   Parameters::SetParam(int integer,int enum_type){

	Param* param=NULL;

	/*first, figure out if the param has already been created: */
	param=dynamic_cast<Param*>(this->FindParamObject(enum_type));

	if(param) param->SetValue(integer); //already exists, just set it.
	else this->AddObject(new IntParam(enum_type,integer)); //just add the new parameter.
}
/*}}}*/
/*FUNCTION Parameters::SetParam(IssmDouble scalar,int enum_type);{{{*/
void   Parameters::SetParam(IssmDouble scalar,int enum_type){

	Param* param=NULL;

	/*first, figure out if the param has already been created: */
	param=dynamic_cast<Param*>(this->FindParamObject(enum_type));

	if(param) param->SetValue(scalar); //already exists, just set it.
	else this->AddObject(new DoubleParam(enum_type,scalar)); //just add the new parameter.
}
/*}}}*/
/*FUNCTION Parameters::SetParam(char* string,int enum_type);{{{*/
void   Parameters::SetParam(char* string,int enum_type){

	Param* param=NULL;

	/*first, figure out if the param has already been created: */
	param=dynamic_cast<Param*>(this->FindParamObject(enum_type));

	if(param) param->SetValue(string); //already exists, just set it.
	else this->AddObject(new StringParam(enum_type,string)); //just add the new parameter.
}
/*}}}*/
/*FUNCTION Parameters::SetParam(char** stringarray,int M, int enum_type);{{{*/
void   Parameters::SetParam(char** stringarray,int M, int enum_type){

	Param* param=NULL;

	/*first, figure out if the param has already been created: */
	param=dynamic_cast<Param*>(this->FindParamObject(enum_type));

	if(param) param->SetValue(stringarray,M); //already exists, just set it.
	else this->AddObject(new StringArrayParam(enum_type,stringarray,M)); //just add the new parameter.
}
/*}}}*/
/*FUNCTION Parameters::SetParam(IssmDouble* IssmDoublearray,int M,int enum_type);{{{*/
void   Parameters::SetParam(IssmDouble* IssmDoublearray,int M, int enum_type){

	Param* param=NULL;

	/*first, figure out if the param has already been created: */
	param=dynamic_cast<Param*>(this->FindParamObject(enum_type));

	if(param) param->SetValue(IssmDoublearray,M); //already exists, just set it.
	else this->AddObject(new DoubleVecParam(enum_type,IssmDoublearray,M)); //just add the new parameter.
}
/*}}}*/
/*FUNCTION Parameters::SetParam(IssmDouble* IssmDoublearray,int M,int N, int enum_type);{{{*/
void   Parameters::SetParam(IssmDouble* IssmDoublearray,int M, int N, int enum_type){

	Param* param=NULL;

	/*first, figure out if the param has already been created: */
	param=dynamic_cast<Param*>(this->FindParamObject(enum_type));

	if(param) param->SetValue(IssmDoublearray,M,N); //already exists, just set it.
	else this->AddObject(new DoubleMatParam(enum_type,IssmDoublearray,M,N)); //just add the new parameter.
}
/*}}}*/
/*FUNCTION Parameters::SetParam(int* intarray,int M,int enum_type);{{{*/
void   Parameters::SetParam(int* intarray,int M, int enum_type){

	Param* param=NULL;

	/*first, figure out if the param has already been created: */
	param=dynamic_cast<Param*>(this->FindParamObject(enum_type));

	if(param) param->SetValue(intarray,M); //already exists, just set it.
	else this->AddObject(new IntVecParam(enum_type,intarray,M)); //just add the new parameter.
}
/*}}}*/
/*FUNCTION Parameters::SetParam(int* intarray,int M,int N, int enum_type);{{{*/
void   Parameters::SetParam(int* intarray,int M, int N, int enum_type){

	Param* param=NULL;

	/*first, figure out if the param has already been created: */
	param=dynamic_cast<Param*>(this->FindParamObject(enum_type));

	if(param) param->SetValue(intarray,M,N); //already exists, just set it.
	else this->AddObject(new IntMatParam(enum_type,intarray,M,N)); //just add the new parameter.
}
/*}}}*/
/*FUNCTION Parameters::SetParam(Vector<IssmDouble>* vector,int enum_type);{{{*/
void   Parameters::SetParam(Vector<IssmDouble>* vector,int enum_type){

	Param* param=NULL;

	/*first, figure out if the param has already been created: */
	param=dynamic_cast<Param*>(this->FindParamObject(enum_type));

	if(param) param->SetValue(vector); //already exists, just set it.
	else this->AddObject(new VectorParam(enum_type,vector)); //just add the new parameter.
}
/*}}}*/
/*FUNCTION Parameters::SetParam(Matrix<IssmDouble>* matrix,int enum_type);{{{*/
void   Parameters::SetParam(Matrix<IssmDouble>* matrix,int enum_type){

	Param* param=NULL;

	/*first, figure out if the param has already been created: */
	param=dynamic_cast<Param*>(this->FindParamObject(enum_type));

	if(param) param->SetValue(matrix); //already exists, just set it.
	else this->AddObject(new MatrixParam(enum_type,matrix)); //just add the new parameter.
}
/*}}}*/
/*FUNCTION Parameters::SetParam(FILE* fid,int enum_type);{{{*/
void   Parameters::SetParam(FILE* fid,int enum_type){

	Param* param=NULL;

	/*first, figure out if the param has already been created: */
	param=dynamic_cast<Param*>(this->FindParamObject(enum_type));

	if(param) param->SetValue(fid); //already exists, just set it.
	else this->AddObject(new FileParam(enum_type,fid)); //just add the new parameter.
}
/*}}}*/
/*FUNCTION Parameters::UnitConversion(int direction_enum);{{{*/
void   Parameters::UnitConversion(int direction_enum){

	vector<Object*>::iterator object;
	Param* param=NULL;

	for ( object=objects.begin() ; object < objects.end(); object++ ){
		param=dynamic_cast<Param*>(*object);
		param->UnitConversion(direction_enum);
	}

}
/*}}}*/

/*FUNCTION Parameters::FindParamObject{{{*/
Object* Parameters::FindParamObject(int enum_type){

	vector<Object*>::iterator object;
	Param* param=NULL;

	for ( object=objects.begin() ; object < objects.end(); object++ ){

		param=dynamic_cast<Param*>(*object);
		if(param->InstanceEnum()==enum_type){
			return (*object);
		}
	}
	return NULL;
}
/*}}}*/
