/*------------------------------------------------------------------------------*
 * File Name: filter_utils.c 													*
 * Creation: 																	*
 * Purpose:  functions for working with filters									*
 * Copyright (c)2003 OriginLab Corp.											*
 * All Rights Reserved															*
 * 																				*
 * Modification Log:															*
 * EJP 07-07-2003 v7.0619 QA70-4783 POST_IMPORT_EXECUTE							*
 * EJP 07-17-2003 v7.0627 QA70-4818 SAVE_FILTER_IN_WKS							*
 * EJP 07-22-2003 v7.0631 QA70-4073 USE_DATAFOLDER_FILTER_WHEN_ONLY_1_APPLICABLE*
 * EJP 07-23-2003 v7.0631 QA70-4575 ADD_SKIPROWS_TO_BINIMP						*
 * EJP 09-09-2003 v7.5689 QA70-4818 UPDATE_ASCIMP_FROM_FILTER_SAVED_TO_WKS		*
 * EJP 09-24-2003 v7.5706 QA70-4073.55 ADD_FILTER_DESCRIPTION					*
 *------------------------------------------------------------------------------*/
 
#include <origin.h>
#include "Filter_Utils.h"
#include "App_Utils.h"
#include "OSelFilter.h"
#include <tree_utils.h>

// Include definitions of all localized strings. $ causes CodeBuilder to look for 
// correct version of Local.h depending on Windows Regional settings.
#include "$Local.h"


#define FILTER_HEADERPARAM_DEFINED		"Defined"

//------------------------------------------------------------
void fuPrepareDefault(TreeNode& trFilter)
{
	trFilter.Reset();

	trFilter.Type.nVal = FILTER_TYPE_ASCII;

	//---------- Common Settings based on ASCII being the default Type
	trFilter.Common.OCFile.Text = FILTER_ASCII_OCFILE;
	trFilter.Common.OCFunction.Text = FILTER_ASCII_OCFUNCTION;

	//---------- Common ASCIMP/BINIMP Settings
	fuSetImportMode(trFilter, ASCIMP_MODE_REPLACE_DATA);
	fuSetApplyRangeToGraph(trFilter, FALSE);
	trFilter.Common.Partial.nVal = 0;
	trFilter.Common.PartialC1.nVal = 0;
	trFilter.Common.PartialC2.nVal = -1;
	trFilter.Common.PartialR1.nVal = 0;
	trFilter.Common.PartialR2.nVal = -1;
	trFilter.Common.LinkWks.nVal = 0;
	trFilter.Common.RenameWks.nVal = 0;

	//---------- Common Other Settings
	fuSetDesignations(trFilter, "XY");
	fuSetRepetitive(trFilter, FALSE);
	fuSetFormats(trFilter, "9");
	fuSetPlotID(trFilter, IDM_PLOT_LINE);
	fuSetTargetWindow(trFilter, EXIST_WKS);
	
	//---------- ASCII Settings
	ASCIMP ascimp = {0};
	ascimp.iDelimited = 1;
	ascimp.iApplyRange = 0;
	fuSetASCIMP(trFilter, ascimp);
	
	//---------- Binary Settings
	BINIMP binimp = {0};
	fuSetBINIMP(trFilter, binimp);
}

//------------------------------------------------------------
int fuGetFilterType(TreeNode& trFilter)
{
	return tree_node_get_int(trFilter.Type, FILTER_TYPE_UNKNOWN);
}

bool fuGetFilterType(TreeNode &trFilter, string &strType)
{
	int iType = fuGetFilterType(trFilter);
	if( IS_FILTER_TYPE(iType) )
	{
		switch( iType )
		{
		case FILTER_TYPE_ASCII:
			strType = "ASCII";
			break;
		case FILTER_TYPE_BINARY:
			strType = "Binary";
			break;
		case FILTER_TYPE_USERDEFINED:
			strType = "User Defined";
			break;
		}
		return true;
	}
	return false;
}

//------------------------------------------------------------
BOOL fuIsRenameWks(TreeNode& trFilter)
{
	if( trFilter.Common && trFilter.Common.RenameWks )
		return trFilter.Common.RenameWks.nVal;
	return FALSE;
}

//------------------------------------------------------------
void fuSetRepetitive(TreeNode& trFilter, BOOL bRepetitive)
{
	trFilter.Common.ColDesignationsRepetitive.nVal = bRepetitive;
}

BOOL fuGetRepetitive(TreeNode& trFilter)
{
	if( trFilter.Common.ColDesignationsRepetitive )
		return trFilter.Common.ColDesignationsRepetitive.nVal;
	return FALSE; // default is off
}

//------------------------------------------------------------
void fuSetImportMode(TreeNode& trFilter, int iImportMode)
{
	if( !IS_IMPORT_MODE(iImportMode) )
		iImportMode = ASCIMP_MODE_REPLACE_DATA;
	trFilter.Common.ImportMode.nVal = iImportMode;
}

int fuGetImportMode(TreeNode& trFilter)
{
	if( trFilter.Common.ImportMode )
	{
		if( IS_IMPORT_MODE(trFilter.Common.ImportMode.nVal) )
			return trFilter.Common.ImportMode.nVal;
	}
	return ASCIMP_MODE_REPLACE_DATA;
}

//------------------------------------------------------------
BOOL fuGetApplyRangeToGraph(TreeNode& trFilter)
{
	if( trFilter.Common.ApplyRangeToGraph )
		return trFilter.Common.ApplyRangeToGraph.nVal;
	return FALSE; // default is off
}

