/*------------------------------------------------------------------------------*
 * File Name: OMLinkObj.h	 													*
 * Creation: SY 01/31/2005 QA70-1995 OC_MATHEMATICA_LINK						*
 * Purpose: OC Mathlink calss													*
 * Copyright (c) ABCD Corp.	2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010		*
 * All Rights Reserved															*
 * 																				*
 * Modification Log:															*
 *	EJP 2007-09-28 v8.0712 QA70-10448 FIX_WRITING_PASS_BUFFER_END				*
 *	Kyle 10/27/2010 ORG-1339-P1 CHECK_IF_MATH_KERNEL_VALID						*
 *------------------------------------------------------------------------------*/

#ifndef _OMLINK_OBJ_H
#define _OMLINK_OBJ_H

#include "OMLink.h"

////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////
#ifndef MLEUSER // defined in "OMLink.h"
#define MLEUSER        1000  /* start of user defined errors */
#endif //MLEUSER

#define	OCMLERROR		MLEUSER+100       
enum
{
	OCMLE_COMMON = OCMLERROR,
	OCMLE_INVALID_DATASET_NAME, 
	OCMLE_DATASET_EMPTY,
	OCMLE_INVALID_DEGREE,
	OCMLE_SEND_DATA,
	OCMLE_RCV_DATA,
	OCMLE_INTERACT,
	OCMLE_OPENLINK,
	OCMLE_LINKOPEN,
};


typedef enum { 
	expression_expected, 
	string_expected,
} MLInputMode;

typedef LPVOID MLINK;
typedef LPVOID MLEnvironment;

#define	RETURN_ERR(id, str) {out_str(str); return id;}
#define MSG_RETURN(_msg, _ret) { MessageBox(NULL, _msg, OMLINK_ERRMSGBOX_CAPTION, MB_OK); return _ret; }
#define MSG_SET(_msg, _variable, _value) { MessageBox(NULL, _msg, OMLINK_ERRMSGBOX_CAPTION, MB_OK); _variable = _value; }


#define OCML_INI_FILE_NAME		"ORIGINML.INI"
#define OCML_OGS_FILE_NAME		"ORIGINML.OGS"
#define OCML_ORG_PACKAGE_NAME 	"Origin.m"
#define OCML_SEQUENCER_NAME		"Sequencer.exe"

////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////

//#define OMLINK_DEBUG
#ifdef OMLINK_DEBUG
	#pragma message("MLVERIFY defined as ml_verify((MLfunc), __FILE__, __LINE__)")

	#define MLVERIFY(MLlink, MLfunc) ml_verify(MLlink, MLfunc, __FILE__, __LINE__)

	int ml_verify(MLINK mlink, int iMLReturn, LPCSTR lpcstrFile, LPCSTR lpcstrLine)
	{
		if( iMLReturn == 0 )
		{
			string str;
			str.Format("File: %s\nLine: %d\nError: %s", lpcstrFile, lpcstrLine, omlink_MLErrorMessage(mlink));
			MessageBox(NULL, str, "MLVERIFY Failure", MB_OK);
			omlink_MLClearError(mlink);
		}
		return iMLReturn;
	}

#else // !OMLINK_DEBUG
	#pragma message("MLVERIFY defined as ml_verify((MLfunc))")

	#define MLVERIFY(MLlink, MLfunc) ml_verify(MLlink, (MLfunc))

	int ml_verify(MLINK mlink, int iMLReturn)
	{
		if( iMLReturn == 0 )
			omlink_MLClearError(mlink);
		return iMLReturn;
	}
#endif // OMLINK_DEBUG


////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////
class OMLinkObj
{
public:
	OMLinkObj()
	{
		init_members();
	}
	
	~OMLinkObj() {}

private: // Data members
	string 		m_strMathlinkPath;	// Mathlink Kernel Path
	bool 		m_bLinkActive;		// For checking if link is active

