/*------------------------------------------------------------------------------*
 * File Name:LabViewImport.c													*
 * Creation: DVT 7/3/2003														*
 * Purpose: OriginC Source C file LabVIEW Import dialog							*
 * Copyright (c) Originlab Corp. 2003, 2004, 2005, 2006, 						*
 * All Rights Reserved															*
 * 																				*
 * Modification Log:															*
 *------------------------------------------------------------------------------*/
 
#include <origin.h>
#include <Dialog.h>
#include "ResizeDialog.h"
#include "GridControl.h"
#include "ODlg.h" // resource IDs, ODlg.dll also use this file for its res ids
#include "HelpID.h"


#include <variant.h>		//for GetLVExportedVIs()
#include <VariantTypes.h>	//for VT_...

//instead of #include "LV_VI.h"			///	DVT	1/27/03 QA70-3725 v7.0498 LABVIEW_IMPORT_DIALOG
#define	LV_TREE_NODE_ATTRIBUTE_LABEL	"Label"

#define LV_TREE_ROOT_NODE				"All_VIs"
#define LV_TREE_ROOT_NODE_LABEL			"All VIs"

#define DISPLAY_VARIANT_TRUE			"true"
#define DISPLAY_VARIANT_FALSE			"false"

#define LT_SHOW_WND						"win -a %H"
#define LV_WKS_NAME						"LabView"
#define LV_FMT_STR_ARRAY_VEC_LONG		"Array of %d vectors, %d long"
#define LV_STR_ARRAY					"Array"
#define LV_STR_VECTOR					"Vector"
#define LV_STR_NOT_HANDLED				"<Not handled>"

// debug macros, 
#define	LV_DEBUG_INT(_1_, _2_)			;//out_int(_1_, _2_)
#define	LV_DEBUG_STR(_arg_)				;//out_str(_arg_)
#define	LV_DEBUG_printf(_1_, _2_, _3_)	;//printf(_1_, _2_, _3_)
//end of #include "LV_VI.h"

#define		DBG_TREE_OUT(_tr, _lpcsMsg)		//tree_dump(_tr, _lpcsMsg, 4);

////////////////	TREE	LV	TREE	LV	TREE	////////////////
////////////////	TREE	LV	TREE	LV	TREE	////////////////
////////////////////////////////////////////////////////////////////////////////////
// Constants
#define LV_HEADER_START					"<VI syntaxVersion="
#define LV_HEADER_START_LENGTH			18
#define LV_CONTROL_START				"<CONTROL ID="
#define LV_CONTROL_START_LENGTH			12
#define LV_CONTROL_START_END			"\">"
#define LV_CONTROL_START_END_LENGTH		2
#define LV_CONTROL_TYPE					"type=\""
#define LV_CONTROL_TYPE_LENGTH			6
#define LV_CONTROL_NAME					" name=\""
#define LV_CONTROL_NAME_LENGTH			7
#define LV_CONTROL_END					"</CONTROL>"
#define LV_CONTROL_END_LENGTH			10


#define LV_CONTENT						"<CONTENT>"
#define LV_CONTENT_LENGTH				8
#define LV_CONTENT_END					"</CONTENT>"
#define LV_CONTENT_END_LENGTH			9


#define LV_STR_CONTROL_VAL_UNKNOWN		"<?>"
#define LV_STR_EOL						"\r"
#define LV_STR_TAB						"\t"
//static	string	s_strNodeName = "e";
#define	LV_STR_NODE_NAME				"e"
#define	LV_TREE_FMT_STR					"Tree"
#define	LV_LIST_FMT_STR					"Name|Type|ID|Value";

#define	LV_FILE_OPEN_STR_VI				"[LabView (*.vi)] *.vi"
#define	LV_COM_OBJ_NAME					"LabVIEW.Application"
// Macros
#define	RETURN_IF_NOT_FOUND(_n,_b)			if(-1==(_n))return _b
////////////////////////////////////////////////////////////////////////////////////

////////////////////////////////////////////////////////////////////////////////////
////////////////	end	TREE	LV	TREE	LV	TREE	////////////////
////////////////	end	TREE	LV	TREE	LV	TREE	////////////////

//////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////
class VIListControl : public GridListControl
{
	bool m_bImport;

public:
	bool FindAndGetCell( string &strName, string &strValue )
	{
		if ( strName.IsEmpty() )
			return false;
		
		int		nRow(0);
		if ( -1 != ( nRow = m_flx.FindRow(strName, m_flx.FixedRows, 0) ) )
		{
			strValue = m_flx.Cell( flexcpText, nRow, m_flx.Cols - 1 );
			return true;
		}
		
		return false;
	}
	
	void OnBeforeEditList(Control ctrl, int nRow, int nCol, BOOL* pCancel)
	{
		//for now, enable only the last column editing. 
		//Should actualy check if even that is editable (not <?>, array, claster and such)
		if ( nCol != m_flx.Cols -1 )
			*pCancel = true;
	}
	
	bool IsImportEnabled()
	{
		return m_bImport;
	}
	
	Clear()
	{
		m_flx.Rows = 1;	//delete all but headers
	}

	void OnSelChange(Control ctrl)
	{
		m_bImport = false;
	
		string	strVal;
		if ( GetSelectedCell( strVal, m_flx.Cols - 1 ) )
			m_bImport = -1 != strVal.Find( LV_STR_ARRAY ) ||
						-1 != strVal.Find( LV_STR_VECTOR );
			
			
		return;
	}
	
	bool Setup(uint nCols = 4)
	{	
		Clear();
		m_flx.FormatString = LV_LIST_FMT_STR
		m_flx.Cols = nCols;
		m_flx.ExtendLastCol = true;
		m_flx.FixedCols = 0;								//hide the Row heading
		m_flx.SelectionMode = flexSelectionByRow;			//Forces selections to span entire rows.
		m_flx.AllowUserResizing = flexResizeColumns;		//allow columns resizing
		m_flx.ExplorerBar = flexExSort;					//sort columns by clicking on their headings
		
		m_flx.AutoSizeMode = flexAutoSizeColWidth;		//Adjust column widths to accommodate the widest entry in each column
		
		// prevent it from entering edit mode by trapping the BeforeEdit event and setting the Cancel parameter to True
		m_flx.Editable = flexEDKbdMouse;//flexEDNone;						///	DVT	1/27/03 QA70-3725 v7.0498 LABVIEW_IMPORT_DIALOG
	    m_flx.AllowSelection = false;						//prevent users from extending the selection 
		return true;
	}