void fuSetApplyRangeToGraph(TreeNode& trFilter, BOOL bEnable)
{
	trFilter.Common.ApplyRangeToGraph.nVal = bEnable;
}

//------------------------------------------------------------
void fuSetASCIMP(TreeNode& trFilter, ASCIMP& ascimp, BOOL bSetCommonNode)
{
	TreeNode trASCIMP = trFilter.GetNode(IMPORT_FILTER_ASCIMP);
	if( !trASCIMP )
		trASCIMP = trFilter.AddNode(IMPORT_FILTER_ASCIMP);
	trASCIMP = ascimp;
	if( bSetCommonNode )
	{
		trFilter.Common.ImportMode.nVal = ascimp.iMode;
		trFilter.Common.RenameWks.nVal = ascimp.iRenameWks;
		trFilter.Common.Partial.nVal = ascimp.iPartial;
		trFilter.Common.PartialC1.nVal = ascimp.iPartialC1;
		trFilter.Common.PartialC2.nVal = ascimp.iPartialC2;
		trFilter.Common.PartialR1.nVal = ascimp.iPartialR1;
		trFilter.Common.PartialR2.nVal = ascimp.iPartialR2;
		trFilter.Common.SkipRows.nVal = ascimp.iSkipRows; /// EJP 07-23-2003 v7.0631 QA70-4575 ADD_SKIPROWS_TO_BINIMP
	}
}

BOOL fuGetASCIMP(TreeNode& trFilter, ASCIMP& ascimp, BOOL bGetCommonNode)
{
	TreeNode trASCIMP = trFilter.GetNode(IMPORT_FILTER_ASCIMP);
	if( trASCIMP )
	{
		ascimp = trASCIMP;
		if( bGetCommonNode )
		{
			ascimp.iMode = trFilter.Common.ImportMode.nVal;
			ascimp.iRenameWks = trFilter.Common.RenameWks.nVal;
			ascimp.iPartial = trFilter.Common.Partial.nVal;
			ascimp.iPartialC1 = trFilter.Common.PartialC1.nVal;
			ascimp.iPartialC2 = trFilter.Common.PartialC2.nVal;
			ascimp.iPartialR1 = trFilter.Common.PartialR1.nVal;
			ascimp.iPartialR2 = trFilter.Common.PartialR2.nVal;
			ascimp.iSkipRows = tree_node_get_int(trFilter.Common.SkipRows, 0); /// EJP 07-23-2003 v7.0631 QA70-4575 ADD_SKIPROWS_TO_BINIMP
		}
		return TRUE;
	}
	return FALSE;
}

//------------------------------------------------------------
void fuSetBINIMP(TreeNode& trFilter, BINIMP& binimp, BOOL bSetCommonNode)
{
	TreeNode trBINIMP = trFilter.GetNode(IMPORT_FILTER_BINIMP);
	if( !trBINIMP )
		trBINIMP = trFilter.AddNode(IMPORT_FILTER_BINIMP);
	trBINIMP = binimp;
	if( bSetCommonNode )
	{
		trFilter.Common.ImportMode.nVal = binimp.iMode;
		trFilter.Common.RenameWks.nVal = binimp.iRenameWks;
		trFilter.Common.Partial.nVal = binimp.iPartial;
		trFilter.Common.PartialC1.nVal = binimp.iPartialC1;
		trFilter.Common.PartialC2.nVal = binimp.iPartialC2;
		trFilter.Common.PartialR1.nVal = binimp.iPartialR1;
		trFilter.Common.PartialR2.nVal = binimp.iPartialR2;
		trFilter.Common.SkipRows.nVal = binimp.iSkipRows; /// EJP 07-23-2003 v7.0631 QA70-4575 ADD_SKIPROWS_TO_BINIMP
	}
}

BOOL fuGetBINIMP(TreeNode& trFilter, BINIMP& binimp, BOOL bGetCommonNode)
{
	TreeNode trBINIMP = trFilter.GetNode(IMPORT_FILTER_BINIMP);
	if( trBINIMP )
	{
		binimp = trBINIMP;
		if( bGetCommonNode )
		{
			binimp.iMode = trFilter.Common.ImportMode.nVal;
			binimp.iRenameWks = trFilter.Common.RenameWks.nVal;
			binimp.iPartial = trFilter.Common.Partial.nVal;
			binimp.iPartialC1 = trFilter.Common.PartialC1.nVal;
			binimp.iPartialC2 = trFilter.Common.PartialC2.nVal;
			binimp.iPartialR1 = trFilter.Common.PartialR1.nVal;
			binimp.iPartialR2 = trFilter.Common.PartialR2.nVal;
			binimp.iSkipRows = tree_node_get_int(trFilter.Common.SkipRows, 0); /// EJP 07-23-2003 v7.0631 QA70-4575 ADD_SKIPROWS_TO_BINIMP
		}
		return TRUE;
	}
	return FALSE;
}

//------------------------------------------------------------
void fuSetDesignations(TreeNode& trFilter, LPCSTR lpcszDesignations)
{
	trFilter.Common.ColDesignations.strVal = lpcszDesignations;
}

string fuGetDesignations(TreeNode& trFilter)
{
	string str;
	if( trFilter.Common.ColDesignations )
		str = trFilter.Common.ColDesignations.strVal;
	return str;
}