	int 		m_mlNumInput;		// number of Input
	int 		m_mlDialogLevel;
	MLINK 		m_mlink;
	MLEnvironment m_mlenvp;
	MLInputMode m_mlInputMode;

////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////
	
public: // Public member functions
	int OpenLink()
	{
		int iSuccess;
		
		IncreaseInputNum(2);
		if( init_and_openlink() )
			///Kyle 10/27/2010 ORG-1339-P1 CHECK_IF_MATH_KERNEL_VALID
			//return false;
			RETURN_ERR(OCMLE_INTERACT, "Error initializing link!");
			///End CHECK_IF_MATH_KERNEL_VALID
	
		// Open mathlink successed
		m_bLinkActive = true;
	
		if( (iSuccess = Evaluate()) == 0 )
		{
			// Some MathLink error occured
			RETURN_ERR(OCMLE_INTERACT, "Error initializing link!");
		};
	
		if( (iSuccess = Evaluate("$Display=\"stdout\";")) == 0 )
		{
			// Some MathLink error occured
			RETURN_ERR(OCMLE_INTERACT, "Error setting display function!");
		};
	
		// Evaluate Origin.m package
		char szInput[OCML_INPUT_BUF];
		if( check_origin_m_package(szInput) )
		{
			if( (iSuccess = Evaluate(szInput)) == 0 )
			{
				// Some MathLink error occured
				RETURN_ERR(OCMLE_INTERACT, "Error reading origin.m package!");
			};
		}	
		out_str("Mathematica Kernel is running.");
		
		return 0;
	}
	
	int CloseLink()
	{
		if( !IsLinkOpen() )
		{
			// Some MathLink error occured
			RETURN_ERR(OCMLE_LINKOPEN, "Error, link is not open!");
		};
	
    	if( m_mlink )
    	{
			MLVERIFY(m_mlink, omlink_MLPutFunction(m_mlink, "Quit", 0));
    		omlink_MLClose(m_mlink);
    		omlink_MLDeinitialize(m_mlenvp);
    	}
		//Evaluate("Quit");
		out_str("Exiting Mathematica Kernel.");
	
		m_bLinkActive = false;
		
		return 0;
	}
	
	bool IsLinkOpen()
	{
		return (m_bLinkActive ? true : false);
	}
	
	int SendArray(LPCSTR lpcszMLVar, double *pColumn, long nRows)
	{
		if( !m_mlink )
			return MLEDEAD;
	
		MLVERIFY(m_mlink, omlink_MLPutFunction(m_mlink, "Set", 2));
		MLVERIFY(m_mlink, omlink_MLPutSymbol(m_mlink, lpcszMLVar));
		MLVERIFY(m_mlink, omlink_MLPutRealList(m_mlink, pColumn, nRows));
		MLVERIFY(m_mlink, omlink_MLEndPacket(m_mlink));
	
		Evaluate();
	
		return 0; 
	}
	
	int SendMatrix(LPCSTR lpcszMLVar, double *pColumn, long nCols, long nRows)
	{
		if( !m_mlink )
			return MLEDEAD;
	
	  	long dims[2];
		dims[0] = nCols;
		dims[1] = nRows;
	
		MLVERIFY(m_mlink, omlink_MLPutFunction(m_mlink,"Set",2));
		MLVERIFY(m_mlink, omlink_MLPutSymbol(m_mlink, lpcszMLVar));
		MLVERIFY(m_mlink, omlink_MLPutRealArray(m_mlink, pColumn, dims, NULL, 2));
		MLVERIFY(m_mlink, omlink_MLEndPacket(m_mlink));
	
		Evaluate();
	
		return 0; 
	}
	