	bool Update( vector<int> &vIDs, vector<string> &vTypes, vector<string> &vNames, vector<string> &vValues )
	{
	    // suspend repainting to increase speed
	    //SetRedraw(FALSE);
	    
		Clear();	//delete all but headers
	
		// populate the control: Name|Type|ID|Value
		
		
		//from vsFlexGrid8.0 FAQ:
		//The fastest way to add data is using the TextMatrix property, and the slowest is using the AddItem method.
		//If the data is already loaded in an array of Variants, then the BindToArray method is even faster. 
		//(BindToArray does not actually load the data, it just tells the control where the data is).
		
		for ( int i = 0; i < vIDs.GetSize(); i++ )
		{
			string strTMP(vIDs[i]);
			string strRow = vNames[i] + LV_STR_TAB +
							vTypes[i] + LV_STR_TAB +
							strTMP + LV_STR_TAB +
							vValues[i];
			
			m_flx.AddItem( strRow );
		}
		
	    // expand outline, resize to fit, collapse outline
	    m_flx.Outline(-1);
	    m_flx.AutoSize(0, 3);
	    m_flx.Outline(1);
		    
	    // repainting is back on
	    //SetRedraw(TRUE);
			
		return true;
	}

	//////////////////////////////////////////////////////////////////////////////////////
	//DVT new for dlgclass: 
	bool GetSelectedCell( string &asName, int nCol = 0 )
	{
		int nR = m_flx.RowSel;
		if ( nR < 0 )
			return false;
		asName = m_flx.Cell( flexcpText, nR, nCol );
		return true;
	}

};

class VITreeControl : public GridControl
{
	//////////////////////////////////////////////////////////////////////////////////////
	bool AddTreeNodes(TreeNode& tNode, int lvl)
	{
		if(tNode == NULL)
			return false;
	
		int			nRow;
		bool		bIsBranch = true;
	
		int			nCnt = tNode.GetNodeCount();
		
		string		strLabel;
		
		///	DVT	1/27/03 QA70-3725 v7.0498 LABVIEW_IMPORT_DIALOG
		if(!tNode.GetAttribute(LV_TREE_NODE_ATTRIBUTE_LABEL, strLabel))
			strLabel = tNode.tagName;
		///	end LABVIEW_IMPORT_DIALOG
		
		LV_DEBUG_INT(strLabel, lvl)
		
		// this function should save some object in the cell and return the object for future
		AddRow(nRow, strLabel, bIsBranch);
		
	
		m_flx.RowOutlineLevel(nRow) = lvl;
	
		// dump child nodes
		TreeNode	cNode = tNode.FirstNode;
		if(cNode == NULL)
			return true;
		
		while(cNode)
		{
			if(!AddTreeNodes(cNode, lvl + 1))
				break;
			cNode = cNode.NextNode;
		}
		return true;
	}
	
	DWORD AddRow(long& nRow, string strItem, bool bIsBranch) // = false
	{
		//strItem += "\t";	  // make 2nd col empty text, will set its value later
	
		m_flx.AddItem(strItem);
		
		nRow = m_flx.Rows - 1L;
	
		m_flx.IsSubtotal(nRow) = bIsBranch;
		
		return 0;
	}
	
	bool AddTreeNodes( Tree& tNode, int lvl )
	{
		if(tNode == NULL)
			return false;
	
		int			nRow(0);
		bool		bIsBranch(true);
	
		int			nCnt( tNode.GetNodeCount() );
		
		string		strLabel;
		
		///	DVT	1/27/03 QA70-3725 v7.0498 LABVIEW_IMPORT_DIALOG
		if(!tNode.GetAttribute(LV_TREE_NODE_ATTRIBUTE_LABEL, strLabel))
			strLabel = tNode.tagName;
		///	end LABVIEW_IMPORT_DIALOG
		
		LV_DEBUG_INT(strLabel, lvl)
		
		// this function should save some object in the cell and return the object for future
		AddRow(nRow, strLabel, bIsBranch);
		
	
		m_flx.RowOutlineLevel(nRow) = lvl;
	
		// dump child nodes
		TreeNode	cNode = tNode.FirstNode;
		if(cNode == NULL)
			return true;
		
		while(cNode)
		{
			if(!AddTreeNodes(cNode, lvl + 1))
				break;
			cNode = cNode.NextNode;
		}
		return true;
	}
	
	
	Clear()
	{
		m_flx.Rows = 1;	//delete all but headers
	}

public:
	int GetSelectedRow()
	{
		int			nRowsSelected = m_flx.SelectedRows;
		if ( 0 >= nRowsSelected )
			return -1;
		ASSERT ( 1 == nRowsSelected );
		
		return m_flx.SelectedRow(0);
	}

	void OnSelChange(Control ctrl)
	{
		return;
	}
	
	bool Setup( uint nCols = 1)
	{	
		Clear();
		m_flx.Cols = nCols;
		m_flx.FixedCols = 0;
		m_flx.ExtendLastCol = true;//false;//true;
		m_flx.FormatString = LV_TREE_FMT_STR;
		
		m_flx.ColAlignment(-1) = flexAlignLeftTop;
		m_flx.SelectionMode = flexSelectionListBox;		//select non-continuous rows
	        
		// outline
		m_flx.OutlineCol = 0;
		m_flx.OutlineBar = flexOutlineBarSimpleLeaf;
	    m_flx.MergeCells = flexMergeSpill;				// allow categories to spill into property column
	
	    m_flx.AllowSelection = false;						//prevent users from extending the selection 
		// other
		m_flx.AllowUserResizing = flexResizeColumns;
	
		return true;
	}
	
	bool Load(Tree& tr)
	{	
		
		m_flx.Redraw = flexRDNone;
		int			nRowHeight = m_flx.RowHeight(0);
		
		
		///	DVT	1/27/03 QA70-3725 v7.0498 LABVIEW_IMPORT_DIALOG
		TreeNode	tNode = tr.FirstNode;
		if(tNode == NULL)	//skip OriginStorage node
			return false;
		AddTreeNodes(tNode, 0);
		///	end LABVIEW_IMPORT_DIALOG
		
		//flx.AutoSize(0L, 1L, 0L, 200L);
		m_flx.Redraw = flexRDBuffered;
		return true;
	}
	
public:
	//////////////////////////////////////////////////////////////////////////////////////
	//DVT new for dlgclass:
	bool GetSelectedCell( string &strVISel )
	{
		int			nRowsSelected = m_flx.SelectedRows;
		if ( 0 >= nRowsSelected )
			return false;
		ASSERT ( 1 == nRowsSelected );
		
		long		nR = m_flx.SelectedRow(0);
		strVISel = m_flx.Cell( flexcpText, nR, 0 );
		return true;
	}
};
//////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////

