/*------------------------------------------------------------------------------*
 * File Name:op_utils.c		 													*
 * Creation: CPY 12/29/2007														*
 * Purpose: Curve Fitting and other Operation XF utilities						*
 * Copyright (c) Originlab Corp. 2007											*
 * All Rights Reserved															*
 * 																				*
 * Modification Log:															*
 *	Hong 01/18/08 QA80-10929 ADD_LT_NLFIT_MECHANISM								*
 *	Hong 01/22/08 QA80-10929 LTNL_ACCESS_FITSESSION_PONTER						*
 *	CPY 1/22/08 LINK_NLFIT_OP_TREE_TO_LT_TREE									*
 *	Hong 01/23/08 QA80-10929 LTNL_ACCESS_WORKAREA_AFTER_INIT					*
 *	Hong 01/24/08 QA80-10929 LT_NLFIT_SUPPORT_SOUURCE_GRAPHPAGE_PREVIEW			* 
 *	ML 1/24/2008 QA70-10929 P3 LABTALK_Y_OF_X_CHANNELED_TO_THE_NEW_NLFIT_LT_ACCESS
 * CPY 1/24/2008 QA70-10929_P3 LABTALK_FIT_CALL_NLFIT_SESSION_DIRECTLY			*
 *	Hong 01/25/08 QA80-10929 FIX_FITWORKAREA_NOT_UPDATE_INTO_FITSESSION_BEFORE_ITERATE
 *	ML 1/25/2008 QA70-10929 CACHING_INFO_ABOUT_LINKED_OPERATION_TREE			*
 *	CPY 1/26/2007 QA70-10929_P5 NOTIFY_STATIC_OP_UTILS_OPERATION_OBJ_TO_DESTROY	*
 *	Arvin 01/29/08 GENERATE_REPORT_FOR_LT_NLFit									*
 *	Hong 01/31/08 QA80-10929 LTNLFIT_MORE_DETAILS_ERROR_MSG						*
 *	Hong 02/01/08 v80.798 FIX_FIRST_TIME_OPEN_PARAM_DLG_VALUE_NOT_UPDATED		*
 *	Hong 02/01/08 v8.0798 UPDATE_LTNL_FITMODE									*
 *	Hong 02/01/08 v8.0798 FIX_CONTANTENATE_FIT_FAIL_WORK						*
 *	Folger 02/13/08 QA80-10929 ADD_FUNCTION_MODEL_TO_CALCULATION_NOTES			*
 *	Folger 02/19/08 QA80-10929 OPTIONAL_DWORD_TO_DISPLAY_KEY_AND_NAME			*
 *	Hong 03/05/08 QA80-10292 v8.0817 NLFIT_SUPPORT_APPLY_DIALOG_THEME			*
 *	Hong 03/18/08 v8.0826 FIX_LTNL_REPLICA_FAIL_WORK							*
 *	Arvin 03/25/08 MOVE_REPLICA_BARANCH_OUT_OF_FIT_CONTROL_BRANCH as CP said	*
 *	Hong 04/17/08 v8.0845 FIX_SET_FUNCTION_FAIL_WHEN_LAST_ITERATION_CONVERGE	*
 *	Hong 06/16/08 QA80-11699 FIX_2D_FITTING_FAIL_GENERATE_REPORT				*
 *	Folger 08/14/08 QA80-12017 ADD_NUMBER_OF_PARAMETERS_AND_DATASETS_INFO_TO_LABTALK_TREE
 *	ML 8/25/2008 PROPER_FITNL_INIT_WHEN_FITTING_FROM_SCRIPT_XFUNCS				*
 *	Kyle 09/05/08 USE_NEW_NLFSESSION_AND_NLFPARAMSCONTROL_IN_NLFPARAMDLG		*
 *	Hong 10/15/08 QA80-12386 v8.0955b FIX_THEME_FAIL_WORK_FOR_SURFACE_FIT		*
 *	Hong 10/31/08 v8.0963b FIX_NLEND_FAIL_CREATE_FIT_CURVE_IN_SRC_GRAPH			*
 *	Hong 10/3/08 v8.0963b SHOULD_UPDATE_PREVIEW_AFTER_FIT						*
 *	Hong 11/04/08 v8.0965b NLLT_NO_NEED_CHECK_ITERATE_RESULT					*
 *	Hong 11/25/08 QA80-12655 FIX_NO_RESSTAT_IN_LT_TREE_AFTER_ITERATE			*
 *	Folger 11/25/08 QA80-12655-P2 v8.0979 FAIL_TO_GET_DERIVED_PARAM_NUMBER_IN_NLFIT_LT_TREE
 *	Folger 11/25/08 QA80-12655-P5 v8.0979 LT_TREE_PARAMS_FAIL_TO_ACCESS_AFTER_NLEND_1_TO_GENERATE_REPORT
 *	Folger 02/17/09 QA80-13125 LT_FUNCTION_FIT_RETURN_BAD_RESULTS_WHEN_NLFIT_NOT_CONVERGED
 *	Folger 03/11/09 QA80-13253 NLFIT_LT_COMMAND_SUPPORT_SPECIFY_WEIGHT_METHOD	*
 *	Folger 06/30/09 QA80-13859 NLFIT_LABTALK_SUPPORT_MULTIPLE_INDEPENDENTS_AND_DEPENDENTS_BY_NEW_XF_NLBEGINR
 *	Sophy 8/5/2009 QA80-14072 SUPPORT_CHANGE_INPUTDATA_IN_NLFIT_FROM_LABTALK	*
 *	Hong 08/12/09 QA80-14123 FIX_NL_LT_ROUTINE_SHOULD_NOT_GENERATE_LAST_USED_THEME
 *	Hong 09/14/09 FIX_LT_NLFIT_FAIL_GET_ALL_SET_CHISQR_AFTER_ITERATE_FOR_SEPARATE_FIT_MODE
 *	Sophy 9/18/2009 QA80-14072 SUPPORT_CHANGE_INPUTDATA_IN_NLFIT_FROM_LABTALK	*
 *	Sim 10-14-2009 QA81-14471 FIX_NLFIT_SET_CONSTRAINTS_FROM_LT_TREE			*
 *	Folger 12/08/09 QA81-14819 CHANGE_PARAM_FROM_OPERATION_CREATED_BY_NLBEGIN_FAILS
 *	Folger 04/16/10 QA81-15323 NLEND_AUTO_UPDATE_MODE_FOLLOW_THEME				*
 *	Folger 10/21/2010 ORG-1297-P1 NLEND_FAILED_TO_ADD_FITTED_CURVE_AND_RESULT_TABLE_TO_SOURCE_GRAPH
 *	Folger 10/22/2010 ORG-1315-P1 WRONG_WEIGHT_METHOD_USE_WHEN_SPECIFY_ERROR_IN_NLBEGIN_INPUT_DATA
 *	Folger 10/22/2010 ORG-1316-P1 REPORT_GENERATED_BY_NLEND_FAILED_TO_DISPLAY_CORRECT_USED_DEFINED_FUNCTION_NAME
 *------------------------------------------------------------------------------*/
#include <Origin.h>
#include <Operation.h>
#include <xfutils.h>/// Iris 3/11/2008 SUPPORT_XYZ_INPUT
#include "op_utils.h" 
#include "nlsf_utils.h" 
#include "NLFitSession.h"
///---Sim 09-10-2008 NLFIT_LABTALK_TREE_ACCESS
#include "FitCommon.h"
#include "FitNL.h"
///---END NLFIT_LABTALK_TREE_ACCESS
#include "NLFitPreviewCtrl.h"
#include "SurfaceFitPreviewCtrl.h"
/// Hong 01/29/08 QA80-10929 LT_NL_ALLOW_UPDATE_PARAMS_BY_DIALOG
#include <xfgraph_utils.h> //CPY 5/1/08 op_utils.c compile err in nlbegin after Hong 01/29/08 QA80-10929 LT_NL_ALLOW_UPDATE_PARAMS_BY_DIALOG
#include "NLParameterDlg.h"
/// end LT_NL_ALLOW_UPDATE_PARAMS_BY_DIALOG

static	string		s_strFuncName; //For NLSF in XOP only
#ifndef execute_init
enum{
	execute_init,
	execute_update,
	execute_run,
	execute_report,
	execute_cleanup,
};
#endif

/// Hong 09/27/08 FIX_LT_TREE_FAIL_GET_SESSION_PTR
// better in other place
#define STR_FIT_POINTER		 			"FitPointer"
/// end FIX_LT_TREE_FAIL_GET_SESSION_PTR
///Arvin 02/21/08 QA70-10929 NLEND_NEED_OUTPUT_REPORT_TABLES_TO_NOTES_WINDOW
enum{
	EXECUTE_REPORT_NONE			= 0,
	EXECUTE_GETNERATE_REPORT  	= 1,
	EXECUTE_OUTPUT_TO_NOTES_WIN = 2,
};
///end NLEND_NEED_OUTPUT_REPORT_TABLES_TO_NOTES_WINDOW

///Arvin 06/29/07 v8.652 XOP_NEED_SUPPORT_NLFIT
static bool _is_nlsf_tool(LPCSTR lpcszClassName)
{
	string strClassName(lpcszClassName);
	return strClassName.Compare(STR_FITTEROPERATION_CLASS_FITNL) == 0 ? true : false;
}

static bool _nlf_function_name(const TreeNode& trOp, string& strFuncName, bool bGet=true)
{
	TreeNode trOutGUI = trOp.GetNode("GUI");
	TreeNode trFuncSel = trOutGUI.FunctionSelection;
	if(trFuncSel)
	{
		if(bGet)
			strFuncName = trFuncSel.FunctionList.strVal;
		else
		{
			if(strFuncName.IsEmpty())
				return false;
			trFuncSel.FunctionList.strVal = strFuncName;
			return true;
		}
	}
	return strFuncName.IsEmpty() ? false : true;
}
///end XOP_NEED_SUPPORT_NLFIT
static string _sep_class_option(LPCSTR lpcszName, int* pnOption = NULL)
{
	string 	strClassName(lpcszName);
	
	vector<string> vs;
	int 	nNumToken = strClassName.GetTokens(vs, '_');
	if(nNumToken > 1) // className_nOption form
	{
		strClassName = vs[0];
		
		if(NULL != pnOption)
		{
			*pnOption = atoi(vs[1]);
		}
	}
	return strClassName;
	
}

static string _get_classname_from_gui_tree(TreeNode& trGUI, int* pnOption)
{
	string	strClassName;
	strClassName = trGUI.name.strVal; //the value written in _construct_gui_tree
	
	strClassName = _sep_class_option(strClassName, pnOption);	
	return strClassName;
}

static void _clean_operation_object(OperationPtr& pOP)
{
	if ( pOP )
	{
		pOP->DestroyInternal();
		pOP = NULL;
	}
}

/*
static bool _is_ANOVA_tool(LPCSTR lpcszClassName, bool* pbTwoWay = NULL, bool* pbRM = NULL)
{
	string strClassName(lpcszClassName);
	strClassName.MakeUpper();
	if(strClassName.Find("ANOVA") < 0)
		return false;
	
	if(NULL != pbTwoWay)
		*pbTwoWay = strClassName.Find("ONE") < 0? true : false;
	
	if(NULL != pbRM)
		*pbRM = strClassName.Find("RM") < 0? false : true;
	return true;
}

static void _construct_anova_input_data_branch(TreeNode& trInputData, bool bTwoWay, bool bRM)
{
	if(ANOVA_INDEXED_DATA == trInputData.Use)
	{
		okutil_anova_switch_to_indexed_data(&trInputData, bTwoWay, bRM);			
	}
	else
	{
		okutil_anova_switch_to_raw_data(&trInputData, bTwoWay, bRM);
	}	
}
*/

