#include <origin.h>
#include <GetNBox.h>
#include <xfutils.h>
enum{
	designation_XY,
	designation_XYYY,
};
//put additional include files here
#include <operation.h>
#include <..\OriginLab\nlsf_utils.h> 
#include <..\OriginLab\NLFitSession.h> 
//#include <..\OriginLab\NumFunctionOrganizer.h>

		/// ML 11/14/2007 QA70-10619 P1 DELETING_COLUMNS_WITHOUT_DESTROYING_OPERATION

#define STR_NLFIT_CLASS			"FitNL"	
#define STR_DEFAULT_CATEGORY  	"Origin Basic Functions"
#define STR_DEFAULT_FUNCTION	"Gauss"
#define STR_X_DESIGNATION		"X"
#define STR_Y_DESIGNATION		"Y"
//#define	STR_DESIGNATION_LIST	"|Y|XY|XYY|XYYY|XYYYY"
#define STR_XY_DESIGNATION		"XY"
#define STR_INPUT_DATA_TAGNAME 	"InputData"
#define STR_RANGE				"Range"
#define AVERAGED_DATA_SHEET_NAME "Averaged Data"

//put your own support static functions here
static bool _set_nlfit_category_list(TreeNode& trGetN, string& strOpCategory = NULL)
{
	trGetN.CategoryList.strVal = STR_DEFAULT_CATEGORY;
	trGetN.FunctionList.strVal = STR_DEFAULT_FUNCTION;
	NLFitSelFunction nlf(trGetN);
	string strCategory;
	if(strOpCategory && !strOpCategory.IsEmpty())
		strCategory = strOpCategory;
	else
		strCategory = STR_DEFAULT_CATEGORY;
	
	if(!nlf.Init(strCategory, NULL, NULL, NULL, true, false))
		return false;
	trGetN.FunctionList.Enable = true;
	trGetN.FunctionList.Enable = true;
	return true;
}

static bool _get_nlfit_function_list(vector<string>& vsFunctionList, string& strCateg)
{
	vector<string> vsFile;
	if(!nslf_get_func_list(vsFunctionList, vsFile, strCateg))
		return false;
	return true;
}
/*
static bool _set_category_node(TreeNode& trGetN, vector<string>& vsCategory, bool bInit = true, string& strOpCategory = NULL)
{
	string strCateList;
	if(vsCategory.GetSize() < 1)
		return false;
	
	strCateList.SetTokens(vsCategory, '|');
	trGetN.category.SetAttribute(STR_COMBO_ATTRIB, strCateList);
	/// Max 07-11-22 COMBO_TEXT_NO_NEEDED_LOCALIZE
	trGetN.category.SetAttribute(STR_OCNTRL_OPTNS, OCNTRLPARAM1_NOT_LOCALIZED);
	/// END COMBO_TEXT_NO_NEEDED_LOCALIZE
	string strCategory;
	if(strOpCategory && !strOpCategory.IsEmpty())
		strCategory = strOpCategory;
	else if(bInit)
		strCategory = STR_DEFAULT_CATEGORY;
	else
		strCategory = vsCategory[0];

	trGetN.category.strVal = strCategory;
	return true;
}
*/
static bool _set_function_node(TreeNode& trGetN, vector<string>& vsFunctionList, bool bInit = true, string& strOpFunction = NULL)
{
	string strFuncList;
	if(vsFunctionList.GetSize() < 1)
		return false;
	strFuncList.SetTokens(vsFunctionList, '|');
	trGetN.FunctionList.SetAttribute(STR_COMBO_ATTRIB, strFuncList);
	/// Max 07-11-22 COMBO_TEXT_NO_NEEDED_LOCALIZE
	trGetN.FunctionList.SetAttribute(STR_OCNTRL_OPTNS, OCNTRLPARAM1_NOT_LOCALIZED);
	/// END COMBO_TEXT_NO_NEEDED_LOCALIZE	
	string strFunction;
	if(strOpFunction && !strOpFunction.IsEmpty())
		strFunction = strOpFunction;
	else if(bInit)
		strFunction = STR_DEFAULT_FUNCTION;
	else
		strFunction = vsFunctionList[0];
	
	trGetN.FunctionList.strVal = strFunction;	
	return true;
}

