/*------------------------------------------------------------------------------*
 * File Name: sys_utils.c				 										*
 * Creation: GJL 3/13/02														*
 * Purpose: Basic and common utilities for general Origin C development.		*
 * Copyright (c) OriginLab Corp.	2002, 2003, 2004, 2005, 2006, 2007			*
 * All Rights Reserved															*
 * 																				*
 * Modification Log:															*
 *	JCG 06/17/03 QA70-4575 IMP_WIZD_BUG_45_AND_28								*
 * EJP 07-10-2003 v7.0622 QA70-4745 SET_PAGE_IMPORT_INFO_ON_123_ASC_IMPORT		*
 * SY 09-12-2003 QA70-5158 v7.0694 OC_NEED_ROBUST_GET_TEMP_PATH_FUNCTION		*
 * EJP 11-20-2003 v7.5764 QA70-5587 FAIL_TO_EXPORT_1200DPI_BITMAP				*
 * EJP 11-24-2003 v7.5769 QA70-5604 LOCALIZE_FILE_TYPE_ALL_FILES				*
 *------------------------------------------------------------------------------*/

#include <origin.h> // main Origin C header that is precompiled and already include most headers 
// TD 10-22-03 REMOVED_DEPENDENCY
//#include "Filter_Utils.h"
#include "local.h"

/// EJP 11-24-2003 v7.5769 QA70-5604 LOCALIZE_FILE_TYPE_ALL_FILES
#define FILETYPE_ALL_FILES _L("[All Files (*.*)] *.*")
/// end LOCALIZE_FILE_TYPE_ALL_FILES

/**
	It appends to the string str the ' ' characters until its size
	reaches nSize. 
*/
void	append_blanks_to_size(string &str, int nSize)
{
	int		nLength = str.GetLength();
	for (int ii = nLength + 1; ii <= nSize; ii++)
		str += ' ';
	
	return;
}

// Function prototypes of static functions

static int GetFDLogBox( StringArray &saFilePaths, FDLogDialogType fdtDialogType );

static int GetFileDialogBox( StringArray &saFilePaths, StringArray &saFiletypes, FDLogDialogType fdtDialogType = FDLOG_TYPE_OPEN_SINGLE,
	 LPCSTR lpcszPath = NULL, LPCSTR lpcszFilename = NULL, LPCSTR lpcszDialogName = NULL );

static int GetFileDialogBox( StringArray &saFilePaths, FDLogUseGroup nFDLogUseGroup, FDLogDialogType fdtDialogType = FDLOG_TYPE_OPEN_SINGLE,
	 LPCSTR lpcszPath = NULL, LPCSTR lpcszFilename = NULL, LPCSTR lpcszDialogName = NULL );

static int GetFileDialogBox( StringArray& saFilePaths, LPCSTR lpcszFileType = NULL, FDLogDialogType fdtDialogType = FDLOG_TYPE_OPEN_SINGLE,
	 LPCSTR lpcszPath = NULL, LPCSTR lpcszFilename = NULL, LPCSTR lpcszDialogName = NULL );

//////////////////////////////////////////////////////////////////////////////////
/**
		Resets or initializes the LabTalk FDLog object. Should be called prior to
		opening an FDLog dialog box.
	Example:
		FDLogInit();
	Parameters:
		None
	Return:
		Returns 0 on successful exit.
*/
int FDLogInit()
{
	_LT_Obj
	{
		FDLog.Reset();                // Reset FDLog object
		FDLOG.OptionDLG$ = "";        // Reset button to off
		FDLOG.Checkname$ = "";        // Reset check box to null
		FDLOG.ShowComment = 0;        // Reset the comments box to closed
		FDLOG.CheckStatus = 0;        // Reset checkbox to off
		FDLOG.DlgName$ = "";		  // Reset dialog name to nothing
		FDLOG.Path$ = "";			  // Reset default path to nothing	
		FDLOG.Default$ = "";		  // Reset contents of "File Name" edit box to nothing
		FDLOG.AsReadOnly = 0;         // Reset read only checkbox to disabled
		//------------------- CPY v6.0252 t6746 1/26/00 MULTI_OPEN_SUPPORT_BY_ROW_AND_BY_COL_APPEND
		FDLOG.MultiOpen.ComboName$ = "";
		if( FDLOG.MultiOpen.ComboSel < 1 || FDLOG.MultiOpen.ComboSel > 3 )
			FDLOG.MultiOpen.ComboSel = 2; // Import into new columns
		//------------------- end t6746

		//------------------- GJL v7.0358 QA70-4078 3/17/03 ORIGINC_MULTI_OPEN_SUPPORT
		FDLOG.Open.MultiSel = 0;      // Reset multiple selection switch (turn off by default)
		//------------------- QA70-4078
	}
	
	return 0;
}

//------------------- GJL v7.0357 QA70-4078 3/17/03 ORIGINC_MULTI_OPEN_SUPPORT
//////////////////////////////////////////////////////////////////////////////////
/**
		Open an FDLog dialog box having the enumerated type FDLogDialogType with
		possible values FDLOG_TYPE_SAVE_AS, FDLOG_TYPE_OPEN_SINGLE, FDLOG_TYPE_OPEN_MULTISEL,
		and FDLOG_TYPE_MULTI_OPEN. Return the path and filename of all selected files. 
	Example:
		See overloaded GetFileDialogBox functions in this source file. 
	Parameters:
		saFilePaths=Output vector of strings containing path and filename of all selected files
		fdtDialogType=Input type of dialog: FDLOG_TYPE_SAVE_AS, FDLOG_TYPE_OPEN_SINGLE, FDLOG_TYPE_OPEN_MULTISEL,
			and FDLOG_TYPE_MULTI_OPEN
	Return:
		Returns the number of selected files.
*/
static int GetFDLogBox( StringArray &saFilePaths, FDLogDialogType fdtDialogType )
{
	char szTemp[ MAXFULLPATH ];
	
	saFilePaths.SetSize(1);                      // Assume 1 file
	saFilePaths[0] = "";                         // Initialize path and filename to ""
	
	using FDLog = LabTalk.FDLog;                 // Use LabTalk FDLog object
	
	switch( fdtDialogType )                      // Open requested dialog type
	{
		case FDLOG_TYPE_SAVE_AS:
			if( FDLog.SaveAs( "A" ) )                    // Open SaveAs dialog box
				return 0;                                // Error, 0 files selected
			else
			{
				LT_get_str( "%A", szTemp, MAXFULLPATH ); // Get filename of selected file from LabTalk variable
				saFilePaths[0] = FDLog.Path$ + szTemp;   // Return path and filename
			}
			return 1;                                    // Return number of selected files
		case FDLOG_TYPE_OPEN_SINGLE:
			FDLog.Open.MultiSel = 0;
			if( FDLog.Open( "A" ) )                      // Open Single Open dialog box without muliple selection
				return 0;                                // Error, 0 files selected
			else
			{
				LT_get_str( "%A", szTemp, MAXFULLPATH ); // Get filename of selected file from LabTalk variable
				saFilePaths[0] = FDLog.Path$ + szTemp;   // Return path and filename
			}
			return 1;                                    // Return number of selected files
		case FDLOG_TYPE_OPEN_MULTISEL:
			FDLog.Open.MultiSel = 1;    
			if( FDLog.Open( "A" ) )                              // Open Single Open dialog box with multiple selection
				return 0;                                        // Error, 0 files selected
			saFilePaths.SetSize(FDLog.MultiOpen.Count);
			for( int ii = 0; ii < FDLog.MultiOpen.Count; ii++ )  // For each file selected
			{
				FDLog.Get("A", ii+1);                            // Get filename into LabTalk variable
				LT_get_str( "%A", szTemp, MAXFULLPATH );         // Get filename of selected file from LabTalk variable
				saFilePaths[ii] = FDLog.Path$ + szTemp;          // Return path and filename
			}
			return ii;                                           // Return number of selected files
		case FDLOG_TYPE_MULTI_OPEN:
			FDLog.MultiOpen.ColView = FDLOG_MULTI_OPEN_SHOW_FILE_SIZE |
			                          FDLOG_MULTI_OPEN_SHOW_MODIFY; // Display Filename, Size, and Modified
			FDLog.Checkname$="";                                 // Clear Checkbox name 
			if( FDLog.MultiOpen() == NANUM )                     // Open Multi-Open dialog box
				return 0;                                        // Error, 0 files selected
			saFilePaths.SetSize(FDLog.MultiOpen.Count);
			for( int ii = 0; ii < FDLog.MultiOpen.Count; ii++ )  // For each file selected
			{
				FDLog.Get("A", ii+1);                            // Get path and filename into LabTalk variable
				LT_get_str( "%A", szTemp, MAXFULLPATH );         // Get path and filename of selected file from LabTalk variable
				saFilePaths[ii] = szTemp;                        // Return path and filename
			}
			return ii;                                           // Return number of selected files
		default:
			return 0;                                    // Return with 0 files saved or opened
	}
	
	return 0;                                    // Return with 0 files saved or opened
}
//------------------- QA70-4078

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

