/*------------------------------------------------------------------------------*
 * File Name: PeakFitHelper.h	 												*
 * Creation: 																	*
 * Purpose: for pfw and	spfw													*
 * Copyright (c) Originlab Corp. 2008											*
 * All Rights Reserved															*
 * 																				*
 * Modification Log:															*
 *	Hong 10/16/08 v8.0956 FIX_PA_DO_FIT_AGAIN_EVEN_CONVERGE						*
 *	Folger 10/16/08 SAVE_PLOT_UIDS_IN_PA_CORE_TO_WORKAROUND_MISSING_PREVIEW_PLOT_IN_PA_FIT
 *	Kyle 10/21/08 CHANGE_FUNCTION_NAME_HASBASELINEPEAK_TO_GETBASELINEFITMODE	*
 *  Iris 10/22/2008 NEW_PA_FIX_BUTTONS											*
 *  Iris 10/22/2008 MORE_ON_AUTO_INIT											*
 *	Folger 10/24/08 v8.0960 SUPPORT_SORT_MULTIPLE_PEAKS_IN_PA					*
 *	Folger 10/24/08 v8.0960 BASELINE_STATUS_IN_NLFSESSION_SHOULD_BE_READY_RIGHT_AFTER_PREPARE_FUNCTION_ON_INIT
 *  Iris 10/27/2008 v8.0960 FIX_OUTPUT_DESTINATION_GUI_SHOW_TEMP_WORK_NAME_AS_OUTPUT*
 *	Hong 10/27/08 v8.0961 FIX_GENERATE_REPORT_WITHOUT_ITERATE_FAIL_GET_PARAM_SETTINGS
 *	Folger 10/28/08 v8.0962 CORRECTLY_UPDATE_PEAK_FIT_DIALOG_WHEN_SWITCH_PAGES	*
 *	Folger 10/29/08 v8.0962 CORRECTLY_SET_AUTO_INIT_STATUS_INTO_PARAMS_TREE		*
 *	Folger 10/29/08 v8.0962 MOVE_REMOVE_FUNCTIONS_IN_NLPARAMSMNGR_TO_VC			*
 *  Iris 10/30/2008 V8.0963b SET_BASELINE_FIXED_AS_SR4							*
 *	Folger 11/01/08 QA80-12509 v8.0964 SUPPORT_PEAK_LABEL_SWITCHING_IN_PA_FIT_CONTROL_DIALOG
 *  Iris 11/04/2008 v8.0965b PA_FIT_ADD_INPUT_REPORT_TABLE						*
 *  Iris 11/04/2008 v8.0965b SAVE_DEFAULT_FUNC_TO_THEME							*
 *  Iris 11/05/2008 v8.0965d NOT_ALLOW_REPORT_TO_SOURCE_GRAPH_IF_SUBTRACTED_BASELINE*
 *  Iris 11/05/2008 v8.0965d NOT_KEEP_REPORT_PLOT_FORMAT_IF_SUBTRACTED_BASELINE *
 *	Folger 11/05/08 QA80-12509 v8.0965 SUPPORT_BOTH_PEAKS_SORTING_AND_REORDERING_FOR_MULTIPLE_PEAKS_FITTING
 *  Iris 11/06/2008 v8.0966b TALK_WITH_MAX_NO_NEED_REMOVE_SOURCE_OPTION_IF_NOT_ADD_BACK_BASELINE*
 *  Iris 11/06/2008 FIX_NOT_SUBTRACTED_FAIL_PLOT_FIT_CURVE_ON_NEW_OUTPUT_GRAPH	*
 *  Iris 11/07/2008 FIX_NOT_SUBTRACT_BASELINE_IN_PARAM_GRID_FOR_CONST_BASELINE_AND_SUBTRACTED*
 *  Iris 11/10/2008 v8.0968 FIX_RUNTIME_ERR_IF_DATA_FROM_WKS					*
 *  Iris 11/10/2008 v8.0968 FIX_IF_SUBTRACTED_THEN_ADDBACKBASELINE_ALWAYS_FIT_ON_ORIGINAL_DATA*
 *	Folger 11/10/08 QA80-12509 v8.0968 ONLY_SET_PLOT_LABEL_TYPE_IN_PEAK_FIT_DIALOG_EXCLUDE_ROTATION
 *	Sophy 11/10/2008 CLEAN_CODE_ADD_BASELINE_INFO_TO_REPORT_TABLE				*
 *  Iris 11/11/2008 v8.0968 REMOVE_SOURCE_GRAPH_OPTION_FROM_COMBO_IF_NOT_SOURCE_GRAPH*
 *	Sophy 11/12/2008 SUPPORT_USE_EXISTING_DATARANGE_AS_BASELINE_IN_NEW_PA		*
 *	Folger 11/12/08 QA80-12488 v8.0969 PA_FITTING_AUTO_UPDATE_SUPPORT			*
 *	Folger 11/13/08 QA80-12488 v8.970 PA_FITTING_AUTO_UPDATE_SUPPORT_USE_VECTOR_FOR_UIDS_STORAGE
 *  Iris 11/14/2008 v8.0971b QA80-12584 FITPEAK_OP_OUTPUT_SUBTRACTED_REPLACE_BASELINE_XF_OUTPUT_SUBTRACTED*
 *  Iris 11/14/2008 v8.0971b QA80-12584 PLOT_SOURCE_DATA_REPLACE_PLOT_SUBTRACTED_DATA_IF_SUBTRACTED_DATA*
 *	Hong 11/14/08 QA80-12584 v8.0971b DISABLE_OPTIONS_INSTEAD_OF_HIDDEN_IT_FOR_BASELINE_OUTPUT_OPTIONS
 *	Folger 11/15/08 v8.0972 SHOULD_NOT_APPLY_PARAMETER_VALUES_WHEN_AUTO_INIT_IS_ON
 *	Folger 11/15/08 QA80-12488 v8.0972 NEED_TO_BRING_BACK_REPORT_GRAPHS_UID_FOR_AUTO_UPDATE
 *	Jasmine 11/17/08 v8.0973 CENTRALIZE_FIT_CODE_TO_SHARE_WITH_NANOSIZER		*
 *  Iris 11/17/2008 QA80-12584-P8 FIX_PROBLEMS_WHEN_RECALCULATE_NOT_PREVIEW_GRAPH*
 *  Iris 11/17/2008 v8.0973 CLEAN_newOutputGraph								*
 *  Iris 11/18/2008 PA_FIT_SUPPORT_NEW_BASELINE_MODE_XPS						*
 *	Jasmine 11/19/08 v8.0975b CENTRALIZE_FIT_CODE_TO_SHARE_WITH_NANOSIZER		*
 *	Folger 11/21/08 v8.0977 CORRECT_WIZOPERATION_OUTPUT_RANGE_BEFORE_PA_EXIT	*
 *	Kyle 11/24/2008 SUBTRACT_BASELINE_BEFORE_CALCULATING_FIT_CURVE_POINTS		*
 *	Sophy 11/28/2008 v8.0980d CHECK_FIT_FUNCTIONS_ON_PARAMS_CHANGE				*
 *  Iris 12/01/2008 v8.0981 FIX_CHANGE_PARAM_ALWAYS_REPLOT_ON_SOURCE_GRAPH		*
 *  Iris 12/02/2008 v8.0981b QA80-12701 FIX_BACK_TO_BASECREATE_NOT_KEEP_BASELINE_FUNC_IF_CHANGE_FUNC_IN_FITPEAK*
 *	Folger 12/03/08 QA80-12701 v8.0982 THEME_SETTING_CONTROL_FOR_BASELINE_FUNCTION_APPLIED_IN_PA_FIT
 *	Folger 12/10/08 QA80-12751 v8.0984d SUPPORT_ALWAYS_GENERATE_OUTPUTS_REGARDLESS_OF_INTERATION_IN_PA_FITTING
 *	Sim 01-13-2009 XFWIZ_CHANGE_PARAM_MAY_CHANGE_THEME_AND_IO_RANGE				*
 *	Kyle 01/16/2009 XF_CHECK_CHECK_SET_LAST_OUTCOME_MESSAGE						*
 *	Folger 01/04/09 QA80-12962 MORE_WORK_ON_GENERATE_INDIVIDUAL_FIT_CURVE_USING_INDEPENDENT_X_IN_PA
 *	Folger 01/19/09 QA80-12962 REDUCE_CUMULATIVE_FIT_CRUVE_DATA_POINTS_IN_PA	*
 *	Folger 01/19/09 QA80-12969 PA_FITTING_SUPPORT_ANALYSIS_TEMPLATE				*
 *	Folger 01/19/09 QA80-12963 PA_FITTING_FAILS_TO_OUTPUT_PROPERLY_WHEN_CHANGE_OUTPUT_IN_CHANGE_PARAM
 *	Folger 01/22/09 PEAK_FITTING_OUTPUTS_HELPER_CLEANUP							*
 *	Folger 02/04/09 QA80-12962 ADD_OPTION_IN_PA_FIT_TO_SWTICH_BACK_TO_OLD_FIT_CURVE_DATA_GENERATION_MECHANISM
 *	Folger 02/06/09 PA_FITTING_RECALCULATION_FAILS_SINCE_WIZOP_REMOVES_ALL_EMPTY_RANGES
 *  Iris 2/17/2009 FIX_LOAD_THEME_INCLIDE_SHARE_PARAMS_BUG						*
 *	Folger 02/20/09 NEED_SUBTRACT_BASELINE_IF_HAS_ONE_FOR_CALCULATE_FIT_CURVE_POINTS
 *  Iris 02/24/2009 QA80-13170 NOT_CORRECT_APPLY_BASELINE_PARAM_WHEN_CHANGE_PARAM*
 *  Iris 2/25/2009 QA80-13180 FIX_NOT_APPLY_CORRECT_DEFAULT_FUNC_FOR_NEWLY_ADD_PEAK*
 *	Folger 02/25/09 QA80-13181 SHARE_BASELINE_FIX_STATUS_BETWEEN_BASELINE_TREATMENT_AND_FITTING
 *  Iris 03/06/2009 FIX_AFTER_RECALCULATE_SOURCE_PLOT_COLOR_IS_RED				*
 *	Folger 03/09/09 PREVIEW_SHOULD_BE_ALWAYS_UPDATED_AFTER_FITTING_REGARDLESS_OF_GOOD_FIT
 *	Folger 03/11/09 SHOULD_ONLY_USE_SHARED_FIXBASE_NODE_WHEN_FITTING_WITH_BASELINE
 *	Folger 03/16/09 QA80-13279 REMINDER_MESSAGE_FOR_SWITCH_TO_REPORT_SHEET_SHOULD_NOT_BE_SHOWN_DURING_AUTO_UPDATE
 *	Folger 04/16/09 QA80-13458-P2 FIT_CURVE_POINTS_FOR_ALL_PEAKS_SHOULD_NOT_BE_LESS_THAN_100
 *	Folger 05/12/09 NANOSIZER_FITTING_BASED_SUPPORT								*
 *	Jasmine 06/12/09 NANOSIZER_NEED_CENTRALIZE									*
 *	Jasmine 07/02/09 PA_AND_NANOSIZER_NEED_UPDATE_DATA_TYPE						*
 *	Folger 09/05/09 FAILS_TO_PASTE_RESULTS_TABLE_TO_REPORT_GRAPH_DURING_CHANGE_PARAM_IN_PA
 *	Folger 10/20/09 NANOSIZER_FAILS_TO_SWITCH_LABEL_PLOT						*
 *	Folger 11/12/09 QA81-14628-P2 PA_FITTING_RUNTIME_ERROR_WHEN_NOT_OUTPUT_RESULT_GRAPH
 *	Folger 11/27/09 AUTO_CALCULATE_FIT_CURVE_POINTS_FAILS_IF_NOT_LINEAR_X_DATA_TYPE
 *------------------------------------------------------------------------------*/

#ifndef _PEAK_FIT_HELPER_H
#define _PEAK_FIT_HELPER_H

#include 	"PAWizCore.h"
#include	"PeakFitHelperBase.h"	///Jasmine 11/17/08 v8.0973 CENTRALIZE_FIT_CODE_TO_SHARE_WITH_NANOSIZER
#include	"PAParamInitHelper.h"	///------ Folger 05/12/09 NANOSIZER_FITTING_BASED_SUPPORT

///------ Folger 01/04/09 QA80-12962 MORE_WORK_ON_GENERATE_INDIVIDUAL_FIT_CURVE_USING_INDEPENDENT_X_IN_PA
/// move to analysis_utils.h
//#define		FITCURVE_POINTS_PER_PEAK		30				///Jasmine 02/01/08 FITCURVE_POINTS_PER_PEAR
///------ End MORE_WORK_ON_GENERATE_INDIVIDUAL_FIT_CURVE_USING_INDEPENDENT_X_IN_PA

/// Iris 10/31/2008 V8.0963d MOVE_2ND_DERVITIVE_PLOT_CODES_TO_PAWIZCORE
//#define		_PREVIEW_RESIDUAL_LAYER					"PrevResid"			
//#define		_PREVIEW_2ND_DERVIA_LAYER				"Prev2ndDerv" 
///end MOVE_2ND_DERVITIVE_PLOT_CODES_TO_PAWIZCORE

enum
{
	INDEX_ORIGIN_LAYER,
	INDEX_PARENT_LAYER
};

////////////////////////////////////////////////////////
////////////////////	PeakFitHelper	////////////////////
//////////////////////////////////////////////////////// 
///Jasmine 11/17/08 v8.0973 CENTRALIZE_FIT_CODE_TO_SHARE_WITH_NANOSIZER
class PeakFitHelper : public PeakFitHelperBase
{
public:
	/// Iris 9/18/2008 NEED_ACCESS_PAWIZCORE_IN_PEAKFITHELPER
	//PeakFitHelper(bool bCreateOp = true);
	PeakFitHelper(FitWizCoreBase *pFitWizCore = NULL, bool bCreateOp = true);
	///end NEED_ACCESS_PAWIZCORE_IN_PEAKFITHELPER
///End CENTRALIZE_FIT_CODE_TO_SHARE_WITH_NANOSIZER
	~PeakFitHelper();
	
	//virtual
	bool	SetFunction(string strFunction, int nFunc = 0, bool bResetFunction = true);
	
	bool	Fit();
	
	//----- Iris 9/11/2008 PA_PREVIEW
	/// Iris 10/31/2008 V8.0963d MOVE_2ND_DERVITIVE_PLOT_CODES_TO_PAWIZCORE
	//void 	InitPreview(const TreeNode& trCurveOptions, GraphLayer& gl);
	//virtual
	void 	InitPreview(const TreeNode& trGetN);
	///end MOVE_2ND_DERVITIVE_PLOT_CODES_TO_PAWIZCORE
	bool	UpdatePreview(DWORD dwUpdateBits = FITPREVIEW_INIT, bool *pbShowResidual = NULL, bool *pbShow2ndDervi = NULL);		//Kyle
	void 	UpdatePeakCenterLabel();
	//-----	
	
	//bool	RePlotPreviewGraph();		///Jasmine 04/17/08 UPDATE_PREVIEW_DATA_AND_PREVIEW_GRAPH_AFTER_CHANGE_WEIGHT
	
	/// Iris 9/22/2008 NEW_PA
	//void 	GetPFWTree(Page& pg, TreeNode& trPFM);
	//bool 	UpdatePFWTree(Page& pg, TreeNode& trPFM);
	//void 	GetRuntimePFWTree(TreeNode& trPFM);
	bool	ConstructPFMParamsTree(TreeNode& trPFMParams);
	///end NEW_PA
	
	// operation relative
	///Jasmine 06/12/09 NANOSIZER_NEED_CENTRALIZE
	///// Iris 9/17/2008 NEW_PA
	////int 	ExecuteOperation(GraphLayer& gl, Page& pg, const TreeNode& trGetN);
	////bool 	PrepareOperationTree(TreeNode& trOp, const TreeNode& trGetN, const TreeNode& trPFM);
	///// Iris 11/15/2008 v8.0972 QA80-12584_P7 FIX_ALWAYS_NEW_REPORT_GRAPH_WHEN_RECALCULATE
	////int 	ExecuteOperation(const GraphLayer& gl, const TreeNode& trGetN, /*DataRange& range, DataRange& range2, DataRange& range3*/TreeNode& trUID);
	//int 	ExecuteOperation(const GraphLayer& gl, TreeNode& trGetN, TreeNode& trUID);
	/////end FIX_ALWAYS_NEW_REPORT_GRAPH_WHEN_RECALCULATE
	/////end NEW_PA
	///End NANOSIZER_NEED_CENTRALIZE
	
	// fit relative
	bool 	OnClickFit(bool *pbEnable);
	//bool 	IsFitReady();	
	//int 	GetNumPeaks();		
	int		GetPeaksInfo(vector* pvCenters = NULL, vector* pvHeights = NULL, vector<string> *pvstrFunctions = NULL);
	bool	SetPeaksInfo(vector* pvCenters = NULL, vector* pvHeights = NULL, vector<string> *pvstrFunctions = NULL);
	bool	SetBaselineInfo(vector* pvParams = NULL, vector<string>* pvsParamNames = NULL, LPCSTR lpcszFunction = NULL);
	bool	SetSourcePlotUID(DWORD dwPlotUID); /// Iris 11/04/2008 v8.0965b NEW_PA_SUPPORT_CREATE_REPORT_GRAPH_ON_SOURCE
	
	/// Iris 9/22/2008 NEW_PA
	/// Iris 11/06/2008 v8.0966b TALK_WITH_MAX_NO_NEED_REMOVE_SOURCE_OPTION_IF_NOT_ADD_BACK_BASELINE
	//void 	UpdatePlotCurveTo(TreeNode& trgpconfig); /// Iris 11/05/2008 v8.0965d NOT_ALLOW_REPORT_TO_SOURCE_GRAPH_IF_SUBTRACTED_BASELINE
	///end TALK_WITH_MAX_NO_NEED_REMOVE_SOURCE_OPTION_IF_NOT_ADD_BACK_BASELINE

	///end NEW_PA
	
	int		OnAfterModifyPeaksCenter(const TreeNode& trPeakCenters, int nModifiedPeakIndex);
	
	// used in param grid to check which param is baseline func param
	//bool	GetBaselineParamIndices(vector<int>& vnIndices); /// Iris 10/30/2008 v8.0963b DISABLE_BASELINE_PARAMETER_SHARE_CELL
	
	//void 	OutputGraphUpdateLegendAndColor(GraphLayer& gl, TreeNode& trGetN);	
	//
	//bool	GetOperationTree(TreeNode& trOp);	
//public:
	//virtual bool 	CheckGetGUITreeFromOp(TreeNode& trGUI);
	//
	//virtual bool 	RemovePreviewPlots(GraphLayer& gl);
	//virtual void 	UpdatePreview(GraphLayer& gl, bool bResidual = true, bool b2ndDeriative = true);
	//
	/////Jasmine 03/11/08 SHOW_FITCONTROL_BRANCH_IN_XF_NOT_IN_PARAMDLG_BY_CP_REQUEST
	////virtual 		void UpdateAdvancedSetting(Page& pg, TreeNode& trGetN);
//protected:

	int GetLastIterateOutCome(string& strOutCome);			///Kyle 01/16/2009 XF_CHECK_CHECK_SET_LAST_OUTCOME_MESSAGE
	
	//------ Folger 10/24/08 v8.0960 SUPPORT_SORT_MULTIPLE_PEAKS_IN_PA
	/// virtual
	bool	UpdatePeaksPropertiesAfterSorting(const vector<uint>& vnIndices);
	//------
	
	///------ Folger 10/20/09 NANOSIZER_FAILS_TO_SWITCH_LABEL_PLOT
	////------ Folger 11/01/08 QA80-12509 v8.0964 SUPPORT_PEAK_LABEL_SWITCHING_IN_PA_FIT_CONTROL_DIALOG
	//bool			AccessPeakLabelSettings(int& nLabelXYType, bool bGet = true);
	////------
	///------ End NANOSIZER_FAILS_TO_SWITCH_LABEL_PLOT
	
	///Sophy 11/28/2008 v8.0980d CHECK_FIT_FUNCTIONS_ON_PARAMS_CHANGE
	int				CheckErrorOnFitFunctions(string& strErr);
	///end CHECK_FIT_FUNCTIONS_ON_PARAMS_CHANGE
	
	///------ Folger 02/25/09 QA80-13181 SHARE_BASELINE_FIX_STATUS_BETWEEN_BASELINE_TREATMENT_AND_FITTING
	/// virutal
	void			CheckSetBaseParamFixMode(bool* pbFixed = NULL);
	///------ End SHARE_BASELINE_FIX_STATUS_BETWEEN_BASELINE_TREATMENT_AND_FITTING
	
private:	
	/// Iris 10/31/2008 V8.0963d MOVE_2ND_DERVITIVE_PLOT_CODES_TO_PAWIZCORE
	//bool 	prepareGraphLayerForPreview( GraphPage & gp, bool bShowResidual, GraphLayer & glResidual, bool  bShow2ndDervi, GraphLayer & gl2ndDervi, bool & bNeedArrange, stLayersGridFormat& stOldFormat);	//Kyle
	bool 	prepareGraphLayerForPreview( bool bShowResidual, GraphLayer & glResidual, bool  bShow2ndDervi, GraphLayer & gl2ndDervi );
	///END MOVE_2ND_DERVITIVE_PLOT_CODES_TO_PAWIZCORE
	