static int _get_report_sheet(const Worksheet& wksSource, Worksheet& wksReport, string& strName)
{
	WorksheetPage wp = wksSource.GetPage();
	if(!wp)
		return false;
	
	wksReport = wp.Layers(strName);
	if(!wksReport.IsValid())
		return false;
	
	return true;
}

static bool _is_nlsf_operation(OperationBase& op)
{
	if(!op)
		return false;
	
	string strOpClassName = op.GetClassName();
	if(strOpClassName.Compare(STR_NLFIT_CLASS))
		return false;
	
	return true;
}


static void  _update_grid_tree(TreeNode& trGetN, bool bIsNLFit = true)
{		
	if(!bIsNLFit)
	{
		trGetN.CategoryList.Show = false;
		trGetN.FunctionList.Show = false;
	}
	else
	{
		trGetN.CategoryList.Show = true;
		trGetN.FunctionList.Show = true;
	}
}

static bool _init_nlfit_category_function_node(TreeNode& trGetN, Worksheet& wksReport, string& strErrMsg)
{
	string strOpCategory, strOpFunction;
	_get_nlfit_category_and_function(wksReport, strOpCategory, strOpFunction);
	if(!_set_nlfit_category_list(trGetN, strOpCategory))
	{
		strErrMsg = CER_GET_NLFIT_CATEGORY_LIST;
		return false;
	}
	
	string strCateg;
	vector<string> vsFunctionList;
	strCateg = trGetN.CategoryList.strVal;
	if(!_get_nlfit_function_list(vsFunctionList, strCateg))
	{
		strErrMsg = CER_GET_NLFIT_FUNCTION_LIST;
		strErrMsg = strErrMsg + ":" + strCateg;
		return false;
	}
	_set_function_node(trGetN, vsFunctionList, true, strOpFunction);
	
	return true;	
}

/*
static void _init_designation_node(TreeNode& trGetN)
{
	trGetN.designation.SetAttribute(STR_COMBO_ATTRIB, STR_DESIGNATION_LIST);
	trGetN.designation.strVal = STR_DESIGNATION_DEFAULT;
}

static int _check_designation_string(string& strDesignations)
{
	strDesignations.TrimRight();
	strDesignations.TrimLeft();
	strDesignations.MakeUpper();
	if(strDesignations.IsEmpty())
		return -1;
	
	if(strDesignations.GetLength() == strDesignations.Count(CHAR_Y_DESIGNATION))
		return 1;
	
	if(!_is_designation_format_legal(strDesignations))
		return -2;

	return 0;
}
*/
static bool _check_and_update_assays_config_tree(TreeNode& trGetN, Worksheet& wksSource, Worksheet& wksReport, string& strErrMsg)
{
	if(!wksReport)
	{
		strErrMsg = REPORT_TREE_NO_REPORT_SHEET;
		return false;
	}
	
	//string strDesignations = trGetN.designation.strVal;
	//int nRet = _check_designation_string(strDesignations);
	//if(nRet < 0)
	//{
		//if( nRet == -1)
		//{
			//strErrMsg = CER_EMPTY_VARIABLE;
			//strErrMsg = strErrMsg + ":" + "designation";
		//}
		//else
			//strErrMsg = ASSAYS_CONFIG_WRONG_DESIGNATION_FORMAT;
	//
		//return false;
	//}
	
	int nReplicates = trGetN.replicates.nVal;
	if(nReplicates < 1)
	{
		strErrMsg = ASSAYS_CONFIG_WRONG_REPLICAS;
		return false;
	}
	int nNumCols = _get_cols_needed(trGetN.designation.nVal, trGetN.replicates.nVal);
	if(nNumCols < wksSource.GetNumCols())
		strErrMsg = ASSAYS_WARN_DEL_COLS;
	
	OperationBase& op = wksReport.GetSrcOperation();
	if(!op.IsValid())
	{
		strErrMsg = CER_GET_OPERATION_OBJECT;
		return false;
	}
	
	bool bIsNLFit = _is_nlsf_operation(op);
	_update_grid_tree(trGetN, bIsNLFit);
	
	return true;
}

bool _update_tree_category_change(TreeNode& trGetN, string& strErrMsg)
{
	/*
	string strCateg;
	vector<string> vsFunctionList;
	strCateg = trGetN.CategoryList.strVal;
	if(!_get_nlfit_function_list(vsFunctionList, strCateg))
	{
		strErrMsg = CER_GET_NLFIT_FUNCTION_LIST;
		strErrMsg = strErrMsg + ":" + strCateg;
		return false;
	}
	_set_function_node(trGetN, vsFunctionList, false);	
	*/
	NLFitSelFunction nlf(trGetN);
	nlf.OnChangeCategoryUpdateFunctionList(false);
	return true;
}