/**
		Open an FDLog SaveAs, Open (with or without multiple selection enabled), or
		MultiOpen dialog box passing the file types to list in an array of strings. 
	Example:
		See overloaded GetSaveAsBox, GetOpenBox, and GetMultiOpenBox functions in
		this source file.
	Parameters:
		saFilePaths=Output vector of strings containing path and filename of all selected files
		saFiletypes=Vector containing file types to list in the dialog box, each element
			of vector must follow syntax of LabTalk FDLog.TypeN$ object property
		fdtDialogType=Input type of dialog: FDLOG_TYPE_SAVE_AS, FDLOG_TYPE_OPEN_SINGLE, FDLOG_TYPE_OPEN_MULTISEL,
			and FDLOG_TYPE_MULTI_OPEN
		lpcszPath=Initial path when dialog opens, default NULL uses FDLog tracking
		lpcszFileName=Initial filename when dialog opens, default NULL uses an empty string 
		lpcszDialogName=Title of the dialog box, default NULL uses "Open" or "Save As" 
	Return:
		Returns the number of selected files.
*/
static int GetFileDialogBox( StringArray &saFilePaths, StringArray &saFiletypes, FDLogDialogType fdtDialogType,
	 LPCSTR lpcszPath, LPCSTR lpcszFilename, LPCSTR lpcszDialogName ) // fdtDialogType = FDLOG_TYPE_OPEN_SINGLE, lpcszPath = NULL, lpcszFilename = NULL, lpcszDialogName = NULL
{
	int ii, iSize;
	string strDefaultPath = lpcszPath;
	string strDefaultFilename = lpcszFilename;
	string strDialogName = lpcszDialogName;
	string strLTCommand;
	
	_LT_Obj
	{
		if( strDefaultPath.IsEmpty() )               // If path is not passed as argument...
			strDefaultPath = FDLog.Path$;            //   get last used path from FDLog object for tracking

		FDLogInit();                                 // Initialize LabTalk FDLog object
		
		if( !strDefaultPath.IsEmpty() )              // If path is passed as argument or is being tracked...
			FDLog.Path$ = strDefaultPath;            //   initialize path

		FDLog.Default$ = strDefaultFilename;         // Initialize filename

		iSize = saFiletypes.GetSize();                // Get number of file types
		if( iSize <= 1 && saFiletypes[ii].IsEmpty() ) // If no file types are specified...
		{
			iSize = 0;                               //   set size as 0
			FDLog.NumTypes = iSize;                  //   initialize number of passed filetypes to 0
		}
		else                                         // Else filetypes are specified...
		{
			FDLog.NumTypes = iSize;                  //   initialize number of passed filetypes
			FDLog.Deftype=1;                         //   initialize default filetype to first in filetype list
			for( ii = 0; ii < iSize; ii++ )          //   loop on all filetypes
			{
				strLTCommand.Format( "FDLog.Type%d$=%s;", ii+1, saFiletypes[ii] ); // create enumerated LabTalk command
				LT_execute( strLTCommand );          //     execute enumerated LabTalk command to initialize filetypes
			}
		}
		FDLog.DlgName$ = strDialogName;              // Initialize dialog box name

		return GetFDLogBox(saFilePaths, fdtDialogType); // Open FDLog dialog box and get path and filename(s)
	}
}

/**
		Open an FDLog SaveAs, Open (with or without multiple selection enabled), or
		MultiOpen dialog box using an enumerated FDLog.UseGroup code to indicate the
		set of file types to list. See sys_utils.h or the Origin.ini file for a list
		of the enumerated FDLOG.UseGroup codes.
	Example:
		See overloaded GetSaveAsBox, GetOpenBox, and GetMultiOpenBox functions in
		this source file.
	Parameters:
		saFilePaths=Output vector of strings containing path and filename of all selected files
		nFDLogUseGroup=A LabTalk FDLog.UseGroup code as enumerated in sys_utils.h and in the Origin.ini file
		fdtDialogType=Input type of dialog: FDLOG_TYPE_SAVE_AS, FDLOG_TYPE_OPEN_SINGLE, FDLOG_TYPE_OPEN_MULTISEL,
			and FDLOG_TYPE_MULTI_OPEN
		lpcszPath=Initial path when dialog opens, default NULL uses FDLog tracking
		lpcszFileName=Initial filename when dialog opens, default NULL uses an empty string 
		lpcszDialogName=Title of the dialog box, default NULL uses "Open" or "Save As" 
	Return:
		Returns the number of selected files.
*/
static int GetFileDialogBox( StringArray &saFilePaths, FDLogUseGroup nFDLogUseGroup, FDLogDialogType fdtDialogType,
	 LPCSTR lpcszPath, LPCSTR lpcszFilename, LPCSTR lpcszDialogName ) // fdtDialogType = FDLOG_TYPE_OPEN_SINGLE, lpcszPath = NULL, lpcszFilename = NULL, lpcszDialogName = NULL
{
	string strFDLogUseGroup;
	string strDefaultPath = lpcszPath;
	string strDefaultFilename = lpcszFilename;
	string strDialogName = lpcszDialogName;
	string strIniKeyName;
	double dNumGroups;
	char szTemp[ MAXFULLPATH ];

	_LT_Obj
	{
		FDLogInit();                                            // Initialize LabTalk FDLog object

		if( nFDLogUseGroup < FDLOG_FILTER_ASCII )
		{
			ini.file$ = "Origin.ini";                               // Look in Origin.ini file for UseGroup NumGroups and Name
			
	        // Check that UseGroup is between 1 and ini.FileExt.NumGroups
			LT_get_var( "ini.FileExt.NumGroups", &dNumGroups );     // Get number of currently defined UseGroups
			if( nFDLogUseGroup > dNumGroups || nFDLogUseGroup < 1 ) // If UseGroup is out of bounds use blank for All Files 
				strFDLogUseGroup = "";
			else                                                    // Else get UseGroup name from Origin.ini
			{
				strIniKeyName.Format( "%%A=ini.FileExt.%d_Name$", nFDLogUseGroup ); // Format LabTalk command to get UseGroup name
				LT_execute( strIniKeyName );                        // Get specfied UseGroup name
				LT_get_str( "%A", szTemp, MAXFULLPATH );
				strFDLogUseGroup = szTemp;
			}
	
			FDLog.UseGroup( strFDLogUseGroup );          // Execute FDLog.UseGroup method to set file types and path
		}
		else
		{
			switch( nFDLogUseGroup )
			{
			case FDLOG_FILTER_ASCII:
				FDLog.UseGroup("ASCII");
				FDLog.AddUserTypes(FILTER_TYPE_ASCII);
				break;
			case FDLOG_FILTER_BINARY:
				FDLog.NumTypes = 0;
				FDLog.AddUserTypes(FILTER_TYPE_BINARY);
				FDlog.AddType(FILETYPE_ALL_FILES);
				break;
			case FDLOG_FILTER_USERDEFINED:
				FDLog.NumTypes = 0;
				FDLog.AddUserTypes(FILTER_TYPE_USERDEFINED);
				FDlog.AddType(FILETYPE_ALL_FILES);
				break;
			}
		}

		if( !strDefaultPath.IsEmpty() )              // If path is passed as argument...
			FDLog.Path$ = strDefaultPath;            //   initialize path overwriting FDLog.UseGroup setting

		FDLog.Default$ = strDefaultFilename;         // Initialize filename

		FDLog.DlgName$ = strDialogName;              // Initialize dialog box name
		
		return GetFDLogBox(saFilePaths, fdtDialogType); // Open FDLog dialog box and get path and filename(s)
	}
}