	/////// create, access and destory object 
	virtual bool 	hasSpecInfo(StringArray& saOptions, string& strSetInfoFromXF);	
	
	/////// end create, access and destory object
	//virtual
	void 	initSessionSettingsFromGetN(const TreeNode& trGetN);
	
	/////// generate output 
	///Sophy 9/24/2008 NEW_PA
	//int 	plotWithNewGraph(const GraphLayer gl, const TreeNode trGetN, TreeNode& trGUI, bool bHasBaselinePeak);
	int 	newOutputGraph(const GraphLayer gl, const TreeNode trGetN, TreeNode& trGUI, bool bHasBaselinePeak);
	///end NEW_PA
	void 	resetInputDataWithNewGraph( const TreeNode trGetN, TreeNode& trGUI, int nPlotUID );
	void 	updateOutputGraphNodeWithNewGraph(TreeNode trGetN, int nPlotUID); /// Iris 11/15/2008 v8.0972 QA80-12584_P7 FIX_ALWAYS_NEW_REPORT_GRAPH_WHEN_RECALCULATE

	///Sophy 10/20/2008 CLEAN_CODE_ADD_BASELINE_INFO_TO_REPORT_TABLE
	//bool 	addBaselineInfo(GraphLayer &gl, Page &pg, TreeNode &trCal);
	bool 	addBaselineInfo(TreeNode &trCal);
	string	getInterpFunc();
	///end CLEAN_CODE_ADD_BASELINE_INFO_TO_REPORT_TABLE
	bool 	addXFInfo( TreeNode &trCal);
	bool 	addInputData( TreeNode &trCal);

	///------ Folger 09/05/09 FAILS_TO_PASTE_RESULTS_TABLE_TO_REPORT_GRAPH_DURING_CHANGE_PARAM_IN_PA
	//virtual void 	afterExecuteOperation(TreeNode& trGetN, TreeNode& trOp);
	/// virtual
	void 	beforeExecuteOperation(const GraphLayer& gl, TreeNode& trGetN, TreeNode& trOp, TreeNode& trUID);
	/// virtual
	void 	afterExecuteOperation(TreeNode& trGetN, TreeNode& trOp, TreeNode& trUID);
	///------ End FAILS_TO_PASTE_RESULTS_TABLE_TO_REPORT_GRAPH_DURING_CHANGE_PARAM_IN_PA
	
		/// Iris 3/09/2009 CLEANUP_TODO_CODES
	//virtual void 	updatePrivateSettings(GraphLayer& gl, TreeNode& trGUI, const TreeNode& trGetN, bool bHasBaselinePeak);
	void 	updatePrivateSettings(TreeNode& trGUI);
	///end CLEANUP_TODO_CODES
	
	virtual bool 	addOtherInformation(TreeNode &trOp);
	
	virtual void 	copySettingsToOperation(const TreeNode& trGetN, TreeNode& trGUI);	
	
	virtual void 	setBaselineRangeToOperation(TreeNode& trGUI);
	
	virtual void	prepareOutputGraph(GraphLayer& gl, TreeNode& trGUI, const TreeNode& trGetN, bool bHasBaselinePeak);	
	///////end generate output
	
	
	
	/////// GUI relative	
protected:	
	//virtual
	void 	initGetN(TreeNode& trGetN);
	
public:
	//virtual
	void 	CalculateFitCurvePoints(TreeNode& trGraph1);
private:
	void 	outputGraphAddBackBaseline(const TreeNode& trGetN); /// Iris 9/22/2008 NEW_PA	
	void	rearrangePreviewLayer( GraphPage& gp, vector<int>& vnLayerIndex, stLayersGridFormat& stOldFormat); ///Sophy 9/27/2008 NEW_PA rearrange fitcurve & residual & derivative preview graphlayer
	/////// end GUI relative
	
	
	/////// Theme relative	
	//bool			checkGUIAppliedTheme(TreeNode& trGetN);
	/// Iris 12/02/2008 v8.0981b QA80-12701 FIX_BACK_TO_BASECREATE_NOT_KEEP_BASELINE_FUNC_IF_CHANGE_FUNC_IN_FITPEAK
	bool			isApplyBaselineFuncFromBaseCreateXF(bool bReset = true); 
	///end FIX_BACK_TO_BASECREATE_NOT_KEEP_BASELINE_FUNC_IF_CHANGE_FUNC_IN_FITPEAK
	bool			applyFunctionsOnTheme(vector<string>& vsFunctions, const TreeNode& trGetN);
	//void			applyAutoParamsInitOnTheme(const TreeNode& trGetN);
	/////// end Theme relative	
	
	
	/////// fit funciton, data, parameters relative
	//virtual
	bool 			setParams(bool bOnInit, TreeNode& trGetN);
	//virtual
	void			prepareFunctions(vector<string>& vsFunctions, bool bOnInit = false, TreeNode& trGetN = NULL, bool bIncludeBaselineFunction = false);
	//virtual
	TreeNode		prepareData(TreeNode& trGetN);	
	
	int				preparePeakInfo(
									PEAKINFOARGUMENTSLISTPARAMS&		stPEAKINFOARGUMENTSLISTPARAMS,
									PEAKINFOARGUMENTSLISTFUNCTIONS&		stPEAKINFOARGUMENTSLISTFUNCTIONS,
									PEAKINFOARGUMENTSLISTBASE&			stPEAKINFOARGUMENTSLISTBASE,
									PEAKINFOARGUMENTSLISTBASELINE*		pstPEAKINFOARGUMENTSLISTBASELINE = NULL);
	
	int				getNumBaselineParams();
	//virtual 
	int 	getBaselineParams(vector* pvParamVals = NULL, vector<string>* pstrParamNames = NULL); /// Iris 3/30/2009 QA80-13362 FIX_CHANGE_BASELINE_FUNC_FIT_STATUS_FROM_NONE_TO_FIT_INSERT_0_FOR_REDUNDANT_BASELINE_PARAM_VAL
	
	///Sophy 10/14/2008 IMPROVE_CODE_CALCU_PEAK_HEIGHT_RELATIVE when add peaks with baseline...
	bool			calcPeakHeights( vector& vHeights, const vector& vCenters);
	///end IMPROVE_CODE_CALCU_PEAK_HEIGHT_RELATIVE
	
	void			resetNLParamsMngr();
	
	bool			needSubtractBaseline();
	
	double			calcAverageWidth(const vector& vX, const vector& vY, const vector& vHeights);
	
	bool			getInputDataRange(XYRange& xyInput);
	/////// end fit funciton, data, parameters relative
	
	//------ Folger 10/24/08 v8.0960 BASELINE_STATUS_IN_NLFSESSION_SHOULD_BE_READY_RIGHT_AFTER_PREPARE_FUNCTION_ON_INIT
	void			prepareFitSessionBaselineStatus(bool bBaselineFitWithPeaks);
	//------
		
	/// Iris 10/27/2008 v8.0961 PREPARE_SUBTRACTED_DATA_RANGE_IN_NLFSESSION
	void 			setFitSessionBaselineDataRange(); 
	void			setBackPlotUIDToDataRange(XYRange& xyInput); 
	///end PREPARE_SUBTRACTED_DATA_RANGE_IN_NLFSESSION	

	
	///------ Folger 02/25/09 QA80-13181 SHARE_BASELINE_FIX_STATUS_BETWEEN_BASELINE_TREATMENT_AND_FITTING
	TreeNode		getFixBaseNode();
	///------ End SHARE_BASELINE_FIX_STATUS_BETWEEN_BASELINE_TREATMENT_AND_FITTING
	
	//virtual 
	bool IsSingleFuncFit(){ return false; }
	
	///------ Folger 05/12/09 NANOSIZER_FITTING_BASED_SUPPORT
	/// virtual
	PeakParamInitHelperBase*		createParamInitHelper();
	/// virtual
	LPCSTR							getBaselineFuncCategory();
	///------ End NANOSIZER_FITTING_BASED_SUPPORT
	
private:
	PAWizCore*			m_pPAWizCore;
	
};

/////////////////////////////////////////////////////////
/////////////////////	PeakFitHelper	/////////////////////
///////////////////////////////////////////////////////// 
//---Jasmine 11/17/08 v8.0973 CENTRALIZE_FIT_CODE_TO_SHARE_WITH_NANOSIZER
///Jasmine 04/10/08 KEEP_OPERATION_IN_PEAK_FITHELPER
/// Iris 9/18/2008 NEED_ACCESS_PAWIZCORE_IN_PEAKFITHELPER
//PeakFitHelper::PeakFitHelper(bool bCreateOp)//(LPCSTR lpcszCategory)
PeakFitHelper::PeakFitHelper(FitWizCoreBase *pFitWizCore, bool bCreateOp) : PeakFitHelperBase(pFitWizCore, bCreateOp)
///end NEED_ACCESS_PAWIZCORE_IN_PEAKFITHELPER
{
	//m_bBaselineFitWithPeaks = false;
	//
	//m_bInitDone 		= false;
	//m_bDeleteFitSession = false;
	
	m_strOperation 	= "FitPeak";
	m_strCategory 	= STR_CATE_NAME_PFM;
	if(bCreateOp)
	{
		bool bRet = createOperation();
		ASSERT(bRet);
	}
	
	m_pPAWizCore = (PAWizCore*)pFitWizCore;
	
	m_pOpOutputHelper = new PeakFitOperationOutputHelper(pFitWizCore->GetXFWizOp(), m_pnlOp);		///------ Folger 01/22/09 PEAK_FITTING_OUTPUTS_HELPER_CLEANUP
		
	SetDefaultFunction(STR_PA_DEFAULT_FUNC);
}

PeakFitHelper::~PeakFitHelper()
{
}
//---end CENTRALIZE_FIT_CODE_TO_SHARE_WITH_NANOSIZER
///End KEEP_OPERATION_IN_PEAK_FITHELPER

////virtual 
bool PeakFitHelper::hasSpecInfo(StringArray& saOptions, string& strSetInfoFromXF)
{
	saOptions.Add(_L("Peak Fit"));
	
	strSetInfoFromXF = m_strOperation;
	
	return true;
}

bool PeakFitHelper::setParams(bool bOnInit, TreeNode& trGetN)
{
	applyAutoParamsInitOnTheme(trGetN); // need call this before InitParams
	
	PEAKINFOARGUMENTSLISTPARAMS		stPEAKINFOARGUMENTSLISTPARAMS;
	PEAKINFOARGUMENTSLISTFUNCTIONS	stPEAKINFOARGUMENTSLISTFUNCTIONS;
	PEAKINFOARGUMENTSLISTBASE		stPEAKINFOARGUMENTSLISTBASE;
	PEAKINFOARGUMENTSLISTBASELINE	stPEAKINFOARGUMENTSLISTBASELINE;
	
	// if baseline not fit with peaks, no need pass this struct
	PEAKINFOARGUMENTSLISTBASELINE	*pstPEAKINFOARGUMENTSLISTBASELINE = NULL;
	if( IsBaselineFitWithPeaks() )
		pstPEAKINFOARGUMENTSLISTBASELINE = &stPEAKINFOARGUMENTSLISTBASELINE;
	
	preparePeakInfo( stPEAKINFOARGUMENTSLISTPARAMS, stPEAKINFOARGUMENTSLISTFUNCTIONS, stPEAKINFOARGUMENTSLISTBASE, pstPEAKINFOARGUMENTSLISTBASELINE);
	
	bool		bBaselineFitWithPeaks = IsBaselineFitWithPeaks();
	int nNumPeaks = InitParams(&stPEAKINFOARGUMENTSLISTPARAMS, &stPEAKINFOARGUMENTSLISTFUNCTIONS, &stPEAKINFOARGUMENTSLISTBASE, pstPEAKINFOARGUMENTSLISTBASELINE, &bBaselineFitWithPeaks, !GetFitSession()->GetAutoInitParams());
	
	// if bOnInit is true and already applied theme on trGetN tree, so need apply param settings from theme
	if( bOnInit && trGetN/* && checkGUIAppliedTheme(trGetN)*/ ) 
	{		
		bool bRet = applyParamsOnTheme(trGetN);
		ASSERT(bRet);
	}
	
	return nNumPeaks > 0;
}

///Sophy 9/23/2008 NEW_PA change static functions to member method
void	PeakFitHelper::prepareFunctions(vector<string>& vsFunctions, bool bOnInit, TreeNode& trGetN, bool bIncludeBaselineFunction/* = false*/)
{
	int		nNumPeaks = GetPeaksInfo(NULL, NULL, &vsFunctions);	
	
	if ( bOnInit )
	{	
		/// Iris 11/07/2008 FIX_NOT_SUBTRACT_BASELINE_IN_PARAM_GRID_FOR_CONST_BASELINE_AND_SUBTRACTED
		//bool		bBaselineFitWithPeaks = m_pPAWizCore->HasBaseline() && m_pPAWizCore->GetBaselineFitMode();
		bool		bBaselineFitWithPeaks = m_pPAWizCore->HasBaseline() && m_pPAWizCore->GetBaselineFitMode() && !m_pPAWizCore->GetSubtractedMode();
		///end FIX_NOT_SUBTRACT_BASELINE_IN_PARAM_GRID_FOR_CONST_BASELINE_AND_SUBTRACTED
		if ( bBaselineFitWithPeaks )
		{
			string	strFunc;
			int		nRet = m_pPAWizCore->GetBaselineFitFunc(strFunc);
			ASSERT(nRet >= 0);
			
			if ( IsBaselineFitWithPeaks() )
				vsFunctions[0] = strFunc;
			else			
				vsFunctions.InsertAt(0, strFunc);
		}
		else if ( !bBaselineFitWithPeaks && IsBaselineFitWithPeaks() )
		{
			if ( vsFunctions.GetSize() )
				vsFunctions.RemoveAt(0);
		}
		//m_bBaselineFitWithPeaks = bBaselineFitWithPeaks;
		//------ Folger 10/24/08 v8.0960 BASELINE_STATUS_IN_NLFSESSION_SHOULD_BE_READY_RIGHT_AFTER_PREPARE_FUNCTION_ON_INIT
		prepareFitSessionBaselineStatus(bBaselineFitWithPeaks);
		//------
		
		int		nSize = vsFunctions.GetSize();
		vsFunctions.SetSize(nNumPeaks + getPeaksOffset());
		for ( int ii=nSize; ii<vsFunctions.GetSize(); ++ii )
		{
			/// Iris 2/25/2009 QA80-13180 FIX_NOT_APPLY_CORRECT_DEFAULT_FUNC_FOR_NEWLY_ADD_PEAK
			//vsFunctions[ii] = STR_GAUSSIAN_FUNC;
			vsFunctions[ii] = GetDefaultFunction();
			///end FIX_NOT_APPLY_CORRECT_DEFAULT_FUNC_FOR_NEWLY_ADD_PEAK
		}
		
		if( trGetN )
		{
			applyFunctionsOnTheme(vsFunctions, trGetN);
		}

		// set peaks function back to pawizcore
		SetPeaksInfo(NULL, NULL, &vsFunctions);
		
		resetNLParamsMngr();		/// should only reset NLParamsMngr here
	}
	else
	{
		if ( !bIncludeBaselineFunction && IsBaselineFitWithPeaks() )
		{
			if ( vsFunctions.GetSize() )
				vsFunctions.RemoveAt(0);
		}
	}
	
	///// Iris 9/22/2008 NEW_PA
	//if( bOnInit && trGetN/* && checkGUIAppliedTheme(trGetN)*/ )// if bOnInit is true will apply function from theme
	//{
		//applyFunctionsOnTheme(vsFunctions, trGetN);
	//}
	/////end NEW_PA
}

//bool	PeakFitHelper::checkGUIAppliedTheme(TreeNode& trGetN)
//{
	//TreeNode trParamValues = trGetN.PFMParams.Values;
	//if( !trParamValues )
		//return false;	
	//if( trParamValues.IsEmpty() )
		//return false;
	//return true;
//}

/// Iris 12/02/2008 v8.0981b QA80-12701 FIX_BACK_TO_BASECREATE_NOT_KEEP_BASELINE_FUNC_IF_CHANGE_FUNC_IN_FITPEAK
// return true: means apply baseline function from theme, 
// return false: apply baseline fucntion from pa_basecreate xfucntion.
bool	PeakFitHelper::isApplyBaselineFuncFromBaseCreateXF(bool bReset)
{
	// when back to pa_basecreate xfucntion, will add attribute STR_BASEFUNC_FROM_BASECREATE_XF_ATTRIB in baseline fit info tree to mark
	// should use baseline funciton from this xf in fit peaks step.
	Tree otr;
	if( m_pPAWizCore->UpdateInfoTree(otr, PA_TREE_BASELINE_FIT_INFO, false) )
	{	
		int nTemp;
		if( otr.GetAttribute(STR_BASEFUNC_FROM_BASECREATE_XF_ATTRIB, nTemp) )
		{
			if(bReset)
			{
				otr.RemoveAttribute(STR_BASEFUNC_FROM_BASECREATE_XF_ATTRIB);
				m_pPAWizCore->UpdateInfoTree(otr, PA_TREE_BASELINE_FIT_INFO, true);
			}
			return true;
		}
	}
	return false;
}
///end FIX_BACK_TO_BASECREATE_NOT_KEEP_BASELINE_FUNC_IF_CHANGE_FUNC_IN_FITPEAK

bool	PeakFitHelper::applyFunctionsOnTheme(vector<string>& vsFunctions, const TreeNode& trGetN)
{
	TreeNode trPFMParams = trGetN.PFMParams;
	
	vector<string> vsThemeFunctions;
	if(trPFMParams && trPFMParams.Functions)
		//------ Folger 12/03/08 QA80-12701 v8.0982 THEME_SETTING_CONTROL_FOR_BASELINE_FUNCTION_APPLIED_IN_PA_FIT
		//vsThemeFunctions = trPFMParams.Functions.strVals;
		AccessPFMTreeFunctions(trPFMParams, vsThemeFunctions);
		//------
	
	/// Iris 12/02/2008 v8.0981b QA80-12701 FIX_BACK_TO_BASECREATE_NOT_KEEP_BASELINE_FUNC_IF_CHANGE_FUNC_IN_FITPEAK
	if( 0 != trPFMParams.BaselineParameters.nVal && IsBaselineFitWithPeaks() && isApplyBaselineFuncFromBaseCreateXF()
		&& vsThemeFunctions.GetSize() > 0 && vsFunctions.GetSize() > 0 )
	{
		//------ Folger 12/03/08 QA80-12701 v8.0982 THEME_SETTING_CONTROL_FOR_BASELINE_FUNCTION_APPLIED_IN_PA_FIT
		//vsThemeFunctions[0] = vsFunctions[0];
		//trPFMParams.Functions.strVals = vsThemeFunctions;
		trPFMParams.BaselineFunction.strVal = vsThemeFunctions[0] = vsFunctions[0];
		//------ End THEME_SETTING_CONTROL_FOR_BASELINE_FUNCTION_APPLIED_IN_PA_FIT
	}
	///end FIX_BACK_TO_BASECREATE_NOT_KEEP_BASELINE_FUNC_IF_CHANGE_FUNC_IN_FITPEAK
	
	//--- Iris 10/06/2008 if theme has not baseline fit, but current has, or converse, fail to apply functions from theme
	/*
	// Iris: Discussed with Jasmine to following old logic, if peak num from theme > current peak num, will not apply functions from theme
	if( vsThemeFunctions.GetSize() > vsFunctions.GetSize() ) 
		return false;
	
	for(int ii = 0; ii < vsThemeFunctions.GetSize(); ii++)
	{
		vsFunctions[ii] = vsThemeFunctions[ii];
	}
	*/
	int	nSourceFunc = 0, nDestFunc = 0;	
	if( 0 != trPFMParams.BaselineParameters.nVal && !IsBaselineFitWithPeaks() )
	{
		nSourceFunc = 1;
	}
	
	if( 0 == trPFMParams.BaselineParameters.nVal && IsBaselineFitWithPeaks() )
	{
		nDestFunc = 1;
	}
		
	for(; nSourceFunc < vsThemeFunctions.GetSize() && nDestFunc < vsFunctions.GetSize(); nSourceFunc++, nDestFunc++)
	{
		vsFunctions[nDestFunc] = vsThemeFunctions[nSourceFunc];
	}
	//---	
	
	/// Iris 11/04/2008 v8.0965b SAVE_DEFAULT_FUNC_TO_THEME
	if(trPFMParams && trPFMParams.DefaultFunction && !trPFMParams.DefaultFunction.IsEmpty())
		SetDefaultFunction(trPFMParams.DefaultFunction.strVal);
	///end SAVE_DEFAULT_FUNC_TO_THEME

	return true;
}

/// Iris 10/27/2008 v8.0961 PREPARE_SUBTRACTED_DATA_RANGE_IN_NLFSESSION
void		PeakFitHelper::setBackPlotUIDToDataRange(XYRange& xyInput)
{
	//------ Folger 10/16/08 SAVE_PLOT_UIDS_IN_PA_CORE_TO_WORKAROUND_MISSING_PREVIEW_PLOT_IN_PA_FIT
	vector<uint>	vnPlots;
	m_pPAWizCore->AccessOriginalRangePlots(vnPlots, true);
	for ( int ii=0; ii<vnPlots.GetSize(); ++ii )
		xyInput.SetPlotUID(vnPlots[ii], ii);
	//------ End SAVE_PLOT_UIDS_IN_PA_CORE_TO_WORKAROUND_MISSING_PREVIEW_PLOT_IN_PA_FIT	
}
///end PREPARE_SUBTRACTED_DATA_RANGE_IN_NLFSESSION