//------------------------------------------------------------
void fuSetFormats(TreeNode& trFilter, LPCSTR lpcszFormats)
{
	trFilter.Common.ColFormats.strVal = lpcszFormats;
}

string fuGetFormats(TreeNode& trFilter)
{
	string str;
	if( trFilter.Common.ColFormats )
		str = trFilter.Common.ColFormats.strVal;
	return str;
}

//------------------------------------------------------------
void fuSetApplicability(TreeNode& trFilter, LPCSTR lpcszApplicability)
{
	trFilter.Common.FileSpec.strVal = lpcszApplicability;
}

string fuGetApplicability(TreeNode& trFilter)
{
	string str;
	if( trFilter.Common.FileSpec )
		str = trFilter.Common.FileSpec.strVal;
	return str;
}

BOOL fuIsApplicable(LPCSTR lpcszFilterFile, LPCSTR lpcszDataFile, int iFilterType)
{
	Tree trFilter(lpcszFilterFile);
	if( trFilter )
		return fuIsApplicable(trFilter, lpcszDataFile, iFilterType);
	return FALSE;
}

BOOL fuIsApplicable(TreeNode &trFilter, LPCSTR lpcszDataFile, int iFilterType)
{
	if( IS_FILTER_TYPE(iFilterType) )
		if( iFilterType != trFilter.Type.nVal )
			return FALSE;

	if( NULL == lpcszDataFile )
		return TRUE; // no file name to compare

	string strDataFile = GetFileName(lpcszDataFile);
	if( strDataFile.IsEmpty() )
		return TRUE; // no file name to compare

	if( strDataFile.Find('.') == -1 ) // if no extension
		strDataFile += '.';

	string strFileSpecs = fuGetApplicability(trFilter);
	
	StringArray saFileSpec;
	strFileSpecs.GetTokens(saFileSpec, ';');

	for( int n = 0; n < saFileSpec.GetSize(); n++ )
	{
		if( strDataFile.Match(saFileSpec[n]) )
			return TRUE;
	}
	return FALSE;
}

//------------------------------------------------------------
void fuGetFilterFiles(StringArray& sarrFilterFiles, LPCSTR lpcszFolderPath, LPCSTR lpcszDataFile, int iFilterType)
{
	sarrFilterFiles.SetSize(0);
	fuAppendFilterFiles(sarrFilterFiles, lpcszFolderPath, lpcszDataFile, iFilterType);
}

void fuAppendFilterFiles(StringArray& sarrFilterFiles, LPCSTR lpcszFolderPath, LPCSTR lpcszDataFile, int iFilterType)
{
	string strFileNames;
	auGetFilenamesInFolder(strFileNames, lpcszFolderPath, IMPORT_FILTER_EXTENSION_WILD, FALSE);
	if( strFileNames.IsEmpty() )
		return;

	StringArray sarrFilterFileNames;
	strFileNames.GetTokens(sarrFilterFileNames, '|');

	string strApplicability;
	if( lpcszDataFile )
		strApplicability = GetFileName(lpcszDataFile);
	
	if( strApplicability.IsEmpty() && FILTER_TYPE_IGNORE == iFilterType )
	{
		///sarrFilterFiles = sarrFilterFileNames;
		//sarrFilterFiles.Append(sarrFilterFileNames);
		for( int iFile = 0; iFile < sarrFilterFileNames.GetSize(); iFile++ )
			sarrFilterFiles.Add(sarrFilterFileNames[iFile]);
		return;
	}

	for( int iFile = 0; iFile < sarrFilterFileNames.GetSize(); iFile++ )
	{
		if( fuIsApplicable(sarrFilterFileNames[iFile], strApplicability, iFilterType) )
			sarrFilterFiles.Add(sarrFilterFileNames[iFile]);
	}
}

void fuGetFilterFiles(StringArray &saFilterFiles, int iFilterType, LPCSTR lpcszDataFile)
{
	saFilterFiles.SetSize(0);

	string strDataPath = GetFilePath(lpcszDataFile);
	if( !strDataPath.IsEmpty() )
		fuAppendFilterFiles(saFilterFiles, strDataPath, lpcszDataFile, iFilterType);

	string strUserPath;
	strUserPath.Format("%s%s", GetAppPath(), FILTERS_FOLDER_NAME);
	if( strUserPath != strDataPath )
		fuAppendFilterFiles(saFilterFiles, strUserPath, lpcszDataFile, iFilterType);

	string strExePath;
	strExePath.Format("%s%s", GetAppPath(TRUE), FILTERS_FOLDER_NAME);
	if( strExePath != strDataPath && strExePath != strUserPath )
		fuAppendFilterFiles(saFilterFiles, strExePath, lpcszDataFile, iFilterType);
}

void fuGetFilterList(StringArray &saFilterList, StringArray &saFilterFiles)
{
	int iPath;
	string str;
	string strLocPrefix(FILTER_LOCATION_PREFIX);
	
	string strUserPath;
	strUserPath.Format("%s%s", GetAppPath(), FILTERS_FOLDER_NAME);
	
	string strOriginPath;
	strOriginPath.Format("%s%s", GetAppPath(TRUE), FILTERS_FOLDER_NAME);

	saFilterList.SetSize(0);
	for( int i = 0; i < saFilterFiles.GetSize(); i++ )
	{
		if( 0 == strOriginPath.CompareNoCase(GetFilePath(saFilterFiles[i])) )
			iPath = FILTER_PATH_ORIGIN;
		else if( 0 == strUserPath.CompareNoCase(GetFilePath(saFilterFiles[i])) )
			iPath = FILTER_PATH_USER;
		else // Data
			iPath = FILTER_PATH_DATA;
		str.Format("%s: %s", strLocPrefix.GetToken(iPath, '|'), GetFileName(saFilterFiles[i], TRUE));
		saFilterList.Add(str);
	}
}