//////////////////////////////////////////////////////////////////////////////////
/**
		An easier to use version of GetFileDialogBox that works for a single file type.
	Example:
		See overloaded GetSaveAsBox, GetOpenBox, and GetMultiOpenBox functions in
		this source file.
	Parameters:
		saFilePaths=Output vector of strings containing path and filename of all selected files
		lpcszFileType="*.ext description", or "[decription (*.ext)] *.ext", or just "*.ext"
		fdtDialogType=Input type of dialog: FDLOG_TYPE_SAVE_AS, FDLOG_TYPE_OPEN_SINGLE, FDLOG_TYPE_OPEN_MULTISEL,
			and FDLOG_TYPE_MULTI_OPEN
		lpcszPath=Initial path when dialog opens, default NULL uses FDLog tracking
		lpcszFileName=Initial filename when dialog opens, default NULL uses an empty string 
		lpcszDialogName=Title of the dialog box, default NULL uses "Open" or "Save As" 
	Return:
		Returns the number of selected files.
*/
static int GetFileDialogBox( StringArray& saFilePaths, LPCSTR lpcszFileType, FDLogDialogType fdtDialogType,
	 LPCSTR lpcszPath, LPCSTR lpcszFilename, LPCSTR lpcszDialogName) // lpcszFileType = NULL, fdtDialogType = FDLOG_TYPE_OPEN_SINGLE, lpcszPath = NULL, lpcszFileName = NULL, lpcszDialogName = NULL
{
	string strFileType;
	if( lpcszFileType )
		strFileType = lpcszFileType;
	else
		strFileType = "*.* All Files";

	string strFileTypeText;
	
	strFileType.TrimLeft();			  // In case there are blanks to ensure proper testing of 1st char
	if(strFileType[0] == '[')
		strFileTypeText = strFileType;// User specified in correct LabTalk syntax, we will use as is
	else
	{
		// We will construct the proper syntax here
		if(strFileType[0] != '*' || strFileType[1] != '.')
			return "";	              // Bad format, return empty string
		
		int nFileTypeTextSeparator = strFileType.Find(' ');
		if(nFileTypeTextSeparator > 0) // There is explanation text after ext
		{
			string strText = strFileType;
			strFileType = strText.Left(nFileTypeTextSeparator);
			strText = strText.Mid(nFileTypeTextSeparator+1);
			strFileTypeText = "[" + strText + " (" + strFileType + ")] " + strFileType;
		}
		else
			strFileTypeText = "[" + strFileType + " (" + strFileType + ")] " + strFileType;
	}
		
	StringArray saFiletypes;
	saFiletypes.SetSize( 1 );
	saFiletypes[0]=strFileTypeText; // "[Project (*.OPJ)] *.OPJ";
	
	return GetFileDialogBox( saFilePaths, saFiletypes, fdtDialogType, lpcszPath, lpcszFilename, lpcszDialogName );
}

//////////////////////////////////////////////////////////////////////////////////
/**
		Open an FDLog Browse (OpenPath) dialog box.
	Example:
		string strPath;
		strPath = BrowseGetPath();                                      // or
		strPath = BrowseGetPath( "C:\\Program Files\\" );               // or
		strPath = BrowseGetPath( GetAppPath() + "OriginC\\", "Browse" );
	Parameters:
		lpcszPath=Initial path when dialog opens, default NULL uses FDLog tracking  
		lpcszDialogName=Title of the dialog box, default NULL uses "Open" 
	Return:
		Returns the path browsed to or an empty string if Cancel button in dialog
		box is clicked.
*/
string BrowseGetPath( LPCSTR lpcszPath, LPCSTR lpcszDialogName ) // lpcszPath = NULL, lpcszDialogName = NULL
{
	double dErr;
	char szTemp[ MAXFULLPATH ];
	string strDefaultPath = lpcszPath;
	string strDialogName = lpcszDialogName;
	string strReturnPath;

	_LT_Obj
	{
		if( strDefaultPath.IsEmpty() )               // If path is not passed as argument...
			strDefaultPath = FDLog.Path$;            //   get last used path from FDLog object for tracking

		FDLogInit();                                 // Initialize LabTalk FDLog object

		if( !strDefaultPath.IsEmpty() )              // If path is passed as argument...
		{
			FDLog.Path$ = strDefaultPath;            //   initialize path
			FDLog.Default$ = strDefaultPath;         //   initialize filename which is same as path for this DB
		}
		FDLog.DlgName$ = strDialogName;              // Initialize dialog box name

		dErr = FDLog.OpenPath( "A" );   // Open browse dialog box and put result into %A Labtalk string
		
		if( dErr )                      // If Cancel button is clicked...
			strReturnPath.Empty();      //   return empty string
		else                            // Else OK is clicked...
		{
			LT_get_str( "%A", szTemp, MAXFULLPATH );//   get path browsed to from %A LabTalk variable
			strReturnPath = szTemp;                 //   return path browsed to
		}
	}

	return strReturnPath;
}

//////////////////////////////////////////////////////////////////////////////////
/**
		Open an FDLog Open dialog box passing the file types to list in an array
		of strings.
	Example:
		string strPath;
		StringArray saFiletypes;
		saFiletypes.SetSize( 3 );
		saFiletypes[0]="[Project (*.OPJ)] *.OPJ";
		saFiletypes[1]="[Old version (*.ORG)] *.ORG";
		saFiletypes[2]="[Worksheets (*.OGW)] *.OGW";
		strPath = GetOpenBox( saFiletypes ); // or
		//strPath = GetOpenBox( saFiletypes, "C:\\Program Files\\" ); // or
		//strPath = GetOpenBox( saFiletypes, "C:\\Program Files\\", "Origin" ); // or
		//strPath = GetOpenBox( saFiletypes, "C:\\Program Files\\", "Origin", "OpenOPJ" );
		if( strPath.IsEmpty() )
			out_str( "User has cancelled the Open dialog box." );
		else
			printf( "The file chosen is %s\n.", strPath );
	Parameters:
		saFiletypes=Vector containing file types to list in the dialog box, each element
			of vector must follow syntax of LabTalk FDLog.TypeN$ object property
		lpcszPath=Initial path when dialog opens, default NULL uses FDLog tracking
		lpcszFileName=Initial filename when dialog opens, default NULL uses an empty string 
		lpcszDialogName=Title of the dialog box, default NULL uses "Open" 
	Return:
		Returns the path and filename of a selecetd file or an empty string if Cancel button
		in dialog box is clicked.
*/
string GetOpenBox( StringArray &saFiletypes, LPCSTR lpcszPath, LPCSTR lpcszFilename,
	 LPCSTR lpcszDialogName ) // lpcszPath = NULL, lpcszFilename = NULL, lpcszDialogName = NULL
{
	//------------------- GJL v7.0357 QA70-4078 3/17/03 ORIGINC_MULTI_OPEN_SUPPORT
	StringArray saFilePaths;
	GetFileDialogBox( saFilePaths, saFiletypes, FDLOG_TYPE_OPEN_SINGLE, lpcszPath, lpcszFilename, lpcszDialogName );
	return saFilePaths[0];
	//return GetFileDialogBox( saFiletypes, FALSE, lpcszPath, lpcszFilename, lpcszDialogName );
	//------------------- QA70-4078
}

/**
		An FDLog.UseGroup version of GetOpenBox that uses an enumerated FDLog.UseGroup
		code to indicate the set of file types to list. See sys_utils.h or the Origin.ini
		file for a list of the enumerated FDLOG.UseGroup codes.
	Example:
		string strPath;
		strPath = GetOpenBox( FDLOG_ORIGIN ); // or
		//strPath = GetOpenBox( FDLOG_EXCEL, "C:\\Program Files\\" ); // or
		//strPath = GetOpenBox( FDLOG_ASCII, "C:\\Program Files\\", "Origin" ); // or
		//strPath = GetOpenBox( FDLOG_SCRIPT, "C:\\Program Files\\", "Origin", "OpenOGS" );
		if( strPath.IsEmpty() )
			out_str( "User has cancelled the Open dialog box." );
		else
			printf( "The file chosen is %s\n.", strPath );
	Parameters:
		nFDLogUseGroup=A LabTalk FDLog.UseGroup code as enumerated in sys_utils.h and in
			the Origin.ini file
		lpcszPath=Initial path when dialog opens, default NULL uses FDLog tracking
		lpcszFileName=Initial filename when dialog opens, default NULL uses an empty string
		lpcszDialogName=Title of the dialog box, default NULL uses "Open"
	Return:
		Returns the path and filename of a selected file or an empty string if Cancel button
		in dialog box is clicked.
*/
string GetOpenBox( FDLogUseGroup nFDLogUseGroup, LPCSTR lpcszPath, LPCSTR lpcszFilename,
	 LPCSTR lpcszDialogName ) // lpcszPath = NULL, lpcszFilename = NULL, lpcszDialogName = NULL
{
	//------------------- GJL v7.0357 QA70-4078 3/17/03 ORIGINC_MULTI_OPEN_SUPPORT
	StringArray saFilePaths;
	GetFileDialogBox( saFilePaths, nFDLogUseGroup, FDLOG_TYPE_OPEN_SINGLE, lpcszPath, lpcszFilename, lpcszDialogName );
	return saFilePaths[0];
	//return GetFileDialogBox( nFDLogUseGroup, FALSE, lpcszPath, lpcszFilename, lpcszDialogName );
	//------------------- QA70-4078

}