////////////////	TREE	LV	TREE	LV	TREE	////////////////
////////////////	TREE	LV	TREE	LV	TREE	////////////////
class LabVIEW
{
	
//private:
	Tree		m_trVI;		// tree from caller
	Object		m_lvapp;	// LabVIEW reference
	bool		m_bNoLabViewTest;	//true - LabVIEW connected
	
public:
	
	// Default Constructor
	LabVIEW()
	{
		m_bNoLabViewTest = false;
		m_lvapp = NULL;
	}
	
	// Copy Constructor
	//LabVIEW( LabVIEW const &lv )
	//{
	//	m_bNoLabViewTest = lv.m_bNoLabViewTest;
	//	m_lvapp = lv.m_lvapp;
	//	m_trVI = lv.m_trVI;
	//}
	
	bool LVDisconnect()
	{
		//leak???
		m_bNoLabViewTest = false;
		return true;
	}
	//discover all VI's in memory (the name comes from LabView property ExportedVIs)
	bool	GetLVExportedVIs( vector<string> &vsALLVIs )
	{
		if(!CheckLabView())
			return false;
		
		_VARIANT	varVIs;
		//varVIs = s_lvapp.AllVIsInMemory;	//Access denied :) reconfigure LV server???
		try
		{
			varVIs = m_lvapp.ExportedVIs;
		}
		catch(int nErr)
		{
		}
	
		if( 0 >= varVIs.GetSize() )
		{
			LV_DEBUG_STR("No ExportedVIs\n");
			return false;
		}
		
		vsALLVIs = varVIs;
		
		return true;
	}

	/////////////////////////////////////////
	//exported for OnRunVI
	bool	GetVIObjectByName( const string &strVI, Object &viOne )
	{
		if ( !CheckLabView() )
			return false;
	
		//it won't be able to query sub-vi if main vi is closed, 
		//consequently, following line will fail GetVIReference
		try
		{
			viOne = m_lvapp.GetVIReference( strVI );
		}
		catch(int nErr)
		{
		}
		
		if ( !viOne )
		{
			LV_DEBUG_STR( strVI + "CANNOT get reference!" );
			return false;
		}
		
		return true;
	}
	/////////////////////////////////////////
	

	bool CheckLabView( bool bTry = true )
	{
		if( !bTry )
		{
			return m_bNoLabViewTest;
		}
		
		if( !m_bNoLabViewTest )
		{
			try
			{
				m_lvapp = CreateObject( LV_COM_OBJ_NAME );
			}
			catch(int nErr)
			{
			}
			if( m_lvapp == NULL )
			{
				LV_DEBUG_STR("Fail to instantiate Labview Application\n");
				return false;
			}
			m_bNoLabViewTest = true;
		}
		return true;
	}
	
	bool IsTopmostVI(string &strVI)
	{
		TreeNode	tNode( m_trVI.FirstNode );		//All_VIs
		int			nCnt(0);
		string		strVal( tNode.tagName );
		
		if ( (0 == (nCnt = tNode.GetNodeCount()) )  || (0 != strVal.Compare(LV_TREE_ROOT_NODE) ) )
			return false;
		
		tNode = tNode.FirstNode;
		while ( tNode )
		{
			tNode.GetAttribute(LV_TREE_NODE_ATTRIBUTE_LABEL, strVal);
			if ( 0 == strVI.Compare( strVal ))
				break;
			tNode = tNode.NextNode;
		}
	
		return tNode ? true : false;
		
	}
	
	bool	ExportVIControls( string &strVI, string &strExportPathName )
	{
		Object viOne;
		if ( !GetVIObjectByName( strVI, viOne ) )
			return false;
	
		//create LabView's tagged file containing list of controls for given VI
		if( !GetTempFileName( strExportPathName ) )
			return false;
	
		try
		{
			viOne.ExportVIStrings( strExportPathName );
		}
		catch(int nErr)
		{
			return false;
		}
		
		if( strExportPathName.IsFile() )
			return true;
		
		return false;
	}
	
	/////////////////////////////////////////////////////////////

////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////
	// set strName, strType, and nID starting search in strSource begining from nStart. Set nStart at the end to prepare for next search.
	///DVT later handle <CONTENT>...</CONTENT> inside control which is inaccesible by lv.GetControlValue()
	/*
		<CONTROL ID=83 type="Cluster" name="Parameters">
			...
			<CONTENT>
				<CONTROL ID=80 type="Numeric" name="Offset (volts)">
					...
				</CONTROL>
				<CONTROL ID=80 type="Numeric" name="Number of Bursts">
					...
				</CONTROL>
				...
			</CONTENT>
		<CONTROL ID=91 type="Path" name="file path (dialog if empty)">
			...
			<PARTS>
				<PART ID=8019 order=0 type="Browse Button">
					<CONTROL ID=79 type="Boolean" >
					...
					</CONTROL>
				</PART>
			</PARTS>
		</CONTROL>
	*/	

	//parser for LabViuew's ExportVIStrings generated tagged files that look like some sort of SGML
	bool AddOneControl(const string &strRead, int &nStart, vector<int> &vIDs, vector<string> &vTypes, vector<string> &vNames )
	{
	
		///DVT later handle <CONTENT>...</CONTENT> inside control which is inaccesible by lv.GetControlValue()
		//handle only top level <CONTROL... patern
		/////////////////////////////////////////////////////////////
		//<CONTROL ID=..."> sequence <CONTROL ID=94 type="Waveform Chart" name="trend1">
		nStart = strRead.Find( LV_CONTROL_START, nStart );
		RETURN_IF_NOT_FOUND(nStart, false);
		
		nStart += LV_CONTROL_START_LENGTH;
		
		int nEnd = strRead.Find( LV_CONTROL_START_END, nStart );
		RETURN_IF_NOT_FOUND(nEnd, false);
		
		//save position for return
		int nStartReturn = nEnd + LV_CONTROL_START_END_LENGTH;
		
		string strName = strRead.Mid( nStart, nEnd - nStart  );
		LV_DEBUG_STR("whole CONTROL:\t" + strName);
		
		//ID
		int nID;
		sscanf( strName, "%d", &nID );
		//nID = atol(strName);	//mess
		LV_DEBUG_INT("ID=",nID);
		
		//type
		nStart = strName.Find( LV_CONTROL_TYPE );
		RETURN_IF_NOT_FOUND(nStart, false);
		
		nStart += LV_CONTROL_TYPE_LENGTH;
		
		nEnd = strName.Find( LV_CONTROL_NAME, nStart );
		RETURN_IF_NOT_FOUND(nEnd, false);
		
		string strType = strName.Mid( nStart, nEnd - 1 - nStart );	//-1 is to remove closing " before | name=|
		LV_DEBUG_STR("type=" + strType);
		
		//name
		nStart = nEnd + LV_CONTROL_NAME_LENGTH;
		strName = strName.Mid( nStart );
		LV_DEBUG_STR("name=" + strName);
	
		if ( -1 == strName.Find( LV_STR_EOL ) )
		{
			vIDs.Add(nID);
			vTypes.Add(strType);
			vNames.Add(strName);
		}
		
		nStart = nStartReturn;
		LV_DEBUG_INT("END nStart\t\t",nStart);
		
		//find next starting position (next <CONTROL on the same top level)
		//DVT HANDLE_CONTENT
		int nCount(0);
		int nNextControl(-1);
		do
		{
			if ( nCount++ > 50 )	//if file is corrupted
				break;
			
			nNextControl = strRead.Find( LV_CONTROL_START, nStart );
			if ( -1 == nNextControl ) break;
			
	
			nEnd = strRead.Find( LV_CONTROL_END, nStart );
			if ( -1 == nEnd ) break;
			
			nStart = nEnd;
			
		} while (nNextControl <= nEnd );	//there is another <CONTROL... before

		return true;
		/*
		//just ignore for now
		int nNextControl = strRead.Find( LV_CONTROL_START, nStart );
		RETURN_IF_NOT_FOUND(nNextControl, true);		//no controls to the end of the file
	
		nEnd = strRead.Find( LV_CONTENT, nStart );
		RETURN_IF_NOT_FOUND(nEnd, true);				//no sub <CONTENT>
		
		if ( nNextControl > nEnd )
		{
			//there are sub controls, inside claster, array, or whatnot
			//go past the </CONTENT>, skip inside for now
			nEnd = strRead.Find( LV_CONTENT_END, nEnd );
			RETURN_IF_NOT_FOUND(nEnd, true);
		
			nStart = nEnd + LV_CONTENT_END_LENGTH;
			LV_DEBUG_INT("END nStart\t\t",nStart);
		}
		*/
		//end HANDLE_CONTENT	
	}
////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////