TreeNode	PeakFitHelper::prepareData(TreeNode& trGetN)
{
	TreeNode trJunk;		/// for errror
	
	XYRange xyOriginal;
	//m_pPAWizCore->GetPeaksRange(xyOriginal);
	getInputDataRange(xyOriginal);
	
	/// Iris 10/27/2008 v8.0961 PREPARE_SUBTRACTED_DATA_RANGE_IN_NLFSESSION
	/*
	//------ Folger 10/16/08 SAVE_PLOT_UIDS_IN_PA_CORE_TO_WORKAROUND_MISSING_PREVIEW_PLOT_IN_PA_FIT
	vector<uint>	vnPlots;
	m_pPAWizCore->AccessOriginalRangePlots(vnPlots, true);
	for ( int ii=0; ii<vnPlots.GetSize(); ++ii )
		xyOriginal.SetPlotUID(vnPlots[ii], ii);
	//------ End SAVE_PLOT_UIDS_IN_PA_CORE_TO_WORKAROUND_MISSING_PREVIEW_PLOT_IN_PA_FIT
	*/	
	setFitSessionBaselineDataRange(); 
	///end PREPARE_SUBTRACTED_DATA_RANGE_IN_NLFSESSION
	
	TreeNode trInputData = trGetN.trAdv.InputData;
	if ( !construct_tree_from_xyrange(trInputData, xyOriginal) )
	{
		ASSERT(false);
		return trJunk;
	}
	
	Tree trRoot;
	TreeNode trTemp;
	vector<string> vsIndep = {"X"};
	vector<string> vsDep = {"Y"};
	
	if ( okutil_create_fitter_data_node_ex(&trTemp, &trRoot, STR_INPUT_RANGE_NAME, STR_INPUT_RANGE_LABEL, &vsIndep, &vsDep, WEIGHT_NONE) )
	{
		TreeNode trTempRange, trRange;
		if(trInputData.Range1)
			trRange = trInputData.Range1;
		if(trTemp.Range1)
			trTempRange = trTemp.Range1;
		trTempRange.X.Replace(trRange.X, true, true, true);
		trTempRange.Y.Replace(trRange.Y, true, true, true);
		
		trRange.Replace(trTempRange, true, true, true);
		
		#ifdef _DEBUG
		if( !okutil_is_fitter_data_node_ready(&trInputData) )
		{
			ASSERT(false);
			error_report("fitter data node is not ready");
			return trJunk;
		}
		#endif	/// _DEBUG
		
		return trInputData;
	}
	
	return trJunk;
}

int		PeakFitHelper::preparePeakInfo( 
										PEAKINFOARGUMENTSLISTPARAMS&		stPEAKINFOARGUMENTSLISTPARAMS,
										PEAKINFOARGUMENTSLISTFUNCTIONS&		stPEAKINFOARGUMENTSLISTFUNCTIONS,
										PEAKINFOARGUMENTSLISTBASE&			stPEAKINFOARGUMENTSLISTBASE,
										PEAKINFOARGUMENTSLISTBASELINE*		pstPEAKINFOARGUMENTSLISTBASELINE/* = NULL*/)
{
	vector	vCenters, vHeights;
	int		nNumPeaks = GetPeaksInfo(&vCenters, &vHeights);
	///////////////////////////////////////////////////////////////////
	
	/// PEAKINFOARGUMENTSLISTPARAMS
	stPEAKINFOARGUMENTSLISTPARAMS.vCenters = vCenters;
	stPEAKINFOARGUMENTSLISTPARAMS.vHeights = vHeights;
	
	/// PEAKINFOARGUMENTSLISTFUNCTIONS
	prepareFunctions(stPEAKINFOARGUMENTSLISTFUNCTIONS.vsFunctions);
	
	/// PEAKINFOARGUMENTSLISTBASE
	XYRange xyOriginal;
	m_pPAWizCore->GetPeaksRange(xyOriginal);
	if ( !xyOriginal.GetData(stPEAKINFOARGUMENTSLISTBASE.vY, stPEAKINFOARGUMENTSLISTBASE.vX) )
	{
		ASSERT(false);
	}
	
	XYRange xyBaseline;
	m_pPAWizCore->GetBaselineRange(xyBaseline);
	if ( !xyBaseline.GetData(stPEAKINFOARGUMENTSLISTBASE.vYBL, stPEAKINFOARGUMENTSLISTBASE.vXBL) )
	{
		ASSERT(false);
	}
	stPEAKINFOARGUMENTSLISTBASE.bSubtractBaseline = !m_pPAWizCore->GetSubtractedMode();//if subtracted, no need to subtract again...
	
	/// if if the data has a baseline(not subtracted yet), subtract it and get the height again
	if ( needSubtractBaseline() )
	{
		//subtract_baseline(stPEAKINFOARGUMENTSLISTBASE.vX, stPEAKINFOARGUMENTSLISTBASE.vY,  stPEAKINFOARGUMENTSLISTBASE.vXBL, stPEAKINFOARGUMENTSLISTBASE.vYBL);
		
		///Sophy 10/14/2008 IMPROVE_CODE_CALCU_PEAK_HEIGHT_RELATIVE when add peaks with baseline...
		/*
		for(int ii = 0; ii < nNumPeaks; ii++)
		{
			double dY;
			double dX = stPEAKINFOARGUMENTSLISTPARAMS.vCenters[ii];
			if ( 0 == ocmath_interpolate(&dX, &dY, 1, stPEAKINFOARGUMENTSLISTBASE.vXBL, stPEAKINFOARGUMENTSLISTBASE.vYBL, stPEAKINFOARGUMENTSLISTBASE.vXBL.GetSize()) )
			{
				stPEAKINFOARGUMENTSLISTPARAMS.vHeights[ii] -= dY;
			}
		}
		*/
		calcPeakHeights( stPEAKINFOARGUMENTSLISTPARAMS.vHeights, stPEAKINFOARGUMENTSLISTPARAMS.vCenters);
		///end IMPROVE_CODE_CALCU_PEAK_HEIGHT_RELATIVE
	}
	
	/*
	IntegrationResult sResult;
	ocmath_integrate(stPEAKINFOARGUMENTSLISTBASE.vX, stPEAKINFOARGUMENTSLISTBASE.vY, 0, stPEAKINFOARGUMENTSLISTBASE.vX.GetSize()-1, &sResult, NULL, ABSOLUTE_AREA);	
	
	if (sResult.dxPeak < 0 && sResult.dxPeak != NANUM)
	{
		sResult.dxPeak *= -1;	
	}
	double dSumHeight;
	vector vAbs; 
	vAbs = abs(stPEAKINFOARGUMENTSLISTPARAMS.vHeights);
	vAbs.Sum(dSumHeight);
	stPEAKINFOARGUMENTSLISTBASE.dAverageWidth = sResult.Area/dSumHeight/sqrt(PI/(4*ln(2)));
	*/
	stPEAKINFOARGUMENTSLISTBASE.dAverageWidth = calcAverageWidth(stPEAKINFOARGUMENTSLISTBASE.vX, stPEAKINFOARGUMENTSLISTBASE.vY, stPEAKINFOARGUMENTSLISTPARAMS.vHeights);
	
	
	stPEAKINFOARGUMENTSLISTBASE.nSmoothPoint = 11;	
	
	/// PEAKINFOARGUMENTSLISTBASELINE
	if ( pstPEAKINFOARGUMENTSLISTBASELINE )
	{
		TreeNode trBaselineInfo;
		if( m_pPAWizCore->UpdateInfoTree(trBaselineInfo, PA_TREE_BASELINE_FIT_INFO, false) && trBaselineInfo)
		{
			if ( !IsBaselineFitWithPeaks() )	//------ Folger 12/03/08 QA80-12701 v8.0982 THEME_SETTING_CONTROL_FOR_BASELINE_FUNCTION_APPLIED_IN_PA_FIT
			{
				string strFunc;
				if( trBaselineInfo.GetAttribute(STR_LABEL_ATTRIB, strFunc) )
					pstPEAKINFOARGUMENTSLISTBASELINE->strFunction  = strFunc;
			}
			//------ Folger 12/03/08 QA80-12701 v8.0982 THEME_SETTING_CONTROL_FOR_BASELINE_FUNCTION_APPLIED_IN_PA_FIT
			else
			{
				vector<string>	vsFunctions;
				GetPeaksInfo(NULL, NULL, &vsFunctions);	
				pstPEAKINFOARGUMENTSLISTBASELINE->strFunction = vsFunctions[0];
			}
			//------ End THEME_SETTING_CONTROL_FOR_BASELINE_FUNCTION_APPLIED_IN_PA_FIT
			
			foreach(TreeNode trParam in trBaselineInfo.Children)
			{
				ASSERT(!trParam.IsEmpty());
				pstPEAKINFOARGUMENTSLISTBASELINE->vParamValues.Add(trParam.dVal);
				
				string strName;
				trParam.GetAttribute(STR_LABEL_ATTRIB, strName);
				ASSERT(!strName.IsEmpty());
				pstPEAKINFOARGUMENTSLISTBASELINE->vsParamNames.Add(strName);
			}
		}
	}
	
	return nNumPeaks;
}
///end Sophy NEW_PA


/// Iris 10/20/2008 CLEAN_INIT_SESSION_CODES
void 	PeakFitHelper::initSessionSettingsFromGetN(const TreeNode& trGetN)
{	
	//------ Folger 10/24/08 v8.0960 BASELINE_STATUS_IN_NLFSESSION_SHOULD_BE_READY_RIGHT_AFTER_PREPARE_FUNCTION_ON_INIT
	//// -- set baseline settings
	//GetFitSession()->SetBaseLineMode(m_pPAWizCore->HasBaseline());
	//GetFitSession()->SetBaselineFitMode( IsBaselineFitWithPeaks() );
	//GetFitSession()->SetSubtractedMode( needSubtractBaseline() );
	//------ End BASELINE_STATUS_IN_NLFSESSION_SHOULD_BE_READY_RIGHT_AFTER_PREPARE_FUNCTION_ON_INIT
	
	/// Iris 10/27/2008 v8.0961 PREPARE_SUBTRACTED_DATA_RANGE_IN_NLFSESSION
	/*
	///Sophy 10/13/2008 GET_CUMULATIVE_DATA_WHITH_BASELINE_MODE
	//if( bHasBaseline )
	XYRange xyBaseline;
	if( !IsBaselineFitWithPeaks() && needSubtractBaseline() ) //if bHasBaseline = true, m_pFitSession()->GetBaselineFitMode() is false
	///end GET_CUMULATIVE_DATA_WHITH_BASELINE_MODE
	{
		if( m_pPAWizCore->GetBaselineRange(xyBaseline) )
			GetFitSession()->SetBaselineRange( xyBaseline );
	}
	else
	{
		GetFitSession()->SetBaselineRange( xyBaseline );
	}
	*/
	///end PREPARE_SUBTRACTED_DATA_RANGE_IN_NLFSESSION	
	
	/// Iris 10/30/2008 V8.0963b SET_BASELINE_FIXED_AS_SR4
	/*
	/// Iris 10/22/2008 NEW_PA_FIX_BUTTONS, set baseline param fix status	
	bool bFix = false;
	if( PA_BM_None == m_pPAWizCore->GetBaseMode() )
		bFix = true;
	else
		bFix = m_pPAWizCore->GetBaseParamFixMode();
	getParamsMngr()->FixBaseline(&bFix);
	///end NEW_PA_FIX_BUTTONS
	*/
	if ( IsBaselineFitWithPeaks() )		///------ Folger 03/11/09 SHOULD_ONLY_USE_SHARED_FIXBASE_NODE_WHEN_FITTING_WITH_BASELINE
	{
		///------ Folger 02/25/09 QA80-13181 SHARE_BASELINE_FIX_STATUS_BETWEEN_BASELINE_TREATMENT_AND_FITTING
		//bool bFix = m_pPAWizCore->GetBaseParamFixMode();
		bool bFix = getFixBaseNode().nVal;
		///------ End SHARE_BASELINE_FIX_STATUS_BETWEEN_BASELINE_TREATMENT_AND_FITTING
		int nRet = getParamsMngr()->FixBaseline(&bFix);	
		///end SET_BASELINE_FIXED_AS_SR4
	}
	///------ Folger 03/11/09 SHOULD_ONLY_USE_SHARED_FIXBASE_NODE_WHEN_FITTING_WITH_BASELINE
	else
	{
		int		nVal = 0;
		if ( !IsRuntimeThemeAvailable(trGetN.PFMParams) )
		{
			bool	bFixed = true;		/// no runtime theme, default should fix y0
			getParamsMngr()->FixBaseline(&bFixed);
		}
	}
	///------ End SHOULD_ONLY_USE_SHARED_FIXBASE_NODE_WHEN_FITTING_WITH_BASELINE
	
	SetTolerance(trGetN.FitControl.Tolerance.dVal);
	SetNumMaxIter(trGetN.FitControl.MaxNum.nVal);
	//SetLinearConstraints(trGetN.FitControl.Constraints, trGetN.FitControl.EnableConstraints.nVal);	
	GetFitSession()->SetEnableLinearConstraints(trGetN.FitControl.Constraints, trGetN.FitControl.EnableConstraints.nVal);
	SetIsGetParamsConf(trGetN.result.wbconfig.Quantities);
}
///end CLEAN_INIT_SESSION_CODES

// init pa_fit GetN on settings, for example, input data...
void 	PeakFitHelper::initGetN(TreeNode& trGetN)
{
	PeakFitHelperBase::initGetN(trGetN);	///Jasmine 07/02/09 PA_AND_NANOSIZER_NEED_UPDATE_DATA_TYPE
	
	if(trGetN.result)
	{
		TreeNode trGraph1 = tree_get_node_by_tagname(trGetN.result, "Graph1", true);
		if( trGraph1 )
		{
			CalculateFitCurvePoints( trGraph1 );///Sandy 2008-4-9 ADD_PG_TO_GET_AVG_WIDTH_FOR_ESTIMATE_FITTING_NPTS
			///Jasmine 07/02/09 PA_AND_NANOSIZER_NEED_UPDATE_DATA_TYPE
			//UpdateFitCurveOptions(trGraph1, true);			///Kyle 10/06/08 ,init data
			UpdateFitCurveOptions(trGraph1, false);
			///End PA_AND_NANOSIZER_NEED_UPDATE_DATA_TYPE
		}

		TreeNode trInputData = tree_get_node_by_tagname(trGetN.trAdv, "InputData", true);
		
		// Iris NEW_PA, NLFitSession not support UpdateGUIOnDataChanged now, in fact here want to update Graph1 fit curve settings, 
		// this already done in above CalculateFitCurvePoints and UpdateFitCurveOptions.
		//m_pFitSession->UpdateGUIOnDataChanged(trInputData, trGraph1); 
		///end NEW_PA
	}	
	
	/// Iris 11/06/2008 v8.0966b TALK_WITH_MAX_NO_NEED_REMOVE_SOURCE_OPTION_IF_NOT_ADD_BACK_BASELINE
	///// Iris 11/05/2008 v8.0965d NOT_ALLOW_REPORT_TO_SOURCE_GRAPH_IF_SUBTRACTED_BASELINE
	//UpdatePlotCurveTo(trGetN.result.gpconfig);
	/////end NOT_ALLOW_REPORT_TO_SOURCE_GRAPH_IF_SUBTRACTED_BASELINE
	///end TALK_WITH_MAX_NO_NEED_REMOVE_SOURCE_OPTION_IF_NOT_ADD_BACK_BASELINE
	/// Iris 11/11/2008 v8.0968 REMOVE_SOURCE_GRAPH_OPTION_FROM_COMBO_IF_NOT_SOURCE_GRAPH
	if( trGetN.result.gpconfig )
	{
		DataPlot dp;
		if( !m_pPAWizCore->GetSourceDataPlot(dp) ) // data got from worksheet, so not source graph
		{
			string strCombo = REPORT_GRAPH_DESTINATION_LIST;
			string strSource = strCombo.GetToken(PLOT_TO_SOURCE_GRAPH, '|');
			remove_str_from_str_list(strSource, strCombo);
			
			TreeNode trPlotCurveTo = trGetN.result.gpconfig.PlotCurveTo;
			ASSERT(trPlotCurveTo);
			trPlotCurveTo.SetAttribute(STR_COMBO_ATTRIB, strCombo);
			if( PLOT_TO_SOURCE_GRAPH == trPlotCurveTo.nVal)
				trPlotCurveTo.nVal = PLOT_TO_NEW_GRAPH;
				
		}
	}
	///end REMOVE_SOURCE_GRAPH_OPTION_FROM_COMBO_IF_NOT_SOURCE_GRAPH
}

/// Iris 11/06/2008 v8.0966b TALK_WITH_MAX_NO_NEED_REMOVE_SOURCE_OPTION_IF_NOT_ADD_BACK_BASELINE
/*
/// Iris 11/05/2008 v8.0965d NOT_ALLOW_REPORT_TO_SOURCE_GRAPH_IF_SUBTRACTED_BASELINE
void 	PeakFitHelper::UpdatePlotCurveTo(TreeNode& trgpconfig)
{
	bool bSubtracted =  m_pPAWizCore->HasBaseline() && m_pPAWizCore->GetSubtractedMode();
	bool bAddBackBaseline = trgpconfig.Graph1.AddBackBaseline.nVal;
	string strNewCombo = REPORT_GRAPH_DESTINATION_LIST;
	if( bSubtracted && !bAddBackBaseline )
	{
		string strSource = strNewCombo.GetToken(PLOT_TO_SOURCE_GRAPH, '|');
		remove_str_from_str_list(strSource, strNewCombo);
	}
	
	TreeNode trPlotCurveTo = trgpconfig.PlotCurveTo;
	ASSERT(trPlotCurveTo);
	if( trPlotCurveTo )
	{
		string strCombo;
		if( trPlotCurveTo.GetAttribute(STR_COMBO_ATTRIB, strCombo) && 0 != strCombo.Compare(strNewCombo) )
		{
			trPlotCurveTo.SetAttribute(STR_COMBO_ATTRIB, strNewCombo);
			if( trPlotCurveTo.nVal >= strNewCombo.GetNumTokens('|') )
				trPlotCurveTo.nVal = strNewCombo.GetNumTokens('|') - 1;
		}
	}	
}
///end NOT_ALLOW_REPORT_TO_SOURCE_GRAPH_IF_SUBTRACTED_BASELINE
*/
///end TALK_WITH_MAX_NO_NEED_REMOVE_SOURCE_OPTION_IF_NOT_ADD_BACK_BASELINE

bool	PeakFitHelper::SetFunction(string strFunction, int nFunc/* = 0*/, bool bResetFunction/* = true*/)
{
	string strCategory = IsBaselineFitWithPeaks() && 0 == nFunc? STR_PA_NLSF_CAT_BASELINE : STR_PA_NLSF_CAT_PEAK;
	return GetFitSession()->SetFunction(strFunction, strCategory, 1, bResetFunction, NULL, true, nFunc);
}

///Kyle 01/16/2009 XF_CHECK_CHECK_SET_LAST_OUTCOME_MESSAGE
int PeakFitHelper::GetLastIterateOutCome(string& strOutCome)
{
	int nRet = GetFitSession()->GetLastIterateOutCome();
	strOutCome = GetFitSession()->GetFitOutCome();
	return nRet;
}
///End XF_CHECK_CHECK_SET_LAST_OUTCOME_MESSAGE

bool	PeakFitHelper::Fit()
{
	bool	bRet;

///------ Folger 03/09/09 PREVIEW_SHOULD_BE_ALWAYS_UPDATED_AFTER_FITTING_REGARDLESS_OF_GOOD_FIT
//#ifdef _DEBUG
//
	//int		nOutCome = FITITER_FAILED;
	//bRet = GetFitSession()->Fit(&nOutCome);
	//
	//#define		MAX_PARAM_NUM_DEBUG		100
	//ASSERT(GetFitSession()->GetNumPeaks() <= MAX_PARAM_NUM_DEBUG / 4);
	//FitParameter	fp[MAX_PARAM_NUM_DEBUG];
	//for ( int ii=0; ii<MAX_PARAM_NUM_DEBUG; ++ii )
		//fp[ii].Value = NANUM;
		//
	//GetFitSession()->GetFitResultsParams(fp);
	//
	//for ( ii=0; ii<MAX_PARAM_NUM_DEBUG && !is_missing_value(fp[ii].Value); ++ii )
		//out_double("", fp[ii].Value);
	//
//#else	/// _DEBUG
//
	//bRet = GetFitSession()->Fit(NULL, false, true);
//
//#endif	/// _DEBUG
	int		nOutCome = FITITER_FAILED;
	bRet = GetFitSession()->Fit(&nOutCome, false, true);
///------ End PREVIEW_SHOULD_BE_ALWAYS_UPDATED_AFTER_FITTING_REGARDLESS_OF_GOOD_FIT

	return bRet;
}