/// Iris 06/22/2007 v8.0646 INTRODUCE_EXECUTE_MODE_VAR
//static bool _do_calculate(TreeNode& trGUI, TreeNode& trOut, TreeNode& trMakeTree, LPCSTR lpcszTheme = NULL, bool bDoReport = report_outTree)
//static int _do_calculate(TreeNode& trGUI, TreeNode& trOut, LPCSTR lpcszTheme = NULL, int nExecuteMode = execute_run)
int op_do_calculate(OperationPtr& pOP,  TreeNode& trGUI, int nExecuteMode, TreeNode& trOut, LPCSTR lpcszTheme)//=NULL=NULL = 0;
{
	int		nOption = 0;
	string	strClassName = _get_classname_from_gui_tree(trGUI, &nOption);
	
	string	strTheme(lpcszTheme);
	if( !strTheme.IsEmpty() )
		theme_apply_analysis_theme(trGUI.name.strVal, trGUI, strTheme); //the first var should be class name + option here, like DescStats_1 for stats on rows, so cannot use strClassName here
	
	/// Iris 06/22/2007 v8.0646 INTRODUCE_EXECUTE_MODE_VAR
	//if(trMakeTree)
		//trMakeTree.Replace(trGUI.Clone());
	///end INTRODUCE_EXECUTE_MODE_VAR	

	//
	//----------Calculation----------
	//
	bool 	bRet;
	///Arvin 06/29/07 v8.652 XOP_NEED_SUPPORT_NLFIT
	//bool	bOK = false;
	//Operation& op = (Operation &)op_create(strClassName, bOK, nOption); 
	//if(op == NULL )
	//	return XFERR_FAIL_TO_CREATE_OPERATION;
	
	//Tree	trOp;
	//op.GetTree(trOp);
	if(NULL == pOP)
		return XFERR_FAIL_TO_CREATE_OPERATION;
	
	///Arvin 06/29/07 v8.652 XOP_NEED_SUPPORT_NLFIT	
	string strOpClassName = pOP->GetClassName();
	if(strClassName.Compare(strOpClassName) != 0)
		return XFERR_WRONG_CLASS_NAME;
	
	if(_is_nlsf_tool(strClassName))
	{
		string strFuncName; 
		_nlf_function_name(trGUI, strFuncName);
		if(	strFuncName.Compare(s_strFuncName) != 0)
			return XFERR_WRONG_FUNC_NAME;
	}
	///end XOP_NEED_SUPPORT_NLFIT
	Tree	trOp;
	pOP->GetTree(trOp);
	///end XOP_NEED_SUPPORT_NLFIT
	
	trOp.GUI.Replace(trGUI.GUI.Clone());
	///Arvin 06/29/07 v8.652 XOP_NEED_SUPPORT_NLFIT
	trOp.Operation.AutoUpdate.nVal = AU_NONE;
	TreeNode trUserSettings = trGUI.UserSettings;
	if(trUserSettings)
	{
		trOp.AddNode("UserSettings");
		trOp.UserSettings.Replace(trUserSettings.Clone());
	}
	///end XOP_NEED_SUPPORT_NLFIT
	
	///Cheney/Arvin 2007-9-10 XOP_NEED_SUPPORT_PFM
	TreeNode trFitWorkArea = trGUI.FitWorkArea;
	if(trFitWorkArea)
	{
		trOp.AddNode("FitWorkArea");
		trOp.FitWorkArea.Replace(trFitWorkArea.Clone());	
	}
	
	TreeNode 	trPFWTree = trGUI.PFWTree;
	if(trPFWTree)
	{
		trOp.AddNode("PFWTree");
		trOp.PFWTree.Replace(trPFWTree.Clone());	
	}
	///end XOP_NEED_SUPPORT_PFM
	
	int     nAutoUpdate = 0;
	///Arvin 06/29/07 v8.652 XOP_NEED_SUPPORT_NLFIT
	//op.SetTree(trOp);
	//op.OnNoEdit(nOption, nAutoUpdate);
	pOP->SetTree(trOp);
	pOP->OnNoEdit(nOption, nAutoUpdate);
	
	///Arvin 11/10/07 XOP_NEED_SUPPORT_CHANGE_FUNCTION
	pOP->GetTree(trOp);
	pOP->ClearOutputTables(trOp);
	pOP->SetTree(trOp);
	///end XOP_NEED_SUPPORT_CHANGE_FUNCTION
	
	///end XOP_NEED_SUPPORT_NLFIT
	//
	//----------Output----------
	//
	/// Iris 06/22/2007 v8.0646 INTRODUCE_EXECUTE_MODE_VAR
	//if(bDoReport)//do report according the settings in GUI.Output.Report nodes
	if(execute_report == nExecuteMode)
	///end INTRODUCE_EXECUTE_MODE_VAR
	{
		///Arvin 06/29/07 v8.652 XOP_NEED_SUPPORT_NLFIT
		//if( !op.Execute() )
		if( !pOP->Execute() )
		///end XOP_NEED_SUPPORT_NLFIT
			return XFERR_FAIL_TO_DO_CALC_OR_REPORT;
	}
	else if(execute_run == nExecuteMode && trOut)
	{
		///Arvin 06/29/07 v8.652 XOP_NEED_SUPPORT_NLFIT
		//bRet = 0 == op.Calculate()? true : false;
		bRet = 0 == pOP->Calculate()? true : false;
		///end XOP_NEED_SUPPORT_NLFIT
		if(bRet)
		{
			///Arvin 06/29/07 v8.652 XOP_NEED_SUPPORT_NLFIT
			//op.GetTree(trOp);	
			pOP->GetTree(trOp);	
			///end XOP_NEED_SUPPORT_NLFIT
			trOut.Replace(trOp.Calculation.Clone());
		}
		else
			return XFERR_FAIL_TO_DO_CALC;
	}
	else
		return XFERR_INCORRECT_VAR_VAL;
	
	return CER_NO_ERROR;
}

//static int _update_gui_tree(TreeNode& trGUI, LPCSTR lpcszTheme = NULL)
int op_update(OperationPtr& pOP,  TreeNode& trGUI, LPCSTR lpcszTheme)
{
	int		nOption = 0;
	string	strClassName = _get_classname_from_gui_tree(trGUI, &nOption);
	// update GUI tree according Theme
	string	strTheme(lpcszTheme);
	if( !strTheme.IsEmpty() )
		theme_apply_analysis_theme(trGUI.name.strVal, trGUI, strTheme);
	///Arvin 06/29/07 v8.652 XOP_NEED_SUPPORT_NLFIT
	/*
	// update GUI tree according to InputData.Use for ANOVA
	bool		bTwoWay, bRM;
	if( _is_ANOVA_tool(strClassName, &bTwoWay, &bRM) )// to construct input data subnodes for all ANOVA tools
	{
		_construct_anova_input_data_branch(trGUI.GUI.InputData, bTwoWay, bRM);
	}
    */
    //bool	bOK = false;
	//Operation& op = (Operation &)op_create(strClassName, bOK, nOption); 
	//if(op == NULL )
		//return XFERR_FAIL_TO_CREATE_OPERATION;
	if(NULL == pOP)
		return XFERR_FAIL_TO_CREATE_OPERATION;
	
	string strOpClassName = pOP->GetClassName();
	if(strClassName.Compare(strOpClassName) != 0)
		return XFERR_WRONG_CLASS_NAME;
	
	Tree 	trOp;
	pOP->GetTree(trOp);
	
    int nRet = pOP->OnInitOperationTreeFromOCLT(trOp, trGUI, false); //Update operation tree
    if(nRet != OP_NOERROR)
    	return XFERR_FAIL_TO_UPDATE_OPERATION_TREE;
    
    //For nlsf, need remember function name
	if(_is_nlsf_tool(strClassName))
	{
		_nlf_function_name(trGUI, s_strFuncName);
	}
    ///end XOP_NEED_SUPPORT_NLFIT
	return CER_NO_ERROR;
}


int op_init(OperationPtr& pOP, LPCSTR lpcszClassOption, TreeNode& trGUI, LPCSTR lpcszTheme, int lParam)
{
	int		nOption = 0;
	//Need reset trGUI for init
	if(trGUI)
		trGUI.Reset();
	
	string	strClassName = _sep_class_option(lpcszClassOption, &nOption);
	if(trGUI)
		trGUI.name.strVal = (string)lpcszClassOption; //will use it when do execute_updateTree, execute_outputTree or execute_generateReport
	
	bool	bOK = false;
	
	_clean_operation_object(pOP);
	
	if(trGUI && strClassName.CompareNoCase("FitPeak")==0)
	{
		TreeNode trPeakNum = tree_check_get_node(trGUI, "PeakNum");
		trPeakNum.nVal = nOption;
		TreeNode trHasBaseline = tree_check_get_node(trGUI, "HasBaseline");
		if(lParam)
			trHasBaseline.nVal = 1;
		else
			trHasBaseline.nVal = 0;
	}
	
	Operation& op = (Operation &)op_create(strClassName, bOK, nOption);	
	if(op == NULL )
		return XFERR_FAIL_TO_CREATE_OPERATION;
	pOP = &op;
	
	Tree 	trOp;
	TreeNode trOutGUI;
	pOP->GetTree(trOp);
	if(trGUI)
	{
		trOutGUI = trGUI.GetNode("GUI");
		if(!trOutGUI)
			trOutGUI = trGUI.AddNode("GUI");
		trOutGUI.Replace(trOp.GUI.Clone());
	}
	else
		trOutGUI = trOp.GUI;
	
	// apply dialog theme
	string	strTheme(lpcszTheme);
	if( !strTheme.IsEmpty() )
		theme_apply_analysis_theme(strClassName, trOutGUI, strTheme);

	if(!trGUI)
		return CER_NO_ERROR;
	
	///Arvin 06/29/07 v8.652 XOP_NEED_SUPPORT_NLFIT
	/*
	//construct InputData subnodes
	TreeNode	trInputData = trOutGUI.InputData;		
	bool		bTwoWay, bRM;
	if( _is_ANOVA_tool(strClassName, &bTwoWay, &bRM) )// to construct input data subnodes for all ANOVA tools
	{
		_construct_anova_input_data_branch(trInputData, bTwoWay, bRM);
	}
	else // to construct input data subnodess for the tools like DescStats, FitLinear, FitPloynomial
	{				
		DWORD		dwDataRule = s_Op.GetDataRules(trOp);//op.GetDataRules(trOp);		
		Project.InitInputDataBranchFromSelection(trInputData, dwDataRule, NULL, NULL);
	}				
	*/
	int nRet = pOP->OnInitOperationTreeFromOCLT(trOp, trGUI);
	if(nRet != OP_NOERROR)
		return XFERR_FAIL_TO_CONSTRUCT_INPUT_DATA_BRANCH;
		
	return CER_NO_ERROR;
}

//////////////////////////////////////////////////////////////////////////////
// CPY 2007-12-28
// NLSF specific support functions
//////////////////////////////////////////////////////////////////////////////
/// Hong 01/18/08 QA80-10929 ADD_LT_NLFIT_MECHANISM
/*
// we must keep a static Operation object

static OperationPtr s_pnlOp = NULL;

void cf_reset(bool bDumpStatusInfo)
{
	op_init(s_pnlOp, "FitNL", NULL);
	if(bDumpStatusInfo)
	{
		Tree 	trOp;
		s_pnlOp->GetTree(trOp);
	
		out_tree(trOp.GUI);
	}
}
// NULL will show current function name
int cf_set_fit_function(LPCSTR lpcszFundName)
{
	if(!s_pnlOp)
		return -1;
	string strFunc = lpcszFundName;
	Tree 	trOp;
	s_pnlOp->GetTree(trOp);

	if(strFunc.IsEmpty())
	{
		_nlf_function_name(trOp, strFunc);
		out_str(strFunc);
	}
	else // set
	{
		if(_nlf_function_name(trOp, strFunc, false))
			s_pnlOp->SetTree(trOp);	
	}
	return 0;
}
int cf_set_data(XYRange& iy, int nMode)
{
	return 0;
}
*/
typedef		NLFitSession*				NLFitSessionPtr;
typedef		NLFitPreviewCtrlBase*	NLFPreviewCtrlPtr;