	int RecvArray(LPCSTR lpcszMLVar, Dataset &ds, int iFirstRow = 0)
	{
		if( !m_mlink )
			return MLEDEAD;
	
		MLVERIFY(m_mlink, omlink_MLPutFunction(m_mlink, "ToExpression", 1));
		MLVERIFY(m_mlink, omlink_MLPutString(m_mlink, lpcszMLVar));
		MLVERIFY(m_mlink, omlink_MLEndPacket(m_mlink));
	
		evaluate_packages();
	
		long nRows = 0;
		double *pdML;
		
		int type = MLVERIFY(m_mlink, omlink_MLGetType(m_mlink));
		if( type == MLTKFUNC && MLVERIFY(m_mlink, omlink_MLGetRealList(m_mlink, &pdML, &nRows)) && nRows > 0)
		{
			ds.SetSize(nRows);
			
			for( int i = iFirstRow; i < nRows; i++ )
				ds[i] = pdML[i];
		}
		else
		{
			// On error we need to discard the packet or expression
			// to prevent hanging future packets.
			MLVERIFY(m_mlink, omlink_MLNewPacket(m_mlink));
			return OCMLE_RCV_DATA;
		}
		
		omlink_MLDisownRealList(m_mlink, pdML, nRows); 
	
		return 0; 
	}
	
	int RecvReal(LPCSTR lpcszMLVar, double *pdData)
	{
		if( !m_mlink )
			return MLEDEAD;
	
		MLVERIFY(m_mlink, omlink_MLPutFunction(m_mlink, "N", 1));
		MLVERIFY(m_mlink, omlink_MLPutFunction(m_mlink, "ToExpression", 1));
		MLVERIFY(m_mlink, omlink_MLPutString(m_mlink, lpcszMLVar));
		MLVERIFY(m_mlink, omlink_MLEndPacket(m_mlink));
	
		evaluate_packages();
		
		double dRes;
		int type = MLVERIFY(m_mlink, omlink_MLGetType(m_mlink));
		if( type == MLTKREAL && MLVERIFY(m_mlink, omlink_MLGetReal(m_mlink, &dRes)) )
			*pdData = dRes;
		else
		{
			// On error we need to discard the packet or expression
			// to prevent hanging future packets.
			MLVERIFY(m_mlink, omlink_MLNewPacket(m_mlink));
			return OCMLE_RCV_DATA;
		}
			
		return 0; 
	}
	
	int RecvMatrix(LPCSTR lpcszMLVar, matrix &omat, int nFirstCol, int iFirstRow)
	{
		if( !m_mlink )
			return MLEDEAD;
	
		MLVERIFY(m_mlink, omlink_MLPutFunction(m_mlink, "ToExpression", 1));
		MLVERIFY(m_mlink, omlink_MLPutString(m_mlink, lpcszMLVar));
		MLVERIFY(m_mlink, omlink_MLEndPacket(m_mlink));
	
		evaluate_packages();
		
		long	*pDims;
		long	nc, nr;
		long	depth;
		double	*pdML;
		char	**ppHeads;
	
		int type = MLVERIFY(m_mlink, omlink_MLGetType(m_mlink));
		if( type == MLTKFUNC && MLVERIFY(m_mlink, omlink_MLGetRealArray(m_mlink, &pdML, &pDims, &ppHeads, &depth)) )
		{
			nc = pDims[0];
			nr = pDims[1];
	
			// Set matrix dimensions.
			long ncMatrix, nrMatrix;
			omat.GetSourceDim(nrMatrix, ncMatrix);
			
			nc = (nFirstCol + nc - 1); 	// calculate last column
			if( nc > ncMatrix )
				ncMatrix = nc;	
			
			nr = (iFirstRow + nr - 1);	// calculate last row
			if( nr > nrMatrix )
				nrMatrix = nr;
			
			// Make sure the destination matrix is big enough to hold the table.
			omat.SetSize(nrMatrix, ncMatrix);
			
			// Copy values received from Mathematica table into Origin's matrix.
			int i = 0;
			for( int iCol = nFirstCol - 1; iCol < nc; iCol++ )
			{
				for( int iRow = iFirstRow - 1; iRow < nr; iRow++ )
				{
					omat[iRow][iCol] = pdML[i++];
				}
			}
			
		}
		else
		{
			// On error we need to discard the packet or expression
			// to prevent hanging future packets.
			MLVERIFY(m_mlink, omlink_MLNewPacket(m_mlink));
			return OCMLE_RCV_DATA;
		}
		
		omlink_MLDisownRealArray(m_mlink, pdML, pDims, ppHeads, depth);
	
		return 0; 
	}
	