	//Helper for ExtractLabView controls
	bool ReadFileInString( LPCSTR lpcszPathName, string &strRead )
	{
		file fil;
		if( fil.Open(lpcszPathName, file::modeRead) )
		{
			// Get file size
			fil.SeekToEnd();
			LONG l = fil.GetPosition();
			fil.SeekToBegin();
			
			// Get buffer
			LPSTR lpstr = strRead.GetBuffer(l + 1);
			LPVOID lpVoid = lpstr;
			if( lpstr )
			{
				// Read whole file into buffer
				fil.Read(lpVoid, l);
				strRead.ReleaseBuffer();
			}
	
			fil.Close();
			return true;
		}
		return false;
	}
	// end Helper for ExtractLabView controls
		
	
	bool	ExtractLabViewControls(LPCSTR lpcszPathName, vector<int> &vIDs, vector<string> &vTypes, vector<string> &vNames, string &strVIName)
	{
		vIDs.SetSize(0);
		vTypes.SetSize(0);	//fixed
		vNames.SetSize(0);
	
		string	strRead;
		if ( !ReadFileInString( lpcszPathName, strRead ) )
			return false;
		
		int nStart = 0;
		
		//header, VI name sequence <VI syntaxVersion=6 LVversion=6108004 revision=20 name="Frequency Response.vi">
		nStart = strRead.Find( LV_HEADER_START );
		RETURN_IF_NOT_FOUND(nStart, false);
	
		nStart += LV_HEADER_START_LENGTH;
		
		int nEnd = strRead.Find( LV_CONTROL_START_END, nStart );
		RETURN_IF_NOT_FOUND(nEnd, false);
		
		nStart = strRead.Find( LV_CONTROL_NAME, nStart );
		
		nStart += LV_CONTROL_NAME_LENGTH;
		strVIName = strRead.Mid( nStart, nEnd - nStart  );
		
		LV_DEBUG_STR("VI name:----" + strVIName + "----");
		
		nStart = nEnd + LV_CONTROL_START_END_LENGTH;
		
		LV_DEBUG_INT("START nStart\t",nStart);
		
		while ( AddOneControl(strRead, nStart, vIDs, vTypes, vNames ) );
	
		LV_DEBUG_INT("vectorSize:", vIDs.GetSize());
		
		return true;
	}

	bool	GetOneControlValueAndType( const Object &viOne, const string &strControlName, string &strDisplay, USHORT &nVarType )
	{		
			//_VARIANT val = viOne.GetControlValue( strControlName );
			_VARIANT val;
			try
			{
				val = viOne.GetControlValue( strControlName );
			}
			catch(int nErr)
			{
				return false;
			}
			
			USHORT nvt = val.vt;
			nVarType = nvt;
			int	nLobyte = nvt & 0x00FF;
			
			//#
			LV_DEBUG_printf( "val.vt: %04x, lobyte %04x\n", nvt, nLobyte );
			
			strDisplay = LV_STR_NOT_HANDLED;
			if ( VT_ARRAY & nvt )
			{
				strDisplay = LV_STR_VECTOR;
				
				WORD	wSimpleType = nvt & VT_TYPEMASK;
				LV_DEBUG_printf( "%s: wSimpleType: %04x\n", strDisplay, wSimpleType );
				if ( VT_VARIANT == wSimpleType )
				{
					int nNumSubVariants = val.GetSize();
					int nNumDimensions = val.GetNumDimensions();
					if ( (1 <= nNumDimensions) && (1 <= nNumSubVariants) )
					{
						_VARIANT vVars;
						//vector<_VARIANT> vVars;
						//vVars.SetSize( nNumSubVariants );
						vector<int> vnSizes;
						vnSizes.SetSize( nNumSubVariants );
						for( int i = 0; i < nNumSubVariants; i++ )
						{
							
							//if ( !val.GetSubVariant(0, vVars[i]) )
							if ( !val.GetSubVariant(i, vVars) )
							{
								///	DVT 4/11/03 REMOVE_TREE_UTILS_FROM_LVDLG
								//out_str("Error geting sub-variant in array");
								LV_DEBUG_STR("Error geting sub-variant in array");
								///	end REMOVE_TREE_UTILS_FROM_LVDLG
								return false;
							}
							//if ( VT_ARRAY & vVars[i].vt )
							//	vnSizes[i] = vVars[i].GetSize();
							if ( VT_ARRAY & vVars.vt )
								vnSizes[i] = vVars.GetSize();
						}
						///	DVT 4/11/03 REMOVE_TREE_UTILS_FROM_LVDLG
						//strDisplay.Format( "Array of %d vectors, %d long", nNumSubVariants, vnSizes[0] );
						strDisplay.Format( LV_FMT_STR_ARRAY_VEC_LONG, nNumSubVariants, vnSizes[0] );
						//out_str(strDisplay);
						LV_DEBUG_STR(strDisplay);
						///	end REMOVE_TREE_UTILS_FROM_LVDLG
					}
				}
			}
			else
			{
				switch (nvt)
				{
				case VT_BOOL:
					short nVar = val;
					strDisplay = ( VARIANT_TRUE == nVar )? DISPLAY_VARIANT_TRUE: DISPLAY_VARIANT_FALSE;
					break;
				case VT_I2:
				case VT_I4:
				case VT_R4:
				case VT_R8:
				case VT_BSTR:
				case VT_I1:
				case VT_UI1:
				case VT_UI4:
				case VT_I8:
				case VT_UI8:
				case VT_INT:
				case VT_UINT:
					strDisplay = val;
					break;
				default:
					break;
				}
			}
			
			return true;
	}
	