class OC_REGISTERED LT_NLF
{
public:
	LT_NLF();
	~LT_NLF() { destroy(); }
	
public:
	///Kyle 09/11/08 MODIFY_FUNCTIONS_TO_SUPPORT_SURFACE_FIT
	//bool			Init(LPCSTR lpcszLinkedLTtreeName, DWORD dwOption = 0);	
	bool			Init(LPCSTR lpcszLinkedLTtreeName, DWORD dwOption = 0, int nFitType = NLFIT_GENERAL_XY_FITTING);	
	///End MODIFY_FUNCTIONS_TO_SUPPORT_SURFACE_FIT
	
	///Sophy 8/5/2009 QA80-14072 SUPPORT_CHANGE_INPUTDATA_IN_NLFIT_FROM_LABTALK
	//int				SetInput(const Range& iy);
	///------ Folger 12/08/09 QA81-14819 CHANGE_PARAM_FROM_OPERATION_CREATED_BY_NLBEGIN_FAILS
	//int				SetInput(const Range& iy, BOOL bFirstTime = TRUE); //bFirstTime = TRUE means first time to set data, else means change data
	int				SetInput(const Range& iy, BOOL bFirstTime = TRUE, LPCSTR lpcszFuncName = NULL); //bFirstTime = TRUE means first time to set data, else means change data
	///------ End CHANGE_PARAM_FROM_OPERATION_CREATED_BY_NLBEGIN_FAILS
	///end SUPPORT_CHANGE_INPUTDATA_IN_NLFIT_FROM_LABTALK
	/// Hong 10/09/08 v8.0953 TAKE_BACK_OLD_FEATURES
	//int				SetFunction(LPCSTR lpcszFuncName, bool* pbAutoInit = NULL);
	int				SetFunction(LPCSTR lpcszFuncName, bool* pbAutoInit = NULL, int* pnFitMode = NULL, int* pnReplica = NULL, LPCSTR lpcszTheme = NULL);
	/// end TAKE_BACK_OLD_FEATURES
	///Sophy 9/18/2009 QA80-14072 SUPPORT_CHANGE_INPUTDATA_IN_NLFIT_FROM_LABTALK
	bool			GetFunction(string& strFuncName);
	///end SUPPORT_CHANGE_INPUTDATA_IN_NLFIT_FROM_LABTALK
	int				Iterate(int nNum, int nMethod);	
	bool			EnableSourceGraphPreview();
	bool 			OpenNLParamsDialog();			///Kyle 09/08/08 ADD_FUNCTIONS_TO_OPEN_NLPARAMSDIALOG
	
	bool			DoCalculation(int nReport, int nAutoUpdate); ///Sophy 10/9/2008 CLEAN_LT_NLEND
	
	/// Hong QA80-12374 10/14/08 NL_LT_ADD_OUTPUT_ACCESS
	int				GUI(TreeNode& trGUI, bool bGet);
	/// end NL_LT_ADD_OUTPUT_ACCESS
	
	int		NLFitYofX(double *prDepValues, double *prIndepValues, int nCount, int nSet);
	
	///------ Folger 03/11/09 QA80-13253 NLFIT_LT_COMMAND_SUPPORT_SPECIFY_WEIGHT_METHOD
	void	SetWeightMethod(int nMethod = WEIGHT_NONE)		{ m_nWeightMethod = nMethod; }
	///------ End NLFIT_LT_COMMAND_SUPPORT_SPECIFY_WEIGHT_METHOD
	
private:
	void			onInit();
	void			destroy();
	NLFitSessionPtr	getSessionPtr();
	NLFPreviewCtrlPtr	getPreviewCtrlPtr();
	void			createPreviewCtrl();
	///---Sim 09-10-2008 NLFIT_LABTALK_TREE_ACCESS
	//int				linkLabtalTree(LPCSTR lpcszLinkedLTtreeName, DWORD dwOption = 0);
	///---END NLFIT_LABTALK_TREE_ACCESS
	
	/// Hong 10/31/08 v8.0963b FIX_NLEND_FAIL_CREATE_FIT_CURVE_IN_SRC_GRAPH			
	void			destroyPreviewCtrl();
	/// end FIX_NLEND_FAIL_CREATE_FIT_CURVE_IN_SRC_GRAPH
	
	/// Hong 09/24/09 QA80-12199 FIT_LT_CALL_SPEED_UP_MOVE_CODE_TO_VC
	void			initLTFitCurveEval();
	void			resetLTFitCurveEval();
	/// end FIT_LT_CALL_SPEED_UP_MOVE_CODE_TO_VC	
	bool			removeWorkAreaAttri();///Sophy 10/9/2008 CLEAN_LT_NLEND
	/// Hong 09/27/08 FIX_LT_TREE_FAIL_GET_SESSION_PTR
	OperationPtr	GetOpPtr() { ASSERT(m_pnlOp); return m_pnlOp; }
	/// end FIX_LT_TREE_FAIL_GET_SESSION_PTR
	
	//------ Folger 11/25/08 QA80-12655-P5 v8.0979 LT_TREE_PARAMS_FAIL_TO_ACCESS_AFTER_NLEND_1_TO_GENERATE_REPORT
	void			updateFitSessionPtrToOpTree();
	//------
	
	///------ Folger 10/22/2010 ORG-1315-P1 WRONG_WEIGHT_METHOD_USE_WHEN_SPECIFY_ERROR_IN_NLBEGIN_INPUT_DATA
	BOOL			UpdateWeightToInputData(TreeNode& trInputData);
	///------ End WRONG_WEIGHT_METHOD_USE_WHEN_SPECIFY_ERROR_IN_NLBEGIN_INPUT_DATA
	
private:
	///---Sim 09-10-2008 NLFIT_LABTALK_TREE_ACCESS
	//string				m_strLinkedLTTreeName;
	//DWORD					m_dwOption;
	///---END NLFIT_LABTALK_TREE_ACCESS
	bool				m_bOpTreeReady;
	/// Hong 09/27/08 FIX_LT_TREE_FAIL_GET_SESSION_PTR
	//Tree				m_trOp;
	/// end FIX_LT_TREE_FAIL_GET_SESSION_PTR
	NLFitSessionPtr		m_pSession;
	NLFPreviewCtrlPtr	m_pNLFitPreviewCtrl;
	NLFitParaDlg*		m_pNLParaDlg;				///Kyle 09/08/08 ADD_FUNCTIONS_TO_OPEN_NLPARAMSDIALOG
	/// Hong 09/12/08 v8.0938 FIX_NEW_LT_NLFIT_MEMORY_LEAD_FORGET_DESTROY_OPERATION
	OperationPtr		m_pnlOp;
	bool				m_bPreserveOpObj; // be true if do recalculation
	/// end FIX_NEW_LT_NLFIT_MEMORY_LEAD_FORGET_DESTROY_OPERATION
	/// Hong QA80-12374 10/14/08 NL_LT_ADD_OUTPUT_ACCESS
	bool				m_bFirstTimeGetGUI;
	/// end NL_LT_ADD_OUTPUT_ACCESS
	
	int					m_nWeightMethod;		///------ Folger 03/11/09 QA80-13253 NLFIT_LT_COMMAND_SUPPORT_SPECIFY_WEIGHT_METHOD
};

static	LT_NLF*	s_pltNLF = NULL;
//////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////LT_NLF Implementation/////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////
LT_NLF::LT_NLF()
{
	m_pSession	= NULL;
	m_pNLParaDlg = NULL;
	m_pNLFitPreviewCtrl = NULL;
	m_bOpTreeReady	= false;
	/// Hong 09/12/08 v8.0938 FIX_NEW_LT_NLFIT_MEMORY_LEAD_FORGET_DESTROY_OPERATION
	m_pnlOp = NULL;
	m_bPreserveOpObj = false;
	/// end FIX_NEW_LT_NLFIT_MEMORY_LEAD_FORGET_DESTROY_OPERATION
	/// Hong QA80-12374 10/14/08 NL_LT_ADD_OUTPUT_ACCESS
	m_bFirstTimeGetGUI = true;
	/// end NL_LT_ADD_OUTPUT_ACCESS
	
	m_nWeightMethod = WEIGHT_NONE;		///------ Folger 03/11/09 QA80-13253 NLFIT_LT_COMMAND_SUPPORT_SPECIFY_WEIGHT_METHOD
}
///Kyle 09/11/08 MODIFY_FUNCTIONS_TO_SUPPORT_SURFACE_FIT
//bool		LT_NLF::Init(LPCSTR lpcszLinkedLTtreeName, DWORD dwOption) // = 0
bool		LT_NLF::Init(LPCSTR lpcszLinkedLTtreeName, DWORD dwOption, int nFitType) // = 0, NLFIT_GENERAL_XY_FITTING
///End MODIFY_FUNCTIONS_TO_SUPPORT_SURFACE_FIT
{
	destroy();

	bool 		bInitOK = false;	
	/// Hong 06/16/08 QA80-11699 FIX_2D_FITTING_FAIL_GENERATE_REPORT
	//Operation& op = (Operation &)op_create("FitNL", bInitOK); 			
	Operation& op = (Operation &)op_create(STR_FITTEROPERATION_CLASS_FITNL, bInitOK, nFitType);
	/// end FIX_2D_FITTING_FAIL_GENERATE_REPORT
	if ( NULL == op )
		return false;	
	if ( !bInitOK )
	{	
		op_destroy_on_cancel(op);
		return false;
	}

	///Kyle 09/11/08 MODIFY_FUNCTIONS_TO_SUPPORT_SURFACE_FIT
	if (NLFIT_XYZ_FITTING == nFitType || NLFIT_MATRIX_FITTING == nFitType)
	{
		StringArray		saOptions, saNames;
		string			strSetInfoFromXF, strCateg;
		if ( NLFIT_XYZ_FITTING == nFitType )
			strSetInfoFromXF = "fitsurface";
		else
			strSetInfoFromXF = "fitmatrix";
		
		strCateg = "Surface Fitting";
		
		int				nOptDef = 0;
		string			strClassName, str2;
		op.SetInfoFromXF(nFitType, strSetInfoFromXF, saOptions, saNames, strCateg);
	}
	///End MODIFY_FUNCTIONS_TO_SUPPORT_SURFACE_FIT

	/// Hong 09/27/08 FIX_LT_TREE_FAIL_GET_SESSION_PTR
	//op.GetTree(m_trOp);
	//nlsf_check_get_GUI_params_with_ID(m_trOp.GUI);
	Tree		trOp;
	op.GetTree(trOp);
	nlsf_check_get_GUI_params_with_ID(trOp.GUI);	
	op.SetTree(trOp);
	/// end FIX_LT_TREE_FAIL_GET_SESSION_PTR
	
	m_bOpTreeReady	= true;
	///---Sim 09-10-2008 NLFIT_LABTALK_TREE_ACCESS
	//m_dwOption	= dwOption;
	//m_strLinkedLTTreeName	= lpcszLinkedLTtreeName;
	op.LinkLabTalkTree(lpcszLinkedLTtreeName);
	// can't use Operation::LinkLabTalkTree(, dwOption) in new NLFIT mechanism
	FitNL* nlfOp = (FitNL*)&op;
	if ( nlfOp )
		nlfOp->SetLTTreeSetting(dwOption);
	///---END NLFIT_LABTALK_TREE_ACCESS
	/// Hong 09/12/08 v8.0938 FIX_NEW_LT_NLFIT_MEMORY_LEAD_FORGET_DESTROY_OPERATION
	m_pnlOp = &op;
	m_bPreserveOpObj = false;	
	/// end FIX_NEW_LT_NLFIT_MEMORY_LEAD_FORGET_DESTROY_OPERATION	
	/// Hong 09/27/08 FIX_LT_TREE_FAIL_GET_SESSION_PTR
	getSessionPtr(); // Hong 09/27/08, force session create, otherwise maybe have problem of nested call of Get/SetTree
	/// end FIX_LT_TREE_FAIL_GET_SESSION_PTR
	return true;
}