BOOL fuGetFilterFileNameFromListItem(LPCSTR lpcszFilterListItem, String &strFileName, LPCSTR lpcszDataPath)
{
	string str = lpcszFilterListItem;
	int i = str.Find(':');
	if( i < 1 )
		return FALSE;
	
	string strItemPrefix = str.Left(i); // everything before the colon
	string strItemName = str.Mid(i + 2); // everything after the colon and space
	
	string strPrefixes(FILTER_LOCATION_PREFIX);
	int iTokens = strPrefixes.GetNumTokens('|');
	for( i = 0; i < iTokens; i++ )
	{
		str = strPrefixes.GetToken(i, '|');
		if( 0 == str.CompareNoCase(strItemPrefix) )
			break;
	}
	if( !IS_FILTER_PATH_ID(i) )
		return FALSE;

	switch( i )
	{
	case FILTER_PATH_USER:
		str = GetAppPath() + FILTERS_FOLDER_NAME;
		break;
	case FILTER_PATH_ORIGIN:
		str = GetAppPath(TRUE) + FILTERS_FOLDER_NAME;
		break;
	default: // Data path
		if( lpcszDataPath )
			str = lpcszDataPath;
		else
			str.Empty();
		break;
	}
	strFileName.Format("%s%s.%s", str, strItemName, IMPORT_FILTER_EXTENSION);
	return TRUE;
}

//--------------------------------------------------------------------------
void fuSetPlotID(TreeNode& trFilter, int nPlotID)
{
	trFilter.Common.PlotType.nVal = nPlotID;
}

int fuGetPlotID(TreeNode& trFilter)
{
	if( trFilter.Common.PlotType )
		return trFilter.Common.PlotType.nVal;
	return IDM_PLOT_LINE; // default plot type
}

void fuSetPlotTemplate(TreeNode& trFilter, LPCSTR lpcszTemplate)
{
	trFilter.Common.PlotTemplate.strVal = lpcszTemplate;
}

string fuGetPlotTemplate(TreeNode& trFilter)
{
	string str;
	if( trFilter.Common.PlotTemplate )
		str = trFilter.Common.PlotTemplate.strVal;
	return str;
}

//--------------------------------------------------------------------------
int fuGetTargetPageType(TreeNode& trFilter)
{
	/*
	int iType;
	if( trFilter.Common.TargetWindowType )
	{
		iType = trFilter.Common.TargetWindowType.nVal;
		if( EXIST_WKS != iType && EXIST_MATRIX != iType )
			iType = EXIST_WKS;
	}
	else
		iType = EXIST_WKS;
	return iType;
	*/
	int iTargetWndType = tree_node_get_int(trFilter.Common.TargetWindowType, EXIST_NONE);
	if( EXIST_NONE == iTargetWndType )
	{
		int iFilterType = fuGetFilterType(trFilter);
		if( FILTER_TYPE_ASCII == iFilterType || FILTER_TYPE_BINARY == iFilterType )
			iTargetWndType = EXIST_WKS;
	}
	return iTargetWndType;
}

BOOL fuIsTargetPageType(TreeNode& trFilter, int iPageType)
{
	return (iPageType == fuGetTargetPageType(trFilter));
}

BOOL fuGetTargetWindow(TreeNode& trFilter, int& iType, string& strTemplate)
{
	iType = fuGetTargetPageType(trFilter);

	if( trFilter.Common.TargetWindowTemplate )
		strTemplate = trFilter.Common.TargetWindowTemplate.strVal;
	else
	/*
	{
		string strType;
		if( EXIST_MATRIX == iType )
			strType = "System.Matrix.DefTemplate$";
		else
			strType = "System.Wks.DefTemplate$";
		char szDefTemplate[NAME_SIZE];
		if( !LT_get_str(strType, szDefTemplate, NAME_SIZE) )
			lstrcpy(szDefTemplate, "Origin");
		strTemplate = szDefTemplate;
	}
	*/
		strTemplate.Empty();
	return TRUE;
}

BOOL fuSetTargetWindow(TreeNode& trFilter, int iType, LPCSTR lpcszTemplate)
{
	trFilter.Common.TargetWindowType.nVal = iType;
	string strTemplate;
	if( lpcszTemplate )
		strTemplate = lpcszTemplate;
	trFilter.Common.TargetWindowTemplate.strVal = strTemplate;
	return TRUE;
}

Page fuCreateTargetPage(TreeNode& trFilter, int iOption)
{
	int iType;
	string strTemplate;
	fuGetTargetWindow(trFilter, iType, strTemplate);
	
	Page pgTarget;
	if( EXIST_MATRIX == iType )
	{
		MatrixPage pgMat;
		if( strTemplate.IsEmpty() )
			strTemplate = LabTalk.System.Matrix.DefTemplate$;
		pgMat.Create(strTemplate, iOption);
		pgTarget = pgMat;
	}
	else if( EXIST_WKS == iType )
	{
		WorksheetPage pgWks;
		if( strTemplate.IsEmpty() )
			strTemplate = LabTalk.System.Wks.DefTemplate$;
		pgWks.Create(strTemplate, iOption);
		pgTarget = pgWks;
	}
	return pgTarget;
}