/*
static bool _is_designation_format_legal(const string& strDesignations)
{
	string strTemp = strDesignations;
	//strTemp.MakeUpper();
	int nX = strTemp.Find(CHAR_X_DESIGNATION);
	if(nX != 0)
		return false;
	strTemp.Delete(nX);
	int nY = strTemp.Count(CHAR_Y_DESIGNATION);
	if(nY != strTemp.GetLength())
		return false;
	return true;
}

static void _prepare_wks_by_input_designations(Worksheet& wks, int nUnitLength, int nReplicates, bool bAllY)
{
	int nNumCols = nUnitLength*nReplicates;
	if(bAllY)
		nNumCols += 1;
	
	int	iNumCols = wks.GetNumCols();
	if(iNumCols <= nNumCols)
	{
		for(int ii = iNumCols; ii < nNumCols; ii++)
			wks.AddCol();
	}
	else
	{
		for(int ii = iNumCols-1; ii >= nNumCols; ii--)
		/// ML 11/14/2007 QA70-10619 P1 DELETING_COLUMNS_WITHOUT_DESTROYING_OPERATION
		//, 	wks.DeleteCol(ii);
			wks.DeleteCol(ii, WKSDELETECOL_LEAVE_OPER_RANGES);
		/// end DELETING_COLUMNS_WITHOUT_DESTROYING_OPERATION
	}
}
*/

static int _get_cols_needed(int nDesignation, int nReplicates)
{
	int nNumCols = 0;
	if(nDesignation == designation_XY)
		nNumCols = 2*nReplicates;
	else
		nNumCols = nReplicates + 1;
	
	return nNumCols;
}
static void _prepare_wks_by_input_designations(Worksheet& wks, int nDesignation, int nReplicates)
{
	int nNumCols = _get_cols_needed(nDesignation, nReplicates);
	int	iNumCols = wks.GetNumCols();
	if(iNumCols <= nNumCols)
	{
		for(int ii = iNumCols; ii < nNumCols; ii++)
			wks.AddCol();
	}
	else
	{
		for(int ii = iNumCols-1; ii >= nNumCols; ii--)
		/// ML 11/14/2007 QA70-10619 P1 DELETING_COLUMNS_WITHOUT_DESTROYING_OPERATION
		//, 	wks.DeleteCol(ii);
			wks.DeleteCol(ii, WKSDELETECOL_LEAVE_OPER_RANGES);
		/// end DELETING_COLUMNS_WITHOUT_DESTROYING_OPERATION
	}
	wks.GetPage().Refresh();
}

static bool _get_input_data_range(DataRange& dr, Worksheet& wks, int nDesignation, int nRangeIndex)
{
	int nX, nY;
	if(nDesignation == designation_XY)
	{
		nX = 2*nRangeIndex - 2;
		nY = 2*nRangeIndex - 1;
	}
	else
	{
		nX = 0;
		nY = nRangeIndex;	
	}
	
	if(nX >= wks.GetNumCols() || nY >= wks.GetNumCols() )
		return false;
	
	dr.Add("X", wks, 0, nX, -1, nX); 
	dr.Add("Y", wks, 0, nY, -1, nY); 
	return true;
}


