/*------------------------------------------------------------------------------*
 * File Name: MatlabImportDlg.h												*
 * Creation: 																	*
 * Purpose: OriginC Source C file												*
 * Copyright (c) ABCD Corp.	2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010		*
 * All Rights Reserved															*
 * 																				*
 * Modification Log:															*
 *		Soapy 11/12/03 7.0749 	DELETE_HIDDEN_MATRIX_WHEN_IMPORT_FAIL			*
 *		Soapy 11/20/03 7.0753   DELETE_TEMPORARY_MATRIX							*
 *------------------------------------------------------------------------------*/

#ifndef _MATLAB_IMPORTDLG_H
#define _MATLAB_IMPORTDLG_H

#include <externApps.h> 	// matlab class
#include "MatImportDlgBase.h"

#define STR_NO_MATLAB "Matlab not available"
#define STR_TEMP_WORKSPACE_NAME	"_TMP_Origin_Import_Save_.mat"
#define STR_TEMP_ARRAY_NAME	"TMP_Var__For_Type_Transfer"

#define MATLAB_OUTPUT_NUMTOKENS		4
#define MATLAB_OUTPUT_SKIP_LINES	2

enum {
	MATLAB_VAR_DOUBLE_ARRAY,
	MATLAB_VAR_COMPLEX_ARRAY,
	MATLAB_VAR_CHAR_ARRAY,
	MATLAB_VAR_INTEGER_ARRAY,
	MATLAB_VAR_SINGLE_ARRAY,
	MATLAB_VAR_UNKNOWN
};

#define MATLAB_OUTPUT_NAME_COL	0
#define MATLAB_OUTPUT_TYPE_COL	3


/*
	This class is for the import dialog of MATLAB variables from MAT file
*/
class MatlabImportDlg : public MatImportDlgBase
{
public:
	MatlabImportDlg() : MatImportDlgBase()
	{
		
	}

public:	
	int DoModalEx(HWND hWndParent = NULL, LPCSTR lpcszMatlabWkspaceName = NULL, BOOL bSingle = FALSE)
	{
		InitMsgMap();// will be called from internal later
		m_strMatlabWorkspaceFilename = lpcszMatlabWkspaceName;   // the MAT file name
		m_bSingle = bSingle;									///	DVT should be connected to m_bRestoreWorkspace
		int nRet = ResizeDialog::DoModal(hWndParent);
		
		return nRet;
	}

protected:
	
EVENTS_BEGIN
	ON_INIT(OnInitDialog) 
	ON_SIZE(OnDlgResize)
	ON_OK(OnClose)
	ON_TIMER(OnTimer)
	ON_DESTROY(OnDestroy)
	ON_BN_CLICKED(IDC_MATLAB_BTN_IMPORT, OnImportAsMatrices)
	ON_BN_CLICKED(IDC_MATLAB_BTN_IMPORT_WKS, OnImportAsSingleWks)
	ON_BN_CLICKED(IDC_MATLAB_CHK_REPLACE_MAT, OnClickReplaceMat)
	ON_BN_CLICKED(IDC_MATLAB_CHK_REPLACE_WKS, OnClickReplaceCol)
	ON_GRID_SEL_CHANGE(IDC_MATLAB_GRID, OnVsFlexSelChange)
	ON_BN_CLICKED(IDC_MATLAB_BTN_IMPORT_UPDATE, OnUpdateWorkSpace)
EVENTS_END

	//ON_BN_CLICKED(IDC_MATLAB_KEEP_RUNNING, OnCheckKeepRunning)

protected:

