/*! \file GenericOption.h 
 *  \brief: header file for generic option object
 */

#ifndef _GENERIC_OPTION_
#define _GENERIC_OPTION_

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

#include <cstring>

#include "../../../include/include.h"
#include "../../../shared/Exceptions/exceptions.h"
#include "../../../io/io.h"
#include "../../../EnumDefinitions/EnumDefinitions.h"
#include "./OptionUtilities.h"

#include "../Object.h"
/*}}}*/

template <class OptionType> 
class GenericOption: public Option {

	public:

		char       *name;
		OptionType  value;

		int         numel;   //in case OptionType is an array
		int         ndims;   //in case OptionType is a multi-dimensional array: */
		int        *size;

		/*GenericOption constructors, destructors*/
		GenericOption(){ /*{{{*/

			name  =NULL;
			numel =0;
			ndims =0;
			size  =NULL;

		} /*}}}*/
		~GenericOption(){ /*{{{*/

			if(size) xDelete<int>(size);
			if(name) xDelete<char>(name);

		} /*}}}*/

		/*Object virtual functions definitions:*/
		void Echo(){ /*{{{*/

			this->DeepEcho();

		} /*}}}*/
		void DeepEcho(){ /*{{{*/

			char  indent[81]="";
			this->DeepEcho(indent);

		} /*}}}*/
		void DeepEcho(char* indent){ /*{{{*/

			char  cstr[81];
			bool  flag=true;

			if(flag) _pprintLine_(indent << "         name: \"" << name << "\"");
			if(flag) _pprintLine_(indent << "         numel: " << numel);
			if(flag) _pprintLine_(indent << "         ndims: " << ndims);
			if(size){
				StringFromSize(cstr,size,ndims);
				if(flag) _pprintLine_(indent << "          size: " << cstr);
			}
			else if(flag) _pprintLine_(indent << "          size: [empty]");
			_printLine_(indent << "         value: " << value);;
		} /*}}}*/
		int   Id(){_error_("Not implemented yet");};
		int   ObjectEnum(){return GenericOptionEnum;};
		Object* copy(){_error_("Not implemented yet");};

		/*GenericOption functions: */
		char* Name(){return name;};
		int   NumEl(){return numel;};
		int   NDims(){return ndims;};
		int*  Size(){return size;};
		void  Get(OptionType* pvalue){ *pvalue=value; };
};

#if defined(_HAVE_ADOLC_) && !defined(_WRAPPERS_)  //We hook off this specific specialization when not running ADOLC, otherwise we get a redeclaration with the next specialization. 
template <> inline void GenericOption<IssmPDouble*>::Get(IssmPDouble** pvalue){ /*{{{*/

	/*Copy vector*/
	IssmPDouble* outvalue=xNew<IssmPDouble>(this->NumEl());
	for(int i=0;i<this->NumEl();i++) outvalue[i]=this->value[i];

	/*Assign output pointer*/
	*pvalue=outvalue;
} /*}}}*/
#endif
template <> inline void GenericOption<IssmDouble*>::Get(IssmDouble** pvalue){ /*{{{*/

	/*Copy vector*/
	IssmDouble* outvalue=xNew<IssmDouble>(this->NumEl());
	for(int i=0;i<this->NumEl();i++) outvalue[i]=this->value[i];

	/*Assign output pointer*/
	*pvalue=outvalue;
} /*}}}*/
template <> inline void GenericOption<char*>::Get(char** pvalue){ /*{{{*/

	int   stringsize=strlen(this->value)+1;
	char* outstring=xNew<char>(stringsize);
	xMemCpy<char>(outstring,this->value,stringsize);

	*pvalue=outstring;
} 
/*}}}*/

#endif  /* _OPTIONOBJECT_H */
