/*------------------------------------------------------------------------------*
 * File Name: Dlg_Utils.c														*
 * Creation: GJL 10/15/2002														*
 * Purpose: Origin C file containing Dialog Builder Utilities					*
 * Copyright (c) OriginLab Corp.	2002-2007									*
 * All Rights Reserved															*
 *------------------------------------------------------------------------------*/
 
////////////////////////////////////////////////////////////////////////////////////
// Included header files
//////////////////////////////////////////////////////////////////////////////////
//
#include <Origin.h>
//#include <common.h>         // Basic data types
//#include <sys_utils.h> // basic routines implemeted through Origin C, see sys_utils.c
//#include <mswin.h>          // WIN API functions
#include <Dialog.h>         // Dialog class
#include <Tree.h>           // Tree class
#include "Wks_Utils.h"      // Wks_Utils function prototypes and non-localized constants 
#include "App_Utils.h"      // App_Utils function prototypes and non-localized constants 
#include "Dlg_Utils.h"      // Dlg_Utils function prototypes and non-localized constants

/**
		Get the current worksheet/workbook sheet selection as a list of non-contiguous
		ranges and populate the specified Dialog Builder list box with the list. The list
		box name and property must be specified but the function enumerates as needed. This
		function can be used with Dialog Builder list boxes, comboxes, and list controls.
	Example:
		string strMsg;
		// Populate Data Range list box, type out error if problem
		if( PopulateListBoxWithNonContiguousSelection( "StatisticsOn!Tab.Operation.DataLBX" ) )
		{
			strMsg = SO_WKS_DATA_SEL_ERROR_MSG;     // Output error message and return
			strMsg.Write( WRITE_MESSAGE_BOX );
			return FALSE;
		}
	Parameters:
		strListBoxName=Input name of Dialog Builder list box, combox, or list control
		strPropertyName=Input name of Dialog Builder property to set like ".V" or .V2_, default is ".V"
		bAppend=Input option to append new selected ranges in list box (TRUE) or to reset list box and
			populate starting in first row (default FALSE)
		bSelectAll=Input option to select entire worksheet/workbook sheet if there is no selection (TRUE)
			or to return a no selection warning code if there is no selection (default FALSE)
	Return:
		Returns DLG_UTILS_NO_ERROR on success and a DLG_UTILS warning or error code on failure.
*/
int PopulateListBoxWithNonContiguousSelection(LPCSTR lpcstrListBoxName, LPCSTR lpcstrPropertyName, BOOL bAppend, 
	BOOL bSelectAll ) // lpcstrPropertyName = NULL, bAppend = FALSE, bSelectAll = FALSE
{
	string strPropertyName = (lpcstrPropertyName ? lpcstrPropertyName : ".V");
	
	string strCommand, strSelectedRange;
	int ii, iRet, iNumRanges;
	double dNumItems;

	iRet = wuGetNonContiguousWksSelection( strSelectedRange, iNumRanges ); // Get current selection range
	
	if( iRet )                                                             // If no selection or bad selection...
	{
		if( bSelectAll && ( iRet == WKS_UTILS_NO_SEL_WARNING ) )           // If bSelectAll is TRUE and no selection...
			iRet = wuGetNonContiguousWksSelection( strSelectedRange, iNumRanges, TRUE ); // Get entire worksheet/workbook as selected data

		if( iRet )                                                         // Now if no selection or bad selection...
			return iRet;                                                   // Return warning or error code
		else
			MessageBeep( MB_OK );                                          // Else just beep to warn about selecting all
	}

	// *** The remaing code will be replaced using Dialog object once fully supported ***
	if( !bAppend )                                                         // If user does not want to append...
	{
		strCommand.Format( "%s.Reset()", lpcstrListBoxName );                 // Build command to reset list box
		LT_execute( strCommand );                                          // Execute command to reset list box
	}
	
	strCommand.Format( "dNumItems=%s.NumItems", lpcstrListBoxName );          // Build command to get number of items in list box
	LT_execute( strCommand );                                              // Execute command to get number of items in list box
	
	LT_get_var( "dNumItems", &dNumItems );                                 // Get number of items from LabTalk variable
	LT_execute( "delete -v dNumItems" );                                   // Delete LabTalk variable
	
	for( ii = 0; ii < iNumRanges; ii++ )                                   // For each selected range
	{
		strCommand.Format( "%s%s%d$=%s", lpcstrListBoxName, strPropertyName, nint(dNumItems) + ii + 1, strSelectedRange.GetToken( ii, ',' ) );
		LT_execute( strCommand );
	}
	
	return DLG_UTILS_NO_ERROR;
}