//////////////////////////////////////////////////////////////////////////////////
/**
		An easier to use version of GetOpenBox that works for a single file type.
	Example:
		string strPath;
		strPath = GetOpenBox(); // or
		//strPath = GetOpenBox( "[Old version (*.ORG)] *.ORG" ); // or
		//strPath = GetOpenBox( "*.OPJ"); // or
		//strPath = GetOpenBox( "*.ocw Workspace", GetAppPath() + "OriginC\\" ); // or
		//strPath = GetOpenBox( "*.ocw Workspace", GetAppPath() + "OriginC\\", "Origin" ); // or
		//strPath = GetOpenBox( "*.ocw Workspace", "C:\\Program Files\\", "Origin", "Open Workspace" );
		if( strPath.IsEmpty() )
			out_str( "User has cancelled the Open dialog box." );
		else
			printf( "The file chosen is %s\n.", strPath );
	Parameters:
		lpcszFileType="*.ext description", or "[decription (*.ext)] *.ext", or just "*.ext"
		lpcszPath=Initial path when dialog opens, default NULL uses FDLog tracking
		lpcszFileName=Initial filename when dialog opens, default NULL uses an empty string
		lpcszDialogName=Title of the dialog box, default NULL uses "Open"
	Return:
		Returns the path and filename of a selecetd file or an empty string if Cancel button
		in dialog box is clicked.
*/
string GetOpenBox( LPCSTR lpcszFileType, LPCSTR lpcszPath, LPCSTR lpcszFilename,
	 LPCSTR lpcszDialogName ) // lpcszFileType = "*.* All Files", lpcszPath = NULL, lpcszFileName = NULL, lpcszDialogName = NULL
{
	//------------------- GJL v7.0357 QA70-4078 3/17/03 ORIGINC_MULTI_OPEN_SUPPORT
	StringArray saFilePaths;
	GetFileDialogBox( saFilePaths, lpcszFileType, FDLOG_TYPE_OPEN_SINGLE, lpcszPath, lpcszFilename, lpcszDialogName );
	return saFilePaths[0];
	//return GetFileDialogBox( lpcszFileType, FALSE, lpcszPath, lpcszFilename, lpcszDialogName );
	//------------------- QA70-4078
}

//////////////////////////////////////////////////////////////////////////////////
/**
		Open an FDLog SaveAs dialog box passing the file types to list in an array
		of strings.
	Example:
		string strPath;
		StringArray saFiletypes;
		saFiletypes.SetSize( 3 );
		saFiletypes[0]="[Project (*.OPJ)] *.OPJ";
		saFiletypes[1]="[Old version (*.ORG)] *.ORG";
		saFiletypes[2]="[Worksheets (*.OGW)] *.OGW";
		strPath = GetSaveAsBox( saFiletypes ); // or
		//strPath = GetSaveAsBox( saFiletypes, "C:\\Program Files\\" ); // or
		//strPath = GetSaveAsBox( saFiletypes, "C:\\Program Files\\", "Origin" ); // or
		//strPath = GetSaveAsBox( saFiletypes, "C:\\Program Files\\", "Origin", "SaveAsOPJ" );
		if( strPath.IsEmpty() )
			out_str( "User has cancelled the SaveAs dialog box." );
		else
			printf( "The file chosen is %s\n.", strPath );
	Parameters:
		saFiletypes=Vector containing file types to list in the dialog box, each element
			of vector must follow syntax of LabTalk FDLog.TypeN$ object property
		lpcszPath=Initial path when dialog opens, default NULL uses FDLog tracking
		lpcszFileName=Initial filename when dialog opens, default NULL uses an empty string 
		lpcszDialogName=Title of the dialog box, default NULL uses "SaveAs" 
	Return:
		Returns the path and filename of a selecetd file or an empty string if Cancel button
		in dialog box is clicked.
*/
string GetSaveAsBox( StringArray &saFiletypes, LPCSTR lpcszPath, LPCSTR lpcszFilename,
	 LPCSTR lpcszDialogName ) // lpcszPath = NULL, lpcszFilename = NULL, lpcszDialogName = NULL
{
	//------------------- GJL v7.0357 QA70-4078 3/17/03 ORIGINC_MULTI_OPEN_SUPPORT
	StringArray saFilePaths;
	GetFileDialogBox( saFilePaths, saFiletypes, FDLOG_TYPE_SAVE_AS, lpcszPath, lpcszFilename, lpcszDialogName );
	return saFilePaths[0];
	//return GetFileDialogBox( saFiletypes, TRUE, lpcszPath, lpcszFilename, lpcszDialogName );
	//------------------- QA70-4078
}

/**
		An FDLog.UseGroup version of GetSaveAsBox that uses an enumerated FDLog.UseGroup
		code to indicate the set of file types to list. See sys_utils.h or the Origin.ini
		file for a list of the enumerated FDLOG.UseGroup codes.
	Example:
		string strPath;
		strPath = GetSaveAsBox( FDLOG_ORIGIN ); // or
		//strPath = GetSaveAsBox( FDLOG_EXCEL, "C:\\Program Files\\" ); // or
		//strPath = GetSaveAsBox( FDLOG_ASCII, "C:\\Program Files\\", "Origin" ); // or
		//strPath = GetSaveAsBox( FDLOG_SCRIPT, "C:\\Program Files\\", "Origin", "SaveAsOGS" );
		if( strPath.IsEmpty() )
			out_str( "User has cancelled the SaveAs dialog box." );
		else
			printf( "The file chosen is %s\n.", strPath );
	Parameters:
		nFDLogUseGroup=A LabTalk FDLog.UseGroup code as enumerated in sys_utils.h and in
			the Origin.ini file
		lpcszPath=Initial path when dialog opens, default NULL uses FDLog tracking
		lpcszFileName=Initial filename when dialog opens, default NULL uses an empty string
		lpcszDialogName=Title of the dialog box, default NULL uses "SaveAs"
	Return:
		Returns the path and filename of a selected file or an empty string if Cancel button
		in dialog box is clicked.
*/
string GetSaveAsBox( FDLogUseGroup nFDLogUseGroup, LPCSTR lpcszPath, LPCSTR lpcszFilename,
	 LPCSTR lpcszDialogName ) // lpcszPath = NULL, lpcszFilename = NULL, lpcszDialogName = NULL
{
	//------------------- GJL v7.0357 QA70-4078 3/17/03 ORIGINC_MULTI_OPEN_SUPPORT
	StringArray saFilePaths;	
	GetFileDialogBox( saFilePaths, nFDLogUseGroup, FDLOG_TYPE_SAVE_AS, lpcszPath, lpcszFilename, lpcszDialogName );
	return saFilePaths[0];
	//return GetFileDialogBox( nFDLogUseGroup, TRUE, lpcszPath, lpcszFilename, lpcszDialogName );
	//------------------- QA70-4078
}

//////////////////////////////////////////////////////////////////////////////////
/**
		An easier to use version of GetSaveAsBox that works for a single file type.
	Example:
		string strPath;
		strPath = GetSaveAsBox(); // or
		//strPath = GetSaveAsBox( "[Old version (*.ORG)] *.ORG" ); // or
		//strPath = GetSaveAsBox( "*.OPJ"); // or
		//strPath = GetSaveAsBox( "*.ocw Workspace", GetAppPath() + "OriginC\\" ); // or
		//strPath = GetSaveAsBox( "*.ocw Workspace", GetAppPath() + "OriginC\\", "Origin" ); // or
		//strPath = GetSaveAsBox( "*.ocw Workspace", "C:\\Program Files\\", "Origin", "SaveAs Workspace" );
		if( strPath.IsEmpty() )
			out_str( "User has cancelled the SaveAs dialog box." );
		else
			printf( "The file chosen is %s\n.", strPath );
	Parameters:
		lpcszFileType="*.ext description", or "[decription (*.ext)] *.ext", or just "*.ext"
		lpcszPath=Initial path when dialog opens, default NULL uses FDLog tracking
		lpcszFileName=Initial filename when dialog opens, default NULL uses an empty string
		lpcszDialogName=Title of the dialog box, default NULL uses "SaveAs"
	Return:
		Returns the path and filename of a selecetd file or an empty string if Cancel button
		in dialog box is clicked.
*/
string GetSaveAsBox( LPCSTR lpcszFileType, LPCSTR lpcszPath, LPCSTR lpcszFilename,
	 LPCSTR lpcszDialogName ) // lpcszFileType = "*.* All Files", lpcszPath = NULL, lpcszFileName = NULL, lpcszDialogName = NULL
{
	//------------------- GJL v7.0357 QA70-4078 3/17/03 ORIGINC_MULTI_OPEN_SUPPORT
	StringArray saFilePaths;	
	GetFileDialogBox( saFilePaths, lpcszFileType, FDLOG_TYPE_SAVE_AS, lpcszPath, lpcszFilename, lpcszDialogName );
	return saFilePaths[0];
	//return GetFileDialogBox( lpcszFileType, TRUE, lpcszPath, lpcszFilename, lpcszDialogName );
	//------------------- QA70-4078
}

