/*  \file * SerialWriteData.c
 *  \brief write data from the "x" code layer to the matlab workspace
 */

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

#include "./io.h"
#include "../DataSet/DataSet.h"
#include "../toolkits/toolkits.h"
#include "../include/macros.h"
#include "../shared/shared.h"


#ifdef _SERIAL_

#undef __FUNCT__ 
#define __FUNCT__ "SerialWriteData"


void SerialWriteData(mxArray** pdataref,void* data,int M, int N,char* data_type,char* sub_data_type){

	int n;

	/*Dataset: */
	DataSet* dataset=NULL;
	char* marshalled_dataset=NULL;
	int   marshalled_dataset_size;

	/*Matrix: */
	Mat        matrix;
	MatType    type;
	
	/*Vector: */
	Vec        vector;

	/*Scalar: */
	double* pscalar=NULL;
	double  scalar;

	/*Integer: */
	int* pinteger=NULL;
	int  integer;

	/*String: */
	char* string=NULL;

	/*Matlab arrays: */
	mxArray* dataref=NULL;

	/*Branch on the type of data:*/
	if (strcmp(data_type,"DataSet")==0){
	
		if(data){
			/* marshall the dataset: */
			dataset=(DataSet*)data;

			marshalled_dataset=dataset->Marshall();
			marshalled_dataset_size=dataset->MarshallSize();
			
			dataref = mxCreateDoubleMatrix(0,0,mxREAL);
			mxSetM(dataref,(mwSize)(marshalled_dataset_size/sizeof(double)));
			mxSetN(dataref,(mwSize)1);
			mxSetPr(dataref,(double*)marshalled_dataset);	
		}
		else{
			/* return empty matrix: */
			dataref=mxCreateDoubleMatrix(0,0,mxREAL);
		}
		*pdataref=dataref;
	}
	else if (strcmp(data_type,"Matrix")==0){

		if(data){
		
			if (sub_data_type && strcmp(sub_data_type,"Mat")==0){
				
				/*data is a double* pointer. Copy into a matrix: */
				dataref = mxCreateDoubleMatrix(0,0,mxREAL);
				mxSetM(dataref,(mwSize)M);
				mxSetN(dataref,(mwSize)N);
				mxSetPr(dataref,(double*)data);
			}
			else{

				/*cast  matrix type: */
				matrix=(Mat)data;

				/*call toolkit routine: */
				PetscMatrixToMatlabMatrix(&dataref,matrix);
			}

		}
		else{
			dataref = mxCreateDoubleMatrix(0,0,mxREAL);
		}
		*pdataref=dataref;
	}
	else if (strcmp(data_type,"Vector")==0){
		
		if(data){

			if (sub_data_type && strcmp(sub_data_type,"Vec")==0){
				
				/*data is a double* pointer. Copy into a vector: */
				dataref = mxCreateDoubleMatrix(0,0,mxREAL);
				mxSetM(dataref,(mwSize)M);
				mxSetN(dataref,(mwSize)1);
				mxSetPr(dataref,(double*)data);
			}
			else{

		
				/*cast  vector type: */
				vector=(Vec)data;

				/*call toolkit routine: */
				PetscVectorToMatlabVector(&dataref,vector);
			}
		}
		else{
			dataref = mxCreateDoubleMatrix(0,0,mxREAL);
		}
		*pdataref=dataref;
	}
	else if (strcmp(data_type,"Scalar")==0){
		/*Get scalar: */
		pscalar=(double*)data;
		scalar=*pscalar;
		
		*pdataref=mxCreateDoubleScalar(scalar);
	}
	else if (strcmp(data_type,"Integer")==0){
		/*Integer is pointed to by data: */
		pinteger=(int*)data;
		integer=*pinteger;
		*pdataref=mxCreateDoubleScalar((double)integer);
	}
	else if (strcmp(data_type,"String")==0){
		/*String is pointed to by data: */
		string=(char*)data;
		*pdataref=mxCreateString(string);
	}
	else{
		throw ErrorException(__FUNCT__,exprintf("%s%s%s","incorrect data type ",data_type," .Only \"Matrix\",\"DataSet\",\"String\",\"Scalar\", or \"Integer\"  are allowed."));
	}
}
#endif //#ifdef _SERIAL_