	//fill values and variant types for controls
	bool	ReadVIControlsValues( const string &strVI,  const vector<int> &vIDs, const vector<string> &vTypes, const vector<string> &vNames, vector<string> &vValues, vector<USHORT> &vVarTypes )
	{
	
		vValues.SetSize(0);
		vVarTypes.SetSize(0);
		UINT		nTotalNumber = vNames.GetSize();
	
		Object viOne;
		//if ( !GetVIObjectByName( lvapp, strVI, viOne ) )
		if ( !GetVIObjectByName( strVI, viOne ) )
			return false;
		
		//Front panel VI is already open when no Callers are identified
		//maybe here also for sub-vi to be able to read controls??	
		// - not needed, crashes where due to inaccessible controls <CONTENT>...</CONTENT> or controls with odd names "...<CR>\n\r..." multilineers
		//that is handled (by ignoring such cases for now) in parser ( AddOneControl() )
		/*
		bool bAlreadyOpen = false;
		if ( !viOne.FPWinOpen )
			viOne.FPWinOpen = true;
		else
			bAlreadyOpen = true;
		*/
		//_VARIANT val;
	
		for (int i = 0; i < nTotalNumber; i++)
		{
	
			USHORT nVarType = VT_EMPTY;
		
			string strControlName = vNames[i];
			strControlName.TrimLeft();
			strControlName.TrimRight();
			if ( strControlName.IsEmpty() )
			{
				vValues.Add( LV_STR_CONTROL_VAL_UNKNOWN );
				vVarTypes.Add( nVarType );
				continue;
			}
	
			string		strDisplay;
			GetOneControlValueAndType( viOne, strControlName, strDisplay, nVarType );
			vValues.Add( strDisplay );
			vVarTypes.Add( nVarType );
		}
		/*
		//not needed
		if ( !bAlreadyOpen )			//do not change the state VI entered this function
			viOne.FPWinOpen = false;
		*/
		return true;
	}
	
	//exported function: given VI name strVI, fill vectors with vIDs, vTypes, and vNames of controls
	bool	GetVIControls( string &strVI,  vector<int> &vIDs, vector<string> &vTypes, vector<string> &vNames, vector<string> &vValues, vector<USHORT> &vVarTypes )
	{
		if( !CheckLabView() )
			return false;
		
		string strExportPathName;
		if ( !ExportVIControls( strVI, strExportPathName ) )
			return false;
		
		string strVIName;
		if ( !ExtractLabViewControls(strExportPathName, vIDs, vTypes, vNames, strVIName) )
			return false;
	
		if ( !ReadVIControlsValues( strVI, vIDs, vTypes, vNames, vValues, vVarTypes ) )
			return false;
		
		DeleteFile( strExportPathName );
	
	
		/*
		//have to strip possible path from strVI first!!!
		//e.g. G:\Program Files\National Instruments\LabVIEW 6.1\examples\comm\hiq\CookieFactoryReport.vi
		if ( strVI != strVIName )			//compare VI name with name from inside:<VI syntaxVersion=... name="Frequency Response.vi">
		{
			ASSERT(FALSE);					//not expected - file corrupted?
			return false;
		}
		
		*/
		
		return true;
	}

	const TreeNode	GetTree() { return m_trVI; }
	
	///VI hierarchy
	//generate the hierarchy tree for all VI's in list
	//this one used by Dlg class LabViewImport:
	bool BuildCallerTree( vector<string> &vsALLVIs )
	{
		//trLV = NULL;
		m_trVI.Reset();
		
		TreeNode trBranch0 = m_trVI.AddNode(LV_TREE_ROOT_NODE);
		trBranch0.SetAttribute(LV_TREE_NODE_ATTRIBUTE_LABEL, LV_TREE_ROOT_NODE_LABEL);
	
		UINT		nTotalNumber = vsALLVIs.GetSize();
		for (int jj = 0; jj < nTotalNumber; jj++)
		{
			vector<string> vsCallersVIs;
			FindVIsCollers( vsALLVIs[jj], vsCallersVIs );
			if( 0 >= vsCallersVIs.GetSize() )
			{
				LV_DEBUG_STR( vsALLVIs[jj] + "-No Callers\n");
				//add as root node
				TreeNode trBranch = trBranch0.AddNode( LV_STR_NODE_NAME );
				trBranch.SetAttribute(LV_TREE_NODE_ATTRIBUTE_LABEL, vsALLVIs[jj]);
	
				//Bad design bellow!
				Object viOne;
				if ( !GetVIObjectByName( vsALLVIs[jj], viOne ) )
					return false;
				//Open front panel (if read from file have to, to be able to query sub vi's and its controls)
				//opening sub-vi's doesn't seem to be necessary to read its controls
				try
				{
					if ( !viOne.FPWinOpen )
						viOne.FPWinOpen = true;
				}
				catch(int nErr)
				{
					return false;
				}
				//end Bad design bellow!
	
				FindAllVIsCollees( trBranch, vsALLVIs[jj] );
			}
		}	
		
		//m_trVI;
	
		return true;
	}
	
	bool	FindVIsCollers( string &strVI, vector<string> &vsCallersVIs  )
	{
		Object viOne;
		if ( !GetVIObjectByName( strVI, viOne ) )
			return false;
		
		///////////////////////////////////////////////////
		////Callers
		_VARIANT	varCallersVIs;
		try
		{
			varCallersVIs = viOne.Callers;
		}
		catch(int nErr)
		{
			return false;
		}
		if( 0 >= varCallersVIs.GetSize() )
		{
			LV_DEBUG_STR( strVI + "-No Callers\n");		//add as root node
		}
		vsCallersVIs = varCallersVIs;
		
		return true;
	}
	
	
	//recursive function to make tree out of callees
	bool	FindAllVIsCollees( TreeNode &trBranch, string &strVI )
	{
	
		vector<string>	vsCalleesVIs;
		
		if ( !FindVIsCollees( strVI, vsCalleesVIs ) )
			return false;
		
		UINT		nTotalNumber = vsCalleesVIs.GetSize();
		for (int jj = 0; jj < nTotalNumber; jj++)
		{
			//add as node
			/*
			string strTMP;
			strTMP = vsCalleesVIs[jj];
			strTMP.Replace(" ",'_');
			strTMP.Replace("()",'-');	//this is too much, should do something about names
			TreeNode trBranchR = trBranch.AddNode( strTMP );
			*/
			//TreeNode trBranchR = trBranch.AddNode( s_strNodeName );
			TreeNode trBranchR = trBranch.AddNode( LV_STR_NODE_NAME );
			trBranchR.SetAttribute(LV_TREE_NODE_ATTRIBUTE_LABEL, vsCalleesVIs[jj]);
			//recursive call
			FindAllVIsCollees( trBranchR, vsCalleesVIs[jj] );
		}
		
		return true;	
	}
	