static bool _construct_input_data_branch(TreeNode& trInput, Worksheet& wks, int nDesignation, int nReplicates)
{
	/// YuI 12/11/07 QA70-10773 ASSAYS_XF_IS_NOT_WROKING_PROPERLY
	/*
	int nNumRanges = nReplicates;
	Tree tr;
	tr.AddNode(STR_INPUT_DATA_TAGNAME);
	TreeNode trTemp = tr.GetNode(STR_INPUT_DATA_TAGNAME);
	TreeNode trInputData = trInput.GetNode(STR_INPUT_DATA_TAGNAME);
	for(int iRange = 1; iRange <= nNumRanges; iRange++)
	{
		DataRange dr;
		if(!_get_input_data_range(dr, wks, nDesignation, iRange))
			return false;
		
		string strTagName = STR_RANGE;
		strTagName += ftoa(iRange);
		if(!dr.GetTree(trTemp, FALSE))
			return false;
		
		trInputData.AddNode(strTagName);
		TreeNode trRange = trInputData.GetNode(strTagName);
		TreeNode trRangeTemp = trTemp.GetNode("Range1");
		trRange.Replace(trRangeTemp, TRUE, TRUE, TRUE);
	}
	*/
	
	// first thing to do is to constract entire range tree
	Tree trRangeTree;
	for( int iRange = 1; iRange <= nReplicates; iRange++ )
	{
		DataRange dr;
		if(!_get_input_data_range(dr, wks, nDesignation, iRange))
			return false;

		// get current subrange tree
		Tree trSubRangeTemp;
		if(!dr.GetTree(trSubRangeTemp, TRUE))
			return false;
		
		string strTagName;
		strTagName.Format("%s%d", STR_RANGE, iRange);
		
		TreeNode trSubRange = trRangeTree.AddNode(strTagName);
		trSubRange.Replace(trSubRangeTemp, TRUE, TRUE);
	}
	
	// range tree is constructed
	// now we must update input tree of the operation
	// it must have the same number of subranges
	// if there are not enough - we will create new once by cloning the first subrange
	
	int nOPSubRangeCount = 0;
	TreeNode trOPSubRange = trInput.FirstNode;
	while( trOPSubRange )
	{
		nOPSubRangeCount++;
		TreeNode trTemp = trOPSubRange;
		trOPSubRange = trOPSubRange.NextNode;
		if( nOPSubRangeCount > nReplicates )
		{
			// too many subranges in operation tree, getting rid of them
			trInput.RemoveChild(trTemp);
		}
	}
	
	// now need to check - maybe operation tree has not enough subranges
	if( nOPSubRangeCount < nReplicates )
	{
		TreeNode trFirstOPSubRange = trInput.FirstNode;
		if( trFirstOPSubRange )
		{
			for( int ii = nOPSubRangeCount; ii < nReplicates; ii++ )
			{
				string strTagName;
				strTagName.Format("%s%d", STR_RANGE, ii + 1);
				TreeNode trAddedSubRange = trInput.AddNode(strTagName);
				trAddedSubRange.Replace(trFirstOPSubRange.Clone(), TRUE, TRUE);
			}
		}
	}
	
	
	// finally we have (supposedly) good tree structure and may copy values
	octree_copy_values(&trRangeTree, &trInput, TREE_COPY_BY_NAME_AND_ORDER);
	/// end ASSAYS_XF_IS_NOT_WROKING_PROPERLY
	
	return true;
}

static void _set_function(TreeNode& trGUI, bool bIsNLFit, const string& strCategory, const string& strFunction)
{
	if(bIsNLFit)
	{
		trGUI.FunctionSelection.CategoryList.strVal = strCategory;
		trGUI.FunctionSelection.FunctionList.strVal = strFunction;
		///Sophy 1/6/2009 v8.0993e FIX_ASSAY_OGW_FAIL_TO_SHOW_CORRECT_EQUATION_IN_REPORT
		Tree trFDF;
		if ( nlsf_load_fdf_tree(trFDF, strFunction, strCategory) )
		{
			string strParaInitCodes, strFormula;
			strParaInitCodes = nlsf_get_param_init_code(trFDF);
			strFormula = nlsf_get_formula(trFDF);
			
			trGUI.Codes.FunctionCode.strVal = strFormula;
			trGUI.Codes.ParaInitCode.strVal = strParaInitCodes;
		}
		///end FIX_ASSAY_OGW_FAIL_TO_SHOW_CORRECT_EQUATION_IN_REPORT
	}	
}
/// YuI 12/11/07 QA70-10773 ASSAYS_XF_IS_NOT_WROKING_PROPERLY
// this function does not appear to be needed anymore
/*
static bool _set_input_data(TreeNode& trGUI, TreeNode& trInputData)
{
	
	TreeNode trGUIInput = trGUI.InputData;
	if(!trGUIInput)
		return false;
	
	trGUIInput.Replace(trInputData, TRUE, TRUE, TRUE);
	return true;
}
*/
/// end ASSAYS_XF_IS_NOT_WROKING_PROPERLY