//--------------------------------------------------------------------------
int fuGetDragDropGraph(TreeNode &trFilter)
{
	if( trFilter.Common.DragAndDrop.Graph )
	{
		if( IS_FILTER_DDGRAPH(trFilter.Common.DragAndDrop.Graph.nVal) )
			return trFilter.Common.DragAndDrop.Graph.nVal;
	}
	return FILTER_DDGRAPH_OPENONLY;
}

void fuSetDragDropGraph(TreeNode& trFilter, int iMode)
{
	if( !IS_FILTER_DDGRAPH(iMode) )
		iMode = FILTER_DDGRAPH_OPENONLY;
	trFilter.Common.DragAndDrop.Graph.nVal = iMode;
}

int fuGetDragDropWorkspace(TreeNode &trFilter)
{
	if( trFilter.Common.DragAndDrop.Workspace )
	{
		if( IS_FILTER_DDWORKSPACE(trFilter.Common.DragAndDrop.Workspace.nVal) )
			return trFilter.Common.DragAndDrop.Workspace.nVal;
	}
	return FILTER_DDWORKSPACE_OPENONLY;
}

void fuSetDragDropWorkspace(TreeNode& trFilter, int iMode)
{
	if( !IS_FILTER_DDWORKSPACE(iMode) )
		iMode = FILTER_DDWORKSPACE_OPENONLY;
	trFilter.Common.DragAndDrop.Workspace.nVal = iMode;
}

//--------------------------------------------------------------------------
int fuGetFilterFile(string &strFilter, LPCSTR lpcszDataFile)
{
	string strFileExt = GetFileName(lpcszDataFile);

	StringArray saFiltersInDataFolder;
	string strDataPath = GetFilePath(lpcszDataFile);
	if( !strDataPath.IsEmpty() )
		fuGetFilterFiles(saFiltersInDataFolder, strDataPath, strFileExt);

	int nCount = saFiltersInDataFolder.GetSize();
	if( 1 == nCount ) // if only 1 applicable filter in data-folder then use it.
	{
		strFilter = saFiltersInDataFolder[0];
		/// EJP 07-22-2003 v7.0631 QA70-4073 USE_DATAFOLDER_FILTER_WHEN_ONLY_1_APPLICABLE
		return 1; // only 1 data-folder filter applicable, so we use it.
		/// end USE_DATAFOLDER_FILTER_WHEN_ONLY_1_APPLICABLE
	}
	else if( 0 == nCount ) // if no applicable filters in data-folder then check ini and exe folders.
	{
		StringArray saFiltersInExeFolder;
		string strExePath;
		strExePath.Format("%s%s", GetAppPath(TRUE), FILTERS_FOLDER_NAME);
		if( !strExePath.IsEmpty() && strExePath != strDataPath )
			fuGetFilterFiles(saFiltersInExeFolder, strExePath, strFileExt);

		nCount += saFiltersInExeFolder.GetSize();
		if( nCount < 2 )
		{
			if( 1 == saFiltersInExeFolder.GetSize() )
				strFilter = saFiltersInExeFolder[0];

			StringArray saFiltersInUserFolder;
			string strIniPath;
			strIniPath.Format("%s%s", GetAppPath(), FILTERS_FOLDER_NAME);
			if( !strIniPath.IsEmpty() && strIniPath != strDataPath && strIniPath != strExePath )
				fuGetFilterFiles(saFiltersInUserFolder, strIniPath, strFileExt);	
			
			nCount += saFiltersInUserFolder.GetSize();
			if( 1 == saFiltersInUserFolder.GetSize() )
				strFilter = saFiltersInUserFolder[0];
		}
	}
	
	if( nCount > 1 )
	{
		strFilter.Empty();

		PFNSELECTFILTER pfn = GET_SELECTFILTER_FUNC;
		if( pfn && pfn(strFilter, lpcszDataFile) )
			nCount = 1;
	}
	
	return nCount;
}

int fuLoadFilterFile(TreeNode &trFilter, LPCSTR lpcszDataFile)
{
	string strFilter;
	int n = fuGetFilterFile(strFilter, lpcszDataFile);
	if( n != 1 )
		return n;

	Tree tr;
	if( tr.Load(strFilter) )
	{
		trFilter = tr;
		return 1;
	}
	return 0;
}

//--------------------------------------------------------------------------
// fuGetImportFunctionPtr
//
//--------------------------------------------------------------------------
PFNIMPORTFUNC fuGetImportFunctionPtr(TreeNode &trFilter)
{
	string strOCFunc = trFilter.Common.OCFunction.strVal;
	string strOCFile = trFilter.Common.OCFile.strVal;
	if( strOCFunc.IsEmpty() || strOCFile.IsEmpty() )
		return NULL;

	PFNIMPORTFUNC pfn = Project.FindFunction(strOCFunc, strOCFile, TRUE);
	return pfn;
}

//--------------------------------------------------------------------------
BOOL fuRemoveHeaderParams(TreeNode &trFilter)
{
	return trFilter.Common.HeaderParameters.Remove();
}

TreeNode fuGetHeaderParams(TreeNode &trFilter)
{
	if( !trFilter.Common.HeaderParameters )
		trFilter.Common.AddNode("HeaderParameters");
	return trFilter.Common.HeaderParameters;
}