	//helper for FindAllVIsCollees, find the first level of callees for given VI
	bool	FindVIsCollees( string &strVI, vector<string> &vsCalleesVIs )
	{
		Object viOne;
		if ( !GetVIObjectByName( strVI, viOne ) )
			return false;
	
		///////////////////////////////////////////////////
		////Callees
		_VARIANT	varCalleesVIs;
		try
		{
			varCalleesVIs = viOne.Callees;
		}
		catch(int nErr)
		{
			return false;
		}
		if( 0 >= varCalleesVIs.GetSize() )
		{
			LV_DEBUG_STR( strVI + "-No Callees\n");
			//final node
		}
		vsCalleesVIs = varCalleesVIs;
		///////////////////////////////////////////////////
		
		return true;
	}
	///end VI hierarchy
	
	//	file open dialog
	bool LabViewLLBFileImport( vector<string> &vsALLVIs  )
	{
		//string strFilename = GetOpenBox( "[LabView (*.llb)] *.llb" );		//don't know how to see inside the library
		string strFilename = GetOpenBox( LV_FILE_OPEN_STR_VI );
		if( strFilename.GetLength() > 0 && strFilename.IsFile() )
		{
			vsALLVIs.SetSize( 0 );
			vsALLVIs.Add( strFilename );
			return true;
		}
		return false;
	}
	
	bool Build( bool bFileOpenIfNoVIs = true )
	{
		vector<string> vsALLVIs;
		if ( !GetLVExportedVIs( vsALLVIs ) )
		{
			if(!CheckLabView( false ))	//Is LV connected? do not try again
				return false;

			LV_DEBUG_STR("No VI's in memory!");
			
			if ( !bFileOpenIfNoVIs )
				return false;
			
			// dir: F:\Program Files\National Instruments\LabVIEW 6.1\examples\comm\hiq
			if ( !LabViewLLBFileImport( vsALLVIs ) )	//reed from file
				return false;
		}
	
		return BuildCallerTree( vsALLVIs );
	}
};
	
////////////////	end	TREE	LV	TREE	LV	TREE	////////////////
////////////////	end	TREE	LV	TREE	LV	TREE	////////////////


////////////////////////////////////////////////////////
// class LabViewImportDlg   
////////////////////////////////////////////////////////     
class LabViewImportDlg : public ResizeDialog
{
private:
	LabVIEW		m_LVTree;
	
public:
	//LabViewImportDlg(LabVIEW &LVTree) : ResizeDialog(IDD_LABVIEW_IMPORT, "ODlg")
	LabViewImportDlg() : ResizeDialog(IDD_LABVIEW_IMPORT, "ODlg")
	{
	}
	
	int	DoModalEx(HWND hParent)
	{
		InitMsgMap();// will be called from internal later
		int nRet = DoModal(hParent);
		return nRet;
	}

	BOOL	CreateEx(HWND hParent)
	{
		InitMsgMap();// will be called from internal later
		BOOL	bRet =  Create(hParent);
		return bRet;
	}
	
	void AttachLabVIEW(LabVIEW &LVTree)
	{
		m_LVTree = LVTree;
	}

protected:

///----------------- Message Map ----------------
EVENTS_BEGIN
	ON_INIT(OnInitDialog) 
	ON_DESTROY(OnDestroy)
	ON_SIZE(OnDlgResize)
	ON_OK(OnClose)
	ON_BN_CLICKED(IDC_LABVIEW_BTN_RUN_VI, OnRunVI)
	ON_BN_CLICKED(IDC_LABVIEW_BTN_IMPORT, OnImportAsMatrices)
	ON_BN_CLICKED(IDC_LABVIEW_BTN_IMPORT_WKS, OnImportAsSingleWks)

	//--- vsFlex related
	ON_GRID_SEL_CHANGE(IDC_LABVIEW_GRID_VI, OnTreeSelChange)
	ON_GRID_SEL_CHANGE(IDC_LABVIEW_GRID_CONTROL, OnListSelChange)
	ON_GRID_BEFORE_EDIT(IDC_LABVIEW_GRID_CONTROL, OnBeforeEditList)
	//---
EVENTS_END
///----------------------------------------------

	///////////////////////////////////////////////////////
	/// Event Handlers
	///////////////////////////////////////////////////////
	
	BOOL OnInitDialog() 
	{
		ResizeDialog::OnInitDialog();

		m_btnRunVI = GetItem( IDC_LABVIEW_BTN_RUN_VI );
		m_btnMat = GetItem( IDC_LABVIEW_BTN_IMPORT );
		m_btnWks = GetItem( IDC_LABVIEW_BTN_IMPORT_WKS );
		
		m_btnClose = GetItem(IDOK);


		m_cntrlVITree.Init(IDC_LABVIEW_GRID_VI, *this);
		m_cntrlVIList.Init(IDC_LABVIEW_GRID_CONTROL, *this);
		
		//m_cntrlVITree.SetTree(m_trVI);//see plotlistcontrol.h, otreeeditor
		
		//// save the group size so we can resize the whole dialog
		RECT r1;
		m_cntrlVITree.GetRect(r1);
		//m_nVITreeGroupHeight = r1.bottom;
		m_cntrlVIList.GetRect(r1);
		//m_nPlotListGroupHeight = GetDlgExtent() - r1.bottom;
		//m_nColListGroupHeight = RECT_HEIGHT(r1);
		////
		
		//resizeAllControls();
		
//////////////////////////////////////////////////////////////		
//////////////////////////////////////////////////////////////		
		
		m_cntrlVITree.Setup();
		m_cntrlVIList.Setup();
		
		m_cntrlVITree.Load(m_LVTree.GetTree());
	
		m_btnRunVI.Enable = FALSE;
		
		return TRUE;
//////////////////////////////////////////////////////////////		
//////////////////////////////////////////////////////////////		
	}
	
	BOOL OnDestroy(void)
	{
		return TRUE;
	}