static string _construct_all_y_designations_string(Worksheet& wks, int nDesignation, int nReplicates)
{
	string strTemp;
	if(nDesignation == designation_XYYY)
		strTemp = STR_X_DESIGNATION;
	
	for(int ii = 0; ii < nReplicates; ii++)
	{
		if(nDesignation == designation_XY)
			strTemp += STR_XY_DESIGNATION;
		else
			strTemp += STR_Y_DESIGNATION;
	}
		
	return strTemp;
}

static bool _get_nlfit_category_and_function(const Worksheet& wksReport, string& strCategory, string& strFunction)
{
	if(!wksReport)
		return false;
	
	OperationBase& op = wksReport.GetSrcOperation();
	if(!op.IsValid())
		return false;
	
	bool bIsNLFit = _is_nlsf_operation(op);
	if(!bIsNLFit)
		return false;
	
	TreeNode trOp;
	op.GetTree(trOp);
	TreeNode trGUI = trOp.GUI;
	if(!trGUI)
		return false;
	
	strCategory = trGUI.FunctionSelection.CategoryList.strVal;
	strFunction = trGUI.FunctionSelection.FunctionList.strVal;
	return true;
}

static bool _update_nlfit_category_function(TreeNode& trGetN, Worksheet& wksReport)
{
	string strCategory, strFunction;
	if(!_get_nlfit_category_and_function(wksReport, strCategory, strFunction))
		return false;
	
	vector<string> vsFunctionList;
	if(!_get_nlfit_function_list(vsFunctionList, strCategory))
		return false;
	
	trGetN.CategoryList.strVal = strCategory;
	_set_function_node(trGetN, vsFunctionList, false, strFunction);
	return true;
}

static bool _get_report_sheet(TreeNode& trGetN, Worksheet& wks, Worksheet& wksReport, string& strErrMsg)
{
	okxf_resolve_string_get_origin_object(trGetN.w.strVal, &wks);
	if(!wks)
	{
		strErrMsg = CER_NO_NUMERIC_WORKSHEET;
		return false;
	}
	
	string strSheetName = trGetN.name.strVal;
	if(!_get_report_sheet(wks, wksReport, strSheetName))
	{
		strErrMsg = REPORT_TREE_NO_REPORT_SHEET;
		return false;
	}
	
	return true;
}

static void _update_tree_by_theme(const TreeNode& trThemeGetN, TreeNode& trGetN)
{
	TreeNode trDesignation = trThemeGetN.XFGUINoTheme.designation;
	if(trDesignation && trDesignation.nVal >= designation_XY && trDesignation.nVal <= designation_XYYY)
		trGetN.designation.nVal = trDesignation.nVal;
	
	TreeNode trReplicates = trThemeGetN.XFGUINoTheme.replicates;
	if(trReplicates && trReplicates.nVal > 0)
		trGetN.replicates.nVal = trReplicates.nVal;
}