bool fuGetHeaderParamDefined(TreeNode &trFilter, int &nVal)
{
	TreeNode trAllParams = fuGetHeaderParams(trFilter);
	if( !trAllParams )
		return false;
	return trAllParams.GetAttribute(FILTER_HEADERPARAM_DEFINED, nVal);
}

void fuSetHeaderParamDefined(TreeNode &trFilter, int nVal)
{
	TreeNode trAllParams = fuGetHeaderParams(trFilter);
	if( !trAllParams )
		return;
	trAllParams.SetAttribute(FILTER_HEADERPARAM_DEFINED, nVal);
}

int fuGetHeaderParamCount(TreeNode &trFilter)
{
	TreeNode trAllParams = fuGetHeaderParams(trFilter);
	if( !trAllParams )
		return 0;
	return trAllParams.GetNodeCount();
}

TreeNode fuGetHeaderParam(TreeNode &trFilter, LPCSTR lpcszName)
{
	TreeNode trParam;
	TreeNode trAllParams = fuGetHeaderParams(trFilter);
	if( !trAllParams )
		return trParam;
	string str(lpcszName);
	foreach(trParam in trAllParams.Children)
	{
		if( trParam.Name && 0 == str.Compare(trParam.Name.strVal) )
			return trParam;
	}
	return trParam;
}

bool fuGetHeaderParamNames(TreeNode &trFilter, StringArray &saNames)
{
	TreeNode trAllParams = fuGetHeaderParams(trFilter);
	if( !trAllParams )
		return false;
	TreeNode trParam;
	foreach(trParam in trAllParams.Children)
	{
		if( trParam.Name )
			saNames.Add(trParam.Name.strVal);
	}
	return true;
}

//--------------------------------------------------------------------------
// fuAddHeaderParam
//
// Do not call this function directly.
// Use fuAddASCHeaderParam or fuAddBinHeaderParam macros.
//--------------------------------------------------------------------------
bool fuAddHeaderParam(TreeNode &trFilter, LPCSTR lpcszName, int nType, int n1, int n2, int n3)
{
	TreeNode trAllParams = fuGetHeaderParams(trFilter);
	if( !trAllParams )
		return false;
	
	string str;
	str.Format("P%d", trAllParams.GetNodeCount());
	TreeNode trParam = trAllParams.AddNode(str);
	if( !trParam )
		return false;

	trParam.Name.strVal = lpcszName;
	trParam.Type.nVal = nType;
	if( FILTER_TYPE_ASCII == trFilter.Type.nVal )
	{
		trParam.Line.nVal = n1;
		trParam.Pos.nVal = n2;
		trParam.End.nVal = n3;
	}
	else // FILTER_TYPE_BINARY
	{
		trParam.Offset.nVal = n1;
		trParam.Size.nVal = n2;
	}

	return true;
}

bool fuAddASCHeaderParam(TreeNode &trFilter, LPCSTR lpcszName, int nType, int nLine, int nPos, int nEnd)
{
	return fuAddHeaderParam(trFilter, lpcszName, nType, nLine, nPos, nEnd);
}

bool fuAddBinHeaderParam(TreeNode &trFilter, LPCSTR lpcszName, int nType, int nOffset, int nSize)
{
	return fuAddHeaderParam(trFilter, lpcszName, nType, nOffset, nSize);
}

bool fuGetHeaderParam(TreeNode &trFilter, LPCSTR lpcszName, int &nType, int &n1, int &n2, int &n3)
{
	TreeNode trParam = fuGetHeaderParam(trFilter, lpcszName);
	if( !trParam )
		return false;
	
	nType = trParam.Type.nVal;
	if( FILTER_TYPE_ASCII == trFilter.Type.nVal )
	{
		if( !trParam.Line || !trParam.Pos || !trParam.End )
			return false;
		n1 = trParam.Line.nVal;
		n2 = trParam.Pos.nVal;
		n3 = trParam.End.nVal;
	}
	else // FILTER_TYPE_BINARY
	{
		if( !trParam.Offset || !trParam.Size )
			return false;
		n1 = trParam.Offset.nVal;
		n2 = trParam.Size.nVal;
		// n3 is not used
	}
	
	return true;
}

bool fuGetASCHeaderParam(TreeNode &trFilter, LPCSTR lpcszName, int &nType, int &nLine, int &nPos, int &nEnd)
{
	return fuGetHeaderParam(trFilter, lpcszName, nType, nLine, nPos, nEnd);
}

bool fuGetBinHeaderParam(TreeNode &trFilter, LPCSTR lpcszName, int &nType, int &nOffset, int &nSize)
{
	int n; // temp var for last arg
	return fuGetHeaderParam(trFilter, lpcszName, nType, nOffset, nSize, n);
}

bool fuGetHdrVarScan(TreeNode &trFilter, int &iFirstLine, int &iLastLine, int &iSeparator)
{
	TreeNode trParams = fuGetHeaderParams(trFilter);
	if( !trParams )
		return false;
	if( !trParams.FirstLine || !trParams.LastLine || !trParams.Separator )
		return false;
	iFirstLine = trParams.FirstLine.nVal;
	iLastLine = trParams.LastLine.nVal;
	iSeparator = trParams.Separator.nVal;
	return true;
}

bool fuSetHdrVarScan(TreeNode &trFilter, int iFirstLine, int iLastLine, int iSeparator)
{
	TreeNode trParams = fuGetHeaderParams(trFilter);
	if( !trParams )
		return false;
	trParams.FirstLine.nVal = iFirstLine;
	trParams.LastLine.nVal = iLastLine;
	trParams.Separator.nVal = iSeparator;
	return true;
}