	int Evaluate(LPSTR lpstrInput = NULL, LPSTR lpstrOutput = NULL)
	{
		static int 		s_iFirstPSPiece = TRUE;
		static int 		s_iComingVerboseMenu = FALSE;
		static HANDLE	s_hGraphFile = (HANDLE)NULL;
	
		DWORD		dwBytesWritten;
		long		lenp, missing;
		int			packet, iMenu, iRet;
		int			iSyntaxErrPos = -1;
		bool		bDone = FALSE;
		string 		str;
		char*		pszOutput[1];
		char**		ppstrOutPut = pszOutput;
		char		szTemp[MAXLINE];
		
		if( lpstrInput )
		{
			if( m_mlInputMode == expression_expected )
			{
				MLVERIFY(m_mlink, omlink_MLPutFunction(m_mlink, "EnterTextPacket", 1));
			}
			else
			{
				MLVERIFY(m_mlink, omlink_MLPutFunction(m_mlink, "TextPacket", 1));
				m_mlInputMode = expression_expected;
			}
			
			MLVERIFY(m_mlink, omlink_MLPutByteString(m_mlink, lpstrInput, lstrlen(lpstrInput)));
			MLVERIFY(m_mlink, omlink_MLEndPacket(m_mlink));
	
			if( check_error() )
				return 0;
		}
	
		while( !bDone )
		{
			switch( packet = omlink_MLNextPacket(m_mlink) )
			{
			case ILLEGALPKT:
				if( !omlink_MLClearError(m_mlink) || !omlink_MLNewPacket(m_mlink) )
					bDone = TRUE;
				break;
				
			case INPUTNAMEPKT:
			case INPUTPKT:
				if( omlink_MLGetByteString(m_mlink, ppstrOutPut, &lenp, missing) )
				{
					//out_str(*ppstrOutPut);
					//if( lpstrOutput )
					//	format_ml_output_text(lpstrOutput, *ppstrOutPut);
					omlink_MLDisownByteString(m_mlink, *ppstrOutPut, lenp); // no return value
				}
				bDone = TRUE;
				break;
				
			case TEXTPKT:
				if( omlink_MLGetByteString(m_mlink, ppstrOutPut, &lenp, missing) )
				{
					//out_str(*ppstrOutPut);
					if( lpstrOutput )
						format_ml_output_text(lpstrOutput, *ppstrOutPut);
					omlink_MLDisownByteString(m_mlink, *ppstrOutPut, lenp); // no return value
				}
				if( s_iComingVerboseMenu )
				{
					s_iComingVerboseMenu = FALSE;
					//out_str(lpstrInput);
					if( lpstrOutput )
						lstrcat(lpstrOutput, lpstrInput);
					bDone = TRUE;
				}
				break;
				
			case OUTPUTNAMEPKT:
				if( omlink_MLGetByteString(m_mlink, ppstrOutPut, &lenp, missing) )
				{
					//out_str(*ppstrOutPut);
					if( lpstrOutput )
						format_ml_output_text(lpstrOutput, *ppstrOutPut);
					omlink_MLDisownByteString(m_mlink, *ppstrOutPut, lenp); // no return value
				}
				break;
				
			case RETURNTEXTPKT:
				if( omlink_MLGetByteString(m_mlink, ppstrOutPut, &lenp, missing) )
				{
					//out_str(*ppstrOutPut);
					if( lpstrOutput )
						format_ml_output_text(lpstrOutput, *ppstrOutPut);
					omlink_MLDisownByteString(m_mlink, *ppstrOutPut, lenp); // no return value
				}
				break;
				
			case DISPLAYPKT:
				#if _OC_VER >= 0x0800
				if( omlink_MLGetByteString(m_mlink, ppstrOutPut, &lenp, missing) )
				{
					if( s_iFirstPSPiece )
					{
						s_hGraphFile = CreateFile("bild.mps",
							GENERIC_WRITE,
							FILE_SHARE_READ,
							NULL,
							CREATE_ALWAYS,
							FILE_ATTRIBUTE_NORMAL,
							NULL);
					}
					s_iFirstPSPiece = FALSE;
				}
				
				WriteFile(s_hGraphFile, *ppstrOutPut, strlen(*ppstrOutPut), &dwBytesWritten, NULL);
				omlink_MLDisownByteString(m_mlink, *ppstrOutPut, lenp); // no return value
				
				#else
	         	
				// NOT IMPLEMENT YET!!!
	           	if( s_iFirstPSPiece )
	                s_iFirstPSPiece = FALSE;
	
	           	if( omlink_MLGetString(m_mlink, ppstrOutPut) )
	            {
					//out_str(*ppstrOutPut);
					if( lpstrOutput )
						format_ml_output_text(lpstrOutput, *ppstrOutPut);
	                omlink_MLDisownString(m_mlink, *ppstrOutPut);
	            }
	
				#endif
				
				break;
				
			case DISPLAYENDPKT:
				#if _OC_VER >= 0x0800
				if( omlink_MLGetByteString(m_mlink, ppstrOutPut, &lenp, missing) )
				{
					WriteFile(s_hGraphFile, *ppstrOutPut, strlen(*ppstrOutPut), &dwBytesWritten, NULL);
					CloseHandle(s_hGraphFile);
				}
				omlink_MLDisownByteString(m_mlink, *ppstrOutPut, lenp); // no return value
				s_iFirstPSPiece = TRUE;
				
				#else
	            
	        	// NOT IMPLEMENT YET!!!
				if( omlink_MLGetString(m_mlink, ppstrOutPut))
	            {
	            	// ppstrOutPut returnning with Mathematica temp output WMF file name
	                omlink_MLDisownString(m_mlink, *ppstrOutPut);
	            }
	            s_iFirstPSPiece = TRUE;
	
				#endif
				
				break;
				
			case SYNTAXPKT:
				MLVERIFY(m_mlink, omlink_MLGetInteger(m_mlink, &iSyntaxErrPos));
				//out_str(lpstrInput);
				if( lpstrOutput )
					lstrcat(lpstrOutput, lpstrInput);
				memset(lpstrInput, ' ', iSyntaxErrPos);
				break;
				
			case INPUTSTRPKT:
				if( omlink_MLGetByteString(m_mlink, ppstrOutPut, &lenp, missing) )
				{
					//out_str(*ppstrOutPut);
					if( lpstrOutput )
						format_ml_output_text(lpstrOutput, *ppstrOutPut);
					omlink_MLDisownByteString(m_mlink, *ppstrOutPut, lenp);
				}
				m_mlInputMode = string_expected;
				bDone = TRUE;
				break;
	
			case MENUPKT:
				MLVERIFY(m_mlink, omlink_MLGetInteger(m_mlink, &iMenu));
				if( omlink_MLGetByteString(m_mlink, ppstrOutPut, &lenp, missing) )
				{
					lstrcpy(lpstrInput, *ppstrOutPut);
					omlink_MLDisownByteString(m_mlink, *ppstrOutPut, lenp);
				}
				m_mlInputMode = string_expected;
				if( iMenu == 0 )
					s_iComingVerboseMenu = TRUE;
				else
					bDone = TRUE;
				break;
				
			case MESSAGEPKT:
				MLVERIFY(m_mlink, omlink_MLNewPacket(m_mlink));
				break;
				
			case SUSPENDPKT:
				MLVERIFY(m_mlink, omlink_MLNewPacket(m_mlink));
				bDone = TRUE;
				break;
				
			case RESUMEPKT:
				MLVERIFY(m_mlink, omlink_MLNewPacket(m_mlink));
				break;
	
			case BEGINDLGPKT:
				MLVERIFY(m_mlink, omlink_MLGetInteger(m_mlink, &m_mlDialogLevel));
				break;
				
			case ENDDLGPKT:
				MLVERIFY(m_mlink, omlink_MLGetInteger(m_mlink, &m_mlDialogLevel));
				m_mlDialogLevel--;
				break;
				
			case RETURNPKT:
				bDone = TRUE;
				break;
	
			default:
				sprintf(szTemp, OMLINK_UNSUPPORTED_PACKET, packet);
				format_ml_output_text(lpstrOutput, szTemp);
				break;
			}
			MLVERIFY(m_mlink, omlink_MLNewPacket(m_mlink));
			if( check_error() )
			{
				return 0;
			}
		}
	
		return( packet);
	}
		