	BOOL OnDlgResize(int nType, int cx, int cy)
	{
		RECT r1;
		GetControlClientRect(IDC_LABVIEW_GRID_VI, r1);
		
		StretchControlHeight(IDC_LABVIEW_GRID_VI, r1.left, r1.top, cy); // need to add to base class
		uint nCntrlsRight[] = {
			IDC_LABVIEW_BTN_RUN_VI,
			IDC_LABVIEW_BTN_IMPORT,
			IDC_LABVIEW_BTN_IMPORT_WKS,
			IDOK,
			0};
		ResizeMoveControlsRightBottom(IDC_LABVIEW_GRID_CONTROL, nCntrlsRight, NULL, cx, cy);
		return TRUE;
	}
	
	///DVT - IDOK in error is in dialog resource instead of IDCANCEL - change
	BOOL OnClose()
	{
		return TRUE;
	}
	
	BOOL OnRunVI(Control ctrl)
	{
		string	strVISel;
		m_cntrlVITree.GetSelectedCell(strVISel);
	
		//this button should have been disabled if not
		ASSERT( m_LVTree.IsTopmostVI(strVISel) );
		
		vector<int> vIDs;
		vector<string> vTypes;
		vector<string> vNames;
		vector<string> vValues;
		vector<USHORT> vVarTypes;
		if (!m_LVTree.GetVIControls( strVISel,  vIDs, vTypes, vNames, vValues, vVarTypes ) )
			return false;
		
		Object viOne;
		if ( !m_LVTree.GetVIObjectByName( strVISel, viOne ) )
			return false;
		
		UINT		nTotalNumber = vNames.GetSize();
		//Object	flxL = THE_LIST;
		for ( int i = 0; i < nTotalNumber; i++ )
		{
			string strName = vNames[i];
			//if ( strName.IsEmpty() )
			//	continue;
			
			string	strValue;
			if ( !m_cntrlVIList.FindAndGetCell( strName, strValue ) )
				continue;
	//////////////////////////////////////////////////////////////		
			
			_VARIANT val;
			bool bValOK(false);
	
			USHORT nvt = vVarTypes[i];
			if ( !(VT_ARRAY & nvt) )
			{
				switch (nvt)
				{
				case VT_BOOL:
					if ( 0 == strValue.CompareNoCase(DISPLAY_VARIANT_TRUE) )
					{
						bValOK = true;
						val = VARIANT_TRUE;
					}
					
					if ( 0 == strValue.CompareNoCase(DISPLAY_VARIANT_FALSE) )
					{
						bValOK = true;
						val = VARIANT_FALSE;
					}
					break;
				case VT_I2:
				case VT_I4:
				case VT_I1:
				case VT_UI1:
				case VT_UI4:
				case VT_INT:
				case VT_UINT:
					int nValue = atol(strValue);
					val = nValue;
					bValOK = true;
					break;
				case VT_R4:
				case VT_R8:
					double dValue = atof(strValue);
					val = dValue;
					bValOK = true;
					break;
				default:
					break;
				}
			}
			
			if ( bValOK )
				try
				{
					viOne.SetControlValue(vNames[i], val);
				}
				catch(int nErr)
				{
					//this will fail for indicators in LV 5.0 !!!
					//no way to distinguish controls from indicators form LV export file, 
					//so users must not Label their indicators if they want
					//RunVI to work (they can have Caption, will be ignored here)
				}
		}
		
		//have to be able to stop if VI start running continuously  
		try
		{
			viOne.Run(0);
		}
		catch(int nErr)
		{
		}
	//////////////////////////////////////////////////////////////		
		
		//refresh list
		return UpdateControlsDisplay( strVISel,  vIDs, vTypes, vNames, vValues, vVarTypes );
	}
	
	//CP's functions from MatlabImport
	//////////
	BOOL OnImportAsMatrices(Control ctrl)
	{
		string	asName;
		string	strResult;
		
		m_cntrlVIList.GetSelectedCell( asName );
		GetLabViewMatrices( asName, strResult );
		
		LV_DEBUG_STR( strResult );
		
		return TRUE;	//for now
	}
	//////////

	//////////////////////////////////////////////////////////////////////////////////////
	bool	GetLabViewMatrices( string &asName, string& strResult )
	{
		bool	bReplaceCurrent = false;
		
		bool bNew = false;
		MatrixLayer mlay(asName);
		
		if(!mlay || (!bReplaceCurrent && mlay))
		{
			if(mlay) // already existed
				mlay.Detach();
				
			if(!mlay.Create(NULL, CREATE_HIDDEN))
				return false;
			//mlay.Create();
			mlay.GetPage().Rename(asName);
			bNew = true;
		}
		
		Matrix<double> mm(mlay);
		if(!GetLVArrayAsMatrix(asName, mm) && bNew)
		{
			mlay.Destroy();
			strResult += asName + " ";
		}
	
		if(!strResult.IsEmpty())
		{
			strResult += ": matrix not found in LabView!";
			return FALSE;
		}
	
		//mlay.GetPage().LT_execute( LT_SHOW_WND );
		mlay.GetPage().SetShow();
	
		return TRUE;
	}
	//////////////////////////////////////////////////////////////////////////////////////

		
	BOOL OnImportAsSingleWks(Control ctrl)
	{
		string	asName;
		m_cntrlVIList.GetSelectedCell( asName );
		
		
		bool	bReplaceCurrent = false;
		bool	bWksCreated = false;
		
		Worksheet wksTemp;
		
		if(!wksTemp.IsValid())
		{
			///	DVT 8/20/03 SYNCHRONIZE_WITH_MATLAB_IMPORT
			//if(!wksTemp.Create(NULL, CREATE_HIDDEN))
			if(!wksTemp.Create())
			{
				///	DVT 4/11/03 REMOVE_TREE_UTILS_FROM_LVDLG
				//out_str("Creating worksheet failed");
				LV_DEBUG_STR("Creating worksheet failed");
				///	end REMOVE_TREE_UTILS_FROM_LVDLG
				return FALSE;
			}
			bWksCreated = true;
		}
		if(bWksCreated)
		{
			while(wksTemp.DeleteCol(0))	 // Remove all columns in worksheet
				;
		}
		
		int nNameCount = 0;
		
		///	DVT 4/10/03 QA70-3684 v7.0557 ORIGIN_AUTO_SERVER_SET_ARRAY_VAR_CRASH_FIX
		//use it for subVariants
		nNameCount += AddLabViewDoubleArray(wksTemp, asName, bReplaceCurrent);
		///	end ORIGIN_AUTO_SERVER_SET_ARRAY_VAR_CRASH_FIX
	
		if( nNameCount > 0 )
		{
			if( bWksCreated )
			{
				wksTemp.GetPage().Rename( LV_WKS_NAME );
				///	DVT 8/20/03 SYNCHRONIZE_WITH_MATLAB_IMPORT
				//wksTemp.GetPage().LT_execute( LT_SHOW_WND );
			}
			return TRUE;
		}
		
		wksTemp.Destroy();
		return FALSE;	
	}
	