///------ Folger 10/21/2010 ORG-1297-P1 NLEND_FAILED_TO_ADD_FITTED_CURVE_AND_RESULT_TABLE_TO_SOURCE_GRAPH
class InputDataImportantAttributesRestoreHelper
{
public:
	InputDataImportantAttributesRestoreHelper(TreeNode& trRanges)
	{
		m_trRanges = trRanges;
		m_vsAttribs.Add(STR_PLOTOBJ_UID_ATTRIB);

		foreach ( TreeNode trRange in m_trRanges.Children )
		{
			for ( int ii=0; ii<m_vsAttribs.GetSize(); ++ii )
			{
				int		nn;
				trRange.GetAttribute(m_vsAttribs[ii], nn);
				m_vnValues.Add(nn);
			}
		}
	}
	~InputDataImportantAttributesRestoreHelper()
	{
		int		nn = 0;
		foreach ( TreeNode trRange in m_trRanges.Children )
		{
			for ( int ii=0; ii<m_vsAttribs.GetSize(); ++ii, ++nn )
			{
				trRange.SetAttribute(m_vsAttribs[ii], m_vnValues[nn]);
			}
		}
	}
private:
	TreeNode		m_trRanges;
	vector<string>	m_vsAttribs;
	vector<int>		m_vnValues;
};
///------ End NLEND_FAILED_TO_ADD_FITTED_CURVE_AND_RESULT_TABLE_TO_SOURCE_GRAPH

///------ Folger 10/22/2010 ORG-1315-P1 WRONG_WEIGHT_METHOD_USE_WHEN_SPECIFY_ERROR_IN_NLBEGIN_INPUT_DATA
BOOL	LT_NLF::UpdateWeightToInputData(TreeNode& trInputData)
{
	foreach ( TreeNode trRange in trInputData.Children )
	{
		TreeNode	trWeight = trRange.GetNode("W");
		if ( trWeight && !trWeight.IsEmpty() )
			trWeight.SetAttribute(STR_FITTER_WEIGHT_METHOD_ATTRIB, m_nWeightMethod);
	}
	
	return TRUE;
}
///------ End WRONG_WEIGHT_METHOD_USE_WHEN_SPECIFY_ERROR_IN_NLBEGIN_INPUT_DATA

///Sophy 8/5/2009 QA80-14072 SUPPORT_CHANGE_INPUTDATA_IN_NLFIT_FROM_LABTALK
//int			LT_NLF::SetInput(const Range& iy)
///------ Folger 12/08/09 QA81-14819 CHANGE_PARAM_FROM_OPERATION_CREATED_BY_NLBEGIN_FAILS
//int			LT_NLF::SetInput(const Range& iy, BOOL bFirstTime/* = TRUE*/)
int			LT_NLF::SetInput(const Range& iy, BOOL bFirstTime/* = TRUE*/, LPCSTR lpcszFuncName/* = NULL*/)
///------ End CHANGE_PARAM_FROM_OPERATION_CREATED_BY_NLBEGIN_FAILS
///end SUPPORT_CHANGE_INPUTDATA_IN_NLFIT_FROM_LABTALK
{	
	if ( !m_bOpTreeReady )
		return -1;
	
	int 		nNumDataset = iy.GetNumData();
	if ( !iy.IsValid() || 0 == nNumDataset )
		return -1;
		
	Tree		trOp;
	GetOpPtr()->GetTree(trOp);
	TreeNode 	trInput = trOp.GUI.InputData;
	///------ Folger 12/08/09 QA81-14819 CHANGE_PARAM_FROM_OPERATION_CREATED_BY_NLBEGIN_FAILS
	if ( NULL == lpcszFuncName )
	{
		TreeNode 	trFunctionList = trOp.GUI.FunctionSelection.FunctionList;
		if ( trFunctionList )
			lpcszFuncName = trFunctionList.strVal;
	}
	///------ End CHANGE_PARAM_FROM_OPERATION_CREATED_BY_NLBEGIN_FAILS
	
	ASSERT(trInput);	
	
	Tree 		trRange;
	iy.GetTree(trRange, false);
	
	///------ Folger 03/11/09 QA80-13253 NLFIT_LT_COMMAND_SUPPORT_SPECIFY_WEIGHT_METHOD
	//trInput.Replace(trRange.Clone(), TRUE, TRUE, TRUE);	
	
	///------ Folger 12/08/09 QA81-14819 CHANGE_PARAM_FROM_OPERATION_CREATED_BY_NLBEGIN_FAILS
	//bool		bAlreadyHandle = false;
	///------ End CHANGE_PARAM_FROM_OPERATION_CREATED_BY_NLBEGIN_FAILS
	
	///------ Folger 06/30/09 QA80-13859 NLFIT_LABTALK_SUPPORT_MULTIPLE_INDEPENDENTS_AND_DEPENDENTS_BY_NEW_XF_NLBEGINR
	//if ( NLFIT_GENERAL_XY_FITTING == getSessionPtr()->GetFitType() )
	///------ Folger 12/08/09 QA81-14819 CHANGE_PARAM_FROM_OPERATION_CREATED_BY_NLBEGIN_FAILS
	//if ( NLFIT_GENERAL_XY_FITTING == getSessionPtr()->GetFitType() && WEIGHT_NONE != m_nWeightMethod )
	int		nFitType = getSessionPtr()->GetFitType();
	if ( NLFIT_GENERAL_XY_FITTING == nFitType )
	///------ End CHANGE_PARAM_FROM_OPERATION_CREATED_BY_NLBEGIN_FAILS
	///------ End NLFIT_LABTALK_SUPPORT_MULTIPLE_INDEPENDENTS_AND_DEPENDENTS_BY_NEW_XF_NLBEGINR
	{
		TreeNode	trRoot = trInput.Parent;
		vector<string> vsIndep = {"X"};
		vector<string> vsDep = {"Y"};
		///------ Folger 12/08/09 QA81-14819 CHANGE_PARAM_FROM_OPERATION_CREATED_BY_NLBEGIN_FAILS
		//if ( okutil_create_fitter_data_node_ex(&trInput, &trRoot, STR_INPUT_RANGE_NAME, STR_INPUT_RANGE_LABEL, &vsIndep, &vsDep, m_nWeightMethod) )
		//{
			//TreeNode	trTempRange = trInput.Range1;
			//if ( trTempRange )
			//{
				//trTempRange = trTempRange.Clone();
				//trInput.Reset(true);
				//
				//foreach ( TreeNode trSubRange in trRange.Children )
				//{
					//TreeNode	trNode = trInput.AddNode(trSubRange.tagName);
					//trNode.Replace(trTempRange, true, true);
					//if ( trSubRange.X )			/// if without X column
						//trNode.X.Replace(trSubRange.X, true, true, true);
					//trNode.Y.Replace(trSubRange.Y, true, true, true);
					//if ( trSubRange.ED )		/// if Y Err specified
						//trNode.W.Replace(trSubRange.ED, true, true, true);
				//}
				//
				//bAlreadyHandle = true;
			//}
		//}
		if ( lpcszFuncName )
		{
			vsIndep.RemoveAll(), vsDep.RemoveAll();
			nlf_get_independent_variables(lpcszFuncName, &vsIndep);
			nlf_get_dependent_variables(lpcszFuncName, &vsDep);
		}

		///------ Folger 10/21/2010 ORG-1297-P1 NLEND_FAILED_TO_ADD_FITTED_CURVE_AND_RESULT_TABLE_TO_SOURCE_GRAPH
		InputDataImportantAttributesRestoreHelper		clHelper(trRange);
		///------ End NLEND_FAILED_TO_ADD_FITTED_CURVE_AND_RESULT_TABLE_TO_SOURCE_GRAPH
		if ( vsIndep.GetSize() > 0 && vsDep.GetSize() > 0 )
		{
			okutil_create_fitter_data_node_ex(&trRange, NULL, STR_INPUT_RANGE_NAME, STR_INPUT_RANGE_LABEL, &vsIndep, &vsDep, m_nWeightMethod);
		}
		trInput.ID = ONODETYPE_FITTER_DATA;
		///------ End CHANGE_PARAM_FROM_OPERATION_CREATED_BY_NLBEGIN_FAILS
		///------ Folger 10/22/2010 ORG-1315-P1 WRONG_WEIGHT_METHOD_USE_WHEN_SPECIFY_ERROR_IN_NLBEGIN_INPUT_DATA
		UpdateWeightToInputData(trRange);
		///------ End WRONG_WEIGHT_METHOD_USE_WHEN_SPECIFY_ERROR_IN_NLBEGIN_INPUT_DATA
	}
	else if ( NLFIT_XYZ_FITTING == nFitType )
	{
		trInput.ID = ONODETYPE_XYZ_DATA_RANGE;
	}
	else if ( NLFIT_MATRIX_FITTING == nFitType )
	{
		trInput.ID = ONODETYPE_DATA_RANGE;
	}
	
	///------ Folger 12/08/09 QA81-14819 CHANGE_PARAM_FROM_OPERATION_CREATED_BY_NLBEGIN_FAILS
	//if ( !bAlreadyHandle )
		//trInput.Replace(trRange.Clone(), TRUE, TRUE, TRUE);
	trInput.Replace(trRange.Clone(), TRUE, TRUE, TRUE);
	///------ End CHANGE_PARAM_FROM_OPERATION_CREATED_BY_NLBEGIN_FAILS
	///------ End NLFIT_LT_COMMAND_SUPPORT_SPECIFY_WEIGHT_METHOD
	
	/// YuI 01/30/08 NO_AUTOUPDATE_IF_FIT_FROM_SCRIPT
	// this should not be done like that - fitter can not rely on XYRange created by XF framework
	// when XF creates XYRange - project has no idea. Only if XF is autoupdated, project gets notified and
	// range gets added to the project'
	// in case of nlbegin - XF itself is not autoupdatable
	// to resolve this issue we may not reuse XYRange, but must follow the some
	// route that used by NLSF from the dialog
	//	trInput.SetAttribute(STR_DATARANGE_UID_ATTRIB, (int)iy.GetUID(true));
	///Sophy 8/5/2009 QA80-14072 SUPPORT_CHANGE_INPUTDATA_IN_NLFIT_FROM_LABTALK
	if ( !bFirstTime ) //chagne data
	{
		trInput.RemoveAttribute(STR_DATARANGE_UID_ATTRIB);
		int nReplicaNumOld = getSessionPtr()->GetNumberMultiplicity();
		getSessionPtr()->SetData(trInput);
		int nReplicaNumNew = getSessionPtr()->GetNumberMultiplicity();
		
		if ( nReplicaNumOld != nReplicaNumNew )
			return OP_MULTI_DATA_SET_NOT_SUPPORT_REPLICA;
	}
	///end SUPPORT_CHANGE_INPUTDATA_IN_NLFIT_FROM_LABTALK
	if ( prepare_input_data_for_operation(trInput, true) )
	{
		GetOpPtr()->SetTree(trOp);
		return OP_NOERROR;
	}
	
	return -1;
}