/////////////////////////////////////////////////////////////////
// These functions make it easy to put complex expression together
/////////////////////////////////////////////////////////////////
//---- CPY 2/3/03 we have decided to change to use Macros so that Re(aa)=1 can be used
//
//double Re(complex cc)
//{
//	return cc.m_re;
//}
//double Im(complex cc)
//{
//	return cc.m_im;
//}
//----
complex Conj(complex cc)
{
	return cc.Conjugate();
}

/** >Character/String Manipulation
		Converts string to a complex. If the input cannot be converted to a value of complex. The return value is undefined.
		The function stops reading the input string at the first character that it cannot recognize as part of a number. 
		This character may be the null character ('\0') terminating the string.
	Parameter:
		lpcsz = the string to convert.
	Return:
		a complex
	Example:
		void	run_atof()
		{
			char	szString[] = " -4.05 - 3.007i";
			complex	c = atof(szString);
			out_complex("value = ", c);
		}
*/
#define IS_INTRODUCTORY_LETTER(_cc) ( (_cc) == 'e' || (_cc) == 'E' || (_cc) == 'd' || (_cc) == 'D' )
#define IS_PLUS_OR_MINUS(_cc) ( (_cc) == '-' || (_cc) == '+' )

complex atoc(LPCSTR lpcsz)
{
	complex c;

	string str(lpcsz);
	str.TrimRight();
	str.TrimLeft();
	
	int nLength = str.GetLength();
	if( nLength <= 0 )
		return c;
	
	LPSTR lpstr = str.GetBuffer(nLength + 1);
	LPSTR lpc = lpstr + nLength - 1;
	
	if( 'i' == *lpc )
	{
		*lpc = '\0';
		
		// Find operator '+' or '-'
		while( lpc > lpstr )
		{
			// if not an exponent sign
			if( IS_PLUS_OR_MINUS(*lpc) && !IS_INTRODUCTORY_LETTER(*(lpc - 1)) )
				break; // we found the operator
			lpc--;
		}
		
		// Get the imaginary part
		LPSTR lpIm;
		if( lpc == lpstr )
			lpIm = lpc;
		else
			lpIm = (lpc + 1);
		
		string strIm(lpIm);
		strIm.TrimRight();
		strIm.TrimLeft();
		
		if( IS_PLUS_OR_MINUS(*lpc) )
			strIm.Insert(0, *lpc);

		if( (c.m_im = atof(strIm)) == 0.0 )
			c.m_im = 1; // If only 'i' in the imaginary part

		*lpc = '\0';
	}
	
	// Get the real part
	c.m_re = atof(lpstr);
	str.ReleaseBuffer(nLength);
	
	return c;
}

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

// this function is added because LabTalk has both rnd and ran, so we allow
// the same in Origin C
double ran(int nSeed)
{
	return rnd(nSeed);
}

//////////////////////////////////////////////////////////////////////////////////
/** >System
		Get the text data copied onto the clipboard.
	Example:
		string strClipboardText;
		BOOL bSuccess;
		bSuccess = GetClipboardText( strClipboardText );
		if( bSuccess )
			out_str( strClipboardText );
		else
			out_str( "Error reading Clipboard or Clipboard is empty." );
	Parameters:
		strData = Output text copied from clipboard
	Return:
		Returns TRUE and a string containing text copied onto the clipboard
		on success or returns FALSE and an empty string on failure or if
		the Clipboard is empty.
*/
BOOL GetClipboardText( string& strData )
{
	BOOL bRet = FALSE;                                        // Declare and intitialize variables                                             
	strData = "";
	
	if( OpenClipboard(NULL) )                                 // If the clipboard opens successflly...
	{
		if( IsClipboardFormatAvailable( CF_TEXT ) )           // If the clipboard contains text data...
		{
			HANDLE hData = GetClipboardData( CF_TEXT );       // Get text data from clipboard
			if( hData )                                       // If handle to clipboard good...
			{
				LPCSTR lpData = (LPCSTR) GlobalLock( hData ); // Lock clipboard
				if( lpData )                                  // If lock successful...
				{
					strData = lpData;                         // Put clipboard data in string
					bRet = TRUE;                              // Tell user about success!
					GlobalUnlock( hData );                    // Unlock clipboard
				}
			}
		}
		CloseClipboard();                                     // Close the clipboard
	}

	return bRet;                                              // Return, strData contains clipboard text
}


//construct a temporary file name in the Windows Temp path
BOOL GetTempFileName(string &strFile, LPCSTR lpcszPrefix)// = NULL)
{
	char sz[MAXFULLPATH];
	/// SY 09-12-2003 QA70-5158 v7.0694 OC_NEED_ROBUST_GET_TEMP_PATH_FUNCTION
	///	DWORD dw = GetTempPath(MAXFULLPATH, sz);
	///	if( dw )
	DWORD dw = get_temp_path(sz, MAXFULLPATH);
	if( 2 != dw )
	/// end OC_NEED_ROBUST_GET_TEMP_PATH_FUNCTION
	{
		strFile = sz;
		string strSignature = lpcszPrefix==NULL? "OTF" : lpcszPrefix;
		
		dw = GetTempFileName(strFile, strSignature, 0, sz);
		if( dw )
		{
			strFile = sz;
			return TRUE;
		}
	}
	return FALSE;
}

/**
		Get the file modification date of a file from an input string containing
		a path and filename.
	Example:
		string strFileDate, strDataFile = "C:\\Origin80\\Origin.ini";
		strFileDate = auGetFileSize(strDataFile);
	Parameters:
		lpcstrPathAndFilename=Input string containing a path and filename with filetype extension
	Return:
		Returns a Windows like file modification date formatted for display. 
*/
string GetFileModificationDate(LPCSTR lpcstrPathAndFilename, WORD wFormat)
{
	string strFileModDate;
	
	WIN32_FILE_ATTRIBUTE_DATA fileInfo;
	if( GetFileAttributesEx(lpcstrPathAndFilename, 0, &fileInfo) )
	{
		FILETIME localFileTime;
		if( FileTimeToLocalFileTime(&fileInfo.ftLastWriteTime, &localFileTime) )
		{
			SYSTEMTIME sysTime;
			if( FileTimeToSystemTime(&localFileTime, &sysTime) )
			{
				LPSTR lpstr = strFileModDate.GetBuffer(MAXFULLPATH);
				if( lpstr )
				{
					systemtime_to_date_str(&sysTime, lpstr, wFormat);
					strFileModDate.ReleaseBuffer();
				}
			}
		}
	}

	return strFileModDate;
}


/**
	List all files of a specified file type found in a folder

Example:
	string strExePath = GetAppPath();
	StringArray saResult;
	FindFiles(saResult, strExePath, "otw");
	
Parameters:
	saResult = the referrence of string array will receive the finding results
	lpcszPath = the file path to search for files
	bCheckExist = true will check the given saReult to see if the file is already in that array
Return:
	Returns TRUE for success, otherwise failure.
*/	
BOOL FindFiles(StringArray& saResult, LPCSTR lpcszPath, LPCSTR lpcszExt, bool bCheckExist)// = false);
{	
	WIN32_FIND_DATAA FileData;
	string strFilePath = lpcszPath;
	string strFileExt = lpcszExt;
	
	if(strFileExt.IsEmpty())
		strFileExt = "*.*";
	else
	{
		if(strFileExt[0] != '*')
		{
			if(strFileExt[0] == '.')
				strFileExt = "*" + strFileExt;
			else	
				strFileExt = "*." + strFileExt;
		}
	}
			
		
	HANDLE hFind = FindFirstFile( strFilePath + strFileExt, &FileData);

	if(INVALID_HANDLE_VALUE != hFind)
	{
		saResult.Add(FileData.cFileName); // the first file name found
		
		int ii; 
		// start the loop
		while(FindNextFile(hFind, &FileData)) 
		{ 
			bool bExist = false; // may need to determin the string existed in the array or not
			if(bCheckExist)
			{
				for(ii = 0; ii < saResult.GetSize(); ii++)
				{				
					if( 0 == saResult[ii].CompareNoCase(FileData.cFileName))
						bExist = true;
				}
			}
	
			if(!bExist)
				saResult.Add(FileData.cFileName);
		}

		FindClose(hFind);	
		return TRUE;
	}
	return FALSE;
}