	//////////////////////////////////////////////////////////////////////////////////////
	bool GetLVArrayAsMatrix( string &strName, Matrix &mm )
	{
		string	strVISel;
		m_cntrlVITree.GetSelectedCell(strVISel);
	
		Object viOne;
		if ( !m_LVTree.GetVIObjectByName( strVISel, viOne ) )
			return false;
		
		//////////////////////////////////////
		//_VARIANT val = viOne.GetControlValue( strName );
		_VARIANT val;
		try
		{
			val = viOne.GetControlValue( strName );
		}
		catch(int nErr)
		{
			return false;
		}
		
		USHORT nvt = val.vt;
		short nVarType = nvt;
		int	nLobyte = nvt & 0x00FF;
		
		//#
		LV_DEBUG_printf( "val.vt: %04x, lobyte %04x\n", nvt, nLobyte );
		
		if ( VT_ARRAY & nvt )
		{
			///	DVT	2/5/03 QA70-3725 v7.0498 ARRAY_VARIANT_FOR_LABVIEW_IMPORT
			mm.SetByArrayInVariant(val);
			return true;
		}
		return false;
	}
	/////////////////////////////////////////////////////
	
	//////////////////////////////////////////////////////////////////////////////////////
	int check_add_wks_col(Worksheet& wks, string strColName, int nSuffix, bool bReplaceCurrent)
	{
		if(nSuffix > 0)
			strColName += nSuffix;
		
		if(bReplaceCurrent)
		{
			Column cc = wks.Columns(strColName);
			if(cc)
				return cc.GetIndex();
		}
		
		return wks.AddCol(strColName);
	}
	
	
	// return number of cols added
	int AddLabViewDoubleArray(Worksheet& wks, string strMatLabVarName, bool bReplaceCurrent)
	{
		MatrixLayer mlTemp;
		if(!mlTemp.Create(NULL, CREATE_HIDDEN))
			return 0;
		
		Matrix<double> mm(mlTemp);
		int nAdded = 0;
		if(!GetLVArrayAsMatrix(strMatLabVarName, mm))
			goto add_wks_done;
		
		int nRows = mm.GetNumRows();
		int nCols = mm.GetNumCols();
		
		int nNewCol = check_add_wks_col(wks, strMatLabVarName, nAdded, bReplaceCurrent);
		
		if(nCols == 1)
		{
			Dataset aa(wks, nNewCol);
			mm.GetColumn(aa, nAdded++);
			goto add_wks_done;
		}
		else if (nRows == 1)
		{
			Dataset aa(wks, nNewCol);
			mm.GetRow(aa, nAdded++);
			goto add_wks_done;
		}
		
		do
		{
			Dataset aa(wks, nNewCol);
			mm.GetColumn(aa, nAdded);
			nAdded++;
			if(nAdded >= nCols)
				break;
			nNewCol = check_add_wks_col(wks, strMatLabVarName, nAdded, bReplaceCurrent);
		} while(1);
		
	
	add_wks_done:
		mlTemp.Destroy();
		return nAdded;
	}
	//////////////////////////////////////////////////////////////////////////////////////
	
	
	
	
	//// vsFlex events
	void OnTreeSelChange(Control flxControl)
	{
		m_cntrlVITree.OnSelChange(flxControl);
		
		//waitCursor	cr;			//ML
		string		strVI;
		if ( ! m_cntrlVITree.GetSelectedCell( strVI ) )
			return;
		
		if ( 1 == m_cntrlVITree.GetSelectedRow() )
		{
			ASSERT ( 0 == strVI.Compare( LV_TREE_ROOT_NODE_LABEL ) );
			m_cntrlVIList.Clear();
			m_btnRunVI.Enable = FALSE;
			return;			//return if selection is on the root ("All VIs")
		}
		
		vector<int>		vIDs;
		vector<string>	vTypes;
		vector<string>	vNames;
		vector<string>	vValues;
		vector<USHORT>	vVarTypes;	//not used here

		UpdateControlsDisplay( strVI,  vIDs, vTypes, vNames, vValues, vVarTypes );
		
		m_btnRunVI.Enable = m_LVTree.IsTopmostVI( strVI );
		
	}
	
	//void OnListSelChange(Control cntrl, long nRow, long nCol, BOOL* pCancel)
	void OnListSelChange( Control cntrl )
	{
		m_cntrlVIList.OnSelChange(cntrl);
		
		m_btnMat.Enable = m_cntrlVIList.IsImportEnabled();
		m_btnWks.Enable = m_cntrlVIList.IsImportEnabled();
	}
	
	void OnBeforeEditList(Control cntrl, long nRow, long nCol, BOOL* pCancel)
	{
		m_cntrlVIList.OnBeforeEditList(cntrl, nRow, nCol, pCancel);
	}
	

	
	///List update////////////////////	
	bool	UpdateControlsDisplay( string &strVISel, vector<int> &vIDs, vector<string> &vTypes, vector<string> &vNames, vector<string> &vValues, vector<USHORT> &vVarTypes )
	{
		if (!m_LVTree.GetVIControls( strVISel, vIDs, vTypes, vNames, vValues, vVarTypes ) )
			return false;
		
		return m_cntrlVIList.Update( vIDs, vTypes, vNames, vValues );
	}
	///////////////////////	
	
	
private:
	// main tables
	VITreeControl		m_cntrlVITree;
	VIListControl		m_cntrlVIList;
	
	/// other controls
	Button	m_btnRunVI;
	Button	m_btnMat;
	Button	m_btnWks;

	Button	m_btnClose;
};

////////////////////////////////////////////////////////
// end class LabViewImportDlg   
////////////////////////////////////////////////////////     
 
bool LabViewImport(LabVIEW &LVTree, HWND hWndParent = NULL)
{
	LabViewImportDlg	MyDlg;
	
	MyDlg.AttachLabVIEW(LVTree);
	
 	int nRet = MyDlg.DoModalEx(hWndParent);
 	return nRet == IDOK? true:false;
}

void LabViewWorkspaceImportDlg()
{
	LabVIEW				LVTree;
	
	if( LVTree.Build() )
	{
		LabViewImport( LVTree, GetWindow() );
	}
	else
		MessageBox(GetWindow(), _L("LabVIEW not available."), _L("LabVIEW Import Dialog"), MB_OK);

}
 	
void testLV()
{
	LabViewWorkspaceImportDlg();
}