int			LT_NLF::SetFunction(LPCSTR lpcszFuncName, bool* pbAutoInit/* = NULL*/, int* pnFitMode/* = NULL*/, int* pnReplica/* = NULL*/, LPCSTR lpcszTheme/* = NULL*/)
{
	if ( !m_bOpTreeReady )
		return -1;
	
	string 		strFuncName(lpcszFuncName);
	if ( strFuncName.IsEmpty()  )
		return OP_CAN_NOT_FIND_FUNC_FDF_FILE;
		
	Tree		trFDF;
	string		strCateName;
	int			nFldLocation = -1;
	if ( !nlf_find_category(lpcszFuncName, strCateName, nFldLocation) )
		return OP_CAN_NOT_FIND_FUNC_FDF_FILE;
	
	NLFunctionList	nlfnList;
	if ( !nlfnList.LoadEx(trFDF, lpcszFuncName, strCateName) )	
		return OP_CAN_NOT_FIND_FUNC_FDF_FILE; 
	
	Tree		trOp;
	GetOpPtr()->GetTree(trOp);
	
	/// Hong 10/09/08 v8.0953 TAKE_BACK_OLD_FEATURES
	/// Hong 03/05/08 QA80-10292 v8.0817 NLFIT_SUPPORT_APPLY_DIALOG_THEME
	if ( NULL != lpcszTheme )
	{
		/// Hong 10/15/08 QA80-12386 v8.0955b FIX_THEME_FAIL_WORK_FOR_SURFACE_FIT
		//if ( !theme_apply_analysis_theme("FitNL", trOp.GUI, lpcszTheme, false) )
		string			strClassName(STR_FITTEROPERATION_CLASS_FITNL);
		FitNL*		pOpPtr = (FitNL*)GetOpPtr();
		ASSERT(pOpPtr);
		if ( pOpPtr )
			strClassName = pOpPtr->GetClassOptionName(trOp);		
		if ( !pOpPtr->ApplyTheme(strClassName, trOp.GUI, lpcszTheme, false) )		
		/// end FIX_THEME_FAIL_WORK_FOR_SURFACE_FIT
			error_report("fail to apply theme in theme_apply_analysis_theme");				
	}
	/// end NLFIT_SUPPORT_APPLY_DIALOG_THEME
	DataRange drInputData;
	drInputData.Create(trOp.GUI.InputData, FALSE);
	
	/// Hong 02/01/08 v8.0798 FIX_CONTANTENATE_FIT_FAIL_WORK
	int nFitMode = AUTO_FIT_MODE, nReplicas = 0; /// Hong 03/18/08 v8.0826 FIX_LTNL_REPLICA_FAIL_WORK
	if ( pnFitMode || pnReplica )
	{			
		//int nFitMode = AUTO_FIT_MODE, nReplicas = 0; /// Hong 03/18/08 v8.0826 FIX_LTNL_REPLICA_FAIL_WORK
		if ( pnFitMode )
			nFitMode = *pnFitMode;
		if ( pnReplica )
			nReplicas = *pnReplica;
		if ( GetOpPtr()->PrepareFitTypeFromInput(trOp, drInputData, strCateName) )
		{
			DWORD		dwRules = GetOpPtr()->GetDataRules(trOp);
			int nNumData = drInputData.GetNumData(dwRules);
			bool bMultipleDataset = nNumData > 1;					
			if ( !bMultipleDataset )
				nFitMode = DATA_MODE_INDEP_CONSOLID;
			else
			{
				nReplicas = 0;
				switch ( nFitMode )
				{		
				///Sophy 10/15/2008 QA80-12130 SUPPORT_INDEP_FIT_CONSOLIDATED_FROM_COMMAND
				case INDEP_CONS_FIT_MODE:
					nFitMode = DATA_MODE_INDEP_CONSOLID;
					break;
				case INDEP_SEP_FIT_MODE:
					nFitMode = DATA_MODE_INDEP_SEP;
					break;
				///end SUPPORT_INDEP_FIT_CONSOLIDATED_FROM_COMMAND
				case CONCAT_FIT_MODE:
					nFitMode = DATA_MODE_CONCATENATE;
					break;
				case GLOBAL_FIT_MODE:
					nFitMode = DATA_MODE_GLOBAL;
					break;
				case AUTO_FIT_MODE:
				default:
					nFitMode = bMultipleDataset ? DATA_MODE_GLOBAL : DATA_MODE_INDEP_CONSOLID;
					break;
				}
			}
		}
		TreeNode trGUI = trOp.GetNode("GUI");
		TreeNode trInput = trGUI.InputData;
		trInput.SetAttribute(STR_USE_ATTRIB, nFitMode);
		///Arvin 03/25/08 MOVE_REPLICA_BARANCH_OUT_OF_FIT_CONTROL_BRANCH as CP said
		//TreeNode trFit = trGUI.Fit;
		//if ( trFit )
		//{
		//	trFit.Replica.Number.nVal = nReplicas;
		//}
		TreeNode trReplica = trGUI.Replica;
		if ( trReplica )
		{
			trReplica.Number.nVal = nReplicas;
		}
		///end MOVE_REPLICA_BARANCH_OUT_OF_FIT_CONTROL_BRANCH
	}
	/// end FIX_CONTANTENATE_FIT_FAIL_WORK
	/// end TAKE_BACK_OLD_FEATURES
	
	///------ Folger 10/22/2010 ORG-1316-P1 REPORT_GENERATED_BY_NLEND_FAILED_TO_DISPLAY_CORRECT_USED_DEFINED_FUNCTION_NAME
	//trOp.GUI.FunctionSelection.FunctionList.strVal = lpcszFuncName;
	string	strFunction;
	trFDF.GetAttribute(STR_LABEL_ATTRIB, strFunction);
	trOp.GUI.FunctionSelection.FunctionList.strVal = strFunction;
	///------ End REPORT_GENERATED_BY_NLEND_FAILED_TO_DISPLAY_CORRECT_USED_DEFINED_FUNCTION_NAME
	trOp.GUI.FunctionSelection.CategoryList.strVal = strCateName;
	
	getSessionPtr()->SetTreeFDF(trFDF);
	getSessionPtr()->GetFittingCodes(trOp.GUI.Codes);
	
	TreeNode 	trAutoParamsInit = trOp.GUI.Parameters.AutoParamsInit;
	trAutoParamsInit.nVal = getSessionPtr()->IsEnableAutoParamsInitFromOperation(trAutoParamsInit);
	TreeNode 	trLinearConstraints = trOp.GUI.Parameters.LinearConstraints;
	trLinearConstraints.nVal = getSessionPtr()->IsEnableConstraintsFromOperation(trLinearConstraints);

	TreeNode	trNode;
	trNode = trOp.FitWorkArea;
	if ( trNode && trNode.Parameters )
		trNode.Parameters.SetAttribute(STR_FIT_OUTCOME_ATTRIB, FITITER_NO_ITERATE);
	
	bool		bHasFitGood = false, bParamsReady = false;
	/// Hong 10/08/08 v8.0952c FIX_SIM_FOUND_LT_INIT_PARAMS_TWICE
	//bool		bRet = getSessionPtr()->InitFromOperationTree(trOp, bHasFitGood, bParamsReady);
	bool		bAutoInit = trAutoParamsInit.nVal;
	if ( pbAutoInit )
		bAutoInit = *pbAutoInit;
	///------ Folger 03/11/09 QA80-13253 NLFIT_LT_COMMAND_SUPPORT_SPECIFY_WEIGHT_METHOD
	//bool		bRet = getSessionPtr()->InitFromOperationTree(trOp, bHasFitGood, bParamsReady, false, bAutoInit ? NLFIT_INIT_PARMAS_AUTO : 0);
	///------ Folger 06/30/09 QA80-13859 NLFIT_LABTALK_SUPPORT_MULTIPLE_INDEPENDENTS_AND_DEPENDENTS_BY_NEW_XF_NLBEGINR
	//bool		bRet = getSessionPtr()->InitFromOperationTree(trOp, bHasFitGood, bParamsReady, false, bAutoInit ? NLFIT_INIT_PARMAS_AUTO : 0, true);
	/// Folger 09/17/09 we should not rely on init data from selection for nlbegin* tools, that will change the input data which user specify, caused tricky bugs
	//bool		bRet = getSessionPtr()->InitFromOperationTree(trOp, bHasFitGood, bParamsReady, false, bAutoInit ? NLFIT_INIT_PARMAS_AUTO : 0, WEIGHT_NONE != m_nWeightMethod ? true : false);
	bool		bRet = getSessionPtr()->InitFromOperationTree(trOp, bHasFitGood, bParamsReady, false, bAutoInit ? NLFIT_INIT_PARMAS_AUTO : 0, false);
	///------ End NLFIT_LABTALK_SUPPORT_MULTIPLE_INDEPENDENTS_AND_DEPENDENTS_BY_NEW_XF_NLBEGINR
	///------ End NLFIT_LT_COMMAND_SUPPORT_SPECIFY_WEIGHT_METHOD
	/// end FIX_SIM_FOUND_LT_INIT_PARAMS_TWICE
	
	/// Hong 10/09/08 v8.0953 TAKE_BACK_OLD_FEATURES
	if ( NULL != lpcszTheme )
	{
		DWORD	dwParamsToSkip = 0;
		if ( !getSessionPtr()->IsAllowSharing() )
			dwParamsToSkip |= NLPARAMETERSETTINGS_SHARED;
		
		if ( bAutoInit )
			dwParamsToSkip |= NLPARAMETERSETTINGS_VALUE;
		getSessionPtr()->OperationGUIToParams(trOp.GUI.Parameters, dwParamsToSkip, true);
	}
	/// end TAKE_BACK_OLD_FEATURES
	
	//------ Folger 02/13/08 QA80-10929 ADD_FUNCTION_MODEL_TO_CALCULATION_NOTES
	TreeNode trModel = tree_get_node_by_tagname(trOp.Calculation, "Model", true);
	if ( trModel )
		trModel.strVal = m_pnlOp->GetResultModel(trOp);
	//------		
	
	//------ Folger 08/14/08 QA80-12017 ADD_NUMBER_OF_PARAMETERS_AND_DATASETS_INFO_TO_LABTALK_TREE
	int		nNumParamsInFunc, nNumDerivedParamsInFunc;
	///Kyle 09/05/08 USE_NEW_NLFSESSION_AND_NLFPARAMSCONTROL_IN_NLFPARAMDLG
	//nNumParamsInFunc = pNLFitSession->GetNumParamsInFunc(0, &nNumDerivedParamsInFunc);
	nNumParamsInFunc = getSessionPtr()->GetNumParameter(0);
	///End USE_NEW_NLFSESSION_AND_NLFPARAMSCONTROL_IN_NLFPARAMDLG
	
	//------ Folger 11/25/08 QA80-12655-P2 v8.0979 FAIL_TO_GET_DERIVED_PARAM_NUMBER_IN_NLFIT_LT_TREE
	nNumDerivedParamsInFunc = getSessionPtr()->GetDerivedParamNum();
	//------
	
	TreeNode trNumDatasets = tree_get_node_by_tagname(trOp.Calculation, "NumDataSets", true);
	if ( trNumDatasets )
		trNumDatasets.nVal = getSessionPtr()->GetNumDataset();
	
	TreeNode trNumParams = tree_get_node_by_tagname(trOp.Calculation, "NumFuncParams", true);
	if ( trNumParams )
		trNumParams.nVal = nNumParamsInFunc;
	
	TreeNode trNumDerivedParams = tree_get_node_by_tagname(trOp.Calculation, "NumDerivParams", true);
	if ( trNumDerivedParams )
		trNumDerivedParams.nVal = nNumDerivedParamsInFunc;
		
	GetOpPtr()->SetTree(trOp);	
	if ( !bRet )
		return -1;		
	/// Hong 10/08/08 v8.0952c FIX_SIM_FOUND_LT_INIT_PARAMS_TWICE
	/*
	bool	bAutoInit = trAutoParamsInit.nVal;
	if ( pbAutoInit )
		bAutoInit = *pbAutoInit;
	
	if ( bAutoInit )
	{
		if ( !getSessionPtr()->ParamsInitValues() )
			return -1;
	}
	*/
	/// end FIX_SIM_FOUND_LT_INIT_PARAMS_TWICE

	return OP_NOERROR;
}