void assays(Worksheet& w, const string& name, const int& designation, const int& replicates, const string& CategoryList, const string& FunctionList, const int& recalculate)
{
	
	//int nRet =  _check_designation_string(strDesignations);
	//if(nRet == -1)
		//XF_THROW_EX(CER_EMPTY_VARIABLE, "designation");
	//if(nRet == -2)
		//XF_THROW(ASSAYS_CONFIG_WRONG_DESIGNATION_FORMAT);
	
	if(replicates < 1)
		XF_THROW(ASSAYS_CONFIG_WRONG_REPLICAS);
	
	//bool bAllY = (nRet == 1);
	//int nLength = strDesignations.GetLength();
	//_prepare_wks_by_input_designations(w, nLength, replicates, bAllY);
	//
	//if(bAllY)
		//_construct_all_y_designations_string(w, strDesignations, replicates);
		
	_prepare_wks_by_input_designations(w, designation, replicates);	
	string strDesignations = _construct_all_y_designations_string(w, designation, replicates);
	
	if(!w.SetColDesignations(strDesignations))
		XF_THROW(ASSAYS_CONFIG_SET_DESIGNATION_FAILED);
	
	Worksheet wksReport;
	if(!_get_report_sheet(w, wksReport, name))
		XF_THROW(REPORT_TREE_NO_REPORT_SHEET);
	
	OperationBase& op = wksReport.GetSrcOperation();
	if(!op.IsValid())
		XF_THROW(CER_GET_OPERATION_OBJECT);
	TreeNode trOp;
	op.GetTree(trOp);
	TreeNode trOpGUI = trOp.GUI;
	if(!trOpGUI)
		XF_THROW(ASSAYS_CONFIG_GUI_TREE_WRONG);
	//As max said, when do fit from averaged data sheet, input data will not change
	bool bFitFromAve = false;
	DataRange drInput;
	if(op.GetInput(drInput) && drInput)
	{
		//Worksheet wksInput;
		//vector			vY, vX, vWeights;
		//matrix			mXs;
		//DWORD			dwPlotUID;
		//DWORD dwRules = op.GetDataRules(trOp);
		string strBook, strSheet;
		drInput.GetBookSheet(strBook, strSheet);
		//drInput.GetData(dwRules, 0, &dwPlotUID, NULL, &vY, &vX, &mXs, NULL, &vWeights, NULL, NULL, &wksInput);
		if(!strSheet.IsEmpty())
			bFitFromAve = (strSheet.Compare(AVERAGED_DATA_SHEET_NAME) == 0);
	}
	if(!bFitFromAve)
	{
		/// YuI 12/11/07 QA70-10773 ASSAYS_XF_IS_NOT_WROKING_PROPERLY
		/*
		Tree trInput;
		trInput.AddNode(STR_INPUT_DATA_TAGNAME);
		if(!_construct_input_data_branch(trInput, w, designation, replicates))
			XF_THROW(ASSAYS_CONFIG_CONSTRUCT_INPUT_FAILED);
		
		//uint 	uid;
		//TreeNode trGUI;
		//if( !wksReport.GetReportTree(trGUI, &uid, 0, GRT_TYPE_GUI))
				//XF_THROW(CER_GET_GUI_TREE_FAILED);	//fail to get GUI tree	
				
		TreeNode trInputData = trInput.GetNode(STR_INPUT_DATA_TAGNAME);
		if(!_set_input_data(trOpGUI, trInputData))
			XF_THROW(ASSAYS_CONFIG_GUI_TREE_WRONG);
		*/
		
		// make copy such that if exception is thrown - operation stats intact
		TreeNode trOpInputData = trOpGUI.InputData;
		if( !trOpInputData )
			XF_THROW(ASSAYS_CONFIG_CONSTRUCT_INPUT_FAILED);
		
		TreeNode trOPInputCopy = trOpInputData.Clone();
		
		// update trOPInputCopy from ranges
		if(!_construct_input_data_branch(trOPInputCopy, w, designation, replicates))
			XF_THROW(ASSAYS_CONFIG_CONSTRUCT_INPUT_FAILED);
		
		// now may set it back
		trOpInputData.Replace(trOPInputCopy, TRUE, TRUE, TRUE);
		/// end ASSAYS_XF_IS_NOT_WROKING_PROPERLY
	}
	
	bool bIsNLFit = _is_nlsf_operation(op);
	_set_function(trOpGUI, bIsNLFit, CategoryList, FunctionList);
	///Arvin 11/23/07 ASSAYS_SHOULD_NOT_SET_PARAM_SETTINGS_FROM_OP_TREE_AFTER_FUNCTION_CHANGED
	TreeNode trFitWorkArea = trOp.FitWorkArea;
	if(trFitWorkArea)
		trFitWorkArea.SetAttribute(STR_AUTO_INIT_PARAMS, AUTO_INIT_PARAMS);
	///END ASSAYS_SHOULD_NOT_SET_PARAM_SETTINGS_FROM_OP_TREE_AFTER_FUNCTION_CHANGED
	//trOpGUI.Replace(trGUI);
	op.SetTree(trOp);
	if(recalculate)
		op.SetModified();
	
}

