/* \file WriteParams.c:
 * \brief: interface for writing parameters dataset into a matlab structure
 */

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


#ifdef _SERIAL_
#include <mex.h>

#include "../objects/Param.h"
#include "./io.h"
#include "../shared/shared.h"

#undef __FUNCT__ 
#define __FUNCT__  "WriteParams"
void WriteParams(DataHandle* pdataref,DataSet* parameters){

	/*output: */
	mxArray* dataref=NULL;
	mwSize nfields;
	const	char**	fnames=NULL;
	mwSize		onebyone[2] = {1,1};
	mwSize		ndim=2;
	mxArray*    pfield=NULL;

	/*intermediary: */
	int         i;
	mxArray*    field=NULL;
	Param*      param=NULL;
	int         integer;
	double      ddouble;
	char*       string;
	double*     doublevec=NULL;
	double*     doublemat=NULL;
	Mat         mat=NULL;
	Vec         vec=NULL;
	double*     serial_vec=NULL;
	double*     serial_mat=NULL;
	mwSize      M,N;

	/*Recover data from the parameters dataset: */
	nfields=(mwSize)parameters->Size();

	fnames=(const char**)xmalloc(nfields*sizeof(char*));
	
	/*Build structure in matlab workspace with all the parameter fields: */
	for(i=0;i<nfields;i++){
		param=(Param*)parameters->GetObjectByOffset(i);
		fnames[i]=(const char*)xmalloc((strlen(param->GetParameterName())+1)*sizeof(char));
		strcpy((char*)fnames[i],param->GetParameterName());
	}
	/*Initialize structure: */
	dataref=mxCreateStructArray( ndim,onebyone,nfields,fnames);

	/*Fill each field: */
	for(i=0;i<nfields;i++){

		param=(Param*)parameters->GetObjectByOffset(i);
		
		switch(param->GetType()){
			case INTEGER:
				param->GetParameterValue((void*)&integer);
				mxSetField( dataref, 0, param->GetParameterName(),mxCreateDoubleScalar((double)integer));
				break;

			case DOUBLE:
				param->GetParameterValue((void*)&ddouble);
				mxSetField( dataref, 0, param->GetParameterName(),mxCreateDoubleScalar((double)ddouble));
				break;

			case STRING:
				param->GetParameterValue((void*)&string);
				mxSetField( dataref, 0, param->GetParameterName(),mxCreateString(string));
				break;

			case DOUBLEVEC:
				param->GetParameterValue((void*)&doublevec);
				M=param->GetM();
				pfield=mxCreateDoubleMatrix(0,0,mxREAL);
				mxSetM(pfield,M);
				mxSetN(pfield,1);
				mxSetPr(pfield,doublevec);
				mxSetField( dataref, 0, param->GetParameterName(),pfield);
				break;

			case DOUBLEMAT:
				param->GetParameterValue((void*)&doublemat);
				M=param->GetM();
				N=param->GetN();
				pfield=mxCreateDoubleMatrix(0,0,mxREAL);
				mxSetM(pfield,M);
				mxSetN(pfield,N);
				mxSetPr(pfield,doublemat);
				mxSetField( dataref, 0, param->GetParameterName(),pfield);
				break;
		
			case PETSCVEC:
				param->GetParameterValue((void*)&vec);
				VecToMPISerial(&serial_vec,vec);
				VecFree(&vec);
				M=param->GetM();
				pfield=mxCreateDoubleMatrix(0,0,mxREAL);
				mxSetM(pfield,M);
				mxSetN(pfield,1);
				mxSetPr(pfield,serial_vec);
				mxSetField( dataref, 0, param->GetParameterName(),pfield);
				break;
		
			case PETSCMAT:
				param->GetParameterValue((void*)&mat);
				MatToSerial(&serial_mat,mat);
				MatFree(&mat);
				M=param->GetM();
				N=param->GetN();
				pfield=mxCreateDoubleMatrix(0,0,mxREAL);
				mxSetM(pfield,M);
				mxSetN(pfield,N);
				mxSetPr(pfield,serial_mat);
				mxSetField( dataref, 0, param->GetParameterName(),pfield);
				break;
			default:
				throw ErrorException(__FUNCT__,exprintf("%s%i","unknown parameter type: ",param->GetType()));
				break;
		}
	}

	/*Assign output pointers:*/
	*pdataref=dataref;

}
#endif