	bool GetIniFile(string &strIniFile)
	{
		strIniFile = GetAppPath();
		strIniFile += OCML_INI_FILE_NAME;
		return true;
	}
	
	bool GetOGSFile(string &strOGSFile)
	{
		strOGSFile = GetAppPath();
		strOGSFile += OCML_OGS_FILE_NAME;
		return true;
	}
	
	LPCSTR GetMathematicaKernel()
	{
		if( m_strMathlinkPath.IsEmpty() )
		{
			string strIniFile;
			GetIniFile(strIniFile);
			
			INIFile ini(strIniFile);
			string strMathematica;
			
			strMathematica = ini.ReadString("Config", "Mathkernel", "");
		
			// If the INI file does not contain Mathematica's Kernel path then the
			// user will need to locate the path using a file open dialog.
			// Once the user locates the file the path and name are written to the
			// INI file.
			if( !strMathematica.IsFile() )
			{
				// Get the path for Mathematica
				strMathematica = GetOpenBox("[Executable (*.EXE)] *.exe", NULL, NULL, "Please Locate Mathematica's Kernel");
			}
			///Kyle 10/27/2010 ORG-1339-P1 CHECK_IF_MATH_KERNEL_VALID
			if( strMathematica.IsEmpty() )		// user cancel
			{
				m_strMathlinkPath.Empty();
				ini.WriteString("Config", "Mathkernel", m_strMathlinkPath);
				return (LPCSTR)m_strMathlinkPath;
			}
			///End CHECK_IF_MATH_KERNEL_VALID
				
			if( GetFileName(strMathematica).CompareNoCase(OCML_SEQUENCER_NAME) )
			{
				// Force to use sequencer.exe in case that user selects MathKernel.exe
				strMathematica = GetFilePath(strMathematica) + OCML_SEQUENCER_NAME;
			}
			
			// Test if sequencer.exe is in Mathematica folder
			BOOL bSequencerExist = TRUE;
			if( !strMathematica.IsFile() )
			{
				// Copy sequencer.exe from Origin into Mathematica folder
				string strFile;
				
				strFile = GetAppPath() + OCML_SEQUENCER_NAME;
				
				if( !strFile.IsFile() )
				{
					strFile = GetAppPath(TRUE) + OCML_SEQUENCER_NAME;
					
					if( !strFile.IsFile() )
						bSequencerExist = FALSE;	
				}
				
				if( bSequencerExist )
					CopyFile(strFile, strMathematica);
			}
			
			m_strMathlinkPath = GetFilePath(strMathematica) + ( bSequencerExist ? OCML_SEQUENCER_NAME : DEFAULT_NAME );
			
			ini.WriteString("Config", "Mathkernel", m_strMathlinkPath);
		}
		
		return (LPCSTR)m_strMathlinkPath;
	}
	