///Sophy 9/18/2009 QA80-14072 SUPPORT_CHANGE_INPUTDATA_IN_NLFIT_FROM_LABTALK
bool		LT_NLF::GetFunction(string& strFuncName)
{
	if ( !m_pSession )
		return false;
	
	strFuncName = m_pSession->GetFunctionName();
	
	return true;
}
///end SUPPORT_CHANGE_INPUTDATA_IN_NLFIT_FROM_LABTALK

int			LT_NLF::Iterate(int nNum, int nMethod)
{
	if ( !m_bOpTreeReady )
		return -1;		
	
	///---Sim 10-14-2009 QA81-14471 FIX_NLFIT_SET_CONSTRAINTS_FROM_LT_TREE
	Tree		trOp;
	GetOpPtr()->GetTree(trOp);
	TreeNode trFit = trOp.GUI.Fit;		
	///---END QA81-14471 FIX_NLFIT_SET_CONSTRAINTS_FROM_LT_TREE
	if ( -1 == nNum )		
	{		
		///---Sim 10-14-2009 QA81-14471 FIX_NLFIT_SET_CONSTRAINTS_FROM_LT_TREE
		//Tree		trOp;
		//GetOpPtr()->GetTree(trOp);
		///---END QA81-14471 FIX_NLFIT_SET_CONSTRAINTS_FROM_LT_TREE
		if ( trFit )
			nNum = trFit.Iterations.MaxNum.nVal;
	}		
	/// Sim 10-14-2009 QA81-14471 FIX_NLFIT_SET_TOL_FROM_LT_TREE
	if ( trFit )
		getSessionPtr()->SetTolerance(trFit.Iterations.Tolerance.dVal);
	/// end FIX_NLFIT_SET_TOL_FROM_LT_TREE
	///---Sim 10-14-2009 QA81-14471 FIX_NLFIT_SET_CONSTRAINTS_FROM_LT_TREE
	if ( trOp.GUI.Parameters.LinearConstraints )
		getSessionPtr()->SetEnableLinearConstraints(trOp.GUI.Codes.Constraints, trOp.GUI.Parameters.LinearConstraints.nVal);
	///---END QA81-14471 FIX_NLFIT_SET_CONSTRAINTS_FROM_LT_TREE
	/// Hong 09/24/09 QA80-12199 FIT_LT_CALL_SPEED_UP_MOVE_CODE_TO_VC
	//return getSessionPtr()->Iterate(nNum, nMethod, true);	
	int		nRet = getSessionPtr()->Iterate(nNum, nMethod, true);
	///------ Folger 02/17/09 QA80-13125 LT_FUNCTION_FIT_RETURN_BAD_RESULTS_WHEN_NLFIT_NOT_CONVERGED
	//if ( 0 == nRet )
	if ( 0 <= nRet )
	///------ End LT_FUNCTION_FIT_RETURN_BAD_RESULTS_WHEN_NLFIT_NOT_CONVERGED
		initLTFitCurveEval();
	/// Hong 11/25/08 QA80-12655 FIX_NO_RESSTAT_IN_LT_TREE_AFTER_ITERATE
	///---Sim 10-14-2009 QA81-14471 FIX_NLFIT_SET_CONSTRAINTS_FROM_LT_TREE
	//Tree		trOp;
	///---END QA81-14471 FIX_NLFIT_SET_CONSTRAINTS_FROM_LT_TREE
	GetOpPtr()->GetTree(trOp);
	/// Hong 09/14/09 FIX_LT_NLFIT_FAIL_GET_ALL_SET_CHISQR_AFTER_ITERATE_FOR_SEPARATE_FIT_MODE
	//getSessionPtr()->ParamsToOperation(trOp, true);
	getSessionPtr()->ParamsToOperation(trOp, true, false);
	/// end FIX_LT_NLFIT_FAIL_GET_ALL_SET_CHISQR_AFTER_ITERATE_FOR_SEPARATE_FIT_MODE
	GetOpPtr()->SetTree(trOp);
	/// end FIX_NO_RESSTAT_IN_LT_TREE_AFTER_ITERATE
	/// Hong 10/3/08 v8.0963b SHOULD_UPDATE_PREVIEW_AFTER_FIT
	if ( m_pNLFitPreviewCtrl )
		getPreviewCtrlPtr()->UpdatePreviewGraph(FITPREVIEW_REPLOT);
	/// end SHOULD_UPDATE_PREVIEW_AFTER_FIT
	return nRet;
	/// end FIT_LT_CALL_SPEED_UP_MOVE_CODE_TO_VC
}

bool		LT_NLF::EnableSourceGraphPreview()
{
	if( !m_pSession )
		return false;
	
	Tree		trOp;
	GetOpPtr()->GetTree(trOp);
	TreeNode 	trPreview = trOp.GUI.Preview;
	if( !trPreview || 0 == trPreview.nVal )
		return false;
	
	GraphPage gp = m_pSession->GetSrcGraphPage();
	if( !gp )
		return false;
	
	getPreviewCtrlPtr()->SetPreviewGraph(gp, PREVIEW_EXTERNAL_DATA_FIT );
	//m_pNLFitPreviewCtrl->UpdateFitSessionPreviewData();
	getPreviewCtrlPtr()->UpdatePreviewGraph(FITPREVIEW_INIT);
	return true;
}
void	LT_NLF::createPreviewCtrl()
{	
	ASSERT(!m_pNLFitPreviewCtrl);
	switch ( getSessionPtr()->GetFitType() )
	{
	case NLFIT_XYZ_FITTING:
		m_pNLFitPreviewCtrl = new XYZSurfaceFitPreviewCtrl(getSessionPtr());
		break;
	case NLFIT_MATRIX_FITTING:
		m_pNLFitPreviewCtrl = new MatSurfaceFitPreviewCtrl(getSessionPtr());
		break;
	case NLFIT_GENERAL_XY_FITTING:
	default:		
		m_pNLFitPreviewCtrl = new NLFitPreviewCtrl(getSessionPtr());
		break;
	}
}

/// Hong 10/31/08 v8.0963b FIX_NLEND_FAIL_CREATE_FIT_CURVE_IN_SRC_GRAPH
void	LT_NLF::destroyPreviewCtrl()
{
	if( NULL != m_pNLFitPreviewCtrl)
	{
		delete m_pNLFitPreviewCtrl;
		m_pNLFitPreviewCtrl = NULL;		
	}
}
/// end FIX_NLEND_FAIL_CREATE_FIT_CURVE_IN_SRC_GRAPH

/// Hong 09/24/09 QA80-12199 FIT_LT_CALL_SPEED_UP_MOVE_CODE_TO_VC
void		LT_NLF::initLTFitCurveEval()
{
	TreeNode			trFDF = getSessionPtr()->GetTreeFDF();
	ASSERT(trFDF);
	
	NLFITCURVEEVALINIT	st;
	st.nSets = getSessionPtr()->GetNumDataset();
	st.nPeaks = getSessionPtr()->GetNumPeaks();
	st.dBaseline = getSessionPtr()->GetBaseline();
	
	vector				vParams;
	vector<int>			vnParamOffsets;
	getSessionPtr()->GetParamValuesAndOffsets(vParams, vnParamOffsets);
	st.pParams = vParams;
	st.pnParams = vnParamOffsets;
	
	Project.FitCurveEval(&st, trFDF);
}

void		LT_NLF::resetLTFitCurveEval()
{
	Project.FitCurveEval();
}
/// end FIT_LT_CALL_SPEED_UP_MOVE_CODE_TO_VC
	
void		LT_NLF::destroy()
{	
	/// Hong 10/31/08 v8.0963b FIX_NLEND_FAIL_CREATE_FIT_CURVE_IN_SRC_GRAPH		
	//if( NULL != m_pNLFitPreviewCtrl)
	//{
		//delete m_pNLFitPreviewCtrl;
		//m_pNLFitPreviewCtrl = NULL;		
	//}
	destroyPreviewCtrl();
	/// end FIX_NLEND_FAIL_CREATE_FIT_CURVE_IN_SRC_GRAPH

	if ( m_pNLParaDlg )
	{
		Window wnd = m_pNLParaDlg->GetWindow();
		if ( wnd )
			wnd.SendMessage(WM_CLOSE);
		
		delete m_pNLParaDlg;
		m_pNLParaDlg = NULL;
	}
	/// Hong 09/12/08 v8.0938 FIX_NEW_LT_NLFIT_MEMORY_LEAD_FORGET_DESTROY_OPERATION
	if ( NULL != m_pnlOp )
	{
		//------ Folger 11/25/08 QA80-12655-P5 v8.0979 LT_TREE_PARAMS_FAIL_TO_ACCESS_AFTER_NLEND_1_TO_GENERATE_REPORT
		updateFitSessionPtrToOpTree();
		//------
		///--- Hong 09/28/08, unlink LT tree need to be call before destroy as it will access FitSession
		Tree		tr;
		m_pnlOp->LinkLabTalkTree(NULL); // unlink LT tree
		///---
		if ( m_bPreserveOpObj )		
			m_pnlOp->OnKeepOpAfterExecute();
		else		
			m_pnlOp->DestroyInternal();				
		m_pnlOp = NULL;
		m_bPreserveOpObj = false;
		/// Hong QA80-12374 10/14/08 NL_LT_ADD_OUTPUT_ACCESS
		m_bFirstTimeGetGUI = false;
		/// end NL_LT_ADD_OUTPUT_ACCESS
	}
	if ( NULL != m_pSession )
	{
		delete m_pSession;
		m_pSession = NULL;
	}
	/// end FIX_NEW_LT_NLFIT_MEMORY_LEAD_FORGET_DESTROY_OPERATION
	m_bOpTreeReady = false;
	resetLTFitCurveEval(); /// Hong 09/24/09 QA80-12199 FIT_LT_CALL_SPEED_UP_MOVE_CODE_TO_VC	
}

NLFitSessionPtr		LT_NLF::getSessionPtr()
{
	if ( NULL == m_pSession )
	{
		m_pSession = new NLFitSession;
		//------ Folger 11/25/08 QA80-12655-P5 v8.0979 LT_TREE_PARAMS_FAIL_TO_ACCESS_AFTER_NLEND_1_TO_GENERATE_REPORT
		/*
		Tree		trOp;
		GetOpPtr()->GetTree(trOp);
		///---Sim 09-10-2008 NLFIT_LABTALK_TREE_ACCESS
		//linkLabtalTree(m_strLinkedLTTreeName, m_dwOption);
		///---END NLFIT_LABTALK_TREE_ACCESS
		m_pSession->SetFitType(trOp.SpecInfo);
		/// Hong 09/27/08 FIX_LT_TREE_FAIL_GET_SESSION_PTR		
		TreeNode	trFitWork = tree_check_get_node(trOp, "FitWorkArea");
		TreeNode 	trFitPointer = tree_check_get_node(trFitWork, STR_FIT_POINTER);
		DWORD 		dw = (DWORD)m_pSession;
		trFitPointer.nVal = dw;		
		GetOpPtr()->SetTree(trOp);
		/// end FIX_LT_TREE_FAIL_GET_SESSION_PTR
		*/
		updateFitSessionPtrToOpTree();
		//------ End LT_TREE_PARAMS_FAIL_TO_ACCESS_AFTER_NLEND_1_TO_GENERATE_REPORT
	}
	
	return m_pSession;
}