//nEventID < 0 on event, like GETNE_ON_INIT, GETNE_ON_OK etc, >0 on change from control
//return 0 to do nothing, return PEVENT_GETN_RET_TO_CLOSE to close dialog
//dwEnables = bOKEnable, bBTN1Enable, bBTN2Enable, bBTN3Enable, , can set to false to disable OK/Apply buttons
//lpcszNodeName = the trGetN TreeNode tag name that generates the event, or is  if GETNE_ON_OK etc
//strAux = optional string for XF Wizard Bar, like DLG_NEED_CHANGE_GRID etc, it will be invalid if from internal node value change event
//strErrMsg = allowing messages to be shown
int assays_event1(TreeNode& trGetN, int nRow, int nEventID, DWORD& dwEnables, LPCSTR lpcszNodeName, WndContainer& DynaCntrlContainer, string& strAux, string& strErrMsg)
{
	if( xf_is_extended_event(nEventID) )
		return assays_event1_ex(trGetN, nRow, nEventID, dwEnables, lpcszNodeName, DynaCntrlContainer, strAux, strErrMsg);
	DECLARE_BUTTON_ENABLES
	///Kyle 09/24/08 SET_NO_NEED_TO_LOCALIZE
	if ( GETNE_ON_INIT == nEventID )
	{
		trGetN.designation.SetAttribute(STR_OCNTRL_OPTNS, OCNTRLPARAM1_NOT_LOCALIZED);
	}
	///End SET_NO_NEED_TO_LOCALIZE
	
	Worksheet wksSource, wksReport;
	bOKEnable = _get_report_sheet(trGetN, wksSource, wksReport, strErrMsg);
	
	if(GETNE_ON_INIT == nEventID)
	{
		//_init_designation_node(trGetN);
		bOKEnable = _init_nlfit_category_function_node(trGetN, wksReport, strErrMsg);
		if(!bOKEnable)
			return false;
	}
	
	bool bIsChangingWks = lstrcmpi(lpcszNodeName,"w") == 0? true:false;
	bool bIsChangingReport =  lstrcmpi(lpcszNodeName,"name") == 0? true:false;
	if(bIsChangingWks || bIsChangingReport)
		 _update_nlfit_category_function(trGetN, wksReport);
	
	if(GETNE_ON_INIT == nEventID || bIsChangingWks || bIsChangingReport)
	{
		Tree trTheme;
		trTheme.AddNode("GetN");
		trTheme.GetN.Replace(trGetN);
		if(theme_active_book_sheet_storage(trTheme, "assays", PDS_BOOK, TRUE))
			_update_tree_by_theme(trTheme, trGetN);
	}
	
	bOKEnable = _check_and_update_assays_config_tree(trGetN, wksSource, wksReport, strErrMsg);
	
	bool bIsChangingCategory = lstrcmpi(lpcszNodeName,"CategoryList") == 0? true:false;
	if(bIsChangingCategory)
		bOKEnable = _update_tree_category_change(trGetN, strErrMsg);
	
	if(nEventID == GETNE_ON_OK)
		theme_active_book_sheet_storage(trGetN, "assays", PDS_BOOK,  FALSE);
	
	return false;

}

int assays_make_tree(TreeNode& tr, LPCSTR lpcszVarName)
{
	return false;
}
//nGetNDialog = 0,1,2, corresponding to the XF GetN dropdown, 0 = dialog is not used
//you can change nRet to be one of XFEVT_PROCEED (defualt), XFEVT_ABORT, XFEVT_PROCEED_NO_DLG or XFEVT_PROCEED_WITH_DLG(when nGetNDialog = 0)
//nGetNDialog = -1 when Ok on GetN dialog to allow handler to preocess <auto> etc variables
//dwCntrl is combination of bits
//LTXF_FROM_GUI_MENU, LTXF_FROM_GUI_PROMPT, LTXF_FROM_AUTO_UPDATE, LTXF_FROM_FUNCTION, LTXF_THEME_USED, LTXF_CHANGE_PARAM
void assays_before_execute(TreeNode& trGetN, int nGetNDialog, int& nRet, int dwCntrl)
{
		//_init_designation_node(trGetN);
		//string strErrMsg;
		//_init_nlfit_category_function_node(trGetN, strErrMsg);
}
//nEventID < 0 on event, like GETNE_ON_INIT, GETNE_ON_OK etc, >0 on change from control
//return 0 to do nothing, return PEVENT_GETN_RET_TO_CLOSE to close dialog
//dwEnables = bOKEnable, bBTN1Enable, bBTN2Enable, bBTN3Enable, , can set to false to disable OK/Apply buttons
//lpcszNodeName = the trGetN TreeNode tag name that generates the event, or is  if GETNE_ON_OK etc
//strAux = optional string for XF Wizard Bar, like DLG_NEED_CHANGE_GRID etc, it will be invalid if from internal node value change event
//strErrMsg = allowing messages to be shown
int assays_event1_ex(TreeNode& trGetN, int nRow, int nEventID, DWORD& dwEnables, LPCSTR lpcszNodeName, WndContainer& DynaCntrlContainer, string& strAux, string& strErrMsg)
{
	return false;
}