	void IncreaseInputNum(int nIncrement = 1) { m_mlNumInput += nIncrement; }

////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////

private:
	void init_members()
	{
		m_bLinkActive = false;		// Link is inactive by default
	
		m_strMathlinkPath = "";		// User must locate this.  Once located it is
									// stored in the INI file.
		m_mlink = NULL;
		m_mlInputMode = -1;
		m_mlNumInput = 1;			// 1st Input
	}
	
	int check_error()
	{
	    int nRet;
	
	    if( !m_mlink ) 
	    	return MLEDEAD;
	
	    if( nRet = omlink_MLError(m_mlink) )
	        MessageBox(NULL, omlink_MLErrorMessage(m_mlink), OMLINK_ERRMSGBOX_CAPTION, MB_OK);
	    
	    return nRet;
	}
	
	int init_and_openlink()
	{
		if( m_mlink && IsLinkOpen() )
			return MLEOK;
		
		// Initialize functions in the MathLink library.  Any external program
		// that uses the MathLink library must call MLInitialize() before calling
		// any other MathLink library functions.
		m_mlenvp = omlink_MLInitialize(NULL);
		if( !m_mlenvp )
			return MLEINIT;
	
		//----------------------------------------------------------------------
		// options for establishing the link
		//char* argv[] = {"-linkname", "MathKernel.exe", "-mathlink", "-LinkOptions", "MLDontInteract", "\0"};
		char* argv[ARGV_SIZE];
		
		argv[0] = LINK_NAME;
	
		char szMathPath[MAX_PATH];
		lstrcpyn(szMathPath, GetMathematicaKernel(), MAX_PATH);
		///Kyle 10/27/2010 ORG-1339-P1 CHECK_IF_MATH_KERNEL_VALID
		if( lstrlen(szMathPath) == 0 )
			return MLEUNKNOWN;
		///End CHECK_IF_MATH_KERNEL_VALID
		argv[1] = szMathPath;
		
		argv[2] = LINK_MATHLINK;
		argv[3] = LINK_OPTION;
		argv[4] = "MLDontInteract";
		argv[ARGS_NUMBER] = "\0";
		//----------------------------------------------------------------------
		
		char** lpArg = argv;
		// Get pointer to ending argument.
		char** lpArgEnd = lpArg + ARGS_NUMBER;
		long err;
		
		// Open a MathLink connection taking parameters from an argv array.
		m_mlink = omlink_MLOpenArgv(m_mlenvp, (LPVOID)lpArg, (LPVOID)lpArgEnd, &err);
		
		return (m_mlink == NULL ? MLEUNKNOWN : MLEOK);
	}
	