	///DVT - IDOK in error is in dialog resource instead of IDCANCEL - change
	BOOL OnClose()
	{
		return TRUE;
	}
	
	
	void OnVsFlexSelChange(Control ctrl)
	{
		if ( m_bDisableImportBtnUpdate )
			return;
		
		BOOL bHasSelection = 0 < m_vsFlex.SelectedRows();
			
		//DVT:	should actualy disable/enable based on importability.
		//this is not complete version, should actualy de-select MATLAB_VAR_UNKNOWN rows
		BOOL bHasWksSelection = FALSE;
		BOOL bHasMatSelection = FALSE;
		
		if( bHasSelection )
		{
			int nRowsSelected = m_vsFlex.SelectedRows();
		    for( int ii=0; ii < nRowsSelected; ii++ )
		    {
				long nR = m_vsFlex.SelectedRow(ii);
				int nVarType = GetMatlabVarType(nR);
	
				if ((nVarType == MATLAB_VAR_DOUBLE_ARRAY )||
					(nVarType == MATLAB_VAR_INTEGER_ARRAY)||
					(nVarType == MATLAB_VAR_SINGLE_ARRAY) ||
					(nVarType == MATLAB_VAR_CHAR_ARRAY))
				{
					bHasWksSelection = TRUE;
					bHasMatSelection = TRUE;
					break;
				}
				if (nVarType == MATLAB_VAR_COMPLEX_ARRAY )
				{
					bHasMatSelection = TRUE;
				}
		    }
		}
			
		EnableImportWksBtn(bHasWksSelection);	
		EnableImportMatBtn(bHasMatSelection);	
	}
	
	
	// Initialize the MatlabImport Dialog
	BOOL OnInitDialog()
	{
		DEBUG_RETURN
		
		MatImportDlgBase::OnInitDialog();
		
		GetWindow().Text = "Connecting to Matlab...";
		
		m_bRestoreWorkspace = false;
		if(!m_strMatlabWorkspaceFilename.IsEmpty()) // file is specified
		{
			if(m_mlObj && !m_bSingle)
			{
				// save workspce and when finish, restore wkspace
				if(SaveCurrentWorkspace())
					m_bRestoreWorkspace = true;
			}
		}
		
		m_nTimerID = SetTimer(5432,300);
		
		// The Update Button
		m_btnUpdate = GetItem(IDC_MATLAB_BTN_IMPORT_UPDATE);

		//Keep Matlab alive check box
		/*
		m_chkKeepRunning = GetItem(IDC_MATLAB_KEEP_RUNNING);
		// CPY make invisible until we have better support
		m_chkKeepRunning.Visible = false;//!m_bSingle;
		
		m_bKeepMatlabAlive = m_mlObj ? m_mlObj.KeepMatlabRunning: FALSE;
		m_chkKeepRunning.Check = m_bKeepMatlabAlive;
		*/
		
		return TRUE;
	}
	
	
	BOOL OnTimer(UINT nTimerID)
	{
		ASSERT(nTimerID==m_nTimerID);
		
		KillTimer(m_nTimerID);
		m_nTimerID = 0;     
	
		//not good loose connection with static in Console!!! if(m_mlObj.Attach( FALSE, m_bSingle ))
		if(m_mlObj.Attach( TRUE, m_bSingle ))
		{
			//if ( m_bSingle )
			//	m_mlObj.Visible = FALSE;
			//not good, it hides all Matlab sessions!
			
			GetWindow().Text = "Matlab Import";
			if( !m_strMatlabWorkspaceFilename.IsEmpty() )
				LoadWorkspace(m_strMatlabWorkspaceFilename);
	
			FillTheGridWithData();
				
			m_vsFlex.ShowTheGrid( );
			m_bDisableImportBtnUpdate = false;
		}
		else
			GetWindow().Text = STR_NO_MATLAB;
		
		return TRUE;
	}
	
	
	BOOL OnDestroy(void)
	{
		DEBUG_RETURN
		
		if(!m_strMatlabWorkspaceFilename.IsEmpty()) // file is specified
		{
			ASSERT(m_mlObj);
			
			if(m_bRestoreWorkspace)
				RestoreWorkspace();
			else
				m_mlObj.Detach();
		}
		
		return TRUE;
	}
	
		
	bool SaveCurrentWorkspace(bool bCleanup = true)
	{
		if(!m_mlObj)
		{
			return false;
		}
		string strExecute;
		
		strExecute.Format("save('%s','*');"
						  "clear all;", STR_TEMP_WORKSPACE_NAME );
		string strRet = m_mlObj.Execute(strExecute);
		
		return strRet.IsEmpty();	//success
	}
	
	
	bool RestoreWorkspace()
	{
		if(!m_mlObj)
		{
			return false;
		}
		string strExecute;
		
		strExecute.Format(	"clear all;"
							"load('%s', '*');"
							"delete('%s');", STR_TEMP_WORKSPACE_NAME, STR_TEMP_WORKSPACE_NAME );
		string strRet = m_mlObj.Execute(strExecute);
		return strRet.IsEmpty();	//success
	}
	
	
	bool LoadWorkspace(LPCSTR lpcstrMatFileName)
	{
		string strExecute;
		strExecute.Format(
						"load('%s', '*');",
						lpcstrMatFileName );
		string strRet = m_mlObj.Execute(strExecute);
		return strRet.IsEmpty();	//success	
	}
	
	
	////////////////////////////////////////////////////////////////
	//this three functions are the CPY code from MatlabConsole.c
	BOOL	GetMatlabRealMatrices( StringArray &asNames, string& strResult )
	{
		//bool	bReplaceCurrent = m_bUpdateMatrix;
		
		for(int ii = 0; ii < asNames.GetSize(); ii++)
		{
			bool bNew = false;
			MatrixLayer mlay(asNames[ii]);
			
			if(!mlay || (!m_bUpdateMatrix && mlay))
			{
				if(mlay) // already existed
					mlay.Detach();
					
				mlay.Create();
				mlay.GetPage().Rename(asNames[ii]);
				bNew = true;
			}
			Matrix<double> mm(mlay);
			if(!m_mlObj.GetMatrix(asNames[ii], &mm) && bNew)
			{
				mlay.Destroy();
				strResult += asNames[ii] + " ";
			}
		}
		if(!strResult.IsEmpty())
		{
			strResult += ": matrices not found in Matlab!";
			return FALSE;
		}
		return TRUE;
	}
	//--------- Soapy 8/12/03 TEMP_SOLUTION_OTHER_DATA_TYPE_SUPPORT_BY_DOUBLE_COPYING
	//use Matlab command double() to cast integer array (int8, int16, int32, uint8, uint16, uint32) and single array to 
	//double before getting their value to Origin. This is to make things to work temporarily for Matlab Import Dialog until
	//related functions are added to Matlab Class.
	BOOL	GetMatlabOtherNumMatrices( StringArray &asNames, string& strResult )
	{
		string strExecute;
		StringArray asNamesTemp;
		
		int nSize = asNames.GetSize();
		
		asNamesTemp.SetSize( nSize );
	
		for(int ii=0; ii<nSize; ii++)
		{
			 asNamesTemp[ii] = STR_TEMP_ARRAY_NAME + ii;
			
			strExecute.Format("%s=%s;"
						  	"%s=double(%s);",
				asNamesTemp[ii], asNames[ii], asNames[ii], asNamesTemp[ii]);
				
			m_mlObj.Execute(strExecute);
		}
				
		BOOL bRet = GetMatlabRealMatrices( asNames, strResult );
		
		for( ii=0; ii<nSize; ii++)
		{
			strExecute.Format("%s=%s;"
							  "clear %s",asNames[ii], asNamesTemp[ii],asNamesTemp[ii]);
			m_mlObj.Execute(strExecute);
		}

		return bRet;		
	}
	int AddMatlabNumArray(Worksheet& wks, string strMatLabVarName, bool bReplaceCurrent)
	{
		string strExecute;

		strExecute.Format("%s=%s;"
						  "%s=double(%s);",
				STR_TEMP_ARRAY_NAME,strMatLabVarName,strMatLabVarName,STR_TEMP_ARRAY_NAME );
		string strRet = m_mlObj.Execute(strExecute);
		if(!strRet.IsEmpty())
			return 0;	
			
		int nRet = AddMatlabDoubleArray(wks, strMatLabVarName, bReplaceCurrent);
		strExecute.Format("%s=%s;"
		                  "clear %s;",strMatLabVarName,STR_TEMP_ARRAY_NAME,STR_TEMP_ARRAY_NAME);
		strRet = m_mlObj.Execute(strExecute);

		return nRet;		
	}
	//------- end Soapy 8/12/03

	
	BOOL	GetMatlabComplexMatrices( StringArray &asNames, string& strResult )
	{
		for(int ii = 0; ii < asNames.GetSize(); ii++)
		{
			MatrixLayer mlay_r, mlay_i;
			bool bNewR= get_Origin_matrix(asNames[ii]+"r", mlay_r);
			bool bNewI= get_Origin_matrix(asNames[ii]+"i", mlay_i);
			
			Matrix<double> mr(mlay_r), mi(mlay_i);
			if(!m_mlObj.GetMatrix(asNames[ii], &mr, &mi))
			{
				if(bNewR)
					mlay_r.Destroy();
				if(bNewI)
					mlay_i.Destroy();
				
				strResult += asNames[ii] + " ";
			}
		}
		if(!strResult.IsEmpty())
			strResult += ": matrices not found in Matlab!";
		return TRUE;
	}
	//end this three functions are the CPY code from MatlabConsole.c
	////////////////////////////////////////////////////////////////
	
	
	int	FillTheGridWithData()
	{
		int iRet = 0;
		string	strRet = m_mlObj.Execute("whos;");
	
		_DBSTR( strRet )
	
		if( -1 == strRet.Find("???") )
		{
			//use strRet's whos output to get the list of variables:
			//  Name                           Size         Bytes  Class
			//
			//  b                              1x1             16  double array (complex)		
			//  t                              1x1            478  struct array
			//  very_very_very_long_name       1x5             10  char array
			//  w                              2x3            600  cell array
			//  x                              2x3             48  double array
			//  y                              2x3             48  double array
			//  z                              1x5             10  char array
			//
			//Grand total is 54 elements using 1194 bytes
	
			//Object vsFlx = VSFLEX_GRID;
			//Object vsFlx = m_vsFlex;
			
			m_vsFlex.SetupTheGrid();	//delete all but headers
	
			if ( strRet.IsEmpty() )
				return iRet;
		
			StringArray strLines;
			int lll = strRet.GetTokens( strLines, '\n' );
			//for(int ln = 0; ln < strLines.GetSize(); ln++)
			//the very first line is the header, the second is white
			//the last two lines are white and summary respectively
			//can be ASSERT-ed here
			for ( int ln = MATLAB_OUTPUT_SKIP_LINES; ln < strLines.GetSize() - MATLAB_OUTPUT_SKIP_LINES; ln++ )
			{
				string strLine = strLines[ln];
			
				StringArray strTokens;
				int nInLine = strLine.GetTokens( strTokens );
	
				if ( MATLAB_OUTPUT_NUMTOKENS > nInLine )	//4 categories: Name,Size,Bytes,Class
					continue;
	
				string strRow = strTokens[0] + "\t" +
								strTokens[1] + "\t" +
								strTokens[2] + "\t" +
								strTokens[3];
				
				if ( MATLAB_OUTPUT_NUMTOKENS + 1 == nInLine )
				{
					//handle the last token that can contain more words better here  "double array (complex)"
					strRow += " " + strTokens[4];
				}
	
				if ( MATLAB_OUTPUT_NUMTOKENS + 2 == nInLine )
				{
					//handle the last token that can contain more words better here  "double array (complex)"
					strRow += " " + strTokens[5];
				}
	
				if ( MATLAB_OUTPUT_NUMTOKENS + 2 < nInLine )
				{
					_DBSTR("DVT Matlab whos: more than 3 tokens in Class")
					continue;
				}
	
				m_vsFlex.AddItem( strRow );
			}
		
		    // expand outline, resize to fit, collapse outline
		    m_vsFlex.ReDraw();
		    
		}
		else
		{
			iRet = -2;
			//try to clean anyways
		}
			
		return iRet;
	}
	
	
	int GetMatlabVarType(long nR)
	{
		string strType = m_vsFlex.GetCell( nR, MATLAB_OUTPUT_TYPE_COL );
		
		if(strType.CompareNoCase("double array") == 0)
			return MATLAB_VAR_DOUBLE_ARRAY;
		else if(strType.CompareNoCase("double complex") == 0)
			return MATLAB_VAR_COMPLEX_ARRAY;
		else if(strType.Find("int") != -1)
			return MATLAB_VAR_INTEGER_ARRAY;
		else if(strType.Find("char") != -1)
			return MATLAB_VAR_CHAR_ARRAY;
		else if(strType.CompareNoCase("single array") == 0)
			return MATLAB_VAR_SINGLE_ARRAY;

		return MATLAB_VAR_UNKNOWN;
	}
	
	
	BOOL OnImportAsMatrices(Control ctrl)
	{
		StringArray	asNames;
		StringArray	asNamesC;
		StringArray asNamesSI;
		int nRowsSelected = m_vsFlex.SelectedRows();
				
	    for( int ii=0; ii < nRowsSelected; ii++ )
	    {
	    	string strOut(m_vsFlex.SelectedRow(ii));
			_DBSTR( strOut )
			long nR = m_vsFlex.SelectedRow(ii);
			int nVarType = GetMatlabVarType(nR);
			if(nVarType == MATLAB_VAR_DOUBLE_ARRAY)
				asNames.Add( m_vsFlex.GetCell( nR, MATLAB_OUTPUT_NAME_COL ) );
			else if(nVarType == MATLAB_VAR_COMPLEX_ARRAY)
				asNamesC.Add( m_vsFlex.GetCell( nR, MATLAB_OUTPUT_NAME_COL ) );
			else if((nVarType == MATLAB_VAR_INTEGER_ARRAY)||
				(nVarType == MATLAB_VAR_SINGLE_ARRAY)||
				(nVarType == MATLAB_VAR_CHAR_ARRAY))
				asNamesSI.Add( m_vsFlex.GetCell( nR, MATLAB_OUTPUT_NAME_COL ) );
			
			
	    }    
	    
		string		strResult;
		
		GetMatlabRealMatrices( asNames, strResult );
		
		GetMatlabComplexMatrices( asNamesC, strResult );
		
		GetMatlabOtherNumMatrices( asNamesSI, strResult );
	
		return TRUE;	//for now
	}
	
	
	