//----- Iris 9/11/2008 PA_PREVIEW
/// Iris 10/31/2008 V8.0963d MOVE_2ND_DERVITIVE_PLOT_CODES_TO_PAWIZCORE
/*
void					PeakFitHelper::InitPreview(const TreeNode& trCurveOptions, GraphLayer& gl)
{
	getPreivewCtrl()->SetFitCurveOptions(trCurveOptions);
	GraphPage gp = gl.GetPage();
	getPreivewCtrl()->SetPreviewGraph(gp, PREVIEW_EXTERNAL_DATA_FIT, gl.GetIndex());
}
*/	
void					PeakFitHelper::InitPreview(const TreeNode& trGetN)
{
	getPreivewCtrl()->SetFitCurveOptions(trGetN.result.gpconfig.Graph1);
	
	GraphLayer gl;
	m_pPAWizCore->GetPreviewLayer( gl );
	
	if ( !gl )
		return;
	
	GraphPage gp = gl.GetPage();
	getPreivewCtrl()->SetPreviewGraph(gp, PREVIEW_EXTERNAL_DATA_FIT, gl.GetIndex());
	
	m_pPAWizCore->SetAdditionalLayersName(_PREVIEW_RESIDUAL_LAYER + "|" + _PREVIEW_2ND_DERVIA_LAYER);
	ASSERT(trGetN.residual);
	ASSERT(trGetN.derivative);
	string strLayersShow = (string)trGetN.residual.nVal + "|" + (string)trGetN.derivative.nVal;
	m_pPAWizCore->SetAdditionalLayersShow(strLayersShow); 	
}
///end MOVE_2ND_DERVITIVE_PLOT_CODES_TO_PAWIZCORE


bool					PeakFitHelper::UpdatePreview(DWORD dwUpdateBits, bool *pbShowResidual, bool  *pbShow2ndDervi)
{
	/// Iris 10/31/2008 V8.0963d MOVE_2ND_DERVITIVE_PLOT_CODES_TO_PAWIZCORE
	/*
	if(pbShowResidual && pbShow2ndDervi)
	{
		bool bShowResidual = * pbShowResidual;
		bool bShow2ndDervi = * pbShow2ndDervi;
		GraphLayer gl;
		if( !m_pPAWizCore->GetPreviewLayer(gl) )
			return false;

		GraphPage gp = gl.GetPage();
		GraphLayer glResidual, gl2ndDervi;
		vector<int> vnLayer;
	
		bool bNeedArrange = false;
		stLayersGridFormat stOldFormat;

		prepareGraphLayerForPreview( gp, bShowResidual, glResidual, bShow2ndDervi, gl2ndDervi, bNeedArrange, stOldFormat);

		m_pPreviewCtrl->SetShowSpecialPreview( bShowResidual, bShow2ndDervi );	// need to change the pointer to PeakFitPreviewCtrl

		vnLayer.Add( gl.GetIndex() );
		if( bShowResidual )
		{
			int nResidualLayer = glResidual.GetIndex();
			m_pPreviewCtrl->SetPreviewGraph(gp, PREVIEW_RESIDUAL, nResidualLayer);
			vnLayer.Add( nResidualLayer );
		}
		if( bShow2ndDervi )
		{
			int nDerivativeLayer = gl2ndDervi.GetIndex();
			m_pPreviewCtrl->SetPreviewGraph(gp, PREIVEW_2ND_DE, nDerivativeLayer);
			vnLayer.Add( nDerivativeLayer );
		}
		if( bNeedArrange)
			rearrangePreviewLayer(gp, vnLayer, stOldFormat );

		page_set_active_layer(gp, gl.GetIndex());
	}
	*/
	/// Iris 11/17/2008 QA80-12584-P8 FIX_PROBLEMS_WHEN_RECALCULATE_NOT_PREVIEW_GRAPH
	GraphLayer glPreview;
	if( !m_pPAWizCore->GetPreviewLayer(glPreview) )
		return true;
	///end FIX_PROBLEMS_WHEN_RECALCULATE_NOT_PREVIEW_GRAPH
	
	bool bShowResidual = m_pPAWizCore->GetAdditionalLayersShow(_PREVIEW_RESIDUAL_LAYER);
	bool bShow2ndDervi = m_pPAWizCore->GetAdditionalLayersShow(_PREVIEW_2ND_DERVIA_LAYER);		
	if(pbShowResidual || pbShow2ndDervi)
	{
		if(pbShowResidual)
			bShowResidual = *pbShowResidual;
		
		if(pbShow2ndDervi)
			bShow2ndDervi = *pbShow2ndDervi;
		
		GraphLayer glResidual, gl2ndDervi;
		prepareGraphLayerForPreview( bShowResidual, glResidual, bShow2ndDervi, gl2ndDervi );
		
		m_pPreviewCtrl->SetShowSpecialPreview( bShowResidual );
		if( bShowResidual && glResidual )		
			m_pPreviewCtrl->SetPreviewGraph((GraphPage)glResidual.GetPage(), PREVIEW_RESIDUAL, glResidual.GetIndex());		
	}
	
	if( bShow2ndDervi )
	{
		if( !m_pPAWizCore->Update2ndDervitivePreivew() )
			return error_report("Fail to update derivative preview");
	}
	///end MOVE_2ND_DERVITIVE_PLOT_CODES_TO_PAWIZCORE
	
	///------ Folger 02/04/09 QA80-12962 ADD_OPTION_IN_PA_FIT_TO_SWTICH_BACK_TO_OLD_FIT_CURVE_DATA_GENERATION_MECHANISM
	//return getPreivewCtrl()->UpdatePreviewGraph(dwUpdateBits);
	if ( m_bPlotCurveOptionChanged )
	{
		if ( !(FITPREVIEW_REMOVE_FITS & dwUpdateBits) )
			dwUpdateBits = FITPREVIEW_REINIT;
		m_bPlotCurveOptionChanged = false;
	}
	
	return getPreivewCtrl()->UpdatePreviewGraph(dwUpdateBits, &m_prevCtrlInfo);
	///------ End ADD_OPTION_IN_PA_FIT_TO_SWTICH_BACK_TO_OLD_FIT_CURVE_DATA_GENERATION_MECHANISM
}

	
/// Iris 10/31/2008 V8.0963d MOVE_2ND_DERVITIVE_PLOT_CODES_TO_PAWIZCORE
//bool 	PeakFitHelper::prepareGraphLayerForPreview( GraphPage & gp, bool bShowResidual, GraphLayer & glResidual, bool  bShow2ndDervi, GraphLayer & gl2ndDervi, bool & bNeedArrange,stLayersGridFormat& stOldFormat )
bool 	PeakFitHelper::prepareGraphLayerForPreview( bool bShowResidual, GraphLayer &glResidual, bool  bShow2ndDervi, GraphLayer &gl2ndDervi )
///end MOVE_2ND_DERVITIVE_PLOT_CODES_TO_PAWIZCORE
{	
	/// Iris 10/31/2008 V8.0963d MOVE_2ND_DERVITIVE_PLOT_CODES_TO_PAWIZCORE
	/*	
	GraphLayer glFitCurve;
	if( !m_pPAWizCore->GetPreviewLayer(glFitCurve) )
		return false;
	
	vnLayerIndex.Add( glFitCurve.GetIndex() );
	
	if( glResidual )
		vnLayerIndex.Add( glResidual.GetIndex() );
	if( gl2ndDervi )
		vnLayerIndex.Add( gl2ndDervi.GetIndex() );
	double dTopLayer, dBottomLayer;
	vnLayerIndex.GetMinMax(dTopLayer, dBottomLayer);

	GraphLayer 	glTop 	= gp.Layers(dTopLayer);
	GraphLayer 	glBottom= gp.Layers(dBottomLayer);
	
	double xx[TOTAL_POS];
	
	glTop.GetPosition(xx);
	glTop.UnitsConvert(M_PERCENT, xx);
	int nLeftMargin 	= xx[LEFT_POS];
	int nRightMargin 	= 100 - xx[LEFT_POS] - xx[WIDTH_POS];
	int	nTopMargin		= xx[TOP_POS];
	
	glBottom.GetPosition(xx);
	glBottom.UnitsConvert(M_PERCENT, xx);
	int	nBottomMargin	= 100 - xx[TOP_POS] - xx[HEIGHT_POS];
	
	stOldFormat.nXGap 		= 5;		
	stOldFormat.nYGap 		= 5;			
	stOldFormat.nLeftMg 	= nLeftMargin;//15
	stOldFormat.nRightMg 	= nRightMargin;//15
	stOldFormat.nTopMg 	= nTopMargin;//15
	stOldFormat.nBottomMg 	= nBottomMargin;//15
	
	if(!bShowResidual && glResidual.IsValid())
	{
		glResidual.Destroy();
		bNeedArrange = true;
	}
	
	if(!bShow2ndDervi && gl2ndDervi.IsValid())
	{
		gl2ndDervi.Destroy();
		bNeedArrange = true;
	}
	
	
	if(bShowResidual && !glResidual.IsValid())
	{
		gp.AddLayer(_PREVIEW_RESIDUAL_LAYER);
		glResidual = gp.Layers(_PREVIEW_RESIDUAL_LAYER);
		bNeedArrange = true;
	}
	
	if(bShow2ndDervi && !gl2ndDervi.IsValid())
	{
		gp.AddLayer(_PREVIEW_2ND_DERVIA_LAYER);
		gl2ndDervi = gp.Layers(_PREVIEW_2ND_DERVIA_LAYER);
		bNeedArrange = true;
	}
	*/
	string strLayersShow;
	strLayersShow = bShowResidual? "1" : "0";  
	strLayersShow += "|";	
	strLayersShow += bShow2ndDervi? "1" : "0";	
	m_pPAWizCore->SetAdditionalLayersShow(strLayersShow);	
	
	m_pPAWizCore->GetAdditionalLayer(glResidual, _PREVIEW_RESIDUAL_LAYER);
	m_pPAWizCore->GetAdditionalLayer(gl2ndDervi, _PREVIEW_2ND_DERVIA_LAYER);	
	///end MOVE_2ND_DERVITIVE_PLOT_CODES_TO_PAWIZCORE

	return true;
}
//-----

/////Jasmine 04/17/08 UPDATE_PREVIEW_DATA_AND_PREVIEW_GRAPH_AFTER_CHANGE_WEIGHT
//bool PeakFitHelper::RePlotPreviewGraph()
//{
	//if(NULL == m_pFitSession)
		//return false;
	//
	//m_pFitSession->UpdateFitSessionPreviewData(false);
	//bool bUpdateLegend = false;
	//return m_pFitSession->UpdatePreviewGraph(FITPREVIEW_REPLOT_FITS, &bUpdateLegend);	///Jasmine 03/20/08 REMOVE_LEGEND_IN_PA_GRAPH
//}
/////End UPDATE_PREVIEW_DATA_AND_PREVIEW_GRAPH_AFTER_CHANGE_WEIGHT

bool PeakFitHelper::ConstructPFMParamsTree(TreeNode& trPFMParams)
{							
	vector 			vCenters, vHeights;
	int				nPeaks = GetPeaksInfo(&vCenters, &vHeights);	
							
	///Jasmine 04/02/08 LOAD_FUNCTION_SETTING_FROM_THEME
	TreeNode trFunctions 	= trPFMParams.Functions;
	TreeNode trBLParams 	= trPFMParams.BaselineParameters;
	
	vector<string> 	vsFunctions;
	if( trFunctions && !trFunctions.IsEmpty() )
		vsFunctions = trFunctions.strVals;
	
	/// Iris 02/24/2009 QA80-13170 NOT_CORRECT_APPLY_BASELINE_PARAM_WHEN_CHANGE_PARAM
	// fix runtime error when vsFunctions is empty but trBLParams is not empty if run PA with theme.
	//if( trBLParams && 0 < trBLParams.nVal )
	if( trBLParams && 0 < trBLParams.nVal && vsFunctions.GetSize() > 0 )
	///end NOT_CORRECT_APPLY_BASELINE_PARAM_WHEN_CHANGE_PARAM
	{
		//there's baseline function in theme functions
		vsFunctions.RemoveAt(0);
	}
	
	if( nPeaks > vsFunctions.GetSize() )
	{
		int nStartIndex = vsFunctions.GetSize();
		vsFunctions.SetSize(nPeaks);
		for(int ii = nStartIndex; ii < nPeaks; ii++)
			vsFunctions[ii] = STR_PA_DEFAULT_FUNC;
	}
	///End LOAD_FUNCTION_SETTING_FROM_THEME	
	return true;
}


///Sandy 2008-4-9 ADD_PG_TO_GET_AVG_WIDTH_FOR_ESTIMATE_FITTING_NPTS 
///when calculate, need to know the average width of peaks, to estimate the really points of fitting curves
//void PeakFitHelper::CalculateFitCurvePoints(TreeNode& trGraph1)
/// Iris 9/17/2008 NEW_PA
//void PeakFitHelper::CalculateFitCurvePoints(TreeNode& trGraph1, Page& pg)
void PeakFitHelper::CalculateFitCurvePoints(TreeNode& trGraph1)
///end NEW_PA
{
	TreeNode trXDataType, trN;
	if(trGraph1)
		trXDataType = trGraph1.XDataType;
	///------ Folger 11/27/09 AUTO_CALCULATE_FIT_CURVE_POINTS_FAILS_IF_NOT_LINEAR_X_DATA_TYPE
	//if(trXDataType && FIT_CURVE_UNIFORM_LINEAR == trXDataType.Use)
	if(trXDataType && FIT_CURVE_SAME_AS_DATA != trXDataType.Use)
	///------ End AUTO_CALCULATE_FIT_CURVE_POINTS_FAILS_IF_NOT_LINEAR_X_DATA_TYPE
	{
		trN = trXDataType.N;
	}
	
	if(trN && 1 == octree_get_auto_support(&trN) && NULL != m_pFitSession)
	{
		int nPeaks = GetFitSession()->GetNumPeaks() - getPeaksOffset();
		
		///Sandy 2008-4-9 ADD_PG_TO_GET_AVG_WIDTH_FOR_ESTIMATE_FITTING_NPTS
		//trN.nVal = nPeaks * FITCURVE_POINTS_PER_PEAK;	
		double dAverageWidth;		
		int npts = nPeaks * FITCURVE_POINTS_PER_PEAK;
		/// Iris 9/17/2008 NEW_PA
		/*
		if(pg.IsValid() && set_get_dValue_to_page(pg, STR_PA_PEAKS_AVG_WIDTH_TAG_NAME, dAverageWidth, false) && dAverageWidth>0)//get average width from page
		{
			vector vx, vy;
			if( get_data_context(pg, vx, vy, PFW_ORIGIN_PLOT_TAGNAME))
			{
				double dMin, dMax;
				vx.GetMinMax(dMin, dMax);
				double dFullWidth = dMax - dMin;
				npts = dFullWidth/dAverageWidth*FITCURVE_POINTS_PER_PEAK;
			}
		}
		*/
		///Kyle 11/24/2008 SUBTRACT_BASELINE_BEFORE_CALCULATING_FIT_CURVE_POINTS
		//vector vX, vY, vHeights;
		vector vX, vY, vHeights, vCenters;
		///End SUBTRACT_BASELINE_BEFORE_CALCULATING_FIT_CURVE_POINTS
		XYRange drSourceData;
		if( m_pPAWizCore->GetOriginalRange(drSourceData) )
			drSourceData.GetData(vY, vX);
		
		///Kyle 11/24/2008 SUBTRACT_BASELINE_BEFORE_CALCULATING_FIT_CURVE_POINTS
		//int nNumPeaks = GetPeaksInfo(NULL, &vHeights);	
		int nNumPeaks = GetPeaksInfo(&vCenters, &vHeights);	
		if(needSubtractBaseline())
		{
			calcPeakHeights(vHeights, vCenters);
		///------ Folger 02/20/09 NEED_SUBTRACT_BASELINE_IF_HAS_ONE_FOR_CALCULATE_FIT_CURVE_POINTS
		}		
		/// Since (vX, vY) are original data that is not subtracted.
		/// so always do subtraction here if has baseline, according to Sandy.
		if ( m_pPAWizCore->HasBaseline() )
		{
		///------ End NEED_SUBTRACT_BASELINE_IF_HAS_ONE_FOR_CALCULATE_FIT_CURVE_POINTS
			XYRange xyBaseline;
			m_pPAWizCore->GetBaselineRange(xyBaseline);
			vector vYBL, vXBL;
			if ( !xyBaseline.GetData(vYBL, vXBL) )
				ASSERT(false);
			subtract_baseline(vX, vY, vXBL, vYBL);
		}
		///End SUBTRACT_BASELINE_BEFORE_CALCULATING_FIT_CURVE_POINTS
		ASSERT(nPeaks == nNumPeaks);
		
		dAverageWidth = calcAverageWidth(vX, vY, vHeights);
		if( dAverageWidth > 0 )
		{
			double dMin, dMax;
			vX.GetMinMax(dMin, dMax);
			double dFullWidth = dMax - dMin;
			npts = dFullWidth/dAverageWidth*FITCURVE_POINTS_PER_PEAK;
			///------ Folger 01/19/09 QA80-12962 REDUCE_CUMULATIVE_FIT_CRUVE_DATA_POINTS_IN_PA
			///------ Folger 02/04/09 QA80-12962 ADD_OPTION_IN_PA_FIT_TO_SWTICH_BACK_TO_OLD_FIT_CURVE_DATA_GENERATION_MECHANISM
			if ( GetFitSession()->GetUseSmartX() )
			{
			///------ End ADD_OPTION_IN_PA_FIT_TO_SWTICH_BACK_TO_OLD_FIT_CURVE_DATA_GENERATION_MECHANISM
				int		nPts2 = GetFitSession()->GetXPtsForEachPeak() * (GetFitSession()->GetNumPeaks() - (GetFitSession()->GetBaselineFitMode() ? 1 : 0));
				if ( nPts2 < npts )
					npts = nPts2;
			}
			///------ End REDUCE_CUMULATIVE_FIT_CRUVE_DATA_POINTS_IN_PA
			///------ Folger 04/16/09 QA80-13458-P2 FIT_CURVE_POINTS_FOR_ALL_PEAKS_SHOULD_NOT_BE_LESS_THAN_100
			if ( npts < FITCURVE_POINTS_FOR_INDIVIDUAL_PEAKS )
				npts = FITCURVE_POINTS_FOR_INDIVIDUAL_PEAKS;
			///------ End FIT_CURVE_POINTS_FOR_ALL_PEAKS_SHOULD_NOT_BE_LESS_THAN_100
		}			
		///end NEW_PA
		trN.nVal = npts;
		//end ADD_PG_TO_GET_AVG_WIDTH_FOR_ESTIMATE_FITTING_NPTS
	}
}
///End FITCURVE_POINTS_PER_PEAR

//string	PeakFitHelper::getOffSetParamName()
//{
	//return m_strCategory.Compare(STR_CATE_NAME_SPFM) == 0 ? STR_OFFSET_PARAM_NAME_SPFM : STR_OFFSET_PARAM_NAME_PFM;
//}
//
/////Jasmine 03/11/08 SHOW_FITCONTROL_BRANCH_IN_XF_NOT_IN_PARAMDLG_BY_CP_REQUEST
///*
////virtual
//void PeakFitHelper::UpdateAdvancedSetting(Page& pg, TreeNode& trGetN)
//{
	//if(pg)
	//{
		//TreeNode trAdvanced = get_fit_peak_binary_storage_tree(pg, STR_ADVANCED_NODE);
		//_copy_value_by_id(trAdvanced, trGetN.trAdv, STR_DATAID_ATTRIB, STR_BACKUP_ID_ATTRIB, "FitControl");
	//}
//}
//*/
/////End SHOW_FITCONTROL_BRANCH_IN_XF_NOT_IN_PARAMDLG_BY_CP_REQUEST
//
/////Jasmine 02/26/08 USE_VECTOR_TREENODE_SAVE_THEME_SETTING	
///*
//void PeakFitHelper::UpdateSettingBeforeExecute(Page& pg, TreeNode& trGetN)
//{
	//if(!pg || !trGetN)
		//return;
	//
	//Tree	trPFM;
	//GetPFWTree(pg, trPFM);
	//
	//if( NULL != m_pFitSession )
	//{
		//TreeNode trParams = trGetN.PFMParams;
		//m_pFitSession->ParamsToOperationGUI(trParams);
		//string strFunctions;
		//foreach(TreeNode trPeak in trPFM.Peaks.Children)
		//{
			//strFunctions += trPeak.Function.FuncName.strVal + "|";
		//}
		//strFunctions.TrimRight("|");
		//trParams.Functions.strVal = strFunctions;
	//}	
	//
	//TreeNode trAdv = trGetN.tradv;
	//TreeNode trAdvFromPage = get_fit_peak_binary_storage_tree(pg, STR_ADVANCED_NODE);
	//_copy_value_by_id(trAdvFromPage, trAdv, STR_DATAID_ATTRIB, STR_BACKUP_ID_ATTRIB, "FitControl");
//}
//*/