//------ Folger 11/25/08 QA80-12655-P5 v8.0979 LT_TREE_PARAMS_FAIL_TO_ACCESS_AFTER_NLEND_1_TO_GENERATE_REPORT
void			LT_NLF::updateFitSessionPtrToOpTree()
{
	Tree		trOp;
	GetOpPtr()->GetTree(trOp);
	///---Sim 09-10-2008 NLFIT_LABTALK_TREE_ACCESS
	//linkLabtalTree(m_strLinkedLTTreeName, m_dwOption);
	///---END NLFIT_LABTALK_TREE_ACCESS
	m_pSession->SetFitType(trOp.SpecInfo);
	/// Hong 09/27/08 FIX_LT_TREE_FAIL_GET_SESSION_PTR		
	TreeNode	trFitWork = tree_check_get_node(trOp, "FitWorkArea");
	TreeNode 	trFitPointer = tree_check_get_node(trFitWork, STR_FIT_POINTER);
	DWORD 		dw = (DWORD)m_pSession;
	trFitPointer.nVal = dw;		
	GetOpPtr()->SetTree(trOp);
	/// end FIX_LT_TREE_FAIL_GET_SESSION_PTR
}
//------ End LT_TREE_PARAMS_FAIL_TO_ACCESS_AFTER_NLEND_1_TO_GENERATE_REPORT

NLFPreviewCtrlPtr	LT_NLF::getPreviewCtrlPtr()
{
	if( NULL == m_pNLFitPreviewCtrl )
	{
		createPreviewCtrl();
		Tree		trOp;
		GetOpPtr()->GetTree(trOp);
		m_pNLFitPreviewCtrl->SetFitCurveOptions( trOp.GUI.Graph1 );
	}
	
	return m_pNLFitPreviewCtrl;
}

///---Sim 09-10-2008 NLFIT_LABTALK_TREE_ACCESS
//int			LT_NLF::linkLabtalTree(LPCSTR lpcszLinkedLTtreeName, DWORD dwOption)
//{	
	//ASSERT(m_pSession);
	//return m_pSession->LinkLabtalkTree(lpcszLinkedLTtreeName, dwOption);
//}
///---END NLFIT_LABTALK_TREE_ACCESS

///Kyle 09/08/08 ADD_FUNCTIONS_TO_OPEN_NLPARAMSDIALOG
bool 		LT_NLF::OpenNLParamsDialog()
{
	if ( !m_pNLParaDlg || !m_pNLParaDlg->GetWindow() )
	{
		m_pNLParaDlg = NULL;

		NLFitSession* pNLFitSession  = getSessionPtr();

		if ( !pNLFitSession )
			return false;

		m_pNLParaDlg = new NLFitParaDlg;
		m_pNLParaDlg->SetFitSession(pNLFitSession);
		m_pNLParaDlg->Create(GetWindow());				
	}
	return true;
}
///End ADD_FUNCTIONS_TO_OPEN_NLPARAMSDIALOG
///Sophy 10/9/2008 CLEAN_LT_NLEND
bool		LT_NLF::removeWorkAreaAttri()
{
		if(!GetOpPtr())
			return false;

		TreeNode trOp;
		GetOpPtr()->GetTree(trOp);
		TreeNode trFitWorkArea = trOp.FitWorkArea;
		if(trFitWorkArea)
		{
			trFitWorkArea.RemoveAttribute(STR_LT_NLFIT_CLASS_ATTRIB);
			trFitWorkArea.RemoveAttribute(STR_NO_INIT_FROM_OP_ATTRIB);
		}
		GetOpPtr()->SetTree(trOp);
		return true;
}

///------ Folger 04/16/10 QA81-15323 NLEND_AUTO_UPDATE_MODE_FOLLOW_THEME
enum
{
	AUTOUPDATE_NONE			= AU_NONE, // no operation will be created as a result
	AUTOUPDATE_AUTO			= AU_AUTO,
	AUTOUPDATE_ON_COMMAND	= AU_ON_COMMAND,
	AUTOUPDATE_FOLLOW_THEME,
};
///------ End NLEND_AUTO_UPDATE_MODE_FOLLOW_THEME

bool		LT_NLF::DoCalculation(int nReport, int nAutoUpdate)
{
	if ( !GetOpPtr() )
		return false;
	/// Hong 10/31/08 v8.0963b FIX_NLEND_FAIL_CREATE_FIT_CURVE_IN_SRC_GRAPH
	destroyPreviewCtrl();
	/// end FIX_NLEND_FAIL_CREATE_FIT_CURVE_IN_SRC_GRAPH
	///Arvin 01/29/08 GENERATE_REPORT_FOR_LT_NLFit
	TreeNode trOp;
	GetOpPtr()->GetTree(trOp);
	GetOpPtr()->ClearOutputTables(trOp);
	///------ Folger 04/16/10 QA81-15323 NLEND_AUTO_UPDATE_MODE_FOLLOW_THEME
	if ( AUTOUPDATE_FOLLOW_THEME == nAutoUpdate )
	{
		TreeNode	trGUIAU = trOp.GUI.AutoUpdate;
		nAutoUpdate = trGUIAU ? trGUIAU.nVal : AUTOUPDATE_ON_COMMAND;
	}
	///------ End NLEND_AUTO_UPDATE_MODE_FOLLOW_THEME
	trOp.Operation.AutoUpdate.nVal = nAutoUpdate; 
	TreeNode trFitWorkArea = trOp.FitWorkArea;
	if(trFitWorkArea)
	{
		trFitWorkArea.SetAttribute(STR_LT_NLFIT_CLASS_ATTRIB, OPERATION_FROM_LT_NLFIT_CALSS);
		trFitWorkArea.SetAttribute(STR_NO_INIT_FROM_OP_ATTRIB, NO_INIT_FIT_SESSION_FROM_OP_TREE);
	}
	/// Hong 08/12/09 QA80-14123 FIX_NL_LT_ROUTINE_SHOULD_NOT_GENERATE_LAST_USED_THEME
	trOp.SetAttribute(STR_NO_OPERATION_THEME_ATTRIB, 1);
	/// end FIX_NL_LT_ROUTINE_SHOULD_NOT_GENERATE_LAST_USED_THEME
	GetOpPtr()->SetTree(trOp);
	
	int nOption = 0;
	//int nAutoUpdate = 0; ///Arvin 01/29/08 GENERATE_REPORT_SUPPORT_RECALCULATE_IN_LT_NLFit
	GetOpPtr()->OnNoEdit(nOption, nAutoUpdate);
	///Arvin 02/21/08 QA70-10929 NLEND_NEED_OUTPUT_REPORT_TABLES_TO_NOTES_WINDOW
	//if( !m_pnlOp->Execute() )
	//{
	//	///Arvin 01/29/08 GENERATE_REPORT_SUPPORT_RECALCULATE_IN_LT_NLFit
	//	m_bPreserveOpOb = false;
	//	removeWorkAreaAttri();
	//	///end GENERATE_REPORT_SUPPORT_RECALCULATE_IN_LT_NLFit
	//	return false;
	//}
	bool	bRet = true;
	if(nReport == EXECUTE_GETNERATE_REPORT)
	{
		bRet = GetOpPtr()->Execute();
	}
	if(nReport == EXECUTE_OUTPUT_TO_NOTES_WIN)
	{
		if(GetOpPtr()->Calculate(0, OP_OUTPUT_REPORT_TABLES_TO_NOTES_WIN))
			bRet = false;	
	}
	if(!bRet)
	{
		m_bPreserveOpObj = false;
		removeWorkAreaAttri();
		return false;
	}
	///end NLEND_NEED_OUTPUT_REPORT_TABLES_TO_NOTES_WINDOW
	
	///Arvin 01/29/08 GENERATE_REPORT_SUPPORT_RECALCULATE_IN_LT_NLFit
	if( AU_NONE == nAutoUpdate )
		m_bPreserveOpObj = false;
	else
		m_bPreserveOpObj = true;
	removeWorkAreaAttri();
	///end GENERATE_REPORT_SUPPORT_RECALCULATE_IN_LT_NLFit
	
	return true;
}
///end CLEAN_LT_NLEND

/// Hong QA80-12374 10/14/08 NL_LT_ADD_OUTPUT_ACCESS
int			LT_NLF::GUI(TreeNode& trGUI, bool bGet)
{
	Tree		trOp;
	GetOpPtr()->GetTree(trOp);
	if ( bGet )
	{		
		if ( m_bFirstTimeGetGUI )
		{
			// Copy from peakfithealper.h
			// in order to call GUIPrepareOutputBranch
			GetOpPtr()->OperationtoGUI(trOp, true, NULL, false);
			GetOpPtr()->SetTree(trOp);
			m_bFirstTimeGetGUI = false;
		}
		vector<int>		vnDataIDs = { 
			IDST_RESIDUAL_TYPE_OPTIONS, 
			IDST_FIT_QUANTITIES_OPTIONS,
			IDST_REPORT_CALIBRATION_TABLE, 
			IDST_OUTPUT_RESULTS_OPTIONS,
			IDE_RESULT_GRAPHS,
			IDE_FIT_RESIDUALS_BRANCH
		};
		vnDataIDs.Sort();
		trGUI = trOp.GUI;
		int				nDataID;
		foreach ( TreeNode trNode in trGUI.Children )
		{			
			if ( !trNode.GetAttribute(STR_DATAID_ATTRIB, nDataID) || -1 == find_in_list(nDataID, vnDataIDs, true) )
				trNode.Remove();
		}
	}
	else
	{
		if ( tree_copy_values_by_id(trGUI, trOp.GUI) )
			GetOpPtr()->SetTree(trOp);
	}
	return OP_NOERROR;
}
/// end NL_LT_ADD_OUTPUT_ACCESS

int			LT_NLF::NLFitYofX(double *prDepValues, double *prIndepValues, int nCount, int nSet)
{
	NLFitSessionPtr pFit = getSessionPtr();
	if(pFit && pFit->GetYFromX(prIndepValues, prDepValues, nCount, nSet))
		return 1;
	
	return 0;
}

	
/// ML 1/24/2008 QA70-10929 P3 LABTALK_Y_OF_X_CHANNELED_TO_THE_NEW_NLFIT_LT_ACCESS
int	NLFitYofX(double *prDepValues, double *prIndepValues, int nCount, int nSet)
{
	//----- CPY 1/26/2007 QA70-10929_P5 NOTIFY_STATIC_OP_UTILS_OPERATION_OBJ_TO_DESTROY
	// use NULL to clean
	if(NULL == prDepValues)
		return lt_nlf_end(0,0);
	//-----

	if ( !s_pltNLF )
		return 0;		// not handled
	
	return s_pltNLF->NLFitYofX(prDepValues, prIndepValues, nCount, nSet);
}
/// end LABTALK_Y_OF_X_CHANNELED_TO_THE_NEW_NLFIT_LT_ACCESS

///Kyle 09/11/08 MODIFY_FUNCTIONS_TO_SUPPORT_SURFACE_FIT
//static bool _lt_nlf_init(LPCSTR lpcszLinkedLTtreeName, DWORD dwOption = 0)
static bool _lt_nlf_init(LPCSTR lpcszLinkedLTtreeName, DWORD dwOption = 0, int nFitType = NLFIT_GENERAL_XY_FITTING)
///End MODIFY_FUNCTIONS_TO_SUPPORT_SURFACE_FIT
{
	if ( NULL == s_pltNLF )
		s_pltNLF = new LT_NLF;
	///Kyle 09/11/08 MODIFY_FUNCTIONS_TO_SUPPORT_SURFACE_FIT
	//return s_pltNLF->Init(lpcszLinkedLTtreeName, dwOption);
	return s_pltNLF->Init(lpcszLinkedLTtreeName, dwOption, nFitType);
	///End MODIFY_FUNCTIONS_TO_SUPPORT_SURFACE_FIT
}