/**
		Get the current worksheet/workbook sheet selection range and populate the specified
		Dialog Builder edit box with it. The selection range must be contiguous and the edit
		box name must be specified as an argument.
	Example:
		string strMsg;
		// Populate Weighting edit box, type out error if problem
		if( PopulateEditBoxWithContiguousSelection( "StatisticsOn!Tab.Operation.WeightingEBX" ) )
		{
			strMsg = SO_WKS_WEIGHT_SEL_ERROR_MSG; // Output error message and return
			strMsg.Write( WRITE_MESSAGE_BOX );
			return FALSE;
		}
	Parameters:
		strEditBoxName=Input name of Dialog Builder edit box
		bSelectAll=Input option to select entire worksheet/workbook sheet if there is no selection (TRUE)
			or to return a no selection warning code if there is no selection (default FALSE)
	Return:
		Returns DLG_UTILS_NO_ERROR on success and a DLG_UTILS warning or error code on failure.
*/
int PopulateEditBoxWithContiguousSelection(LPCSTR lpcstrEditBoxName, BOOL bSelectAll) // bSelectAll = FALSE
{
	string strCommand, strSelectedRange;
	int iRet;

	iRet = wuGetContiguousWksSelection( strSelectedRange );                // Get current selection range
	
	if( iRet )                                                             // If no selection or bad selection...
	{
		if( bSelectAll && ( iRet == WKS_UTILS_NO_SEL_WARNING ) )           // If bSelectAll is TRUE and no selection...
			iRet = wuGetContiguousWksSelection( strSelectedRange, TRUE );  // Get entire worksheet/workbook as selected data

		if( iRet )                                                         // Now if no selection or bad selection...
			return iRet;                                                   // Return warning or error code
		else
			MessageBeep( MB_OK );                                          // Else just beep to warn about selecting all
	}
	
	strCommand.Format( "%s.V1$=%s", lpcstrEditBoxName, strSelectedRange ); // Assign selected range to edit box
	LT_execute( strCommand );
	
	return DLG_UTILS_NO_ERROR;
}