//event for after click Add, Modify/Del button in pa_fit xf
int		PeakFitHelper::OnAfterModifyPeaksCenter(const TreeNode& trPeakCenters, int nModifiedPeakIndex)
{
	if(!trPeakCenters)
		return -1;
	
	int 	nPeaks = GetPeaksInfo();
	int 	nPeaksAfterChange = trPeakCenters.xc.dVals.GetSize();
	int 	nPeakUpdateType = PEAK_UPDATE_INVALID_TYPE;
	if( nPeaks < nPeaksAfterChange )
	{
		nPeakUpdateType = PEAK_ADD;
	}
	else if( nPeaks > nPeaksAfterChange )
	{
		nPeakUpdateType = PEAK_DELETE;
	}
	else
		nPeakUpdateType = PEAK_MODIFY;		
	
	vector<int>			vnChangedPeakIndecies;
	vector<string> 		vsFunctions;
	if ( PEAK_ADD == nPeakUpdateType )
	{
		vnChangedPeakIndecies.Data(nPeaks, nPeaksAfterChange - 1);
	
		GetPeaksInfo(NULL, NULL, &vsFunctions);
		string 	strPeakFunction = GetDefaultFunction(); //default function
		while( nPeaks < nPeaksAfterChange )
		{
			SetFunction(strPeakFunction, nPeaks + getPeaksOffset());
			vsFunctions.Add(strPeakFunction);
			nPeaks++;	
		}
	}
	else
	{
		vnChangedPeakIndecies.Add(nModifiedPeakIndex);
	}
	
	//vector<int>		vnChangedPeakIndecies;
	//if( PEAK_ADD == nPeakUpdateType ) // for add peak case, returned nModifiedPeakIndex is -1
	//{
		//nModifiedPeakIndex = nPeaks - 1;
	//}
	
	/// should consider baseline peak
	//int		nModifiedPeakIndexWithBaseline = IsBaselineFitWithPeaks() ? nModifiedPeakIndex + 1 : nModifiedPeakIndex;
	//vnChangedPeakIndecies.Add(nModifiedPeakIndexWithBaseline);
	
	// set back peak info to PAWizCore
	vector 			vCenters, vHeights;
	vCenters = trPeakCenters.xc.dVals;
	vHeights = trPeakCenters.h.dVals;
	SetPeaksInfo(&vCenters, &vHeights, &vsFunctions); 
	
	//set function for newly added peak
	//if( PEAK_ADD == nPeakUpdateType )
		//SetFunction(strPeakFunction, nModifiedPeakIndexWithBaseline);
	
	// reinit parameters after add peak or modify peak
	
	PEAKINFOARGUMENTSLISTPARAMS		stPEAKINFOARGUMENTSLISTPARAMS;
	
	if ( PEAK_DELETE != nPeakUpdateType )
	{
		vector vPeakCenters, vPeakHeights;
		for ( int ii=0; ii<vnChangedPeakIndecies.GetSize(); ++ii )
		{
			vPeakCenters.Add(vCenters[vnChangedPeakIndecies[ii]]);
			vPeakHeights.Add(vHeights[vnChangedPeakIndecies[ii]]);
		}
		
		if ( needSubtractBaseline() )
			calcPeakHeights(vPeakHeights, vPeakCenters);
		
		stPEAKINFOARGUMENTSLISTPARAMS.vCenters = vPeakCenters;
		stPEAKINFOARGUMENTSLISTPARAMS.vHeights = vPeakHeights;		
	}
	
	ReinitParamsOnPeakChange(vnChangedPeakIndecies, stPEAKINFOARGUMENTSLISTPARAMS, GetDefaultFunction(), !GetFitSession()->GetAutoInitParams(), PEAK_DELETE == nPeakUpdateType);
	
	DWORD dwUpdateBits = PEAK_MODIFY == nPeakUpdateType? FITPREVIEW_REPLOT : FITPREVIEW_REINIT;	
	UpdatePreview( dwUpdateBits);
	
	return nPeakUpdateType;
}
	
int	PeakFitHelper::GetPeaksInfo(vector* pvCenters, vector* pvHeights, vector<string> *pvstrFunctions)
{
	Tree otr;
	if( !m_pPAWizCore->UpdateInfoTree(otr, PA_TREE_PEAKS_CENTER_INFO, false) )
		return 0;
	
	ASSERT(otr.xc);	
	if( pvCenters )
		*pvCenters = otr.xc.dVals;
	
	if( pvHeights )
	{
		ASSERT(otr.h);
		*pvHeights = otr.h.dVals;
	}
	
	if( pvstrFunctions )
	{
		if( otr.strFunc )
			*pvstrFunctions = otr.strFunc.strVals;
		else
		{
			GetFitSession()->GetAllFunctions(*pvstrFunctions);
		}			
	}
	
	return otr.xc.dVals.GetSize();	// return the number of peaks
}

bool	PeakFitHelper::SetPeaksInfo(vector* pvCenters, vector* pvHeights, vector<string> *pvstrFunctions)
{
	Tree otr;
	if( !m_pPAWizCore->UpdateInfoTree(otr, PA_TREE_PEAKS_CENTER_INFO, false) )
		return error_report("Fail to get peakinfo tree from PAWizCore");
	
	ASSERT(otr.xc);
	if( pvCenters )
		otr.xc.dVals = *pvCenters;
	
	if( pvHeights )
	{
		ASSERT(otr.h);
		otr.h.dVals = *pvHeights;
	}	
	
	if( pvstrFunctions && otr.strFunc)
	{
		otr.strFunc.strVals = *pvstrFunctions;
	}
	
	if( !m_pPAWizCore->UpdateInfoTree(otr, PA_TREE_PEAKS_CENTER_INFO, true) )
		return error_report("Fail to set peakinfo tree to PAWizCore");
	
	return true;	
}

bool	PeakFitHelper::SetBaselineInfo(vector* pvParams, vector<string>* pvsParamNames, LPCSTR lpcszFunction)
{
	Tree otr;
	if( !m_pPAWizCore->UpdateInfoTree(otr, PA_TREE_BASELINE_FIT_INFO, false) )
		return error_report("Fail to get baseline into tree from PAWizCore");
	
	if(pvParams && pvParams->GetSize() > 0)
	{
		otr.Reset(true);
		for(int nn = 0; nn < pvParams->GetSize(); nn++)
		{
			string str = "P" + (nn+1);
			otr.AddNumericNode(pvParams[0][nn], str);
		}
	}
	
	if(pvsParamNames && pvsParamNames->GetSize() > 0)
	{
		ASSERT(otr.GetNodeCount() == pvsParamNames->GetSize());
		int nn = 0;
		foreach(TreeNode trN in otr.Children)
		{
			if( nn < pvsParamNames->GetSize())
				trN.SetAttribute(STR_LABEL_ATTRIB, pvsParamNames[0][nn++]);
		}
	}
	
	if(lpcszFunction && lstrlen(lpcszFunction) > 0)
	{
		otr.SetAttribute(STR_LABEL_ATTRIB, lpcszFunction);
	}
	
	if( !m_pPAWizCore->UpdateInfoTree(otr, PA_TREE_BASELINE_FIT_INFO, true) )
		return error_report("Fail to set baseline into tree to PAWizCore");
	
	return true;
	
}
	
//need call this after peak center changed
void 	PeakFitHelper::UpdatePeakCenterLabel()
{	
	GraphLayer gl;
	if( !m_pPAWizCore->GetPreviewLayer(gl) )
		return;
	
	vector vpx, vpy;
	int nPeaks = GetFitSession()->GetPeakCenterOrWidth(vpx, true, false);
	if(1 > nPeaks)
		return;
		
	vector vpxOld, vpyOld;
	GetPeaksInfo(&vpxOld);
	
	bool bIsSame = false;
	if(nPeaks == vpxOld.GetSize() && OE_NOERROR == ocmath_compare_data(nPeaks, vpx, vpxOld, &bIsSame) && bIsSame)	
		return;
	
	vector vxi, vyi;
	//if(!get_data_context(pg, vxi, vyi, PFW_PARENT_PLOT_TAGNAME))
		//get_data_context(pg, vxi, vyi, PFW_ORIGIN_PLOT_TAGNAME);
	XYRange xySource;
	if( !m_pPAWizCore->GetSubtractedRange(xySource) )
		m_pPAWizCore->GetPeaksRange(xySource);
	xySource.GetData(vyi, vxi);
	
	snap_points_to_source_data(vxi, vyi, vpx, vpy);
	
	//pa8_save_peak_vector(trPFW, vpx, vpy);		
	//save_pfw_tree_in_page(pg, trPFW);
	
	XYRange yp;
	//pa8_check_get_peak_temp_range(yp);
	m_pPAWizCore->GetPeaksCenterRange(yp);
	if( yp.IsValid())
	 	yp.SetData(&vpy, &vpx);
	
	int sl, lc, lr, sc;
	GraphPage pg = gl.GetPage();
	//set_get_peak_labels_format_to_page(pg,  sl, lc, lr, sc, false);
	//pa8_update_label_plot(gl, sl, lc, lr, sc);
}

//virtual
int 	PeakFitHelper::getBaselineParams(vector* pvParamVals, vector<string>* pstrParamNames)
{
	vector vParamVals;
	vector<string> vstrParamNames;
	
	TreeNode trBL;
	if( m_pPAWizCore->UpdateInfoTree(trBL, PA_TREE_BASELINE_FIT_INFO, false) )
	{	
		foreach(TreeNode trN in trBL.Children)
		{
			vParamVals.Add(trN.dVal);
			
			string str;
			trN.GetAttribute(STR_LABEL_ATTRIB, str);
			vstrParamNames.Add(str);
		}
		
		if(pvParamVals)
			*pvParamVals = vParamVals;
		if(pstrParamNames)
			*pstrParamNames = vstrParamNames;
		
		ASSERT(vParamVals.GetSize() == vstrParamNames.GetSize());
		return vParamVals.GetSize();		
	}
	return 0; // no baseline fit function
}

int		PeakFitHelper::getNumBaselineParams()
{
	///Kyle 10/21/08 CHANGE_FUNCTION_NAME_HASBASELINEPEAK_TO_GETBASELINEFITMODE
	//if( m_pFitSession->HasBaselinePeak() )
	if( m_pFitSession->GetBaselineFitMode() )
	///End CHANGE_FUNCTION_NAME_HASBASELINEPEAK_TO_GETBASELINEFITMODE
		return m_pFitSession->GetNumParameter(0);
		
	/// Iris 2/17/2009 FIX_LOAD_THEME_INCLIDE_SHARE_PARAMS_BUG
	// if set Baseline Mode as User Defined, and share w1 and w2 as 1 and save as theme. Open PA and load this theme, set Baseline Mode as Constant, 
	// ==> Shared values for w__1 and w__2 are gone, xc__2 is shared as 1.
	//return 0;	
	return 1; // if not fit mode, at least have y0 as baseline parameter
	///end FIX_LOAD_THEME_INCLIDE_SHARE_PARAMS_BUG
}

///Sophy 10/14/2008 IMPROVE_CODE_CALCU_PEAK_HEIGHT_RELATIVE when add peaks with baseline...
bool	PeakFitHelper::calcPeakHeights(vector& vHeights, const vector& vCenters)
{
	int nNumPeaks = vCenters.GetSize();
	
	ASSERT( vHeights.GetSize() == nNumPeaks );
	
	vector		vXBaseline, vYBaseline;
	XYRange xyBaseline;
	m_pPAWizCore->GetBaselineRange(xyBaseline);
	if ( !xyBaseline.GetData(vYBaseline, vXBaseline) )
		return false;
	
	if( vHeights.GetSize() != nNumPeaks )
		return false;
	
	for(int ii = 0; ii < nNumPeaks; ii++)
	{
		double dY;
		double dX = vCenters[ii];
		if ( 0 == ocmath_interpolate(&dX, &dY, 1, vXBaseline, vYBaseline, vXBaseline.GetSize()) )
		{
			vHeights[ii] -= dY;
		}
	}
	return true;
}
///end IMPROVE_CODE_CALCU_PEAK_HEIGHT_RELATIVE

void		PeakFitHelper::resetNLParamsMngr()
{
	NLParametersManager		*pNLParamsMngr = GetFitSession()->GetNLParamsMngr();
	//------ Folger 10/29/08 v8.0962 MOVE_REMOVE_FUNCTIONS_IN_NLPARAMSMNGR_TO_VC
	//for ( int nFunc=pNLParamsMngr->GetNumFitFunctions()-1; nFunc>=0; --nFunc )
		//pNLParamsMngr->RemoveFunction(nFunc);
	pNLParamsMngr->RemovePeak(-1);
	//------ End MOVE_REMOVE_FUNCTIONS_IN_NLPARAMSMNGR_TO_VC
}

bool		PeakFitHelper::needSubtractBaseline()
{
	return m_pPAWizCore->HasBaseline() && !m_pPAWizCore->GetSubtractedMode();
}

bool		PeakFitHelper::getInputDataRange(XYRange& xyInput)
{
	/// Iris 10/27/2008 v8.0960 FIX_OUTPUT_DESTINATION_GUI_SHOW_TEMP_WORK_NAME_AS_OUTPUT
	//if ( IsBaselineFitWithPeaks() )
	//	return m_pPAWizCore->GetOriginalRange(xyInput);
	
	//return m_pPAWizCore->GetPeaksRange(xyInput);
	bool bRet = false;
	
	/// Iris 11/14/2008 v8.0971b QA80-12584 FITPEAK_OP_OUTPUT_SUBTRACTED_REPLACE_BASELINE_XF_OUTPUT_SUBTRACTED
	/*
	if( m_pPAWizCore->HasBaseline() )
	{
		if( m_pPAWizCore->GetSubtractedMode() ) // subtracked baseline
		{
			bRet = m_pPAWizCore->GetSubtractedRange(xyInput);
		}
		else
		{
			if (  m_pPAWizCore->GetBaselineFitMode() )
			{
				bRet = m_pPAWizCore->GetOriginalRange(xyInput); 
			}
			else
			{
				/// Iris 10/27/2008 v8.0961 PREPARE_SUBTRACTED_DATA_RANGE_IN_NLFSESSION
				// for this case, will save original data range to trInputData node below, but set peaks(subtracted) data range to NLFitSession
				// NLFitSession will set peaks(subtracted) data range as input data range since must fit on subtracted data.
				bRet = m_pPAWizCore->GetOriginalRange(xyInput);					
				
				XYRange xyPeaks;
				if( m_pPAWizCore->GetPeaksRange(xyPeaks) )
				{
					GetFitSession()->SetPeaksRange(xyPeaks);
					setBackPlotUIDToDataRange(xyPeaks);
				}
				return bRet;
				///end PREPARE_SUBTRACTED_DATA_RANGE_IN_NLFSESSION				
			}
		}
	}
	else
	{
		bRet = m_pPAWizCore->GetOriginalRange(xyInput);	
	}
	*/
	bRet = m_pPAWizCore->GetOriginalRange(xyInput);
	
	if(bRet)
		setBackPlotUIDToDataRange(xyInput);	
		
	/// Iris 11/14/2008 v8.0971b QA80-12584 FITPEAK_OP_OUTPUT_SUBTRACTED_REPLACE_BASELINE_XF_OUTPUT_SUBTRACTED	
	if( m_pPAWizCore->HasBaseline() )	
	{		
		XYRange 	xyPeaks;
		bool 		bGetRange;
		if( m_pPAWizCore->GetSubtractedMode() )
		{
			bGetRange = m_pPAWizCore->GetSubtractedRange(xyPeaks);
		}
		else if( !m_pPAWizCore->GetBaselineFitMode() )			
		{
			bGetRange = m_pPAWizCore->GetPeaksRange(xyPeaks);
		}
		
		if( bGetRange && xyPeaks )
		{
			setBackPlotUIDToDataRange(xyPeaks);	
			GetFitSession()->SetSubtractedDataRange(xyPeaks);
		}
		
	}	
	///end FITPEAK_OP_OUTPUT_SUBTRACTED_REPLACE_BASELINE_XF_OUTPUT_SUBTRACTED
	
	return bRet;
	///end FIX_OUTPUT_DESTINATION_GUI_SHOW_TEMP_WORK_NAME_AS_OUTPUT
}

//------ Folger 10/24/08 v8.0960 BASELINE_STATUS_IN_NLFSESSION_SHOULD_BE_READY_RIGHT_AFTER_PREPARE_FUNCTION_ON_INIT
void		PeakFitHelper::prepareFitSessionBaselineStatus(bool bBaselineFitWithPeaks)
{
	// -- set baseline settings
	/// Iris 11/12/2008 v8.0969 QA80-12584 OUTPUT_BASELINE_AND_SUBTRACTED_DATA_IN_FIT_PEAK_OP, just renmae SetBaseLineMode to SetHasBaseLineMode, old name not good
	//GetFitSession()->SetBaseLineMode(m_pPAWizCore->HasBaseline());
	GetFitSession()->SetHasBaseLine(m_pPAWizCore->HasBaseline());
	///end OUTPUT_BASELINE_AND_SUBTRACTED_DATA_IN_FIT_PEAK_OP
	
	GetFitSession()->SetBaselineFitMode( bBaselineFitWithPeaks );
	
	/// Iris 11/12/2008 v8.0969 QA80-12584 OUTPUT_BASELINE_AND_SUBTRACTED_DATA_IN_FIT_PEAK_OP, talk with Folger, original code is incorrect.
	//GetFitSession()->SetSubtractedMode( needSubtractBaseline() );
	GetFitSession()->SetSubtractedMode( m_pPAWizCore->GetSubtractedMode() );
	///end OUTPUT_BASELINE_AND_SUBTRACTED_DATA_IN_FIT_PEAK_OP	
	
	/// Iris 11/12/2008 v8.0969 QA80-12584 OUTPUT_BASELINE_AND_SUBTRACTED_DATA_IN_FIT_PEAK_OP
	XYRange drSubtracted;
	if( m_pPAWizCore->GetSubtractedMode() && m_pPAWizCore->GetSubtractedRange(drSubtracted) )
	{
		GetFitSession()->SetSubtractedDataRange(drSubtracted);
	}
	///end OUTPUT_BASELINE_AND_SUBTRACTED_DATA_IN_FIT_PEAK_OP
}
//------ End BASELINE_STATUS_IN_NLFSESSION_SHOULD_BE_READY_RIGHT_AFTER_PREPARE_FUNCTION_ON_INIT

/// Iris 10/27/2008 v8.0961 PREPARE_SUBTRACTED_DATA_RANGE_IN_NLFSESSION
void 		PeakFitHelper::setFitSessionBaselineDataRange()
{
	///Sophy 10/13/2008 GET_CUMULATIVE_DATA_WHITH_BASELINE_MODE
	//if( bHasBaseline )
	XYRange xyBaseline;
	/// Iris 11/12/2008 v8.0969 QA80-12584 OUTPUT_BASELINE_AND_SUBTRACTED_DATA_IN_FIT_PEAK_OP, even already subtracted baseline, but if AddBackBaseline checkbox is checked, still need baseline data range in FitSession.
	// And FitPeak will according to baseline mode and other conditions to decide if report baseline range, so here always get baseline range and to set without check any condition.
	//if( !IsBaselineFitWithPeaks() && needSubtractBaseline() ) //if bHasBaseline = true, m_pFitSession()->GetBaselineFitMode() is false
	///end OUTPUT_BASELINE_AND_SUBTRACTED_DATA_IN_FIT_PEAK_OP
	///end GET_CUMULATIVE_DATA_WHITH_BASELINE_MODE
	{
		m_pPAWizCore->GetBaselineRange(xyBaseline);
	}
	GetFitSession()->SetBaselineRange( xyBaseline );
}
///end PREPARE_SUBTRACTED_DATA_RANGE_IN_NLFSESSION

double		PeakFitHelper::calcAverageWidth(const vector& vX, const vector& vY, const vector& vHeights)
{
	IntegrationResult sResult;
	ocmath_integrate(vX, vY, 0, vX.GetSize()-1, &sResult, NULL, ABSOLUTE_AREA);	
	
	if (sResult.dxPeak < 0 && sResult.dxPeak != NANUM)
	{
		sResult.dxPeak *= -1;	
	}
	
	double dSumHeight;
	vector vAbs; 
	///Sandy 2009-1-8 SPEED_UP_VECTOR_ABS
	//vAbs = abs(vHeights);
	vAbs = vHeights;
	vAbs.Abs();
	//end SPEED_UP_VECTOR_ABS
	
	vAbs.Sum(dSumHeight);
	double dAverageWidth = sResult.Area/dSumHeight/sqrt(PI/(4*ln(2)));
	return dAverageWidth;	
}

/// Iris 10/30/2008 v8.0963b DISABLE_BASELINE_PARAMETER_SHARE_CELL	
//#define	NUM_BASELINE_PARAM_INDEX_FROM		0 ///// Iris 9/22/2008 NEW_PA discussed with Folger can assume baseline fit parameter index always begin from 0
//
//bool	PeakFitHelper::GetBaselineParamIndices(vector<int>& vnIndices)
//{
	//int nNumPeaks = getNumBaselineParams();
	//if( 0 != nNumPeaks)
	//{
		//vnIndices.Data(NUM_BASELINE_PARAM_INDEX_FROM, nNumPeaks - 1, 1);
		//return vnIndices.GetSize() > 0;
	//}
	//
	//return false; // false, if not baseline fit function 	
//}
///end DISABLE_BASELINE_PARAMETER_SHARE_CELL

