/* \file MatlabNArrayToNArray.cpp
 * \brief: convert a sparse or dense matlab n-dimensional array to cpp n-dimensional array
 */


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

#include "../../shared/shared.h"
#include "../../include/include.h"

#include <mex.h>

/*FUNCTION MatlabNArrayToNArray(double** pmatrix,int* pmatrix_numel,int* pmatrix_ndims,int** pmatrix_size,const mxArray* mxmatrix){{{*/
int MatlabNArrayToNArray(double** pmatrix,int* pmatrix_numel,int* pmatrix_ndims,int** pmatrix_size,const mxArray* mxmatrix){

	int  i,j,rows,cols;
	int  numel,ndims;
	int *size,*dims;
	double* mxmatrix_ptr=NULL;
	const mwSize* ipt=NULL;

	/*output: */
	double* matrix=NULL;

	/*matlab indices: */
	mwIndex*    ir=NULL;
	mwIndex*    jc=NULL;
	double* pr=NULL;
	int     count;
	int     nnz;
	int     nz;

	/*get Matlab matrix information: */
	numel=mxGetNumberOfElements(mxmatrix);
	ndims=mxGetNumberOfDimensions(mxmatrix);
	ipt  =mxGetDimensions(mxmatrix);
	size =xNew<int>(ndims);
	for (i=0;i<ndims;i++) size[i]=(int)ipt[i];

	/*Ok, first check if we are dealing with a sparse or full matrix: */
	if (mxIsSparse(mxmatrix)){

		/*Dealing with sparse matrix: recover size first: */
		rows=mxGetM(mxmatrix);
		cols=mxGetN(mxmatrix);
		nnz=mxGetNzmax(mxmatrix);
		nz=(int)((double)nnz/(double)rows);

		matrix=xNewZeroInit<double>(rows*cols);

		/*Now, get ir,jc and pr: */
		ir=mxGetIr(mxmatrix);
		jc=mxGetJc(mxmatrix);
		pr=mxGetPr(mxmatrix);

		/*Now, start inserting data into double* matrix: */
		count=0;
		for(i=0;i<cols;i++){
			for(j=0;j<(jc[i+1]-jc[i]);j++){
				*(matrix+rows*ir[count]+i)=pr[count];
				count++;
			}
		}

	}
	else{

		/*Dealing with dense matrix: recover pointer and size: */
		mxmatrix_ptr=(double*)mxGetPr(mxmatrix);
		
		/*Create serial matrix: */
		matrix=xNewZeroInit<double>(numel);

		dims=xNew<int>(ndims);
		for(i=0;i<numel;i++){
			ColumnWiseDimsFromIndex(dims,i,size,ndims);
			j=IndexFromRowWiseDims(dims,size,ndims);
			*(matrix+j)=*(mxmatrix_ptr+i);
		}
		xDelete<int>(dims);
		
	}

	/*Assign output pointer: */
	*pmatrix=matrix;
	*pmatrix_numel=numel;
	*pmatrix_ndims=ndims;
	*pmatrix_size=size;

	return 1;
}
/*}}}*/
/*FUNCTION MatlabNArrayToNArray(bool** pmatrix,int* pmatrix_numel,int* pmatrix_ndims,int** pmatrix_size,const mxArray* mxmatrix){{{*/
int MatlabNArrayToNArray(bool** pmatrix,int* pmatrix_numel,int* pmatrix_ndims,int** pmatrix_size,const mxArray* mxmatrix){

	int  i,j,rows,cols;
	int  numel,ndims;
	int *size,*dims;
	bool* mxmatrix_ptr=NULL;
	const mwSize* ipt=NULL;

	/*output: */
	bool* matrix=NULL;

	/*matlab indices: */
	mwIndex*    ir=NULL;
	mwIndex*    jc=NULL;
	bool*   pm=NULL;
	int     count;
	int     nnz;
	int     nz;

	/*get Matlab matrix information: */
	numel=mxGetNumberOfElements(mxmatrix);
	ndims=mxGetNumberOfDimensions(mxmatrix);
	ipt  =mxGetDimensions(mxmatrix);
	size =xNew<int>(ndims);
	for (i=0;i<ndims;i++) size[i]=(int)ipt[i];

	/*Ok, first check if we are dealing with a sparse or full matrix: */
	if (mxIsSparse(mxmatrix)){

		/*Dealing with sparse matrix: recover size first: */
		rows=mxGetM(mxmatrix);
		cols=mxGetN(mxmatrix);
		nnz=mxGetNzmax(mxmatrix);
		nz=(int)((double)nnz/(double)rows);

		matrix=xNewZeroInit<bool>(rows*cols);

		/*Now, get ir,jc and pm: */
		ir=mxGetIr(mxmatrix);
		jc=mxGetJc(mxmatrix);
		pm=(bool*)mxGetData(mxmatrix);

		/*Now, start inserting data into bool* matrix: */
		count=0;
		for(i=0;i<cols;i++){
			for(j=0;j<(jc[i+1]-jc[i]);j++){
				*(matrix+rows*ir[count]+i)=pm[count];
				count++;
			}
		}

	}
	else{

		/*Dealing with dense matrix: recover pointer and size: */
		mxmatrix_ptr=(bool*)mxGetData(mxmatrix);
		
		/*Create serial matrix: */
		matrix=xNew<bool>(numel);
		dims=xNew<int>(ndims);
		for(i=0;i<numel;i++){
			ColumnWiseDimsFromIndex(dims,i,size,ndims);
			j=IndexFromRowWiseDims(dims,size,ndims);
			*(matrix+j)=(bool)*(mxmatrix_ptr+i);
		}
		xDelete<int>(dims);
	}

	/*Assign output pointer: */
	*pmatrix=matrix;
	*pmatrix_numel=numel;
	*pmatrix_ndims=ndims;
	*pmatrix_size=size;

	return 1;
}
/*}}}*/
/*FUNCTION MatlabNArrayToNArray(char** pmatrix,int* pmatrix_numel,int* pmatrix_ndims,int** pmatrix_size,const mxArray* mxmatrix){{{*/
int MatlabNArrayToNArray(char** pmatrix,int* pmatrix_numel,int* pmatrix_ndims,int** pmatrix_size,const mxArray* mxmatrix){

	int           i,j,rows,cols;
	int           numel,ndims;
	int          *size , *dims;
	mxChar       *mxmatrix_ptr = NULL;
	const mwSize *ipt          = NULL;

	/*output: */
	char* matrix=NULL;

	/*matlab indices: */
	mwIndex *ir    = NULL;
	mwIndex *jc    = NULL;
	char    *pm    = NULL;
	int      count;
	int      nnz;
	int      nz;

	/*get Matlab matrix information: */
	numel=mxGetNumberOfElements(mxmatrix);
	ndims=mxGetNumberOfDimensions(mxmatrix);
	ipt  =mxGetDimensions(mxmatrix);
	size =xNew<int>(ndims);
	for (i=0;i<ndims;i++) size[i]=(int)ipt[i];

	/*Ok, first check if we are dealing with a sparse or full matrix: */
	if (mxIsSparse(mxmatrix)){

		/*Dealing with sparse matrix: recover size first: */
		rows=mxGetM(mxmatrix);
		cols=mxGetN(mxmatrix);
		nnz=mxGetNzmax(mxmatrix);
		nz=(int)((double)nnz/(double)rows);

		matrix=xNew<char>(rows*cols);

		/*Now, get ir,jc and pm: */
		ir=mxGetIr(mxmatrix);
		jc=mxGetJc(mxmatrix);
		pm=(char*)mxGetData(mxmatrix);

		/*Now, start inserting data into char* matrix: */
		count=0;
		for(i=0;i<cols;i++){
			for(j=0;j<(jc[i+1]-jc[i]);j++){
				*(matrix+rows*ir[count]+i)=(char)pm[count];
				count++;
			}
		}

	}
	else{

		/*Dealing with dense matrix: recover pointer and size: */
		mxmatrix_ptr=mxGetChars(mxmatrix);
		
		/*Create serial matrix: */
		matrix=xNew<char>(numel+1);
		matrix[numel]='\0';

		/*looping code adapted from Matlab example explore.c: */
		int elements_per_page = size[0] * size[1];
		/* total_number_of_pages = size[2] x size[3] x ... x size[N-1] */
		int total_number_of_pages = 1;
		for (i=2; i<ndims; i++) {
			total_number_of_pages *= size[i];
		}

		i=0;
		for (int page=0; page < total_number_of_pages; page++) {
			int row;
			/* On each page, walk through each row. */
			for (row=0; row<size[0]; row++)  {
				int column;
				j = (page * elements_per_page) + row;

				/* Walk along each column in the current row. */
				for (column=0; column<size[1]; column++) {
					*(matrix+i++)=(char)*(mxmatrix_ptr+j);
					j += size[0];
				}
			}
		}
	}

	/*Assign output pointer: */
	*pmatrix=matrix;
	*pmatrix_numel=numel;
	*pmatrix_ndims=ndims;
	*pmatrix_size=size;

	return 1;
}
/*}}}*/