bool fuGetHdrSave(TreeNode &trFilter, int &iFirstLine, int &iNumLines)
{
	if( !trFilter.Common.HdrSaveFirstLine || !trFilter.Common.HdrSaveNumLines )
		return false;
	iFirstLine = trFilter.Common.HdrSaveFirstLine.nVal;
	iNumLines = trFilter.Common.HdrSaveNumLines.nVal;
	return true;
}

bool fuSetHdrSave(TreeNode &trFilter, int iFirstLine, int iNumLines)
{
	trFilter.Common.HdrSaveFirstLine.nVal = iFirstLine;
	trFilter.Common.HdrSaveNumLines.nVal = iNumLines;
	return true;
}

//--------------------------------------------------------------------------
bool fuGetFileSpec(TreeNode &trFilter, string &strFileSpec)
{
	if( trFilter.Common.FileSpec )
		strFileSpec = trFilter.Common.FileSpec.strVal;
	else
		strFileSpec.Empty();
	return true;
}

bool fuSetFileSpec(TreeNode &trFilter, LPCSTR lpcstrFileSpec)
{
	trFilter.Common.FileSpec.strVal = lpcstrFileSpec;
	return true;
}

bool fuGetFilesOfTypeGroupName(TreeNode &trFilter, string &strName)
{
	if( trFilter.Common.GroupName )
		strName = trFilter.Common.GroupName.strVal;
	else
		strName.Empty();
	return true;
}

bool fuSetFilesOfTypeGroupName(TreeNode &trFilter, LPCSTR lpcstrName)
{
	trFilter.Common.GroupName.strVal = lpcstrName;
	return true;
}

bool fuGetFilesOfType(TreeNode &trFilter, StringArray &saFileSpecNames)
{
	if( trFilter &&	trFilter.Common && trFilter.Common.FilesOfType && trFilter.Common.FilesOfType.Names )
	{
		TreeNode trName = trFilter.Common.FilesOfType.Names.FirstNode;
		while( trName )
		{
			saFileSpecNames.Add(trName.strVal);
			trName = trName.NextNode;
		}
		return true;
	}
	return false;
}

bool fuSetFilesOfType(TreeNode &trFilter, StringArray &saFileSpecNames)
{
	trFilter.Common.FilesOfType.RemoveChild("Names");
	TreeNode trNames = trFilter.Common.FilesOfType.AddNode("Names");
	if( trNames )
	{
		string str;
		for( int i = 0; i < saFileSpecNames.GetSize(); i++ )
		{
			str.Format("Type%d", i);
			trNames.AddTextNode(saFileSpecNames[i], str);
		}
		return true;
	}
	return false;
}

//--------------------------------------------------------------------------
BOOL fuIsFileNameToWksLabel(TreeNode &trFilter)
{
	if( trFilter.Common.FileNameToWksLabel )
		return trFilter.Common.FileNameToWksLabel.nVal;
	return TRUE; // on by default 
}

void fuSetFileNameToWksLabel(TreeNode &trFilter, BOOL bSet)
{
	trFilter.Common.FileNameToWksLabel.nVal = bSet;
}

//--------------------------------------------------------------------------
/// EJP 07-07-2003 v7.0619 QA70-4783 POST_IMPORT_EXECUTE
bool fuGetPostImportScript(TreeNode &trFilter, string &strScript)
{
	if( !trFilter.Common.PostImportScript )
		return false;
	strScript = trFilter.Common.PostImportScript.strVal;
	
	// The string went into the filter with CR-LF combo, but the tree or XML
	// code strips the CR char.  Here I will replace all LF chars with CR-LF combo.
	// First check if combo is there in case tree or XML behavior changes.
	if( -1 == strScript.Find("\r\n") ) // If CR-LF combo is not found
		strScript.Replace("\n", "\r\n"); // Replace LF with CR-LF
	
	return true;
}

void fuSetPostImportScript(TreeNode &trFilter, LPCSTR lpcszScript)
{
	trFilter.Common.PostImportScript.strVal = lpcszScript;
}
/// end POST_IMPORT_EXECUTE

//--------------------------------------------------------------------------
/// EJP 07-17-2003 v7.0627 QA70-4818 SAVE_FILTER_IN_WKS
bool fuGetPageFilterName(string &strName, int iType)
{
	switch( iType )
	{
	case FILTER_TYPE_ASCII:
		strName += "ImportFilter_ASCII";
		break;
	case FILTER_TYPE_BINARY:
		strName += "ImportFilter_Binary";
		break;
	case FILTER_TYPE_USERDEFINED:
		strName += "ImportFilter_UserDefined";
		break;
	default:
		return false;
	}
	return true;
}

bool fuIsOneFilterInPage(Page &pgTarget, LPCSTR lpcszDataFile, int &iFilterType)
{
	int iType;
	int iCount = 0;
	
	if( fuIsFilterInPage(pgTarget, FILTER_TYPE_ASCII, lpcszDataFile) )
	{
		iType = FILTER_TYPE_ASCII;
		iCount++;
	}
	if( fuIsFilterInPage(pgTarget, FILTER_TYPE_BINARY, lpcszDataFile) )
	{
		iType = FILTER_TYPE_BINARY;
		iCount++;
	}
	if( fuIsFilterInPage(pgTarget, FILTER_TYPE_USERDEFINED, lpcszDataFile) )
	{
		iType = FILTER_TYPE_USERDEFINED;
		iCount++;
	}

	if( 1 == iCount )
	{
		iFilterType = iType;
		return true;
	}
	return false;
}