//------ Folger 10/24/08 v8.0960 SUPPORT_SORT_MULTIPLE_PEAKS_IN_PA
/// virtual
bool	PeakFitHelper::UpdatePeaksPropertiesAfterSorting(const vector<uint>& vnIndices)
{
	vector		vCenters;
	vector		vHeights;
	int			nSize = GetPeaksInfo(&vCenters, &vHeights);
	ASSERT(nSize == vnIndices.GetSize());
	
	vCenters.Reorder(vnIndices);
	vHeights.Reorder(vnIndices);
	
	SetPeaksInfo(&vCenters, &vHeights);
	
	///------ Folger 05/12/09 NANOSIZER_FITTING_BASED_SUPPORT
	//GetParamInitHelper()->UpdatePeaksCenterAndWidth(vCenters, vHeights);
	PEAKINFOARGUMENTSLISTPARAMS		stPEAKINFOARGUMENTSLISTPARAMS;
	stPEAKINFOARGUMENTSLISTPARAMS.vCenters = vCenters;
	stPEAKINFOARGUMENTSLISTPARAMS.vHeights = vHeights;
	GetParamInitHelper()->UpdatePeaksParams(stPEAKINFOARGUMENTSLISTPARAMS);
	///------ End NANOSIZER_FITTING_BASED_SUPPORT
	
	XYRange yp;
	m_pPAWizCore->GetPeaksCenterRange(yp);
	if( yp.IsValid())
	 	yp.SetData(&vHeights, &vCenters);
	
	return true;
}
//------ End SUPPORT_SORT_MULTIPLE_PEAKS_IN_PA

///------ Folger 10/20/09 NANOSIZER_FAILS_TO_SWITCH_LABEL_PLOT
// //------ Folger 11/01/08 QA80-12509 v8.0964 SUPPORT_PEAK_LABEL_SWITCHING_IN_PA_FIT_CONTROL_DIALOG
// bool			PeakFitHelper::AccessPeakLabelSettings(int& nLabelXYType, bool bGet/* = true*/)
// {
// 	//------ Folger 11/10/08 QA80-12509 v8.0968 ONLY_SET_PLOT_LABEL_TYPE_IN_PEAK_FIT_DIALOG_EXCLUDE_ROTATION
// 	/*
// 	int		nLabelXYType1;
// 	bool	bRotateLabel;
// 	m_pPAWizCore->AccessPeakLabelSettings(nLabelXYType1, bRotateLabel);
// 	if ( bGet )
// 	{
// 		nLabelXYType = nLabelXYType1;
// 	}
// 	else
// 	{
// 		update_peaks_center_label(m_pPAWizCore, true, true, nLabelXYType, bRotateLabel);
// 		m_pPAWizCore->AccessPeakLabelSettings(nLabelXYType, bRotateLabel, false);
// 	}
// 	*/
// 	return m_pPAWizCore->AccessPeakLabelSettings(nLabelXYType, bGet);
// 	//------ End ONLY_SET_PLOT_LABEL_TYPE_IN_PEAK_FIT_DIALOG_EXCLUDE_ROTATION
// }
// //------ End SUPPORT_PEAK_LABEL_SWITCHING_IN_PA_FIT_CONTROL_DIALOG
///------ End NANOSIZER_FAILS_TO_SWITCH_LABEL_PLOT

///Sophy 11/28/2008 v8.0980d CHECK_FIT_FUNCTIONS_ON_PARAMS_CHANGE
int			PeakFitHelper::CheckErrorOnFitFunctions(string& strErr)
{
	int nPeakOffset = getPeaksOffset();
	for( int ii = nPeakOffset; ii < GetFitSession()->GetNumberFitFunctions(); ii++ )
	{
		Tree trFDF;
		trFDF = GetFitSession()->GetTreeFDF(ii);
		vector<string> vsInvalidParams;
		if( !peak_fit_is_peak_func(trFDF, &vsInvalidParams) )
		{
			strErr = GetFitSession()->GetFunctionName(NULL, ii);
			string	strInvalidParams;
			strInvalidParams.SetTokens(vsInvalidParams, PARAM_SEPERATE_CHAR);
			strErr += "|" + strInvalidParams;
			return XFERR_PEAK_FUNC;
		}
			
	}
	return CER_NO_ERROR;
}
///end CHECK_FIT_FUNCTIONS_ON_PARAMS_CHANGE


bool PeakFitHelper::OnClickFit(bool *pbEnable)
{
	///------ Folger 03/09/09 PREVIEW_SHOULD_BE_ALWAYS_UPDATED_AFTER_FITTING_REGARDLESS_OF_GOOD_FIT
	//if( Fit() )
	Fit();
	///------ End PREVIEW_SHOULD_BE_ALWAYS_UPDATED_AFTER_FITTING_REGARDLESS_OF_GOOD_FIT
	{	
		if( pbEnable )
			*pbEnable = !IsFitConverged();
		UpdatePreview( FITPREVIEW_REPLOT);
		return true;
	}
	return false;
}

//int PeakFitHelper::GetNumPeaks()
//{
	//if(NULL != m_pFitSession)
		//return m_pFitSession->GetNumPeaks();
	//return -1;
//}

bool PeakFitHelper::SetSourcePlotUID(DWORD dwPlotUID)
{
	if(NULL != m_pFitSession)
	{
		m_pFitSession->SetSourcePlotUID(0, dwPlotUID);
		return true;
	}
	return false;
}

///------ Folger 01/22/09 PEAK_FITTING_OUTPUTS_HELPER_CLEANUP

//static	void	_set_output_range(Operation* pOp, /*int nIndex, const DataRange& range*/const vector<int>& vnUIDs)
//{
	////------ Folger 11/13/08 QA80-12488 v8.970 PA_FITTING_AUTO_UPDATE_SUPPORT_USE_VECTOR_FOR_UIDS_STORAGE
	///*
	//if ( range.GetNumRanges() > 0 )
	//{
		//int			r1, c1, r2, c2;
		//Worksheet	ds;
		//string		strName;
		//range.GetRange(0, r1, c1, r2, c2, ds, &strName);
		//
		//DataRange rng;
		//string		strUID;
		//_parse_subrange_uid_and_name(strName, &strUID);
		//rng = (DataRange)Project.GetObject(atoi(strUID));
		//
		//for ( int jj=0; jj<rng.GetNumRanges(); ++jj )
		//{
			//rng.GetRange(jj, r1, c1, r2, c2, ds, &strName);
			//string		strName1;
			//_parse_subrange_uid_and_name(strName, NULL, &strName1);
			//rng.SetRange(jj, ds, r1, c1, r2, c2, strName1);
			//break;
		//}
		//
		//int nRet = pOp->SetOutput(rng, nIndex);
	//}
	//*/
	//for ( int ii=0; ii<vnUIDs.GetSize(); ++ii )
	//{
		//DataRange rng;
		//rng = (DataRange)Project.GetObject(vnUIDs[ii]);
		//if ( rng )
			//int nRet = pOp->SetOutput(rng, ii);
	//}
	////------ End PA_FITTING_AUTO_UPDATE_SUPPORT_USE_VECTOR_FOR_UIDS_STORAGE
//}

///------ End PEAK_FITTING_OUTPUTS_HELPER_CLEANUP

//------ End PA_FITTING_AUTO_UPDATE_SUPPORT

///------ Folger 01/22/09 PEAK_FITTING_OUTPUTS_HELPER_CLEANUP

///// YuI 11/14/08 NEED_TO_REMOVE_AND_THEN_RESTORE_OUTPUTS
//static void	_remove_wizard_operation_outputs(vector<int>& vnUIDs, vector<int>& vWizardOutputUIDs, int& nWizardOperationUID)
//{
	//// first - we need to find wizard operation
	//// we may somehow pass this information to XFCore from XFWizScript::Run
	//// but looks like not available now. Need to search
	//for ( int ii=0; ii<vnUIDs.GetSize(); ++ii )
	//{
		//DataRange rng;
		//rng = (DataRange)Project.GetObject(vnUIDs[ii]);
		//if ( rng )
		//{
			//int nDummyIndex = 0;
			//OperationBase& opWizard = rng.GetIncomingOperation(TRUE, nDummyIndex);
			//if( opWizard.IsValid() )
			//{
				//nWizardOperationUID = opWizard.GetUID();
				//vWizardOutputUIDs.SetSize(opWizard.GetOutputCount());
				//for( int ii = 0; ii < vWizardOutputUIDs.GetSize(); ii++ )
				//{
					//DataRange rngWizardOutput;
					//opWizard.GetOutput(rngWizardOutput, ii);
					//if( rngWizardOutput )
					//{
						//vWizardOutputUIDs[ii] = rngWizardOutput.GetUID();
						//opWizard.RemoveOutput(rngWizardOutput, FALSE);
					//}
				//}
				//break;
			//}
		//}
	//}
//}
//
//static void _restore_wizard_operation_outputs(vector<int>& vWizardOutputUIDs, int nWizardOperationUID)
//{
	//OperationBase opWizard;
	//opWizard = (OperationBase)Project.GetObject(nWizardOperationUID);
	//if( opWizard )
	//{
		//for( int ii = 0; ii < vWizardOutputUIDs.GetSize(); ii++ )
		//{
			//DataRange rng;
			//rng = (DataRange)Project.GetObject(vWizardOutputUIDs[ii]);
			//if( rng )
			//{
				//opWizard.SetOutput(rng, ii);
			//}
		//}
	//}
//}
//
///// end NEED_TO_REMOVE_AND_THEN_RESTORE_OUTPUTS
//
/////------ Folger 01/19/09 QA80-12969 PA_FITTING_SUPPORT_ANALYSIS_TEMPLATE
//static	void	_update_range_uids_by_wiz_op(TreeNode& trRangeUIDs, const Operation* pOp)
//{
	//vector<int>		vnUIDs;
	//bool			bNonEmptyStart = false;
	//for ( int ii=0; ii<pOp->GetOutputCount(); ++ii )
	//{
		//DataRange rng;
		//pOp->GetOutput(rng, ii);
		//
		//if ( rng )
		//{
			//if ( rng.GetName().Compare(PA_FITTING_OUTPUT_EMPTY_RANGE_NAME) != 0 )
				//continue;
			//
			//vnUIDs.Add(rng.GetNumRanges() > 0 ? rng.GetUID() : 0);
		//}
	//}
	//trRangeUIDs.nVals = vnUIDs;
//}
/////------ End PA_FITTING_SUPPORT_ANALYSIS_TEMPLATE

///------ End PEAK_FITTING_OUTPUTS_HELPER_CLEANUP

/// Iris 9/17/2008 NEW_PA
void PeakFitHelper::outputGraphAddBackBaseline(const TreeNode& trGetN)
{
	if(PLOT_TO_NEW_GRAPH != trGetN.result.gpconfig.PlotCurveTo.nVal)
		return;
	
	GraphLayer gl;
	get_gl_from_xyr_treenode(gl, trGetN.trAdv.OutputGraph.Range1);
	if(!gl)
		return;
	
	bool 		bAddBackBaseline = false;
	TreeNode 	trAddBackBaseline = tree_get_node_by_tagname(trGetN.result, "AddBackBaseline", true);
	if(trAddBackBaseline && trAddBackBaseline.nVal && trAddBackBaseline.Show)
		bAddBackBaseline = true;
	
	for(int nPlotIndex = gl.DataPlots.Count() - 1; nPlotIndex >= 0; nPlotIndex--)
	{
		DataPlot dp = gl.DataPlots(nPlotIndex);
		if(!dp || dp.Show)
			continue;
		
		if(bAddBackBaseline)
			dp.Show = true;
		else
			dp.Destroy();
	}	
}

///Sophy 9/27/2008 NEW_PA rearrange fitcurve & residual & derivative preview graphlayer
void	PeakFitHelper::rearrangePreviewLayer( GraphPage& gp, vector<int>& vnLayerIndex, stLayersGridFormat& stOldFormat )
{
	page_arrange_layers(gp, vnLayerIndex.GetSize(), 1, &stOldFormat, false, false, vnLayerIndex);
	return;
}
///end Sophy NEW_PA

///------ Folger 09/05/09 FAILS_TO_PASTE_RESULTS_TABLE_TO_REPORT_GRAPH_DURING_CHANGE_PARAM_IN_PA
/// virtual
void 	PeakFitHelper::beforeExecuteOperation(const GraphLayer& gl, TreeNode& trGetN, TreeNode& trOp, TreeNode& trUID)
{
	PeakFitHelperBase::beforeExecuteOperation(gl, trGetN, trOp, trUID);

	/// Iris 12/01/2008 v8.0981 FIX_CHANGE_PARAM_ALWAYS_REPLOT_ON_SOURCE_GRAPH
	TreeNode trSourceGraphIDMap = trGetN.trAdv.GetNode("SourceGraphIDMap");
	TreeNode trSourceGraphUID = trGetN.trAdv.GetNode("SourceGraphUID");
	if(trSourceGraphIDMap && !trSourceGraphIDMap.IsEmpty() && trSourceGraphUID && !trSourceGraphUID.IsEmpty())
	{
		trOp.Operation.SourceGraphIDMap.nVals = trSourceGraphIDMap.nVals;
		trOp.Operation.SourceGraphUID.nVals = trSourceGraphUID.nVals;
	}	
	///end FIX_CHANGE_PARAM_ALWAYS_REPLOT_ON_SOURCE_GRAPH

	TreeNode	trReport = tree_get_node_by_tagname(trOp.GUI, "PasteResultTable", true);
	if ( trReport )
	{
		trReport.SetAttribute(TREE_UID, trUID.result_table_uid.nVal);
	}
}
///------ End FAILS_TO_PASTE_RESULTS_TABLE_TO_REPORT_GRAPH_DURING_CHANGE_PARAM_IN_PA

///------ Folger 09/05/09 FAILS_TO_PASTE_RESULTS_TABLE_TO_REPORT_GRAPH_DURING_CHANGE_PARAM_IN_PA
//void PeakFitHelper::afterExecuteOperation(TreeNode& trGetN, TreeNode& trOp)
void PeakFitHelper::afterExecuteOperation(TreeNode& trGetN, TreeNode& trOp, TreeNode& trUID)
///------ End FAILS_TO_PASTE_RESULTS_TABLE_TO_REPORT_GRAPH_DURING_CHANGE_PARAM_IN_PA
{	
	///------ Folger 09/05/09 FAILS_TO_PASTE_RESULTS_TABLE_TO_REPORT_GRAPH_DURING_CHANGE_PARAM_IN_PA
	PeakFitHelperBase::afterExecuteOperation(trGetN, trOp, trUID);
	///------ End FAILS_TO_PASTE_RESULTS_TABLE_TO_REPORT_GRAPH_DURING_CHANGE_PARAM_IN_PA
	outputGraphAddBackBaseline(trGetN);
	
	/// Iris 12/01/2008 v8.0981 FIX_CHANGE_PARAM_ALWAYS_REPLOT_ON_SOURCE_GRAPH
	// because always delete PeakFit operation after execute, so not remember treenode SourceGraphIDMap and SourceGraphUID in trOp.Operation
	// the two nodes used in WksReportOperation::getSourceGraphIdUIDtoMap to get source graph uid.
	TreeNode trSourceGraphIDMap = trGetN.trAdv.GetNode("SourceGraphIDMap");
	TreeNode trSourceGraphUID = trGetN.trAdv.GetNode("SourceGraphUID");
	if(trSourceGraphIDMap && trSourceGraphUID) 
	{
		///------ Folger 11/12/09 QA81-14628-P2 PA_FITTING_RUNTIME_ERROR_WHEN_NOT_OUTPUT_RESULT_GRAPH
		//trSourceGraphIDMap.nVals = trOp.Operation.SourceGraphIDMap.nVals;
		//trSourceGraphUID.nVals = trOp.Operation.SourceGraphUID.nVals;
		TreeNode	trSourceGraphIDMapFromOP = trOp.Operation.SourceGraphIDMap;
		TreeNode	trSourceGraphUIDFromOP = trOp.Operation.SourceGraphUID;
		if ( trSourceGraphIDMapFromOP && trSourceGraphUIDFromOP )
		{
			trSourceGraphIDMap.nVals = trSourceGraphIDMapFromOP.nVals;
			trSourceGraphUID.nVals = trSourceGraphUIDFromOP.nVals;
		}
		else
		{
			trSourceGraphIDMap.Reset(TRUE);
			trSourceGraphUID.Reset(TRUE);
		}
		///------ End PA_FITTING_RUNTIME_ERROR_WHEN_NOT_OUTPUT_RESULT_GRAPH
	}	
	///end FIX_CHANGE_PARAM_ALWAYS_REPLOT_ON_SOURCE_GRAPH

	///------ Folger 09/05/09 FAILS_TO_PASTE_RESULTS_TABLE_TO_REPORT_GRAPH_DURING_CHANGE_PARAM_IN_PA
	TreeNode	trReport = tree_get_node_by_tagname(trOp.GUI, "PasteResultTable", true);
	if ( trReport )
	{
		int		nUID = 0;
		if ( trReport.GetAttribute(TREE_UID, nUID) )
			trUID.result_table_uid.nVal = nUID;
	}
	///------ End FAILS_TO_PASTE_RESULTS_TABLE_TO_REPORT_GRAPH_DURING_CHANGE_PARAM_IN_PA
}



// assume only return one plot for datarange
static bool _get_dataplot_by_range(const DataRange& dr, const GraphLayer& gl, DataPlot& dp)
{
	vector<int> vnPlotIndices;
	if(check_has_plotted_in_graph(dr, gl, vnPlotIndices) > 0 && vnPlotIndices.GetSize() > 0)
	{
		dp = gl.DataPlots( vnPlotIndices[0] );
		return dp.IsValid();
	}
	return false;
}


int 	PeakFitHelper::newOutputGraph(const GraphLayer gl, const TreeNode trGetN, TreeNode& trGUI, bool bHasBaselinePeak)
{
	if( !trGetN )
		return -1;
	
	GraphPage 	gp;
	if( gl )
		gp = gl.GetPage();
	
	XYRange 	drOriginal, drBaseline, drParent;
	m_pPAWizCore->GetOriginalRange(drOriginal);
	m_pPAWizCore->GetBaselineRange(drBaseline);		
	m_pPAWizCore->GetSubtractedRange(drParent);
	
	bool bAddBackBaseline = false;
	TreeNode trAddBackBaseline = tree_get_node_by_tagname(trGetN.result, "AddBackBaseline", true);
	if(trAddBackBaseline && trAddBackBaseline.nVal && trAddBackBaseline.Show)
		bAddBackBaseline = true;	

	// check and get output graph. In change Parameters or Recalculate, this graph already existed.
	GraphLayer 	glNew;	
	TreeNode 	trOutputGraph = tree_get_node_by_tagname(trGetN.trAdv, "OutputGraph", true);
	if( trOutputGraph.LayerUID &&  !trOutputGraph.LayerUID.IsEmpty() ) // when change parameter or recalculate, output graph already existed.
	{
		glNew = (GraphLayer) Project.GetObject(trOutputGraph.LayerUID.nVal);		
	}
	
	Tree		trSourcePlotFormat;
	int			nSourcePlotType = IDM_PLOT_LINE;
	GraphPage	gpNew;
	if( !glNew )
	{
		gpNew.Create("PKREPORT");
		glNew = gpNew.Layers(0);		
	}
	else
	{
		gpNew = glNew.GetPage();
		
		// before remove all plots need to backup plot type and other plotting format, and used to apply on new plotting below.
		DataPlot dpSource;
		if( !m_pPAWizCore->GetSourceDataPlot(dpSource) || m_pPAWizCore->GetSubtractedMode() && !bAddBackBaseline )	
		{
			vector<int> vnPlotIndex; 
			if( 1 <= check_has_plotted_in_graph(drOriginal, glNew, vnPlotIndex) && vnPlotIndex.GetSize() > 0 )
			{
				dpSource = glNew.DataPlots(vnPlotIndex[0]);
			}
		}
		
		if( dpSource )
		{
			trSourcePlotFormat = dpSource.GetFormat(FPB_ALL, FOB_ALL, true, true);
			nSourcePlotType = dpSource.GetPlotType();
		}
				
		// for recalculate and change parameter case, need remove all existed plots and replot in fit peak op 
		// since source plot can be original plot also can be subtracted data plot.
		/// Iris 03/06/2009 FIX_AFTER_RECALCULATE_SOURCE_PLOT_COLOR_IS_RED
		// to fix bug, after recalculate the color of source plot be changed to red
		//while( glNew.RemovePlot(0) ); 
		if( glNew.DataPlots.Count() > 0 )
			while( glNew.RemovePlot(glNew.DataPlots.Count()-1) );
		///end FIX_AFTER_RECALCULATE_SOURCE_PLOT_COLOR_IS_RED
	}
		
	// check get source plot and baseline plot from preview graph page
	GraphLayer 	glOriginal;
	DataPlot 	dpOriginal, dpBaseline;	
	if( gp )
	{
		glOriginal = gp.Layers(INDEX_ORIGIN_LAYER);
		
		if(glOriginal)
		{
			_get_dataplot_by_range(drOriginal, glOriginal, dpOriginal);
			_get_dataplot_by_range(drBaseline, glOriginal, dpBaseline);		
		}
	}	
	
	// plot source plot on output graph
	int nSourcePlotIndex = -1;
	if(dpOriginal)// if exist preview graph page, dpOriginal will be valid
	{
		vector<int> vnPlotIndex; 
		if( 1 > check_has_plotted_in_graph(drOriginal, glNew, vnPlotIndex) )
		{
			nSourcePlotIndex = glNew.AddPlot(dpOriginal);
		}
		else
			nSourcePlotIndex = vnPlotIndex[0];
	}
	else // if not preview graph, then directly plot with data range, and apply original plot format.
	{
		nSourcePlotIndex = glNew.AddPlot(drOriginal, nSourcePlotType);
		
		if( !trSourcePlotFormat.IsEmpty() && nSourcePlotIndex >= 0 )
		{
			DataPlot dpOriginal = glNew.DataPlots(nSourcePlotIndex);			
			if( dpOriginal )
			{
				dpOriginal.ApplyFormat(trSourcePlotFormat);
			}
		}			
	}
	
	// check and plot baseline		
	int ndpBaseline = -1;
	if( !m_pPAWizCore->GetSubtractedMode() || bAddBackBaseline )
	{
		if(dpBaseline)
		{
			vector<int> vnPlotIndex; 
			if( 1 > check_has_plotted_in_graph(drBaseline, glNew, vnPlotIndex) )
			{
				ndpBaseline = glNew.AddPlot(dpBaseline);
			}
			else
			{
				ndpBaseline = vnPlotIndex[0];
			}
		}
		else
		{
			ndpBaseline = glNew.AddPlot(drBaseline);
		}
	
		if(-1 < ndpBaseline)
			glNew.DataPlots(ndpBaseline).SetColor(SYSCOLOR_BLUE);
	}
	
	
	glNew.Rescale(ANL_CHK_DATA_OUTSIDE);
	
	DataPlot dp = glNew.DataPlots(nSourcePlotIndex);
	if( dp )
		return dp.GetUID( true );
	return 0;
}
///end CLEAN_newOutputGraph