int lt_nlf_end(int nReport, int nAutoUpdate, bool bPrintErr) // = AU_NONE, false
{
	///Sophy 10/9/2008 CLEAN_LT_NLEND
	if( !s_pltNLF )
		return -1;
	
	bool	bRet = true;
	if( nReport )
	{
		bRet = s_pltNLF->DoCalculation( nReport, nAutoUpdate );
	}
	///end CLEAN_LT_NLEND
	if ( NULL != s_pltNLF )
	{
		delete s_pltNLF;
		s_pltNLF = NULL;
	}

	return 0;
}

///Kyle 09/11/08 MODIFY_FUNCTIONS_TO_SUPPORT_SURFACE_FIT
//int lt_nlf_nlbegin(const Range& iy, LPCSTR lpcszFunc, TreeNode& nltree, int nFitMode, int nReplica, LPCSTR lpcszTheme, int nParamNotation)
//---- Iris 10/10/2008 ADD_XFVAR_TO_CONTROL_IF_AUTO_INIT_PARAM
//int lt_nlf_nlbegin(const Range& iy, LPCSTR lpcszFunc, TreeNode& nltree, int nFitMode, int nReplica, LPCSTR lpcszTheme, int nParamNotation, int nFitType) // = NLFIT_GENERAL_XY_FITTING
///------ Folger 03/11/09 QA80-13253 NLFIT_LT_COMMAND_SUPPORT_SPECIFY_WEIGHT_METHOD
//int lt_nlf_nlbegin(const Range& iy, LPCSTR lpcszFunc, TreeNode& nltree, int nFitMode, int nReplica, LPCSTR lpcszTheme, int nParamNotation, int nFitType, bool* pbAutoInit) // = NLFIT_GENERAL_XY_FITTING, = NULL
int lt_nlf_nlbegin(const Range& iy, LPCSTR lpcszFunc, TreeNode& nltree, int nFitMode, int nReplica, LPCSTR lpcszTheme, int nParamNotation, int nFitType, bool* pbAutoInit, int nWeightMethod/* = WEIGHT_NONE*/) // = NLFIT_GENERAL_XY_FITTING, = NULL
///------ End NLFIT_LT_COMMAND_SUPPORT_SPECIFY_WEIGHT_METHOD
//----
///End MODIFY_FUNCTIONS_TO_SUPPORT_SURFACE_FIT
{
	if ( !nltree )
		return -1;
	
	string strLTtreeName;
	nltree.GetAttribute(STR_XF_VAR_VALDATA, strLTtreeName);
	if ( strLTtreeName.IsEmpty() )
		return -1;
	
	///Kyle 09/11/08 MODIFY_FUNCTIONS_TO_SUPPORT_SURFACE_FIT
	//if ( !_lt_nlf_init(strLTtreeName) )
		//return -1;
	DWORD dwOption = 0;
	switch ( nParamNotation )
	{
	case param_notation_para:
		dwOption |= NLFIT_DISPLAY_NODE_NAME;
		break;
	case param_notation_abbr:
		dwOption |= NLFIT_DISPLAY_NODE_KEY;
		break;
	case param_notation_both:
		dwOption |= NLFIT_DISPLAY_NODE_KEY;
		dwOption |= NLFIT_DISPLAY_NODE_NAME;
		break;
	default:
		break;
	}	
	if ( !_lt_nlf_init(strLTtreeName, dwOption, nFitType) )
		return -1;
	///End MODIFY_FUNCTIONS_TO_SUPPORT_SURFACE_FIT
	
	s_pltNLF->SetWeightMethod(nWeightMethod);		///------ Folger 03/11/09 QA80-13253 NLFIT_LT_COMMAND_SUPPORT_SPECIFY_WEIGHT_METHOD
	
	int		nRet;		
	///------ Folger 12/08/09 QA81-14819 CHANGE_PARAM_FROM_OPERATION_CREATED_BY_NLBEGIN_FAILS
	//if ( (nRet = lt_nlf_set_inputdata(iy)) )
	if ( (nRet = lt_nlf_set_inputdata(iy, lpcszFunc)) )
	///------ End CHANGE_PARAM_FROM_OPERATION_CREATED_BY_NLBEGIN_FAILS
		return nRet;

	/// Hong 10/08/08 v8.0952c FIX_SIM_FOUND_LT_INIT_PARAMS_TWICE
	//bool	bAutoInit = true;
	//string	strFuncName(lpcszFunc);
	//if ( (nRet = lt_nlf_set_function(strFuncName, &bAutoInit) ) )	
	string	strFuncName(lpcszFunc);
	/// Hong 10/09/08 v8.0953 TAKE_BACK_OLD_FEATURES
	//if ( (nRet = lt_nlf_set_function(strFuncName) ) )
	//---- Iris 10/10/2008 ADD_XFVAR_TO_CONTROL_IF_AUTO_INIT_PARAM
	//if ( (nRet = lt_nlf_set_function(strFuncName, NULL, &nFitMode, &nReplica, lpcszTheme) ) )
	if ( (nRet = lt_nlf_set_function(strFuncName, pbAutoInit, &nFitMode, &nReplica, lpcszTheme) ) )
	//----	
	/// end TAKE_BACK_OLD_FEATURES
	/// end FIX_SIM_FOUND_LT_INIT_PARAMS_TWICE
		return nRet;

	lt_nlf_enable_source_page_preview();
	return 0;
}

///Kyle 09/08/08 ADD_FUNCTIONS_TO_OPEN_NLPARAMSDIALOG
bool lt_nlf_params()
{
	if ( !s_pltNLF )
		return false;
	
	return s_pltNLF->OpenNLParamsDialog();
}
//End ADD_FUNCTIONS_TO_OPEN_NLPARAMSDIALOG

///------ Folger 12/08/09 QA81-14819 CHANGE_PARAM_FROM_OPERATION_CREATED_BY_NLBEGIN_FAILS
//int lt_nlf_set_inputdata(const Range& iy)
int lt_nlf_set_inputdata(const Range& iy, LPCSTR lpcszFuncName)
///------ End CHANGE_PARAM_FROM_OPERATION_CREATED_BY_NLBEGIN_FAILS
{
	if ( !s_pltNLF )
		return OP_NO_OPERATION_OBJECT;

	///------ Folger 12/08/09 QA81-14819 CHANGE_PARAM_FROM_OPERATION_CREATED_BY_NLBEGIN_FAILS
	//return s_pltNLF->SetInput(iy);
	return s_pltNLF->SetInput(iy, TRUE, lpcszFuncName);
	///------ End CHANGE_PARAM_FROM_OPERATION_CREATED_BY_NLBEGIN_FAILS
}

///Sophy 9/18/2009 QA80-14072 SUPPORT_CHANGE_INPUTDATA_IN_NLFIT_FROM_LABTALK
int	lt_nlf_get_function_name(string& strFuncName)
{
	if ( !s_pltNLF )
		return OP_NO_OPERATION_OBJECT;
	
	if ( s_pltNLF->GetFunction(strFuncName) )
		return OP_NOERROR;
	
	return -1;
}
///end SUPPORT_CHANGE_INPUTDATA_IN_NLFIT_FROM_LABTALK
///Sophy 8/5/2009 QA80-14072 SUPPORT_CHANGE_INPUTDATA_IN_NLFIT_FROM_LABTALK
int lt_nlf_change_inputdata(const Range& iy)
{
	if ( !s_pltNLF )
		return OP_NO_OPERATION_OBJECT;
	
	return s_pltNLF->SetInput(iy, FALSE);	
}
///end SUPPORT_CHANGE_INPUTDATA_IN_NLFIT_FROM_LABTALK

/// Hong 10/09/08 v8.0953 TAKE_BACK_OLD_FEATURES
//int lt_nlf_set_function(LPCSTR lpcszFuncName, bool* pbAutoInit) // = NULL
int lt_nlf_set_function(LPCSTR lpcszFuncName, bool* pbAutoInit/* = NULL*/, int* pnFitMode/* = NULL*/, int* pnReplica/* = NULL*/, LPCSTR lpcszTheme/* = NULL*/)
/// end TAKE_BACK_OLD_FEATURES
{
	if ( !s_pltNLF )
		return OP_NO_OPERATION_OBJECT;
	
	/// Hong 10/09/08 v8.0953 TAKE_BACK_OLD_FEATURES
	//return s_pltNLF->SetFunction(lpcszFuncName, pbAutoInit);
	return s_pltNLF->SetFunction(lpcszFuncName, pbAutoInit, pnFitMode, pnReplica, lpcszTheme);
	/// end TAKE_BACK_OLD_FEATURES
}


int lt_nlf_iterate(int nNum, int nMethod) // = -1, LM_ITERATE_METHOD
{
	if ( !s_pltNLF )
		return OP_NO_OPERATION_OBJECT;
	
	if ( LM_ITERATE_METHOD == nMethod )
		nMethod = FITMETH_LEVENBERG_MARQUARDT;
	else if ( SIMPLEX_ITERATE_METHOD == nMethod )
		nMethod = FITMETH_SIMPLEX;
	else
		return -1;
	/// Hong 11/04/08 v8.0965b NLLT_NO_NEED_CHECK_ITERATE_RESULT
	//return s_pltNLF->Iterate(nNum, nMethod);
	s_pltNLF->Iterate(nNum, nMethod);
	return OP_NOERROR;
	/// end NLLT_NO_NEED_CHECK_ITERATE_RESULT
}

bool	lt_nlf_enable_source_page_preview()
{
	if( NULL == s_pltNLF )
		return false;
	
	return s_pltNLF->EnableSourceGraphPreview();
}

/// Hong QA80-12374 10/14/08 NL_LT_ADD_OUTPUT_ACCESS
int		lt_nlf_gui(TreeNode& trGUI, bool bGet)
{
	if( NULL == s_pltNLF )
		return OP_NO_OPERATION_OBJECT;
	
	return s_pltNLF->GUI(trGUI, bGet);
}
/// end NL_LT_ADD_OUTPUT_ACCESS

int cvt_op_err_to_nlf_xf_err(int nOpErrCode)
{
	///Kyle 09/11/08 MODIFY_FUNCTIONS_TO_SUPPORT_SURFACE_FIT
	//return OP_NOERROR;
	int nErr;
	switch (nOpErrCode)
	{
	case OP_FAIL_LOAD_FDF_TO_TREE:
		nErr = XFERR_LOAD_FDF_TREE_FAILED;
		break;
	case OP_CAN_NOT_FIND_FUNC_FDF_FILE:
		nErr = XFERR_WRONG_FUNC_NAME;
		break;
	case OP_FAILED_INIT_FROM_OPERATION_TREE:
		nErr = XFERR_FAIL_INIT_FROM_OP_TREE;
		break;
	case OP_WRONG_TYPE_DATA_RANGE:
		nErr = XFERR_AT_LEAST_ONE_XYRANGE;
		break;
	case OP_INVALID_INPUT_DATA_NODE:
	case OP_FAILED_GET_TREE_FROM_DATA_RANGE:
		nErr = XFERR_INVALID_RANGE;
		break;
	case OP_NO_OPERATION_OBJECT:
		nErr = XFERR_NO_CREATED_NLFIT_OBJ;
		break;
	case OP_UNKNOWN_ERROR:
	default:
		nErr = CER_UNKNOWN_ERROR;
		break;
	}	
	return nErr;
	///End MODIFY_FUNCTIONS_TO_SUPPORT_SURFACE_FIT
}