BOOL SetFileToCurrentTime(LPCSTR lpcszFilename)
{
	BOOL bRet = FALSE;
	HANDLE hFile = CreateFile(lpcszFilename, GENERIC_WRITE, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
	if (hFile != INVALID_HANDLE_VALUE)
	{
		FILETIME ft;
		SYSTEMTIME st;
		GetSystemTime(&st);              // gets current time
		SystemTimeToFileTime(&st, &ft);  // converts to file time format
		bRet = SetFileTime(hFile,NULL, NULL, &ft);
		CloseHandle(hFile);
	}
	return bRet;
}

/** >File Management
	Copy file and also set destination file's attribute
Example:
Parameters:
	lpcszSrc = [in] Pointer to a null-terminated string that specifies the name of an existing file. 
	lpcszDest =	[in] Pointer to a null-terminated string that specifies the name of the new file. 
	dwAttribute = the file attribute to set on the new file lpcszDest
	bSetCurrentTime = set the destination file to the current time or not
Return:
	Returns TRUE for success, otherwise failure.
Remark:
	This function will call CopyFile with default bFailIfExists = FALSE
*/
BOOL FileCopy(LPCSTR lpcszSrc, LPCSTR lpcszDest, DWORD dwAttribute, bool bSetCurrentTime)// = FILE_ATTRIBUTE_NORMAL, true);
{
	if(CopyFile(lpcszSrc, lpcszDest))
	{
		SetFileAttributes(lpcszDest, dwAttribute);
		if(bSetCurrentTime)
		{
			SetFileToCurrentTime(lpcszDest);
		}
		return TRUE;
	}
	return FALSE;
}

// export a page to an image using settings from a tree node
bool export_page(Page &pg, LPCSTR lpcszFileName, const TreeNode &trExport)
{
	// get image format
	string str = trExport.tagName;
	
	// backup ini settings
	Tree trIniSettings;
	tree_read_image_export_settings(trIniSettings, str);

	// write tree settings to ini
	tree_write_image_export_settings(trExport, str);
	
	// export page to image
	bool bRet = export_page_to_image(pg, lpcszFileName, str, false);
	
	// restore ini settings
	tree_write_image_export_settings(trIniSettings, str, true);

	return bRet;
}

// export a page to an image using the page's export settings
bool export_page(Page &pg, LPCSTR lpcszFileName, LPCSTR lpcszFormat)
{
	Tree trIniSettings;
	bool bPageSettings = false;

	// get page settings
	Tree trPageSettings;
	if( tree_get_page_image_export_settings(trPageSettings, pg, lpcszFormat) )
	{
		bPageSettings = true;

		// backup ini settings
		tree_read_image_export_settings(trIniSettings, lpcszFormat);

		// write page settings to ini
		tree_write_image_export_settings(trPageSettings, lpcszFormat);
	}
	
	// export page to image
	bool bRet = export_page_to_image(pg, lpcszFileName, lpcszFormat, false);

	if( bPageSettings )
	{
		// restore ini settings
		tree_write_image_export_settings(trIniSettings, lpcszFormat, true);
	}
	
	return bRet;
}

// export a page to an image using current ini settings or prompt user with export options
bool export_page_to_image(Page &pg, LPCSTR lpcszFileName, LPCSTR lpcszFormat, BOOL bShowOptions)
{
	if( EXIST_PLOT != pg.GetType() && EXIST_LAYOUT != pg.GetType() )
		return false; // invalid page type
	string str;
	str.Format("Image.ShowOptions=%d;Image.FileName$=%s;", bShowOptions, lpcszFileName);
	pg.LT_execute(str);

	// LabTalk's Image.Export.PageDPI arguments:
	// 1  File format extension (str)
	// 2  dots per inch (int)
	// 3  bits per pixel (int)
	// 4  compression (int)
	/// EJP 11-20-2003 v7.5764 QA70-5587 FAIL_TO_EXPORT_1200DPI_BITMAP
	///str.Format("Image.Export.PageDPI(%s);", lpcszFormat);
	str.Format("imgexp = Image.Export.PageDPI(%s);", lpcszFormat);
	/// end FAIL_TO_EXPORT_1200DPI_BITMAP
	if( !pg.LT_execute(str) )
		return false;

	return true;
}

// export a page to an image using the specified settings
bool export_page_to_image(LPCSTR lpcszFileName, LPCSTR lpcszFormat, Page &pg, int nWidth, int nHeight, int nBitsPerPixel, int nCompression)
{
	if( EXIST_PLOT != pg.GetType() && EXIST_LAYOUT != pg.GetType() )
		return false; // invalid page type
	
	string str;
	str.Format("Image.ShowOptions=0;Image.FileName$=%s;", lpcszFileName);
	if( !pg.LT_execute(str) )
		return false;
	
	if( 0 == nHeight ) // height not specified, use width as DPI
		str.Format("Image.Export.PageDPI(%s, %d, %d, %d);", lpcszFormat, nWidth, nBitsPerPixel, nCompression);	
	else
		str.Format("Image.Export.PagePixel(%s, %d, %d, %d, %d);", lpcszFormat, nWidth, nHeight, nBitsPerPixel, nCompression);	
	return pg.LT_execute(str) ? true : false;
}

//------------------- GJL v7.0357 QA70-4078 3/17/03 ORIGINC_MULTI_OPEN_SUPPORT
//////////////////////////////////////////////////////////////////////////////////
/**
		Open an FDLog Open dialog box passing the file types to list in an array
		of strings. Optionally uses a simple Open dialog with multiple selection
		enabled or a Multi-Open dialog box.
	Example:
		int iNumSelFiles;
		string strPath;
		StringArray saFiletypes, saFilePaths;
		saFiletypes.SetSize( 3 );
		saFiletypes[0]="[Project (*.OPJ)] *.OPJ";
		saFiletypes[1]="[Old version (*.ORG)] *.ORG";
		saFiletypes[2]="[Worksheets (*.OGW)] *.OGW";
		iNumSelFiles = GetMultiOpenBox( saFilePaths, saFiletypes ); // or
		iNumSelFiles = GetMultiOpenBox( saFilePaths, saFiletypes, "C:\\Program Files\\" ); // or
		iNumSelFiles = GetMultiOpenBox( saFilePaths, saFiletypes, "C:\\Program Files\\", "Origin" ); // or
		iNumSelFiles = GetMultiOpenBox( saFilePaths, saFiletypes, "C:\\Program Files\\", "Origin", "OpenOPJ" ); // or
		iNumSelFiles = GetMultiOpenBox( saFilePaths, saFiletypes, "C:\\Program Files\\", "Origin", "OpenOPJ", true );
	Parameters:
		saFilePaths=Output vector of strings containing path and filename of all selected files
		saFiletypes=Input vector containing file types to list in the dialog box, each element
			of vector must follow syntax of LabTalk FDLog.TypeN$ object property
		lpcszPath=Input initial path when dialog opens, default NULL uses FDLog tracking
		lpcszFileName=Input initial filename when dialog opens, default NULL uses an empty string 
		lpcszDialogName=Input title of the dialog box, default NULL uses "Open"
		bMultiSelection=Input flag specifiying to use multi-selection Open (default true) or Multi-Open (false) dialog box
	Return:
		Returns the path and filename of all selected files or an empty string if Cancel button
		in dialog box is clicked. Also returns the number of files selected.
*/
int GetMultiOpenBox( StringArray& saFilePaths, StringArray &saFiletypes, LPCSTR lpcszPath, LPCSTR lpcszFilename,
	 LPCSTR lpcszDialogName, bool bMultiSelection ) // lpcszPath = NULL, lpcszFilename = NULL, lpcszDialogName = NULL, bMultiSelection = true
{
	if( bMultiSelection )
		return GetFileDialogBox( saFilePaths, saFiletypes, FDLOG_TYPE_OPEN_MULTISEL, lpcszPath, lpcszFilename, lpcszDialogName );
	else
		return GetFileDialogBox( saFilePaths, saFiletypes, FDLOG_TYPE_MULTI_OPEN, lpcszPath, lpcszFilename, lpcszDialogName );
}

/**
		An FDLog.UseGroup version of GetMultiOpenBox that uses an enumerated FDLog.UseGroup
		code to indicate the set of file types to list. See sys_utils.h or the Origin.ini
		file for a list of the enumerated FDLOG.UseGroup codes. Optionally uses a simple
		Open dialog with multiple selection enabled or a Multi-Open dialog box.
	Example:
		int iNumFiles;
		StringArray saFilePaths;
		iNumFiles = GetMultiOpenBox( saFilePaths, FDLOG_ORIGIN ); // or
		iNumFiles = GetMultiOpenBox( saFilePaths, FDLOG_EXCEL, "C:\\Program Files\\" ); // or
		iNumFiles = GetMultiOpenBox( saFilePaths, FDLOG_ASCII, "C:\\Program Files\\", "Origin" ); // or
		iNumFiles = GetMultiOpenBox( saFilePaths, FDLOG_SCRIPT, "C:\\Program Files\\", "Origin", "OpenOGS" );
		iNumFiles = GetMultiOpenBox( saFilePaths, FDLOG_SCRIPT, "C:\\Program Files\\", "Origin", "OpenOGS", false );
	Parameters:
		saFilePaths=Output vector of strings containing path and filename of all selected files
		nFDLogUseGroup=Input LabTalk FDLog.UseGroup code as enumerated in sys_utils.h and in
			the Origin.ini file
		lpcszPath=Input initial path when dialog opens, default NULL uses FDLog tracking
		lpcszFileName=Input initial filename when dialog opens, default NULL uses an empty string 
		lpcszDialogName=Input title of the dialog box, default NULL uses "Open"
		bMultiSelection=Input flag specifiying to use multi-selection Open (default true) or Multi-Open (false) dialog box
	Return:
		Returns the path and filename of all selected files or an empty string if Cancel button
		in dialog box is clicked. Also returns the number of files selected.
*/
int GetMultiOpenBox( StringArray& saFilePaths, FDLogUseGroup nFDLogUseGroup, LPCSTR lpcszPath, LPCSTR lpcszFilename,
	 LPCSTR lpcszDialogName, bool bMultiSelection ) // lpcszPath = NULL, lpcszFilename = NULL, lpcszDialogName = NULL, bMultiSelection = true
{
	if( bMultiSelection )
		return GetFileDialogBox( saFilePaths, nFDLogUseGroup, FDLOG_TYPE_OPEN_MULTISEL, lpcszPath, lpcszFilename, lpcszDialogName );
	else
		return GetFileDialogBox( saFilePaths, nFDLogUseGroup, FDLOG_TYPE_MULTI_OPEN, lpcszPath, lpcszFilename, lpcszDialogName );
}

//////////////////////////////////////////////////////////////////////////////////
/**
		An easier to use version of GetMultiOpenBox that works for a single file type.
		Optionally uses a simple Open dialog with multiple selection enabled or a
		Multi-Open dialog box.
	Example:
		int iNumFiles;
		StringArray saFilePaths;
		iNumFiles = GetMultiOpenBox(saFilePaths); // or
		iNumFiles = GetMultiOpenBox( saFilePaths, "[Old version (*.ORG)] *.ORG" ); // or
		iNumFiles = GetMultiOpenBox( saFilePaths, "*.OPJ"); // or
		iNumFiles = GetMultiOpenBox( saFilePaths, "*.ocw Workspace", GetAppPath() + "OriginC\\" ); // or
		iNumFiles = GetMultiOpenBox( saFilePaths, "*.ocw Workspace", GetAppPath() + "OriginC\\", "Origin" ); // or
		iNumFiles = GetMultiOpenBox( saFilePaths, "*.ocw Workspace", "C:\\Program Files\\", "Origin", "Open Workspace", false );
	Parameters:
		saFilePaths=Output vector of strings containing path and filename of all selected files
		lpcszFileType=Input file type string like "*.ext description", "[decription (*.ext)] *.ext", or just "*.ext"
		lpcszPath=Input initial path when dialog opens, default NULL uses FDLog tracking
		lpcszFileName=Input initial filename when dialog opens, default NULL uses an empty string 
		lpcszDialogName=Input title of the dialog box, default NULL uses "Open"
		bMultiSelection=Input flag specifiying to use multi-selection Open (default true) or Multi-Open (false) dialog box
	Return:
		Returns the path and filename of all selected files or an empty string if Cancel button
		in dialog box is clicked. Also returns the number of files selected.
*/
int GetMultiOpenBox( StringArray& saFilePaths, LPCSTR lpcszFileType, LPCSTR lpcszPath, LPCSTR lpcszFilename,
	 LPCSTR lpcszDialogName, bool bMultiSelection ) // lpcszFileType = "*.* All Files", lpcszPath = NULL, lpcszFileName = NULL, lpcszDialogName = NULL, bMultiSelection = true
{
	if( bMultiSelection )
		return GetFileDialogBox( saFilePaths, lpcszFileType, FDLOG_TYPE_OPEN_MULTISEL, lpcszPath, lpcszFilename, lpcszDialogName );
	else
		return GetFileDialogBox( saFilePaths, lpcszFileType, FDLOG_TYPE_MULTI_OPEN, lpcszPath, lpcszFilename, lpcszDialogName );
}
//------------------- QA70-4078

/**
		Compute a LabTalk (1 based) index from a C (0 based) index and add an offset.
	Parameters:
		iCindex=Input 0 based C index
		nOffset=Input offset, default is 0
	Return:
		Returns a LabTalk 1 based index with added offset.
*/
int c_index_to_labtalk_index(int iCindex, int nOffset) // nOffset = 0
{
	return iCindex + 1 + nOffset;	
}

/**
		Compute a C (0 based) index from a LabTalk (1 based) index and add an offset.
	Parameters:
		iLTindex=Input 1 based LabTalk index
		nOffset=Input offset, default is 0
	Return:
		Returns a C 0 based index with added offset.
*/
int labtalk_index_to_c_index(int iLTindex, int nOffset) // nOffset = 0
{
	return iLTindex - 1 + nOffset;
}


int ExportActiveGraphPageToImage()
{
	PageBase pbActive;
	pbActive = Project.Pages();
	if( EXIST_PLOT != pbActive.GetType() && EXIST_LAYOUT != pbActive.GetType() )
		return 1; // invalid page type
	string strPgName = pbActive.GetName();
	
	using FDlog = LabTalk.FDLog;
	using Image = LabTalk.Image;

	FDLogInit(); // call sys_utils func		

	FDlog.CheckName$ = SHOW_EXPORT_OPTIONS;
	FDlog.CheckStatus = Image.ShowOptions;
	FDlog.Default$ = strPgName;
	FDlog.UseGroup("Image");
	Image.GetExtList("z","e");

	char szUseType[MAX_PATH];
	if( !LT_get_str( "%z", szUseType, sizeof(szUseType) ) )
		return 1;
	FDlog.UseType(szUseType);

	if( FDlog.SaveAs("a") )
		return 1; // user canceled or error

	string strFileName;
	strFileName.Format("%s%s", FDlog.Path$, FDlog.Default$);

	bool bShowOptions = (FDlog.CheckStatus ? true : false);
	
	Page pg(strPgName);
	if( !export_page_to_image(pg, strFileName, FDlog.DefTypeExt$, bShowOptions) )
	{
		/// EJP 11-20-2003 v7.5764 QA70-5587 FAIL_TO_EXPORT_1200DPI_BITMAP
		double dErr;
		if( LT_get_var("imgexp", &dErr) )
			ImageExportErrorMessageBox((int)dErr);
		/// end FAIL_TO_EXPORT_1200DPI_BITMAP
		return 1;
	}

	// Copy export settings into page.info
	Tree trSettings;
	if( !tree_read_image_export_settings(trSettings, FDlog.DefTypeExt$) )
		return 1;
	if( !tree_set_page_image_export_settings(trSettings, pg, FDlog.DefTypeExt$) )
		return 1;
	return 0;
}

/// EJP 11-20-2003 v7.5764 QA70-5587 FAIL_TO_EXPORT_1200DPI_BITMAP
int ImageExportErrorMessageBox(int iErr)
{
	string strFormat = _L("Error %d\n%s");
	string strDescrip;
	switch( iErr )
	{
	case 301: // OERR_ORIGIN_INTERNAL_BMP
		strDescrip = _L("Internal bitmap error");
		break;
	case 302: // OERR_ORIGIN_CREATE_BMP_FILE
		strDescrip = _L("Error creating bitmap file");
		break;
	case 309: // OERR_ORIGIN_INTERNAL_BMP_COLOR_DEPTH
		strDescrip = _L("Internal bitmap color depth error");
		break;
	}

	string strMsg;
	strMsg.Format(strFormat, iErr, strDescrip);
	MessageBox(GetWindow(), strMsg, _L("Origin Image Export"));
	return iErr;
}
/// end FAIL_TO_EXPORT_1200DPI_BITMAP

#define IS_CHAR_LETTER(_ch)		(('A' <= (_ch) && (_ch) <= 'Z') || ('a' <= (_ch) && (_ch) <= 'z'))
#define IS_CHAR_NUMBER(_ch)		('0' <= (_ch) && (_ch) <= '9')
bool validate_identifier_name(string &strName)
{
	/// JCG 06/17/03 QA70-4575 IMP_WIZD_BUG_45_AND_28
	/// if( !IS_CHAR_LETTER(strName[0]) && strName[0] != '_' )
	///	strName.Delete(0);
	//
	// when scan header lines, the identifier name can be only a number such "1"
	// so shouldn't remove it, otherwise, this line can not be scanned.
	if( !IS_CHAR_LETTER(strName[0]) && strName[0] != '_' )
	{
		if( strName.GetLength() > 1 ) // keep it if only a number
			strName.Delete(0);
	}
	/// end IMP_WIZD_BUG_45_AND_28
	int n = 0;
	while( n < strName.GetLength() )
	{
		if( IS_CHAR_LETTER(strName[n]) || IS_CHAR_NUMBER(strName[n]) || '_' == strName[n] )
			n++;
		else
			strName.Delete(n);
	}
	return true;
}


/**
		Makes sure that a Note window with the name strNoteWnd exists. If not, it will be created
		and given that name. If strNoteWnd is empty, it will just create a new Note window.  
	Example:
	Parameters:
		lpcszName=the Note window name
	Return:
		Returns TRUE if OK, otherwise FALSE.
*/
bool	get_create_Note(string &strNoteWnd)
{
	BOOL		bDone = FALSE;
	if (!strNoteWnd.IsEmpty())	// specified?
	{
		Note		nt(strNoteWnd);
		if (nt)
		{
			return true;
		}
	}
	
	// does not exist, must be created:
	Note		ntNew;
	if (ntNew.Create())
	{
		if (!strNoteWnd.IsEmpty())
			ntNew.Rename(strNoteWnd);
		
		strNoteWnd = ntNew.GetName();
	}
	else
		return false;

	return true;
}


BOOL	worksheets_are_same(Worksheet &wks1, Worksheet &wks2)
{
	if (!wks1 || !wks2)
		return FALSE;	// one not attached consider the different
	
	WorksheetPage	wp1;
	wks1.GetParent(wp1);
	
	WorksheetPage	wp2;
	wks2.GetParent(wp2);
	
	if (!wp1 || !wp2)
		return FALSE;
	
	string		strName1 = wp1.GetName();
	string		strName2 = wp2.GetName();
	
	BOOL		bSame = strName1.CompareNoCase(strName2) == 0;
	
	return bSame;
}

/// EJP 07-10-2003 v7.0622 QA70-4745 SET_PAGE_IMPORT_INFO_ON_123_ASC_IMPORT
BOOL set_page_import_info(Page &pgTarget, LPCSTR lpcszFile, int iDataType)
{
	if( !pgTarget )
		return FALSE;
	
	// file date
	double dJulianDate = 0.0;
	WIN32_FILE_ATTRIBUTE_DATA fad;
	if( GetFileAttributesEx(lpcszFile, 0, &fad) )
	{
		SYSTEMTIME st;
		if( FileTimeToSystemTime(&fad.ftLastWriteTime, &st) )
			SystemTimeToJulianDate(&dJulianDate, &st);
	}
	pgTarget.Info.System.Import.FileDate = dJulianDate;

	pgTarget.Info.System.Import.FileName$ = GetFileName(lpcszFile);
	pgTarget.Info.System.Import.FilePath$ = lpcszFile;
	pgTarget.Info.System.Import.Filter$ = ""; // filter file unknown
	pgTarget.Info.System.Import.FileType = iDataType;
	return TRUE;
}
/// end SET_PAGE_IMPORT_INFO_ON_123_ASC_IMPORT

//--------------------------------------------------------- CPY 8/12/03 QA70-4999
bool add_file_extension(string& strFilename, LPCSTR lpcszExt)
{
	LPSTR lpstr = strFilename.GetBuffer(MAXFULLPATH);
	char	szTemp[20];// file ext only 3 chars
	bool	bRet = false;
	if(check_add_file_ext(lpstr, NULL, szTemp) || lstrcmpi(szTemp, lpcszExt) != 0) // NO file extension, or is diff
	{
		lstrcat(lpstr, ".");
		lstrcat(lpstr, lpcszExt);
		bRet = true;
	}
	strFilename.ReleaseBuffer();
	return bRet;
}
//---------------------------------------------------------

string get_system_font_name(int nType, int* lpnCharSet) // = ANSI_VAR_FONT, NULL);
{
	int nFontSize;
	byte nCharSet = ANSI_CHARSET;
	
	string str;
	char	szTemp[LF_FACESIZE + 1];
	if(get_system_font_info(nType, &nFontSize, &nCharSet, szTemp, LF_FACESIZE))
		str = szTemp;
	if(lpnCharSet)
		*lpnCharSet = nCharSet;
	
	return str;
}

bool is_win2k(bool bAndLater) // true
{
	DWORD	dwVersion = GetVersion();
	// Get major and minor version numbers of Windows
	WORD loword = LOWORD(dwVersion);
	int lowbyte = LOBYTE(loword);
	int hibyte =  HIBYTE(loword);
	if(!(dwVersion & 0x80000000))                // Windows NT, 2000, XP
	{
		if(bAndLater)
			return lowbyte >= 5? true:false;
		
		return (5 == lowbyte && 0 == hibyte)? true:false;
	}
	// Windows 95, 98, ME
	return false;
}

static void separate_file_name_ext(string& strFileName, string& strExt)
{
	char	szExt[20];// file ext only 3 chars
	char	szTemp[MAXFULLPATH];
	lstrcpyn(szTemp, strFileName, MAXFULLPATH);
	if(check_add_file_ext(szTemp, NULL, szExt))
		strExt.Empty();
	else
	{
		strExt = szExt;
		int nExtLen = strExt.GetLength();
		strFileName.Delete(strFileName.GetLength() - nExtLen-1, nExtLen+1);
	}
}

//Check to find the strPathFilename that does not already exist 
bool get_next_file_name(string& strPathFilename, bool bCheckCreatePath) /// = true
{
	string strPath = GetFilePath(strPathFilename);
	if(bCheckCreatePath && !CheckMakePath(strPath))
		return false;

	if(!bCheckCreatePath && !strPath.IsPath())
		return false;
	
	string strFilename = GetFileName(strPathFilename);
	string strExt;
	separate_file_name_ext(strFilename, strExt);
	int nn = 1;
	while(strPathFilename.IsFile())
	{
		string strTemp = strPath + strFilename + (nn++);
		if(!strExt.IsEmpty())
			strTemp += "." + strExt;
		strPathFilename = strTemp;
	}
	return true;
}

bool is_str_valid_for_filename(LPCSTR lpcszFilename)
{
	string strPath = GetFilePath(lpcszFilename);
	if(!strPath.IsEmpty())
		return false;
	//IsFile seems not able to handle filename with * and ?, so better check first
	string strTest = lpcszFilename;
	if(strTest.IsEmpty() || strTest.Find('*') >=0 || strTest.Find('?') >= 0)
		return false;
	
	char szTempPath[MAXFULLPATH];
	DWORD dw = GetTempPath(MAXFULLPATH, szTempPath);
	if( dw )
	{
		strTest = szTempPath;
		strTest += lpcszFilename;
		if(strTest.IsFile())
			return true; // already existed in temp folder, must be good filename
		
		// not a file in temp folder, safe to create and delete
		HANDLE hFile = CreateFile(strTest,GENERIC_READ, FILE_SHARE_READ,// share for reading
						NULL,                      // no security
						CREATE_NEW,             // new file only
						FILE_ATTRIBUTE_NORMAL,     // normal file
						NULL);                     // no attr. template
		if (hFile == INVALID_HANDLE_VALUE)
			return false;
		CloseHandle(hFile);// must close file after reading	
		DeleteFile(strTest);
		return true;
	}
	return false;
}

// for used in LatTalk to access to this path
// example:
// get_project_attached_files_path %A;
// %Z=%Atest.dat; 
bool get_project_attached_files_path(string& strPath)
{
	strPath = GetProjectAttachedFilesPath();
	return strPath.IsEmpty()? false:true;
}

string	BuildBitwiseORSeparatedString(vector<string> &vInput)
{
	string		str;
	int			nSize = vInput.GetSize();
	for (int ii = 0; ii < nSize; ii++)
	{
		string		strTemp = vInput[ii];
		str += strTemp;
		if (ii < nSize - 1)
			str += "|";
	}
	
	return str;
}


	
	
	