///Sophy 9/22/2008 NEW_PA
void PeakFitHelper::resetInputDataWithNewGraph( const TreeNode trGetN, TreeNode& trGUI, int nPlotUID )
{
	DataPlot dp;
	dp = Project.GetObject(nPlotUID);
	if( !dp )
		return;
	
	DataRange dr;
	dp.GetDataRange( dr );
	XYRange xyRange( dr );
	trGUI.InputData.Reset();
	construct_tree_from_xyrange(trGUI.InputData, xyRange);
	
	if(trGUI.InputData.Range1)
	{	
		TreeNode trNew = tree_check_get_node(trGUI.InputData.Range1, "W");
		TreeNode trW = tree_get_node_by_tagname(trGetN.trAdv.InputData, "W", true);
		if(trW)
			trNew.Replace(trW);
	
		/// Iris 11/15/2008 v8.0972 QA80-12584_P7 FIX_ALWAYS_NEW_REPORT_GRAPH_WHEN_RECALCULATE
		//TreeNode trRange1 = trGetN.trAdv.OutputGraph.AddNode("Range1");
		//trRange1.Replace(trGUI.InputData.Range1.Clone());
		///end FIX_ALWAYS_NEW_REPORT_GRAPH_WHEN_RECALCULATE
		
		/// Hong 10/16/08 v8.0956 FIX_PA_DO_FIT_AGAIN_EVEN_CONVERGE
		//GetFitSession()->SetData( trGUI.InputData ); ///Sophy 9/25/2008 NEW_PA should reset dataobject's plot UIDs
		/// Iris 11/10/2008 v8.0968 FIX_IF_SUBTRACTED_THEN_ADDBACKBASELINE_ALWAYS_FIT_ON_ORIGINAL_DATA
		// if subtracker baseline, should fit on subtracted data not source data, if AddBackBaseline selected, then add baseline to fitted data.
		// But the following line always use source data tree to SetData again, in fact, input data range should follow the logic in ::getInputDataRange
		// here just reset plot uid for session.
		//GetFitSession()->SetData( trGUI.InputData, NULL, 0, 0, true );
		///end FIX_IF_SUBTRACTED_THEN_ADDBACKBASELINE_ALWAYS_FIT_ON_ORIGINAL_DATA
		/// end FIX_PA_DO_FIT_AGAIN_EVEN_CONVERGE
		
		/// Iris 11/06/2008 FIX_NOT_SUBTRACTED_FAIL_PLOT_FIT_CURVE_ON_NEW_OUTPUT_GRAPH
		int dw;
		if( trGUI.InputData.Range1.GetAttribute(STR_PLOTOBJ_UID_ATTRIB, dw) )
		{
			const int nDataIndex = 0;
			GetFitSession()->SetSourcePlotUID(nDataIndex, dw);
		}
		else
			error_report("Error, fail to get data plot uid from newly created output graph");
		///end FIX_NOT_SUBTRACTED_FAIL_PLOT_FIT_CURVE_ON_NEW_OUTPUT_GRAPH
		return;
	}
	
	///End ADD_BACK_BASELINE_TO_BOTH_FITCURVE_AND_REPORT_GRAPH
	return;
}
///end NEW_PA

/// Iris 11/15/2008 v8.0972 QA80-12584_P7 FIX_ALWAYS_NEW_REPORT_GRAPH_WHEN_RECALCULATE
void PeakFitHelper::updateOutputGraphNodeWithNewGraph(TreeNode trGetN, int nPlotUID)
{
	TreeNode trLayerUID = trGetN.trAdv.OutputGraph.GetNode("LayerUID");
	ASSERT(trLayerUID);
	if( trLayerUID && 0 != nPlotUID)
	{
		DataPlot dp;
		dp = (DataPlot)Project.GetObject(nPlotUID);
		if( dp )
		{
			GraphLayer gl;
			dp.GetParent(gl);
			trLayerUID.nVal = gl.GetUID(true);
		}
		else
			ASSERT(false);
	}	
}
///end FIX_ALWAYS_NEW_REPORT_GRAPH_WHEN_RECALCULATE

////------ Folger 04/21/08 ADD_BASELINE_MODE_TABLE_TO_OUTPUT_REPORT
//static bool _get_data_from_page_storage(vector &vx, vector &vy, const Page &pg, LPCSTR lpcszStorageName)
//{
	//XYRange		xy;
	//get_data_context_from_page(pg, xy, lpcszStorageName);
	//if ( !xy.GetData(vy, vx) )
		//return false;
	//return true;
//}
////------ End ADD_BASELINE_MODE_TABLE_TO_OUTPUT_REPORT
//
////------ Folger 11/26/07 PFW_OTHER_INFORMATION_TABLE
///Sophy 10/20/2008 CLEAN_CODE_ADD_BASELINE_INFO_TO_REPORT_TABLE
string	PeakFitHelper::getInterpFunc()
{
	int nFuncType = m_pPAWizCore->GetBaseIntepType();
	ASSERT( nFuncType < 3 );
	string	strFuncList = STR_INTERP_FUNCTION_LIST;
	string	strFunc = "";
	if( nFuncType < 3 )
		strFunc = strFuncList.GetToken( nFuncType, '|' );
	
	return strFunc;
}

//bool PeakFitHelper::addBaselineInfo(GraphLayer &gl, Page &pg, TreeNode &trCal)
bool PeakFitHelper::addBaselineInfo(TreeNode &trCal)
///end CLEAN_CODE_ADD_BASELINE_INFO_TO_REPORT_TABLE
{
	//------ Folger 04/21/08 ADD_BASELINE_MODE_TABLE_TO_OUTPUT_REPORT
	/*
	TreeNode trBL = trCal.InsertNode(trCal.Input, "BLInfo");
	if (!trBL)
		return false;
		
	XYRange dr;
	
	Tree trBLStorage;
	
	if(EXIST_PLOT == pg.GetType())
	{
		DataPlot dp;
		if(!check_baseline_dataplot(gl, dp))
			return false;
		dp.GetDataRange(dr);
		dp.GetBinaryStorage("OriginStorage", trBLStorage);
	}
	else
	{
		Column colY;
		if(!check_baseline_range(pg, dr) || !dr.GetYColumn(colY))
			return false;
		colY.GetBinaryStorage("OriginStorage", trBLStorage);		
	}
	
	dr.GetTree(trBL);
	
	if(trBLStorage.Function && trBLStorage.Parameters)
	{
		TreeNode trFitBaseline = trCal.InsertNode(trCal.Input, "FitBaseline");
		trFitBaseline.Replace(trBLStorage, true, true);
	}
	*/
	///Sophy 9/22/2008 NEW_PA
	/*
	int nMode = BM_None;
	set_get_nValue_to_page(pg, PBW_OPT_BASE_MODE, nMode, false);
	
	if ( nMode == BM_None )
		return false;
	*/
	int nMode = m_pPAWizCore->GetBaseMode();
	if( PA_BM_None == nMode )
		return false;
	///end Sophy NEW_PA
		
	TreeNode	trBL = trCal.InsertNode(trCal.Parameters, "Baseline");
	if ( !trBL )
		return false;
	LPCSTR lpcszMode = "Mode";
	trBL.AddNumericNode(nMode, lpcszMode);
	
	//------ Folger 05/16/08 IMPROVE_BASELINE_MODE_TABLE
	int		nSubtracted = 0;
	///Sophy 9/22/2008 NEW_PA
	//set_get_nValue_to_page(pg, PFW_BASELINE_SUBTRACTED, nSubtracted, false);
	nSubtracted = m_pPAWizCore->GetSubtractedMode();
	///end Sophy NEW_PA
	LPCSTR	lpcszSubtracted = "Subtracted";
	trBL.AddNumericNode(nSubtracted, lpcszSubtracted);
	//------
	
	vector vx, vy;
	
	switch ( nMode )
	{
	case PA_BM_CONSTANT:
		///Sophy 9/22/2008 NEW_PA
		/*
		if ( !_get_data_from_page_storage(vx, vy, pg, PFW_BASELINE_PLOT_TAGNAME) )
			return false;
		*/
		XYRange xyRange;
		if( !m_pPAWizCore->GetBaselineRange( xyRange ) )
			return false;
		xyRange.GetData( vy, vx );
		///end NEW_PA
		trBL.AddNumericNode(vy[0], "Constant");
		break;
		
	case PA_BM_USERDEF:
		{
			///Sophy 9/22/2008 NEW_PA
			/*
			if ( !_get_data_from_page_storage(vx, vy, pg, PFW_BASELINE_ANCHOR_TAGNAME) )
				return false;
			*/
			XYRange drAnch;
			if( !m_pPAWizCore->GetBaseAnchorsRange( drAnch ) )
				return false;
			drAnch.GetData( vy, vx );
			///end NEW_PA
			#define		CONNECT_INTERPOLATE			0
			#define		CONNECT_FITTING				1
			int nConnect = CONNECT_INTERPOLATE, nFunc = 0;
			///Sophy 9/22/2008 NEW_PA
			//set_get_nValue_to_page(pg, PFW_BASELINE_FITFUNC_INDEX, nFunc, false);
			nFunc = m_pPAWizCore->GetBaselineFitFunc();
			///end NEW_PA
			if ( nFunc >= 0 )
				nConnect = CONNECT_FITTING;
			
			trBL.AddTextNode(nConnect == CONNECT_INTERPOLATE ? _L("Interpolation") : _L("Fit Function"), "Connect");
			
			string strFunc;
			if ( nConnect == CONNECT_INTERPOLATE )
			{
				///Sophy 10/20/2008 CLEAN_CODE_ADD_BASELINE_INFO_TO_REPORT_TABLE
				//set_get_strVal_to_page(pg, PFW_BASELINE_INTERPLOLATE_FUNCTION, strFunc, false);
				strFunc = getInterpFunc();
				///end CLEAN_CODE_ADD_BASELINE_INFO_TO_REPORT_TABLE
			}
			else
			{
				vector<string> vsFuncs, vsFiles;
				nslf_get_func_list(vsFuncs, vsFiles, STR_PA_NLSF_CAT_BASELINE);//"Baseline");
				strFunc = vsFuncs[nFunc];
			}	
			trBL.AddTextNode(strFunc, "Function");
			
			///Sophy 11/10/2008 CLEAN_CODE_ADD_BASELINE_INFO_TO_REPORT_TABLE
			
			TreeNode trX = trBL.AddNode("X");
			TreeNode trY = trBL.AddNode("Y");
			trX.dVals = vx;
			trY.dVals = vy;
			
			//------ Folger 05/16/08 IMPROVE_BASELINE_MODE_TABLE
			int		nFit = 0;
			///Sophy 10/20/2008 CLEAN_CODE_ADD_BASELINE_INFO_TO_REPORT_TABLE
			//set_get_nValue_to_page(pg, PFW_BASELINE_FIT_WITH_PEAK, nFit, false);
			nFit = m_pPAWizCore->GetBaselineFitMode();
			///end CLEAN_CODE_ADD_BASELINE_INFO_TO_REPORT_TABLE
			
			if ( nConnect == CONNECT_FITTING && nSubtracted == 0 && nFit == 0 )
			{
				TreeNode		trNode;
				///Sophy 11/10/2008 CLEAN_CODE_ADD_BASELINE_INFO_TO_REPORT_TABLE
				//if ( set_get_baseline_tree_in_page(pg, trNode, false) )
				//{
					//trBL.AddNode(trNode);
				//}
				if( m_pPAWizCore->UpdateInfoTree( trNode, PA_TREE_BASELINE_FIT_INFO, false ) )
				///end CLEAN_CODE_ADD_BASELINE_INFO_TO_REPORT_TABLE
				{
					trBL.AddNode( trNode );
				}
			}
			//------		
			///end CLEAN_CODE_ADD_BASELINE_INFO_TO_REPORT_TABLE
			///end Sophy NEW_PA
		}
		break;
		
	case PA_BM_USE_EX:
		///Sophy 9/22/2008 NEW_PA need to continue
		///*
		{
			//Tree tr;
			//HWND hwnd;
			//load_GetN_from_page(pg, tr,  hwnd, STR_STORAGE_NAME);
			//
			//TreeNode trRange = tree_check_get_node(tr, PFW_BASELINE_EXIST_DATASET_TAGNAME);
			//trBL.Replace(trRange, true, true);
			//trBL.AddNumericNode(BM_USE_EX, lpcszMode);
			////------ Folger 05/16/08 IMPROVE_BASELINE_MODE_TABLE
			//trBL.AddNumericNode(nSubtracted, lpcszSubtracted);
			//double rOffset = 0;
			//set_get_dValue_to_page(pg, PFW_BASELINE_EXIST_DATASET_OFFSET, rOffset, false);
			//trBL.AddNumericNode(rOffset, "Offset");
			//------
			///Sophy 11/12/2008 SUPPORT_USE_EXISTING_DATARANGE_AS_BASELINE_IN_NEW_PA
			Tree trBaseline;
			XYRange drBaseline;
			m_pPAWizCore->GetExistingBaselineRange( drBaseline );
			if( !drBaseline )
				return false;
			
			drBaseline.GetTree( trBaseline, false );
			string strRange;
			int nR1, nC1, nR2, nC2;
			Datasheet ds;
			drBaseline.GetRange( 0, nR1, nC1, nR2, nC2, ds );
			if( nR2 < 0 ) //full range case, nR2 is -1
			{
				vector vXRange;
				drBaseline.GetData( &vXRange, 0 );
				nR2 = nR1 + vXRange.GetSize() - 1;
			}
			strRange.Format( "[%d*:%d*]", nR1 + 1, nR2 + 1 );
	
			trBaseline.Range.strVal = strRange;
			trBL.Replace( trBaseline, true, true );
			trBL.AddNumericNode( PA_BM_USE_EX, lpcszMode );
			trBL.AddNumericNode( nSubtracted, lpcszSubtracted );
			trBL.AddNumericNode( m_pPAWizCore->GetBaseOffset(), "Offset" );
			///end SUPPORT_USE_EXISTING_DATARANGE_AS_BASELINE_IN_NEW_PA
		}
		break;
		//*/
		///end Sophy NEW_PA
		
		/// Iris 11/18/2008 PA_FIT_SUPPORT_NEW_BASELINE_MODE_XPS
#ifdef PA_WITH_XPS_BASELINE 
	case PA_BM_XPS:
		string strXPSMethod;
		switch(m_pPAWizCore->GetXPSMethod())
		{
		case PA_XPS_BASELINE_SHIRLEY:
			strXPSMethod = STR_XPS_METHOD_SHIRLEY;
			break;
		case PA_XPS_BASELINE_TOUGAARD:
			strXPSMethod = STR_XPS_METHOD_TOUGAARD;
			break;
		default:
			ASSERT(false);
			break;
		}
		TreeNode trMethod = trBL.AddTextNode(strXPSMethod, "Method");
		break;
#endif //PA_WITH_XPS_BASELINE
		///end PA_FIT_SUPPORT_NEW_BASELINE_MODE_XPS

	default:
		break;
	}
	//------ End ADD_BASELINE_MODE_TABLE_TO_OUTPUT_REPORT
	
	return true;
}
	
bool PeakFitHelper::addXFInfo( TreeNode &trCal)
{
	vector<string> vstrXFList, vstrDesc;
	///Sophy 9/22/2008 NEW_PA
	/*
	if(!read_xfs_info_from_page(pg, vstrXFList, vstrDesc) || vstrXFList.GetSize() != vstrDesc.GetSize())
		return false;	
	*/
	m_pPAWizCore->GetSteps(vstrXFList, vstrDesc);
	///end Sophy NEW_PA
	TreeNode trXFInfo = trCal.InsertNode(trCal.Input, "XFInfo");
	if (!trXFInfo)
		return false;
	
	TreeNode trXF = trXFInfo.AddNode("XF");
	trXF.strVals = vstrXFList;
	TreeNode trDesc = trXFInfo.AddNode("Description");
	trDesc.strVals = vstrDesc;
	
	return true;
}
	/////Sandy 2007-12-25 reuse page storage tree to save the input of wizard
	////static bool _add_input_data(TreeNode &trCal)
bool PeakFitHelper::addInputData( TreeNode &trCal)
{
	/// Iris 11/04/2008 v8.0965b PA_FIT_ADD_INPUT_REPORT_TABLE
	/*
	TreeNode trTmp;
	///---Jasmine 12/25/07 skip firstnode
	//if (!get_original_input_of_wizard(gp, trTmp))//Sandy 2007-12-25
	if(get_original_input_of_wizard(pg, trTmp))
		trTmp = trTmp.FirstNode;	
	TreeNode trInputData = trCal.InsertNode(trCal.Input, "PFWInputData");
	if (!trInputData || !trTmp)
		return false;
	///---end
	trCal.Input.SetAttribute(STR_LABEL_ATTRIB, _L("Fit Data"));
	
	trInputData.Replace(trTmp, true, true);
	//---Jasmine 04/16/08 XFExeContext::AddInputToTree will set Y range short name as label attribute
	trInputData.SetAttribute(STR_LABEL_ATTRIB, _L("Input Data"));		
	//---end
	*/	
	XYRange drOriginal;
	if( !m_pPAWizCore || !m_pPAWizCore->GetSourceRange( drOriginal ) )
		return error_report("fail to get source range in PeakFitHelper::addInputData");		
	
	TreeNode trInputData = trCal.InsertNode(trCal.Input, "PFWInputData");	
	if( !m_pPAWizCore->GetInputDataTable(trInputData) )
		return error_report("fail to get input data report table in PeakFitHelper::addInputData");	
	///end PA_FIT_ADD_INPUT_REPORT_TABLE
	
	trCal.Input.SetAttribute(STR_LABEL_ATTRIB, _L("Fit Data"));	
	//---Jasmine 04/16/08 XFExeContext::AddInputToTree will set Y range short name as label attribute
	trInputData.SetAttribute(STR_LABEL_ATTRIB, _L("Input Data"));		
	return true;
}	
bool PeakFitHelper::addOtherInformation(TreeNode &trOp)
{
	TreeNode trCal, trInputData;
	if(trOp.Calculation && trOp.Calculation.Parameters)
		trCal = trOp.Calculation;
			
	//Page& pg = gl.GetPage();
	addInputData( trCal);		//------ Folger 04/18/08 HIDE_FIT_DATA_TABLE_IN_PA_REPORT
	addXFInfo( trCal);
	addBaselineInfo( trCal );
	
	return true;
}
////------ End PFW_OTHER_INFORMATION_TABLE
//
//virtual 
void PeakFitHelper::copySettingsToOperation(const TreeNode& trGetN, TreeNode& trGUI)
{
	TreeNode trResultFromGetN = trGetN.result;
	TreeNode trAdvancedFromGetN = trGetN.trAdv;
	
	if(trResultFromGetN)
		copyValueByID(trResultFromGetN, trGUI, STR_BACKUP_ID_ATTRIB, STR_DATAID_ATTRIB);
			
	if(trAdvancedFromGetN)
		trGUI.InputData.Replace(trAdvancedFromGetN.InputData.Clone());
	
	copyValueByID(trGetN.result, trGUI.Residuals, STR_BACKUP_ID_ATTRIB, STR_DATAID_ATTRIB, "Graph2");		///Jasmine 04/16/08 ADD_RESIDUAL_PLOT_TO_PA_FIT
	
	///Jasmine 03/11/08 SHOW_FITCONTROL_BRANCH_IN_XF_NOT_IN_PARAMDLG_BY_CP_REQUEST
	if(trGetN.FitControl)
	{	
		trGUI.Fit.Iterations.MaxNum.nVal = trGetN.FitControl.MaxNum.nVal;
		trGUI.Fit.Iterations.Tolerance.dVal = trGetN.FitControl.Tolerance.dVal;
		
		if(trGetN.FitControl.Constraints)
			trGUI.Codes.Constraints.Replace(trGetN.FitControl.Constraints, true, true); 
		
		trGUI.Parameters.LinearConstraints.nVal = trGetN.FitControl.EnableConstraints? trGetN.FitControl.EnableConstraints.nVal : false;
	}
	///End SHOW_FITCONTROL_BRANCH_IN_XF_NOT_IN_PARAMDLG_BY_CP_REQUEST
	
	
	//these nodes have different path, must copy value 1 to 1	
	///Jasmine 05/20/08 REPORT_GRAPH_SHOULD_BE_BE_ABLE_TO_TURN_OFF
	//trGUI.PlotCurveTo.nVal = trGetN.result.Output.PlotCurveTo.nVal;
	trGUI.PlotCurveTo.nVal = trGetN.result.gpconfig.PlotCurveTo.nVal;
	if(PLOT_TO_NONE == trGUI.PlotCurveTo.nVal)
		trGUI.Graph1.PlotFit.nVal = false;		
	///End REPORT_GRAPH_SHOULD_BE_BE_ABLE_TO_TURN_OFF
	trGUI.PlotCurves.nVal = trGetN.result.gpconfig.Graph1.PlotCurves.nVal;
	
	
	TreeNode trAddBackBaseline = tree_get_node_by_tagname(trGetN.result, "AddBackBaseline", true);
	if(trAddBackBaseline)
		trGUI.AddBackBaseline.nVal = trAddBackBaseline.nVal && trAddBackBaseline.Show;
	
	/// Iris 11/12/2008 v8.0969 QA80-12584 OUTPUT_BASELINE_AND_SUBTRACTED_DATA_IN_FIT_PEAK_OP
	/// Hong 11/14/08 QA80-12584 v8.0971b DISABLE_OPTIONS_INSTEAD_OF_HIDDEN_IT_FOR_BASELINE_OUTPUT_OPTIONS
	/*
	TreeNode trSubtractedOutput = tree_get_node_by_tagname(trGetN.result.output, "SubtractedData", true);
	if(trSubtractedOutput)
		trGUI.Output.SubtractedData.Show = trSubtractedOutput.Show;

	TreeNode trBaselineOutput = tree_get_node_by_tagname(trGetN.result.output, "BaselineData", true);
	if(trBaselineOutput)
		trGUI.Output.BaselineData.Show = trBaselineOutput.Show;
	*/
	TreeNode		trDest = trGUI.Output;
	TreeNode		trSrc = trGetN.result.output;
	octree_copy_atts_by_id(&trSrc, &trDest, STR_SHOW_ATTRIB, STR_BACKUP_ID_ATTRIB, STR_DATAID_ATTRIB, STR_ENABLE_ATTRIB);	
	/// end DISABLE_OPTIONS_INSTEAD_OF_HIDDEN_IT_FOR_BASELINE_OUTPUT_OPTIONS
	///end OUTPUT_BASELINE_AND_SUBTRACTED_DATA_IN_FIT_PEAK_OP
}