/**
		Search a windows folder adding any files that match a specified file filter to a Dialog Builder
		list box. Options specify whether or not subfolders are to be recursively searched and whether
		or not the files are to be appended to or are to replace existing files in the list box. The list
		box name and property must be specified but the function enumerates as needed. This function can
		be used with Dialog Builder list boxes, comboxes, and list controls.
	Example:
		string strPath = GetAppPath() + "Filters\";
		PopulateListBoxWithFilenames( "AIW!Page.Source.Filters", ".V", FALSE, strPath, "*.oaf", 3 );
	Parameters:
		strListBoxName=Input name of Dialog Builder list box, combox, or list control
		strPropertyName=Input name of Dialog Builder property to set like ".V" or .V2_, default is ".V"
		bAppend=Input option to append new selected ranges in list box (TRUE) or to reset list box and
			populate starting in first row (default FALSE)
		strPath=Input path to start searching, default "" is path to Origin ini file  
		strFileFilter=Input file filter which may include DOS wild card characters, default is "*.*"
		bRecursive=Input option to recursively search subfolders, default is FALSE
		wDisplayOptions=Input bitwise flag specifying display options, default value DLG_UTILS_FILE_WITH_PATH
			displays path, filename and filetype, DLG_UTILS_FILE_NO_PATH displays filename and filetype without
			path, DLG_UTILS_FILE_NO_EXT displays path and filename with out filetype extension, and
			DLG_UTILS_FILE_NO_PATH | DLG_UTILS_FILE_NO_EXT displays file name without path or filetype extension
	Return:
		Returns DLG_UTILS_NO_ERROR on success and a DLG_UTILS warning or error code on failure.
*/
int PopulateListBoxWithFilenames(
	LPCSTR lpcstrListBoxName,
	LPCSTR lpcstrPropertyName,
	BOOL bAppend,
	LPCSTR lpcstrPath,
	LPCSTR lpcstrFileFilter,
	BOOL bRecursive,
	UINT wDisplayOptions)
{
	string strPropertyName = (lpcstrPropertyName ? lpcstrPropertyName : ".V");
	string strPath = (lpcstrPath ? lpcstrPath : GetAppPath());
	string strFileFilter = (lpcstrFileFilter ? lpcstrFileFilter : "*.*");

	double dInitChoice;
	string strCommand;                                       
	if( bAppend )                                               // If user wants to append to list box...
	{
		strCommand.Format("dInitChoice=%s.Choice", lpcstrListBoxName); // Build command to get initial list box choice
		LT_execute(strCommand);                                 // Execute command to get initial list box choice
		LT_get_var("dInitChoice", &dInitChoice);                // Get initial list box choice from LabTalk variable
		LT_execute("Delete -v dInitChoice");                    // Delete LabTalk variable
	}
	else                                                        // Else user does not want to append...
	{
		strCommand.Format( "%s.Reset()", lpcstrListBoxName );   // Build command to reset list box
		LT_execute(strCommand);                                 // Execute command to reset list box
		dInitChoice = 1;                                        // Initialize list box choice
	}
		
	string strSearchPathFilter;
	strSearchPathFilter.Format( "%s*.*", strPath );             // Build search start path\file name
		
	WIN32_FIND_DATAA find;

	HANDLE hFile = FindFirstFile( strSearchPathFilter, &find ); // Find first file/folder that matches
	if( hFile != INVALID_HANDLE_VALUE )                         // If valid handle...
	{
		double dNumItems;
		string strFileFound, strFilename;
		do                                                      // Do while next file/folder is found...
		{
			if( find.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY )                     // If folder is next...                     
			{
				if( bRecursive )                                                       // If user wants to recurse...
				{
					strFileFound = find.cFileName;
					if( strFileFound.Compare(".") && strFileFound.Compare("..") )      // If file found (folder) is not  
					{
						strFileFound.Format("%s%s\\", strPath, find.cFileName);

						PopulateListBoxWithFilenames( lpcstrListBoxName, strPropertyName, // Recurse into subfolder
							 TRUE, strFileFound, strFileFilter, TRUE, wDisplayOptions );
					}
				}
			}
			else                                                                       // Else file is next...
			{
				strFilename = find.cFileName;
				if( strFilename.Match( strFileFilter ) )                               // If file name matches file filter...
				{
					strCommand.Format( "dNumItems=%s.NumItems", lpcstrListBoxName );      // Build command to get number of items in list box
					LT_execute( strCommand );                                          // Execute command to get number of items in list box
					LT_get_var( "dNumItems", &dNumItems );                             // Get number of items from LabTalk variable
	
					if( wDisplayOptions & DLG_UTILS_FILE_NO_PATH )                     // If user does not want path...
						strFileFound = strFilename;                                    // Just use filename
					else
						strFileFound.Format("%s%s", strPath, find.cFileName);          // Else use path and filename 
					if( wDisplayOptions & DLG_UTILS_FILE_NO_EXT )                      // If user does not want file extension...
						strFileFound = GetFilenameWithoutExt( strFileFound );          // Strip off file extension from filename

					strCommand.Format( "%s%s%d$=%s", lpcstrListBoxName, strPropertyName, nint(dNumItems) + 1, strFileFound ); // Build command to add file to list box
					LT_execute( strCommand );                                          // Add file to list box
				}
			}
		} while( FindNextFile( hFile, &find ) );                // While next file is found... 

		FindClose( hFile );                                     // Close find
		
		if( dNumItems >= 1 && dInitChoice < dNumItems )         // If at least one item is added to list box and choice is in range...
		{
			strCommand.Format( "%s.Choice=%d", lpcstrListBoxName, nint(dInitChoice) ); // Build command to choose slected item in list box
			LT_execute( strCommand );                           // Execute command to choose selected item in list box
			LT_execute( "delete -v dNumItems" );                // Delete LabTalk variable
		}

		return DLG_UTILS_NO_ERROR;
	}

	return DLG_UTILS_NO_FILES_FOUND_ERROR;
}

