 /*      
 *          Copyright (C) 2000 RasSimTech Ltd. 
 *
 *  This program is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU General Public License
 *  as published by the Free Software Foundation; either version 2
 *  of the License, or (at your option) any later version. 
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 *  GNU General Public License for more details. 
 *  You should have received a copy of the GNU General Public License
 *  along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 
 */


//   $Revision: 1.0.1 $  $Date: 2000/10/31 00:00:00 $

#include "mex.h"
#include <map>

#include "AVDS2MATLAB.h"
#include <afxmt.h>


typedef std::map<int,CAVDS2MATLAB> MCAVDS2MATLAB;
static MCAVDS2MATLAB mpavds2Matlab;

enum enCallType {enOpenConnection=1,enSendData,enReceiveData,enCloseConnection}; 
	// using enCloseConnection as the last mode, if more modes are added insert them before enCloseConnection

void mexFunction(int nlhs,mxArray *plhs[],int nrhs,const mxArray* prhs[])
{
	char caErrorString[512];
	int iMode = 0;	//this is a user input, used to decide which function to call
	BOOL bError = FALSE;

	/////////////////////////////////////////////
	/*  check for proper number of arguments */
	/////////////////////////////////////////////

	// check right-hand side arguments
	switch(nrhs)
	{
	case 1:		// mode, ConnectionID (close) 
	case 2:		// mode, ConnectionID (receive) 
	case 3:		// mode, ConnectionID,data (send,vector)
	case 6:		// mode, ConnectionID,AVDS ID,Size of ToAVDS vector,MATLAB ID,Size of ToMATLAB vector (open,int iToAVDSID,int iNumberToAVDS,int iToMATLABID,int iNumberToMATLAB)
		/* Get the mode. */
		if( !mxIsNumeric(prhs[0]) || !mxIsDouble(prhs[0]) ||
			mxIsEmpty(prhs[0]) || mxIsComplex(prhs[0]) ||
			mxGetN(prhs[0])*mxGetM(prhs[0])!=1 ) 
		{
			mexErrMsgTxt("AVDSSimulation:: Operating mode (first input) must be a scalar.\n");
		}
		iMode = mxGetScalar(prhs[0]);
		bError = FALSE;
		switch(iMode)
		{
		case enOpenConnection:
			if(nrhs != 6)
			{
				bError = TRUE;
			}
			break;
		case enSendData:
			if(nrhs != 3)
			{
				bError = TRUE;
			}
			break;
		case enReceiveData:
			if(nrhs != 2)
			{
				bError = TRUE;
			}
			break;
		case enCloseConnection:
			if(nrhs != 1)
			{
				bError = TRUE;
			}
			break;
		default:
			bError = TRUE;
			break;
		}
		if(bError)
		{
			sprintf(caErrorString,"AVDSSimulation:: Wrong number of inputs encoutered for the AVDSSimulation MEX function mode selected: Mode Selected = %d Number of Inputs = %d \n Please see the file 'ReadMe.txt' for more information.\n",iMode,nrhs);
			mexErrMsgTxt(caErrorString);
		}
		break;
	default:
		sprintf(caErrorString,"AVDSSimulation:: Wrong number of inputs encoutered while executing the AVDSSimulation MEX function: %d inputs \n Must be 1, 2 or 5, please see the file 'ReadMe.txt' for more information.\n",nrhs);
		mexErrMsgTxt(caErrorString);
		break;
	}

	// check left-hand side arguments
	switch(nlhs)
	{
	case 0:		
		break;
	case 1:		// (receive)
		if(iMode != enReceiveData)
		{
			sprintf(caErrorString,"AVDSSimulation:: Wrong number of outputs encoutered while executing the AVDSSimulation MEX function: %d inputs \n Must be 0, please see the file 'ReadMe.txt' for more information.\n",nrhs);
			mexErrMsgTxt(caErrorString);
		}
		break;
	default:
		sprintf(caErrorString,"AVDSSimulation:: Wrong number of outputs encoutered while executing the AVDSSimulation MEX function: %d inputs \n Must be 0 or 1, please see the file 'ReadMe.txt' for more information.\n",nrhs);
		mexErrMsgTxt(caErrorString);
		break;
	}

	/////////////////////////////////////////////
	/* execute the functions */
	/////////////////////////////////////////////

	if ((iMode == 0) || (iMode > enCloseConnection))
	{
		sprintf(caErrorString,"AVDSSimulation:: Operating Mode must be a scalar between 1 and %d.\nMode number input was found to be %d. , please see the file 'ReadMe.txt' for more information\n",enCloseConnection,iMode);
		mexErrMsgTxt(caErrorString);
	}
	else	//if ((iMode == 0) || (iMode > enCloseConnection))
	{

		int iIndexArg = 0;	// temporary storage for argument numbers


		// get Connection ID
		int iIDConnection = -1;
		if(iMode != enCloseConnection)
		{
			iIndexArg = 1;
			if( !mxIsNumeric(prhs[iIndexArg]) || !mxIsDouble(prhs[iIndexArg]) ||
				mxIsEmpty(prhs[iIndexArg]) || mxIsComplex(prhs[iIndexArg]) ||
				mxGetN(prhs[iIndexArg])*mxGetM(prhs[iIndexArg])!=1 ) 
			{
				mexErrMsgTxt("AVDSSimulation:: Size of ToAVDS vector must be a scalar.\n");
			}
			iIDConnection = mxGetScalar(prhs[iIndexArg]);
		}
		MCAVDS2MATLAB::iterator itAVDS2Matlab;

		switch(iMode)
		{
		case enOpenConnection:
			{
				// first: check and get arguments
				// get AVDS ID
				iIndexArg = 2;
				if( !mxIsNumeric(prhs[iIndexArg]) || !mxIsDouble(prhs[iIndexArg]) ||
					mxIsEmpty(prhs[iIndexArg]) || mxIsComplex(prhs[iIndexArg]) ||
					mxGetN(prhs[iIndexArg])*mxGetM(prhs[iIndexArg])!=1 ) 
				{
					mexErrMsgTxt("AVDSSimulation:: Size of ToAVDS vector must be a scalar.\n");
				}
				int iIDAVDS = mxGetScalar(prhs[iIndexArg]);

				// get the Size of ToAVDS vector
				iIndexArg = 3;
				if( !mxIsNumeric(prhs[iIndexArg]) || !mxIsDouble(prhs[iIndexArg]) ||
					mxIsEmpty(prhs[iIndexArg]) || mxIsComplex(prhs[iIndexArg]) ||
					mxGetN(prhs[iIndexArg])*mxGetM(prhs[iIndexArg])!=1 ) 
				{
					mexErrMsgTxt("AVDSSimulation:: Size of AVDS ID must be a scalar.\n");
				}
				int iSizeToAVDS = mxGetScalar(prhs[iIndexArg]);

				// get MATLAB ID
				iIndexArg = 4;
				if( !mxIsNumeric(prhs[iIndexArg]) || !mxIsDouble(prhs[iIndexArg]) ||
					mxIsEmpty(prhs[iIndexArg]) || mxIsComplex(prhs[iIndexArg]) ||
					mxGetN(prhs[iIndexArg])*mxGetM(prhs[iIndexArg])!=1 ) 
				{
					mexErrMsgTxt("AVDSSimulation:: Size of ToMATLAB vector must be a scalar.\n");
				}
				int iIDMATLAB = mxGetScalar(prhs[iIndexArg]);

				// get Size of ToMATLAB vector
				iIndexArg = 5;
				if( !mxIsNumeric(prhs[iIndexArg]) || !mxIsDouble(prhs[iIndexArg]) ||
					mxIsEmpty(prhs[iIndexArg]) || mxIsComplex(prhs[iIndexArg]) ||
					mxGetN(prhs[iIndexArg])*mxGetM(prhs[iIndexArg])!=1 ) 
				{
					mexErrMsgTxt("AVDSSimulation:: Size of MATLAB ID must be a scalar.\n");
				}
				int iSizeToMATLAB = mxGetScalar(prhs[iIndexArg]);

				itAVDS2Matlab = mpavds2Matlab.find(iIDConnection);	
				if(itAVDS2Matlab != mpavds2Matlab.end())
				{
					mpavds2Matlab.erase(itAVDS2Matlab);
				}
				CAVDS2MATLAB mpavds2matlabTemp;
				std::pair<MCAVDS2MATLAB::iterator,bool> prAVDS2Matlab = mpavds2Matlab.insert(MCAVDS2MATLAB::value_type(iIDConnection,mpavds2matlabTemp));
				if(!prAVDS2Matlab.second)
				{
					sprintf(caErrorString,"AVDSSimulation:: Error encountered while opening the connection.\nArguments were:\niIDAVDS = %g,iSizeToAVDS = %g,iIDMATLAB = %g,iSizeToMATLAB = %g \n",iIDAVDS,iSizeToAVDS,iIDMATLAB,iSizeToMATLAB);
					mexErrMsgTxt(caErrorString);
				}
				itAVDS2Matlab = prAVDS2Matlab.first;
				CAVDS2MATLAB* pavds2MATLAB = &(*itAVDS2Matlab).second;
				// third: open connection
				if(!pavds2MATLAB->bOpenConnection(iIDAVDS,iSizeToAVDS,iIDMATLAB,iSizeToMATLAB))
				{
					sprintf(caErrorString,"AVDSSimulation:: Error encountered while opening the connection.\nArguments were:\niIDAVDS = %g,iSizeToAVDS = %g,iIDMATLAB = %g,iSizeToMATLAB = %g \n",iIDAVDS,iSizeToAVDS,iIDMATLAB,iSizeToMATLAB);
					mexErrMsgTxt(caErrorString);
				}
			}	//case enOpenConnection:

			break;
		case enSendData:
			{
				itAVDS2Matlab = mpavds2Matlab.find(iIDConnection);	
				if(itAVDS2Matlab == mpavds2Matlab.end())
				{
					sprintf(caErrorString,"AVDSSimulation:: Unable to   find connection #%d",iIDConnection);
					mexErrMsgTxt(caErrorString);
				}
				CAVDS2MATLAB* pavds2MATLAB = &(*itAVDS2Matlab).second;
				if(!pavds2MATLAB->bGetConnectionOpen())	// make sure there is an instance of the class available and the connection is open
				{
					mexErrMsgTxt("AVDSSimulation:: Connection must be opened before sending data.\n");
				}
				//  create a pointer to the input data vector 
				double* pdSendData = mxGetPr(prhs[2]);
				//  get the dimensions of the input data vector 
				int iMrowsIn = mxGetM(prhs[2]);
				int iNcolsIn = mxGetN(prhs[2]);
				// check the dimensions 
				if(!((iMrowsIn==1) || (iNcolsIn==1)))	// must be column or row vector 
				{
					sprintf(caErrorString,"AVDSSimulation:: Input must be a vector\n");
					mexErrMsgTxt(caErrorString);
				}
				if(((iMrowsIn*iNcolsIn) != pavds2MATLAB->iGetNumberToAVDS()))	// must have the correct dimension
				{
					sprintf(caErrorString,"AVDSSimulation:: Wrong length of input vector.\nLength of input vector was defined in OpenConnection to be: %d\nThis input vector's length is %d\n",pavds2MATLAB->iGetNumberToAVDS(),iMrowsIn*iNcolsIn);
					mexErrMsgTxt(caErrorString);
				}
				// call the function
				if(!pavds2MATLAB->bSendData(pdSendData))
				{
					sprintf(caErrorString,"AVDSSimulation:: Error encountered while sending data.\n");
					mexErrMsgTxt(caErrorString);
				}
			}	//case enSendData:
			break;
		case enReceiveData:
			{
				itAVDS2Matlab = mpavds2Matlab.find(iIDConnection);	
				if(itAVDS2Matlab == mpavds2Matlab.end())
				{
					sprintf(caErrorString,"AVDSSimulation:: Unable to   find connection #%d",iIDConnection);
					mexErrMsgTxt(caErrorString);
				}
				CAVDS2MATLAB* pavds2MATLAB = &(*itAVDS2Matlab).second;
				if(!pavds2MATLAB->bGetConnectionOpen())	// make sure there is an instance of the class available and the connection is open
				{
					mexErrMsgTxt("AVDSSimulation:: Connection must be opened before sending data.\n");
				}
				//  set the output pointer to the output matrix
				plhs[0] = mxCreateDoubleMatrix(pavds2MATLAB->iGetNumberToMATLAB(),1, mxREAL);
				//  create a pointer to a copy of the output matrix 
				double* pdReceiveData = mxGetPr(plhs[0]);
				// call the function
				if(!pavds2MATLAB->bReceiveData(pdReceiveData))
				{
					sprintf(caErrorString,"AVDSSimulation:: Error encountered while receiving data.\n");
					mexErrMsgTxt(caErrorString);
				}
			}	//case enReceiveData:
			break;
		case enCloseConnection:
			{
				for(itAVDS2Matlab = mpavds2Matlab.begin();itAVDS2Matlab != mpavds2Matlab.end();itAVDS2Matlab++)
				{
					CAVDS2MATLAB* pavds2MATLAB = &(*itAVDS2Matlab).second;
					pavds2MATLAB->CloseConnection();
				}
				mpavds2Matlab.clear();
			}
			break;
		default:
			sprintf(caErrorString,"AVDSSimulation:: Unknown mode encoutnered, mode: %d \n ",iMode);
			mexErrMsgTxt(caErrorString);
			break;
		}	//switch(iMode)
	}	//if ((iMode == 0) || (iMode > enCloseConnection))
}