///Jasmine 06/12/09 NANOSIZER_NEED_CENTRALIZE
//virtual
void PeakFitHelper::setBaselineRangeToOperation(TreeNode& trGUI)
{
	ASSERT(trGUI && trGUI.AddBackBaseline);
	
	///Jasmine 05/14/08 OPERATION_TREE_NEED_BASELINE_RANGE_FOR_ADD_BACK
	//if(trGUI.AddBackBaseline && true == trGUI.AddBackBaseline.nVal)	///Jasmine 05/16/08 ADD_BACK_BASELINE_TO_BOTH_FITCURVE_AND_REPORT_GRAPH
	{
		TreeNode trBaselineData = trGUI.InsertNode(trGUI.AddBackBaseline, "BaselineData");
		/// Iris 9/17/2008 NEW_PA
		//construct_treenode_from_data_context(pg, trBaselineData, PFW_BASELINE_PLOT_TAGNAME);
		XYRange xyBaseline;
		if( m_pPAWizCore->GetBaselineRange(xyBaseline) )
		{
			Tree trBaseline;
			xyBaseline.GetTree(trBaseline);
			trBaselineData.Replace(trBaseline.Clone(), true, true, true); // keep tagname, attribute for show to getn
		}
		///end NEW_PA
	}
	///End OPERATION_TREE_NEED_BASELINE_RANGE_FOR_ADD_BACK
}

//virtual 
void PeakFitHelper::prepareOutputGraph(GraphLayer& gl, TreeNode& trGUI, const TreeNode& trGetN, bool bHasBaselinePeak)
{
	/// Iris 11/17/2008 QA80-12584-P8 FIX_PROBLEMS_WHEN_RECALCULATE_NOT_PREVIEW_GRAPH
	//if(PLOT_TO_NEW_GRAPH == trGUI.PlotCurveTo.nVal && gl.IsValid())
	if(PLOT_TO_NEW_GRAPH == trGUI.PlotCurveTo.nVal )
	///end FIX_PROBLEMS_WHEN_RECALCULATE_NOT_PREVIEW_GRAPH
	{
		int uID = newOutputGraph(gl, trGetN, trGUI, bHasBaselinePeak );
		if( 0 != uID)
		{
			resetInputDataWithNewGraph( trGetN, trGUI, uID );
			updateOutputGraphNodeWithNewGraph(trGetN, uID); /// Iris 11/15/2008 v8.0972 QA80-12584_P7 FIX_ALWAYS_NEW_REPORT_GRAPH_WHEN_RECALCULATE
		}
	}
}
///End NANOSIZER_NEED_CENTRALIZE

//
//bool PeakFitHelper::getPreviewData(vector& vx, vector& vy, vector& vyCum)
//{
	//if( NULL == m_pFitSession )
		//return error_report("Found invalid Fit Session pointer");
	//
	//if(!m_pFitSession->GetInputData(vx, vy))
		//return error_report("m_pFitSession->GetInputData failed");
	//
	//return m_pFitSession->GetCumulativeData(vyCum);		
//}
//

//virtual 
/// Iris 3/09/2009 CLEANUP_TODO_CODES
//void PeakFitHelper::updatePrivateSettings(GraphLayer& gl, TreeNode& trGUI, const TreeNode& trGetN, bool bHasBaselinePeak)
void PeakFitHelper::updatePrivateSettings(TreeNode& trGUI)
///end CLEANUP_TODO_CODES
{
	trGUI.Replica.PeakCurve.nVal = trGUI.PlotCurves.nVal != PLOT_CUM_CURVE;
	trGUI.Replica.CumulativeCurve.nVal = trGUI.PlotCurves.nVal != PLOT_PEAK_CURVE;
	///Sophy 9/22/2008 NEW_PA move to beforeExecuteOperation
	/*
	if(PLOT_TO_NEW_GRAPH == trGUI.PlotCurveTo.nVal && gl.IsValid())
	{
		/// Iris 9/17/2008 NEW_PA, no need SetPlotUID here since in new fit mechanism will store Source Plot UID in NLFData object when do NLFDataBase::SetData
		//int uID = resetInputDataWithNewGraph(gl, trGetN, trGUI, bHasBaselinePeak);
		//if(uID > 0 && NULL != m_pFitSession)			
		//	m_pFitSession->SetPlotUID(uID, 0);		
		int uID = plotWithNewGraph(gl, trGetN, trGUI, bHasBaselinePeak);
		///end NEW_PA
	}
	*/
	///end Sophy NEW_PA
}

//void PeakFitHelper::updateReportSetting(Page& pg, TreeNode& trGUI, TreeNode& trGetN)
//{
	//TreeNode trInput = trGUI.InputData;
	//if(!trInput || trInput.IsEmpty())
		//ASSERT(FALSE);
	//
	//TreeNode trReport;
	//octree_get_node_by_id(&trGUI, &trReport, IDST_REPORT_SHEET_OPTIONS, true);
	//
	//if(trReport && trReport.Book)
		//trReport.Book.SetAttribute( STR_ALLOW_REPORT_TO_SOURCE_BOOK_ATTRIB, true);
		//
//#ifndef _MOVE_FIT_OUTPUT_TO_OC_CLASS /// Iris 3/26/2008 v8.0832 CLEANUP_OUTPUT_BOOK_SHEET_AREA_TO_CLASS
	//update_output_report_and_curve_setting(trGUI, get_source_page_name(trGUI));
//#else
	//OutputGUIManagerBase	OutputGUIObj(false);	
	//OutputGUIObj.UpdateOutputReportAndCurveSetting(trGUI,get_source_page_name(trGUI));
	/////Iris 4/10/2008 PEAK_FIT_REPORT_PEAK_CHARACTERISTICS_TO_SEPARATE_SHEET, always delete op after used, so this pointer cannot be keep too, waitting Jasmine fix this.
	///*
	//GET_OUTPUT_MANAGER_POINTER	pfn = Project.FindFunction("get_output_GUI_manager_pointer", "OriginLab\\wksOperation.c", true);
	//ASSERT(pfn);
	//if(pfn)
	//{
		//OutputGUIManagerBase* pOutputManager = pfn(trGUI);
		//ASSERT(pOutputManager);
		//if(pOutputManager)
			//pOutputManager->UpdateOutputReportAndCurveSetting(trGUI, get_source_page_name(trGUI));
	//}
	//*/
	/////end PEAK_FIT_REPORT_PEAK_CHARACTERISTICS_TO_SEPARATE_SHEET
//#endif //_MOVE_FIT_OUTPUT_TO_OC_CLASS	
	//
	//_copy_value_by_id(trGUI, trGetN.result, STR_DATAID_ATTRIB, STR_BACKUP_ID_ATTRIB, "Output");
//}
///---END HARD_CODE_TO_REMOVE_REPEAT_ID

////////////////////////////////////////////////////////
///SurfacePeakFitHelper/////////////////////////////////////
////////////////////////////////////////////////////////

/////Jasmine 08/22/08 REPORT_SOURCE_DATA_ROI_IN_NANOSIER
//#ifdef _NANO_H
	//#define STR_ROI_NODE	STR_ROI
//#else
	//#define STR_ROI_NODE	"ROI"
//#endif//_NANO_H
/////End REPORT_SOURCE_DATA_ROI_IN_NANOSIER
//
//#define 	NLSF_3D_FITTING_GRAPH_TEMPLATE 		"XYZ2MAT3D"//"WIREFACE"
//#define 	NLSF_MAT_FITTING_GRAPH_TEMPLATE		"CONTOUR"//"ReportMatResidual"
//
//class SurfacePeakFitHelper : public PeakFitHelper
//{
//public:
	//~SurfacePeakFitHelper()
	//{
		//ERR_MSG("~SurfacePeakFitHelper");
	//}
//public:
	////all virtual function here 
	//bool CheckGetGUITreeFromOp(TreeNode& trGUI);
	//bool RemovePreviewPlots(GraphLayer& gl);
	//void UpdatePreview(GraphLayer& gl, bool bFitCurve = true, bool bShow = true);
//private:
	////all virtual function here
	//bool createFitSessionAndPAParamInitHelper(bool bPreview);
	//void setNumberMultiplicity(const TreeNode& trPFM, TreeNode& trGUI);
	/// Iris 9/22/2008 NEW_PA
	//void afterExecuteOperation(const TreeNode& trGetN, TreeNode& trOp){}
	//void afterExecuteOperation(const TreeNode& trGetN){}
	///end NEW_PA
	//void initBaselineData(Page& pg, TreeNode& trPFM){}//do nothing
	//void updatePrivateSettings(GraphLayer& gl, TreeNode& trGUI, const TreeNode& trGetN, bool bHasBaselinePeak){}
	//bool addOtherInformation(GraphLayer& gl, Page& pg, TreeNode &trOp);//{return true;}
	//void copySettingsToOperation(const TreeNode& trGetN, TreeNode& trGUI);
	//int  getValueSettingsFromTree(const TreeNode& trParams, const TreeNode& trPFM, vector& vValues, bool& bAutoInit);
	//bool setParamValToPFMTree(Page& pg, const TreeNode& trGetN, TreeNode& trPFM);
	////bool prepareFitCurveBranch(const TreeNode& trGetN, TreeNode& trGUI){return false;}
//private:
	//bool preparePreviewGraph(GraphPage& gp, bool bFitCurve);
//};
//
////virtual 
//bool SurfacePeakFitHelper::CheckGetGUITreeFromOp(TreeNode& trGUI)
//{
	//if(PeakFitHelper::CheckGetGUITreeFromOp(trGUI))
	//{
		/////Jasmine 03/12/08 FITTED_CURVE_HIDE_NODE_NOT_WORK_FOR_SURFACE_FIT
		//if(trGUI.Graph1)
		//{
			//foreach(TreeNode trNode in trGUI.Graph1.Children)
			//{
				//if( 0 == trNode.tagName.CompareNoCase("DoPlot") )
					//continue;
				//trNode.Show = false;
			//}
		//}
		/////End FITTED_CURVE_HIDE_NODE_NOT_WORK_FOR_SURFACE_FIT
		//
		//return true;
	//}
	//return false;
//}
//
////virtual
//bool SurfacePeakFitHelper::RemovePreviewPlots(GraphLayer& gl)
//{
	//m_gpResidual.Destroy();
	//return true;
//}
////virtual
//void SurfacePeakFitHelper::UpdatePreview(GraphLayer& gl, bool bFitCurve, bool bShow)
//{
	//if(!gl)
	//{
		//error_report("GraphLayer is invalid to update preview");
		//return;
	//}
	//
	//GraphPage gp;
	//
	//if( !bFitCurve )//now only residual
	//{
		//if( bShow && !m_gpResidual )
		//{
			//preparePreviewGraph(m_gpResidual, false);
			//
			//m_pFitSession->SetFitPreviewGraph(m_gpResidual, PREVIEW_RESIDUAL);
			//
			//bool bUpdateLegend = false;
			//m_pFitSession->UpdatePreviewGraph(FITPREVIEW_REINIT, &bUpdateLegend);	///Jasmine 03/20/08 REMOVE_LEGEND_IN_PA_GRAPH
		//}
		//
		//gp = m_gpResidual;
	//}	
	//
	//if(gp)
	//{
		//int nShow = bShow? PAGE_ACTIVATE : PAGE_HIDDEN;
		//gp.SetShow(nShow);
	//}
//}
//
////virtual
//bool SurfacePeakFitHelper::createFitSessionAndPAParamInitHelper(bool bPreview)
//{
	//if( NULL == m_pFitSession && 0 == m_strOperation.CompareNoCase("FitNanoPeak"))	///Jasmine 05/13/08 NANOSIZER_NEED_CALC_PFM_PEAK_RESULTS
	//{
		//m_pFitSession = new XYZSurfaceFitSession(false, bPreview);//bool bDeleteFitCurvesOnFinish
		//m_pFitSession->SetGroupShared(true);		//------ Folger 04/23/08 SUPPORT_GROUP_SHARED_IN_NANOSIZER
	//}
	//
	//if(NULL == m_pFitSession)
		//return error_report("fail to new m_pFitSession");
	//return true;
//}
////virtual 
//void SurfacePeakFitHelper::setNumberMultiplicity(const TreeNode& trPFM, TreeNode& trGUI)
//{
	//if(trPFM && trPFM.Peaks)
	//{
		//int nPeaks = trPFM.Peaks.GetNodeCount();
		//if(trPFM.Peaks.GetNode(PFM_BASELINE_PEAK_TAG_NAME))
			//nPeaks--;
		/////Arvin 03/25/08 MOVE_REPLICA_BARANCH_OUT_OF_FIT_CONTROL_BRANCH as CP said
		////if(trGUI && trGUI.Fit && trGUI.Fit.Replica)
		////	trGUI.Fit.Replica.Number.nVal = nPeaks - 1;
		//if(trGUI && trGUI.Replica)
			//trGUI.Replica.Number.nVal = nPeaks - 1;
		/////end MOVE_REPLICA_BARANCH_OUT_OF_FIT_CONTROL_BRANCH
	//}
//}
//
////virtual 
//int SurfacePeakFitHelper::getValueSettingsFromTree(const TreeNode& trParams, const TreeNode& trPFM, vector& vValues, bool& bAutoInit)
//{	
	//PeakFitHelper::getValueSettingsFromTree(trParams, trPFM, vValues, bAutoInit);
	//
	//if(bAutoInit)
	//{
		////since XYZSurfaceFitSession has not PFM tree, Here is a tricky way to pass the PFM tree value into FitSession
		//bAutoInit	= false;
		//
		////use param value in pfm tree instead trParams of trGetN
		//vector<string> 	vsInitValues;
		//tree_get_attributes(trPFM.Peaks, vsInitValues, STR_CHANGED_ATTRIB);
		/////Jasmine 04/29/08 TRIM_WILL_REMOVE_THE_TRUE_MISSINNG_VALUE
		////if(0 < convert_str_vector_to_num_vector(vsInitValues, vValues))
		////	vValues.Trim();
		//remove_empty_item(vsInitValues);
		//convert_str_vector_to_num_vector(vsInitValues, vValues);
		/////End TRIM_WILL_REMOVE_THE_TRUE_MISSINNG_VALUE
	//}
	//
	//return vValues.GetSize();
//}
//
////virtual 
//bool SurfacePeakFitHelper::setParamValToPFMTree(Page& pg, const TreeNode& trGetN, TreeNode& trPFM)
//{
	//if(!trGetN.PFMParams || !trGetN.PFMParams.Values)
		//return false;
	//
	//TreeNode trPara = trGetN.PFMParams;
	//vector 	vParams;
	//vParams = trPara.Values.dVals;
	//
	//int nSize = vParams.GetSize();
	//int nOffset = (NULL != m_pFitSession && m_pFitSession->HasBaselinePeak())? 0 : 1;
	//int nCurrent;
	//for(int ii = 0; ; ii++)
	//{
		//string strName = "Peak" + (string)(ii+nOffset);
		//TreeNode trPeak = tree_get_node_by_tagname(trPFM, strName, true);
		//if(!trPeak.IsValid())
			//break;
		//TreeNode trParams = trPeak.GetNode("Parameters");
		//foreach( TreeNode trNode in trParams.Children )
		//{
			////since trPara has only one offset parameter, y0 or z0
			////skip offset parameter in peaks except 1st peak
			//if(0 == trNode.tagName.CompareNoCase(STR_OFFSET_PARAM_NAME_PFM) || 0 == trNode.tagName.CompareNoCase(STR_OFFSET_PARAM_NAME_SPFM))
			//{
				//if(ii > nOffset)
					//continue;
			//}
			////trNode.dVal = nCurrent < nSize? vParams[nCurrent] : NANUM;///Jasmne 10/22/07 QA70-10543 PFM_TREE_STRUCTURE_CHANGE
			//trNode.Value.dVal = nCurrent < nSize? vParams[nCurrent] : NANUM;
			//nCurrent++;
		//}
	//}
	//HWND hwnd;
	//Tree tr;
	//if(load_GetN_from_page(pg, tr,  hwnd, STR_STORAGE_NAME))
	//{
		//TreeNode trPFMInPage = tr.GetNode(PFW_TREE_TAG_NAME);//PFM_PEAKS_TREE_TAG_NAME	
		//if(trPFMInPage)
		//{
			//trPFMInPage.Replace(trPFM, true, true);
			//save_GetN_to_page(pg, tr,  hwnd, STR_STORAGE_NAME);
			//return true;
		//}
	//}
	//return false;
//}
//
//

///------ Folger 02/25/09 QA80-13181 SHARE_BASELINE_FIX_STATUS_BETWEEN_BASELINE_TREATMENT_AND_FITTING
/// virtual
void		PeakFitHelper::CheckSetBaseParamFixMode(bool* pbFixed/* = NULL*/)
{
	if ( NULL != pbFixed )
	{
		getFixBaseNode().nVal = *pbFixed;
		return;
	}
	
	vector<int>		vnFixed;
	GetFitSession()->GetParamNumericValues(vnFixed, NLPARAMGRIDCOLTYPE_FIXED);
	vector<int>		vnFixedBaseline;
	vnFixed.GetSubVector(vnFixedBaseline, 0, getNumBaselineParams() - 1);
	int		nn = 0;
	vnFixedBaseline.Sum(nn);
	
	if ( nn == 0 || nn == vnFixedBaseline.GetSize() )
	{
		getFixBaseNode().nVal = nn == 0 ? 0 : 1;
	}
}

TreeNode	PeakFitHelper::getFixBaseNode()
{
	TreeNode trGetN;
	m_pPAWizCore->GetGetN(trGetN);
	return trGetN.fixbase;
}
///------ End SHARE_BASELINE_FIX_STATUS_BETWEEN_BASELINE_TREATMENT_AND_FITTING

///------ Folger 05/12/09 NANOSIZER_FITTING_BASED_SUPPORT
/// virtual
PeakParamInitHelperBase*		PeakFitHelper::createParamInitHelper()
{
	return new PAParamInitHelper(GetFitSession());
}

/// virtual
LPCSTR							PeakFitHelper::getBaselineFuncCategory()
{
	return STR_PA_NLSF_CAT_BASELINE;
}
///------ End NANOSIZER_FITTING_BASED_SUPPORT

#endif	//_PEAK_FIT_HELPER_H