/**
		Get the current worksheet/workbook sheet selection range and populate the specified
		Dialog Builder edit box with it. The selection range must be contained within a single
		worksheet/workbook column and the Dialog Builder edit box control must be passed by
		reference.
	Example:
		Edit ebxWeighting = dlgStatisticsOn.GetItem(IDC_SO_WEIGHT_EBX, IDD_SO_OP_TAB);
		// Populate Weighting edit box, type out error if problem
		if( PopulateEditBoxWithOneColumnRange(ebxWeighting) )
		{
			strMsg = SO_WKS_WEIGHT_SEL_ERROR_MSG; // Output error message and return
			strMsg.Write(WRITE_MESSAGE_BOX);
			return false;
		}
	Parameters:
		ebx=Input reference to Dialog Builder edit box
	Return:
		Returns DLG_UTILS_NO_ERROR on success and a DLG_UTILS warning or error code on failure.
*/
int PopulateEditBoxWithOneColumnRange(Edit& ebx)
{
	string strSelectedRange;
	int iRet, iNumRanges;

	if(!ebx)                                                                   // If edit box is invalid...
		return DLG_UTILS_INVALID_EBX_ERROR;
	else                                                                       // Else populate edit box...
	{
		iRet = wuGetNonContiguousWksSelection(strSelectedRange, iNumRanges);   // Get current selection range

		if( iRet )                                                             // If no selection or bad selection...
			return iRet;
		else
		{
			if( iNumRanges != 1 )                                              // If selection range spans more than single column...
				return DLG_UTILS_NO_SINGLE_COL_ERROR;
			else                                                               // Else single column range
				ebx.Text = strSelectedRange;                                   // Set range in edit box
		}
	}

	return DLG_UTILS_NO_ERROR;
}

/**
		Populate the specified list box with string values from each subnode of the 
		specified TreeNode.
	Example:
		See function call in StatisticsOn.c.
	Parameters:
		tr=Input TreeNode whose subnodes will be used to populate a list box
		bAppend=Input option to append string values from each subnode (true) or to
			reset list box and populate starting in first item (default false)
	Return:
		Returns DLG_UTILS_NO_ERROR on success.
*/
int PopulateListBoxFromTreeNode(ListBox& lbx, TreeNode& tr, bool bAppend) // bAppend = false
{
	if( !lbx )                                    // If listbox is invalid...
		return DLG_UTILS_INVALID_LBX_ERROR;
	else                                          // Else populate listbox...
	{
		if( !tr )                                 // If TreeNode is invalid...
			return DLG_UTILS_INVALID_TREENODE_ERROR;
		else                                      // Else populate listbox
		{
			TreeNode trSubNode;
		
			if( !bAppend )                        // If user does not want to append items to list box...
				lbx.ResetContent();               // Reset list box
		
			trSubNode = tr.FirstNode;             // Get first subnode
			while( trSubNode )                    // While subnodes exist...
			{
				lbx.AddString(trSubNode.Display.strVal); // Add display value of subnode to list box
				trSubNode = trSubNode.NextNode;   // Get next subnode
			}
		}
	}

	return DLG_UTILS_NO_ERROR;
}