bool fuIsFilterInPage(Page &pgTarget, int iType, LPCSTR lpcszDataFile)
{
	/*
	string strName;
	if( fuGetPageFilterName(strName, iType) )
	{
		vector<byte> vb;
		if( pgTarget.GetMemory(strName, vb) )
		{
			if( !lpcszDataFile )
				return true;
			
			Tree trFilter(lpcszFilterFile);
	if( trFilter )
			return fuIsApplicable(trFilter, lpcszDataFile, iType);
		}
	}
	*/	
	if( IS_FILTER_TYPE(iType) )
	{
		Tree trFilter;
		if( fuLoadFilterFromPage(trFilter, pgTarget, iType) )
			return fuIsApplicable(trFilter, lpcszDataFile, iType);
	}
	else
	{
		if( fuIsFilterInPage(pgTarget, FILTER_TYPE_ASCII, lpcszDataFile) )
			return true;
		if( fuIsFilterInPage(pgTarget, FILTER_TYPE_BINARY, lpcszDataFile) )
			return true;
		if( fuIsFilterInPage(pgTarget, FILTER_TYPE_USERDEFINED, lpcszDataFile) )
			return true;
	}
	return false;
}

bool fuSaveFilterToPage(TreeNode &trFilter, Page &pgTarget)
{
	string strFilter = trFilter.XML;
	vector<byte> vb;
	if( strFilter.GetBytes(vb) )
	{
		string strName;
		if( fuGetPageFilterName(strName, trFilter.Type.nVal) )
		{
			if( pgTarget.SetMemory(strName, vb) )
				return true;
		}
	}
	return false;
}

bool fuLoadFilterFromPage(TreeNode &trFilter, Page &pgTarget, int iType)
{
	string strName;
	if( fuGetPageFilterName(strName, iType) )
	{
		vector<byte> vb;
		if( pgTarget.GetMemory(strName, vb) )
		{
			string strFilter;
			if( strFilter.SetBytes(vb) )
			{
				trFilter.XML = strFilter;
				return true;
			}
		}
	}
	return false;
}
/// end SAVE_FILTER_IN_WKS

bool fuGetUserDefinedFunction(TreeNode &trFilter, string &strOCFile, string &strOCFunction)
{
	if( trFilter.Common.OCFile && trFilter.Common.OCFunction )
	{
		strOCFile = trFilter.Common.OCFile.strVal;
		strOCFunction = trFilter.Common.OCFunction.strVal;
		return true;
	}
	return false;
}

bool fuSetUserDefinedFunction(TreeNode &trFilter, LPCSTR lpcszOCFile, LPCSTR lpcszOCFunction)
{
	trFilter.Common.OCFile.strVal = lpcszOCFile;
	trFilter.Common.OCFunction.strVal = lpcszOCFunction;
	return true;
}

/// EJP 09-09-2003 v7.5689 QA70-4818 UPDATE_ASCIMP_FROM_FILTER_SAVED_TO_WKS
bool fuUpdatePageASCIMP(Page &pg, bool bUpdateInternal)
{
	Tree trFilter;
	if( !fuLoadFilterFromPage(trFilter, pg, FILTER_TYPE_ASCII) )
		return false; // page does not have an ASCII filter

	Worksheet wks(pg.GetName());
	if( !wks )
		return false; // failed to get reference to wks

	ASCIMP ascimp;
	if( bUpdateInternal ) // update internal settings from filter
	{
		if( !fuGetASCIMP(trFilter, ascimp) )
			return false; // failed to get ASCIMP from filter
		wks.SetASCIMP(ascimp);
	}
	else // update filter from internal settings
	{
		wks.GetASCIMP(ascimp);
		fuSetASCIMP(trFilter, ascimp);
		fuSaveFilterToPage(trFilter, pg);
	}
	return true; // ascimp updated
}
/// end UPDATE_ASCIMP_FROM_FILTER_SAVED_TO_WKS

bool fuSave(TreeNode &trFilter, LPCSTR lpcszFile)
{
	if( !lpcszFile )
		return false;

	double d;
	LT_get_var("@V", &d);
	trFilter.OriginVersion.dVal = d;

	Tree tr;
	tr = trFilter;
	
	return tr.Save(lpcszFile);
}

bool fuLoad(TreeNode &trFilter, LPCSTR lpcszFile)
{
	if( !lpcszFile )
		return false;

	Tree tr;
	tr = trFilter;

	return tr.Load(lpcszFile);
}

/// EJP 09-24-2003 v7.5706 QA70-4073.55 ADD_FILTER_DESCRIPTION
bool fuGetDescription(TreeNode &trFilter, string &strDescrip)
{
	TreeNode trn;
	trn = trFilter.Common.Description;
	if( trn )
	{
		strDescrip = trFilter.Common.Description.strVal;
		return true;
	}
	return false;
}

bool fuSetDescription(TreeNode &trFilter, LPCSTR lpcszDescrip)
{
	if( trFilter && lpcszDescrip )
	{
		trFilter.Common.Description.strVal = lpcszDescrip;
		return true;
	}
	return false;
}
/// end ADD_FILTER_DESCRIPTION