	void evaluate_packages()
	{
		int		result;
		char	*psym, *pstr;
	
		int packet = MLVERIFY(m_mlink, omlink_MLNextPacket(m_mlink));
	
		while( packet != RETURNPKT && packet != ILLEGALPKT )
		{
			switch( packet )
			{
			case MESSAGEPKT:
				MLVERIFY(m_mlink, omlink_MLGetSymbol(m_mlink, &psym));
				MLVERIFY(m_mlink, omlink_MLGetString(m_mlink, &pstr));
				
				omlink_MLDisownSymbol(m_mlink, psym); 
				omlink_MLDisownString(m_mlink, pstr); 
				break;
				
			case INPUTPKT:
			case RETURNTEXTPKT:
			case INPUTNAMEPKT:
			case OUTPUTNAMEPKT:
			case DISPLAYPKT:
				MLVERIFY(m_mlink, omlink_MLGetString(m_mlink, &pstr));
				omlink_MLDisownString(m_mlink, pstr); // no return value
				break;
				
			case TEXTPKT:
				MLVERIFY(m_mlink, omlink_MLGetString(m_mlink, &pstr));
				printf("%s\n", pstr);
				omlink_MLDisownString(m_mlink, pstr); // no return value
				break;
	
			case DISPLAYENDPKT:
			case MENUPKT:
			case CALLPKT:
				break;
			}
			MLVERIFY(m_mlink, omlink_MLNewPacket(m_mlink));
			packet = MLVERIFY(m_mlink, omlink_MLNextPacket(m_mlink));
		}
	}
	