	// return number of cols added
	int AddMatlabDoubleArray(Worksheet& wks, string strMatLabVarName, bool bReplaceCurrent)
	{
		MatrixLayer mlTemp;
		if(!mlTemp.Create(NULL, CREATE_HIDDEN))
			return 0;
		
		Matrix<double> mm(mlTemp);
		///Soapy 11/20/03 7.0753   DELETE_TEMPORARY_MATRIX
		/*
		if(!m_mlObj.GetMatrix(strMatLabVarName, &mm))
		{			
			mlTemp.Destroy();  ///Soapy 11/12/03 7.0749 	DELETE_HIDDEN_MATRIX_WHEN_IMPORT_FAIL
			return 0;
		}
		*/
		int nRet=0;
		if(m_mlObj.GetMatrix(strMatLabVarName, &mm))
		{	
			nRet = MatToWks(mm, wks, strMatLabVarName);
		}
		
		mlTemp.Destroy();  
		return nRet;
	}	
	
	// return number of cols added
	int AddMatlabComplexArray(Worksheet& wks, string strMatLabVarName)
	{
		//MatrixLayer mlTemp;
		//if(!mlTemp.Create(NULL, CREATE_HIDDEN))
		//	return 0;
		// more codes goes here
		printf("%s: complex matrix not supported\n");
		return 0;
	}
	
			
	BOOL OnImportAsSingleWks(Control ctrl)
	{
		int nRowsSelected = m_vsFlex.SelectedRows();
		
		bool	bWksCreated = false;
		
		Worksheet wksTemp;
		if(m_bUpdateCols)
			wksTemp.Attach(MATLAB_WKS_NAME);
		
		if(!wksTemp.IsValid())
		{
			//CPY 1/29/03 SHOW_WKS_WHEN_IMPORT
			//if(!wksTemp.Create(NULL, CREATE_HIDDEN))
			if(!wksTemp.Create())
			{
				_DBSTR("Creating worksheet failed")
				return FALSE;
			}
			bWksCreated = true;
		}
		if(bWksCreated)
		{
			while(wksTemp.DeleteCol(0))	 // Remove all columns in worksheet
				;
		}
		
		int nNameCount = 0;
		
		for( int ii = 0; ii < nRowsSelected; ii++ )
		{
			long nR = m_vsFlex.SelectedRow(ii);
			int nVarType = GetMatlabVarType(nR);
			string strVarName = m_vsFlex.GetCell( nR, MATLAB_OUTPUT_NAME_COL );
			
			if(nVarType == MATLAB_VAR_DOUBLE_ARRAY)				
				nNameCount += AddMatlabDoubleArray(wksTemp, strVarName, m_bUpdateCols);
			else if(nVarType == MATLAB_VAR_COMPLEX_ARRAY)
				nNameCount += AddMatlabComplexArray(wksTemp, strVarName);
			else if((nVarType == MATLAB_VAR_SINGLE_ARRAY)||
				(nVarType == MATLAB_VAR_INTEGER_ARRAY) || 
				(nVarType == MATLAB_VAR_CHAR_ARRAY))
				nNameCount += AddMatlabNumArray(wksTemp, strVarName, m_bUpdateCols);
			else
			{
				printf("%d: %s -- Data type not supported\n", strVarName);
			}
		}
		//---- CPY 1/29/03 SHOW_WKS_WHEN_IMPORT
		/*
		if(nNameCount > 0 && bWksCreated)
		{
			wksTemp.GetPage().Rename(MATLAB_WKS_NAME);
			wksTemp.GetPage().SetShow();
			return TRUE;
		}
		*/
		if(bWksCreated)
		{
			if(0==nNameCount)
				wksTemp.Destroy();
			else
				wksTemp.GetPage().Rename(MATLAB_WKS_NAME);
		}
		//----			
			
		return nNameCount > 0? TRUE : FALSE;	
	}
	
	BOOL OnUpdateWorkSpace(Control ctrl)
	{
		if(m_mlObj)
		{
			FillTheGridWithData();
		}
		return TRUE;
	}
	

	/*
	BOOL OnCheckKeepRunning(Control ctrl)
	{
		if(m_mlObj)
		{
			m_bKeepMatlabAlive = !m_bKeepMatlabAlive;
			m_mlObj.KeepMatlabRunning = m_bKeepMatlabAlive;
		}
		return TRUE;
	}
	*/
	
	
	
private:
	
	int m_nTimerID;
	
	bool 	m_bRestoreWorkspace;
	
	Matlab m_mlObj;
	
	Button m_btnUpdate;
	//CP IDC_MATLAB_KEEP_RUNNING
	/*
	Button m_chkKeepRunning;
	BOOL	m_bKeepMatlabAlive;	
	*/
	
	bool	m_bSingle;
	
};

#endif //_MATLAB_IMPORTDLG_H
	