	//---------------------------------------------------------------------------
	// format_ml_output_text
	//
	//	Convert '\n' to '\r\n' of the Mathematic returned text and append it to output string
	//
	//---------------------------------------------------------------------------
	int format_ml_output_text(LPSTR lpstrOutput, LPSTR lpstrMLText)
	{
		/// EJP 2007-09-28 v8.0712 QA70-10448 FIX_WRITING_PASS_BUFFER_END
		///if( !lpstrMLText )
		if( !lpstrOutput || !lpstrMLText ) // both arguments are required
		/// end FIX_WRITING_PASS_BUFFER_END
			return 0;
		
		DWORD dw = lstrlen(lpstrMLText);

		/// EJP 2007-09-28 v8.0712 QA70-10448 FIX_WRITING_PASS_BUFFER_END
		// Make sure there is enough space in the output buffer.
		if( lstrlen(lpstrOutput) + dw > OCML_OUTPUT_BUF )
			return 0;
		/// end FIX_WRITING_PASS_BUFFER_END

		HGLOBAL hMem = GlobalAlloc(GHND, dw * 2);
		if( hMem ) // If memory allocated
		{
			LPSTR lpstr, lpstrMem;
			char c;
	
			lpstr = lpstrMem = (LPSTR)GlobalLock(hMem);
			if( lpstr ) // If memory locked
			{
				while( (c = *lpstrMLText++) )
				{
					if( c == '\n' ) // convert '\n' to '\r\n'
						*lpstr++ = '\r';
					*lpstr++ = c;
				}
				lstrcat(lpstrOutput, lpstrMem);
				lstrcat(lpstrOutput, "\r\n");
			}
			GlobalFree(hMem);
		}
	
		return 0;
	}
	
	//---------------------------------------------------------------------------
	// backslash_to_slash
	//
	//	Mathematic uses Unix style slash in file name, so need to convert '\\' to '/' in Windows filename
	//
	//---------------------------------------------------------------------------
	bool backslash_to_slash(LPSTR lpszUnixFilename, LPCSTR lpcszWinFilename)
	{
		if( !lpcszWinFilename || !lpszUnixFilename )
			return false;
		
		char c;
		while( (c = *lpcszWinFilename++) )
		{
			if( c == '\\' ) // convert '\\' to '/'
				c = '/';
			
			*lpszUnixFilename++ = c;
		}
		
		return true;
	}
	
	bool check_origin_m_package(LPSTR lpszPackageName)
	{
		string strOrgPackageFile;
		file filom;
		bool bFoundPackage = true;
		
		// Try origin.m in INI first, then EXE
		strOrgPackageFile.Format("%s%s", GetAppPath(), OCML_ORG_PACKAGE_NAME); 
		if( !strOrgPackageFile.IsFile() )
		{
			strOrgPackageFile.Format("%s%s", GetAppPath(TRUE), OCML_ORG_PACKAGE_NAME);
			if( !strOrgPackageFile.IsFile() )
				bFoundPackage = false;
		}
		
		if( bFoundPackage )
		{
			/// Mathematica requires filenames with spaces to be enclosed in quotes.
			char szTemp[MAX_PATH];
			backslash_to_slash(szTemp, strOrgPackageFile);
		
			sprintf(lpszPackageName, "<<\"%s\";", szTemp);
		}
		
		return bFoundPackage;
	}
};     


#endif //_OMLINK_OBJ_H