/*------------------------------------------------------------------------------*
 * File Name:				 													*
 * Creation: 																	*
 * Purpose: OriginC Source C file												*
 * Copyright (c) ABCD Corp.	2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010		*
 * All Rights Reserved															*
 * 																				*
 * Modification Log:															*
 *	Cheney 2007-7-30 ADD_NEW_FUNC_TO_SUPPORT_PFM_LOAD_FDF						*
 *	Cheney 2007-8-1 CORRECT_LOGIC_OF_LOADING_THEME								*
 *	Jasmine 08/23/07 SPFM_NO_NEED_CALC_PFM_PEAK_RESULTS							*
 *	Cheney/Arvin 2007-9-10 XOP_NEED_SUPPORT_PFM									*
 *	Jasmine 11/05/07 SUBTRACT_BASELINE_BEFORE_PFM_FIT							*
 *	Jasmine 11/10/07 ADD_PFW_FIT_FUNCTIONS_TABLE								*
 *	Jasmine 11/14/07 FIT_BASELINE_AS_WELL_AS_OTHER_PEAKS						*
 *	Folger 11/27/07 ADD_OTHER_IMFORMATION_TABLE									*
 *	Sim 11-29-2007 ADD_INFO_INTO_REPORT_GRAPH									*
 *	Folger 12/04/07 ADD_MORE_INFO_TO_REPORT_GRAPH								*
 *	Folger 12/07/07 ADD_BASELINE_INFO_AND_FIT_INFO_TABLE						*
 *	Folger 12/08/07 LOCALIZED_PEAK_FIT_REPORT_TEXT								*
 *	Jasmine 12/17/07 SHOULD_UPDATE_PFW_TREE_AFTER_FITTING						*
 *	Jasmine 02/01/08 PLOT_TO_SOURCE_GRAPH 										*
 *	Jasmine 02/01/08 FITCURVE_POINTS_PER_PEAR									*
 *	Jasmine 03/11/08 SHOW_FITCONTROL_BRANCH_IN_XF_NOT_IN_PARAMDLG_BY_CP_REQUEST	*
 *	Jasmine 03/24/08 MAKECUSTOMTABLETHEME_REQUIRE_TREETABLE_ATTRIB_AND_NODEID	*
 *	Jasmine 03/26/08 RESERVE_ID_RANGE_FOR_REPORT_FIELD							*
 *	Jasmine 03/26/08 SAME_DEFAULT_REPORT_FIELD_ITEM_AS_75						*
 *	Folger 04/10/08 QA80-11364 OPTIMIZE_CALCULATE_OUTPUT_RESULT_FOR_PA_FIT		*
 *	Hong 04/10/08 v8.0840c PEAK_FIT_REPORT_PEAK_CHARACTERISTICS_TO_SEPARATE_SHEET
 *	Jasmine 04/15/08 GET_FITSESSION_POINTER_IN_InitFitSessionPointer			*
 *	Jasmine 04/16/08 ADD_RESIDUAL_PLOT_TO_PA_FIT								*
 *	Jasmine 04/16/08 SET_Variance_SkewExcess_DEFAULT_FALSE_BY_SANDY_REQUEST		*
 *	Jasmine 04/16/08 MODEL_SHOW_MULTI_FUNCS_OR_FITFUNC_IF_ONLY_ONE_IN_FITPEAK	*
 *	Folger 04/21/08 ADD_BASELINE_MODE_TABLE_TO_OUTPUT_REPORT					*
 *	Hong 04/22/08 v8.0847b CHANGE_DEFAULT_REPORT_ITEN_AVOID_SIMILAR_INFO		*
 *	Hong 04/22/08 v8/0847b SET_COL_DESIGNATION_OF_PEAKS_REPORT_SHEET			*
 *	Folger 04/23/08 SUPPORT_GROUP_SHARED_IN_NANOSIZER							*
 *	Folger 04/29/08 FIX_INPUT_DATA_AND_BASELINE_FAIL_TO_SHOW_IN_PA_REPORT_GRAPH	*
 *	Jasmine 05/04/08 UPDATE_COLOR_OF_BOTH_REPORT_GRAPH_AND_EMBED_GRAPH_IN_REPORT_SHEET
 *	Folger 05/04/08 FIX_ANCHOR_POINTS_TABLE_USE_NORMAL_CELL_VALUE_INSTEAD_OF_VECTOR
 *	Jack 05/04/2008 AVOID_ZERO_SIZED_VECTOR_PASS 								*
 *	Jasmine 05/13/08 NANOSIZER_NEED_CALC_PFM_PEAK_RESULTS						*
 *	Jasmine 05/14/08 dWidthAtPercent_VALUES_ARE_MISSING_IN_REPORT				*
 *	Folger 05/14/08 HIDE_BASE_MODE_TABLE_WHEN_BASELINE_IS_CONSTANT				*
 *	Folger 05/15/08 USE_FOOTNOTE_TO_REPRESENT_NUMBER_OF_ANCHOR_AND_CONNECT_FUNCTION
 *	Folger 05/16/08 IMPROVE_BASELINE_MODE_TABLE									*
 *	Jasmine 05/16/08 ADD_BACK_BASELINE_TO_BOTH_FITCURVE_AND_REPORT_GRAPH		*
 *	Jasmine 05/16/08 MOMENTS_COMPUTE_METHOD										*
 *	Jasmine 05/20/08 REPORT_GRAPH_SHOULD_BE_BE_ABLE_TO_TURN_OFF					*
 *	Jasmine 05/27/08 v8.0871 PA_PLOT_FITCURVE_ON_SRC_GRAPH_ALTHOUGH_HIDE_THIS_NODE
 *	Folger 07/16/08 FIX_BASELINE_MODE_FAIL_TO_DISPLAY_IN_REPORT_GRAPH_DUE_TO_REPORT_SHEET_NODE_CHANGE
 *	Jasmine 08/13/08 QA80-12009 PARAM_HAS_SAME_NOTATION_AS_75_FOR_MULTI_DS_AND_REPLICA_AND_PEAK
 *	Kyle 09/24/08 SET_NO_NEED_TO_LOCALIZE										*
 *	Folger 10/14/08 WRONG_NLF_CURVES_CLASS_IN_PA_MAKES_WRONG_REPORT				*
 *	Kyle 10/20/08 SHOULD_GET_BASELINE_CONDITION_FROM_NLFSESSION					*
 *	Kyle 10/21/08 CHANGE_FUNCTION_NAME_HASBASELINEPEAK_TO_GETBASELINEFITMODE	*
 *	Folger 11/06/08 QA80-12536 v8.0966 LOWER_AND_UPPER_BOUNDS_FAILS_TO_REPORT_IN_PA
 *	Sophy 11/10/2008 CLEAN_CODE_ADD_BASELINE_INFO_TO_REPORT_TABLE				*
 *  Iris 11/14/2008 TEMP_FIX_SOPHY_CODES_CAUSE_CRASH							*
 *	Hong 11/14/08 v80.971b SET_REPORT_SHEET_COL_DESIGNATION						*
 *	Hong 11/14/08 QA80-12584 v8.0971b DISABLE_OPTIONS_INSTEAD_OF_HIDDEN_IT_FOR_BASELINE_OUTPUT_OPTIONS
 *  Iris 11/15/2008 FIX_ADDBACKBASELINE_FAIL_TO_GET_BASELINE_DATA				*
 *	Hong 11/15/08 QA80-12584 v8.0972 SBUTRACTED_DATA_IS_FIT_SRC_DATA_AND_SHOULD_REPLACE_DRAW_SRC_DATA
 *	Hong 11/18/08 QA80-12584 v8.0974 PLOT_BASELINE_IN_SRC_GRAPH_IF_ADD_BACK		*
 *  Iris 11/21/2008 v8.0977c FIX_REPORT_OBJECTS_ALL_EMPTY_IF_BASELINE_FROM_EXSTING_DATA*
 *	Folger 11/21/08 v8.0977 SHOULD_NOT_OUTPUT_SUBTRACTED_DATA_AND_BASELINE_DATA_WHEN_FITTING_WITH_NO_BASELINE
 *	Sophy 11/24/2008 SET_BASELINE_PLOT_AS_BLUE_IN_REPORT_GRAPH_AS_SR4			*
 *	Sophy 11/25/2008 v8.979 SHOULD_RESCALE_REPORT_RESULT_GRAPH_AFTER_PLOT		*
 *	Kyle 11/26/2008 SUPPORT_GETTING_FIT_Y_WITHOUT_OFFSET_FOR_PA					*
 *	Sophy 12/5/2008 v8.0982 PA_REPORT_WEIGHT_INFO_IN_INPUTDATA_TABLE_AS_NLFIT	*
 *  Iris 12-09-2008 FIX_CRASH_IF_NOT_REPORT_ANY_PARAM							*
 *	Sophy 12/11/2008 v8.0985 FIX_BASELINE_MODE_FAIL_TO_DISPLAY_IN_REPORT_GRAPH_DUE_TO_REPORT_SHEET_NODE_CHANGE
 *	Folger 12/16/08 v8.0987b ONLY_PLOT_BASELINE_DATA_ON_REPORT_GRAPH_WHEN_PEAKS_NOT_FIITING_WITH_BASELINE
 *	Sandy 2008-12-17 ADD_PROGRESSBOX_AND_GIVE_USER_FEEDBACK_AND_CANCEL_WHEN_THE_PROGRESS_SLOW
 *	Hong 12/23/08 v8.0990 PA_AVOID_NESTED_LOOP_BY_CACHE_LAST_RESULT				*
 *	Folger 01/07/09 QA80-12925-P1 v8.0994b ORIGIN_CRASH_IN_PA_FITTING_WHEN_NEW_PROJECT
 *	Hong 01/13/09 v8.0995d IMPROVE_CODE_OF_MEMORY_CONSUMER_IN_PA				*
 *	Folger 01/04/09 QA80-12962 MORE_WORK_ON_GENERATE_INDIVIDUAL_FIT_CURVE_USING_INDEPENDENT_X_IN_PA
 *	Hong 01/20/09 FIX_PA_DERIVED_PARAM_NAME_NOT_CORRECT_EXCEPT_FIRST_PEAK_IN_REPORT
 *	Hong 01/22/09 FIX_PEAK_ORDER_IN_CHARACTERIZATION_FIELD_OPPOSITE				*
 *	Folger 02/03/09 PA_FITTING_WITH_BASELINE_FAILS_TO_GET_CORRECT_RESIDUAL_DATA	*
 *	Folger 02/04/09 QA80-12962 ADD_OPTION_IN_PA_FIT_TO_SWTICH_BACK_TO_OLD_FIT_CURVE_DATA_GENERATION_MECHANISM
 *	Folger 02/16/09 ADD_BACK_BASELINE_FAILS_WHEN_USING_SAMRT_XDATA_FOR_FIT_CURVE*
 *	Folger 02/23/09 PLOTTED_CURVES_FAILS_TO_CONTROL_PEAK_PLOTTING_OUTPUT_IN_REPORT_GENERATION
 *	Sophy 3/5/2009 QA80-12584 v8.0992 FIX_LOSE_SOURCE_CURVE_WHEN_FIT_FROM_GRAPH_ARRANGE_SAME_PLOTS_ON_ONE_GRAPH
 *	Folger 03/06/09 SHOULD_NOT_NEW_SHEET_IF_NO_PEAK_PROPERTIES_OUTPUT			*
 *  Iris 3/24/2009 FIX_CREATE_NEW_NLFIT_FINDXY_REPORT_WHEN_RECALCULATE			*
 *  Iris 04/14/2009 FIX_NUM_PARAMS_IN_NOTE_TABLE_IS_1							*
 *	YuI 06/23/09 QA70-13835 ORIGIN_FREEZE_AFTER_DESCRIPTIVE_STATISTICS			*
 *  Iris 6/29/2009 NEED_PEAK_NO_IN_PEAK_PROPERTIES_REPORT						*
 *	Folger 07/01/09 THEME_SAVED_IN_SR5_FAILS_TO_BE_APPLIED_AFTER_NEW_RESULTS_NODE_ADDED_IN_PA
 *  Iris 7/06/2009 ADD_PEAK_INDEX_ON_REPORT_GRAPH_SAME_AS_SR5_REPORT			*
 *	Folger 07/16/09 NANOSIZER_FAILS_TO_REPORT_PARAMETER_BOUNDS_FROM_2ND_PEAK	*
 *	Kyle 08/10/2009 QA80-14077 ADD_PARAMETER_UNIT_TO_FITTING_REPORT				*
 *	Folger 09/24/09 SHOW_FUNCTION_NAME_IN_REPORT_NOTES_TABLE_WHEN_PA_FITTING_WITH_ONE_SAME_FUNCTION
 *	Folger 10/28/09 QA81-14552 WRONG_REPORT_STATUS_WHEN_CHANGE_PARAM_IN_PA		*
 *  Iris 10/28/2009 QA81-14546 CHANGE_GUI_REPORT_TABLE_LABEL					*
 *	Sophy 11/9/2009 GET_OUTPUT_NODE_BY_BACKUPID_WHEN_FAIL_BY_DATAID				*
 *	Kenny 12/24/2009 QA81-14875-P2 PROGRESS_BAR_IN_BUILTIN_TOOL_SHOULD_NOT_KEEP_TOPMOST*
 *  Iris 2/24/2010 QA81-15140 FIT_NOT_CONVERGE_BAD_PARAM_VALUE_CAUSE_BAD_REPORT	*
 *	Folger 03/24/10 QA81-15237 GENERATE_FITY_BASED_ON_BASELINE_FOR_BETTER_PEAK_PROPERTIES_CALCULATION
 *------------------------------------------------------------------------------*/
 
// Right-click on the line below and select 'Open "Origin.h"' to open the Origin.h
// system header file.
#include <Origin.h>
////////////////////////////////////////////////////////////////////////////////////


////////////////////////////////////////////////////////////////////////////////////
// Include your own header files here.

#include "FitCommon.h"
#include "pa_utils.h" ///Sophy 11/10/2008 CLEAN_CODE_ADD_BASELINE_INFO_TO_REPORT_TABLE use baseline mode
#include "PFM_utils.h"
#include "curve_utils.h"
//#include "MulFuncsFitSession.h"//"NLFitSession.h"	///Jasmine 11/07/07 MOVE_MULFUNC_FITSESSION_TO_SEPARATE_FILE
#include "NLFitSession.h"
#include "FitNL.h"
#include "PeakFitHelperBase.h"		///------ Folger 01/07/09 QA80-12925-P1 v8.0994b ORIGIN_CRASH_IN_PA_FITTING_WHEN_NEW_PROJECT
#include "FitPeak.h"
///Cheney/Arvin 2007-9-10 XOP_NEED_SUPPORT_PFM
#ifdef _FOR_SMART_LOADING_ONLY
#include "nlsf_utils.h" 
#include "grobj_utils.h"
#include <XFGraph_Utils.h>
#include <event_utils.h>
#include <report_utils.h>
//#include "blpwiz.h"
#include "wksOperation.h"
#include "analysis_utils.h"
#include <stats_utils.h>
#include "stats_guis.h"
#include "stats_operations.h"
#include "graph_utils.h" //---- Iris 11/19/2008 v8.0975 QA80-12591-P2 FIX_APPARENT_FIT_ON_GRAPH_CUSTOM_RANGE_GET_INCORRECT_X
#endif
///end XOP_NEED_SUPPORT_PFM

///------ Folger 01/07/09 QA80-12925-P1 v8.0994b ORIGIN_CRASH_IN_PA_FITTING_WHEN_NEW_PROJECT
//#include "PeakFitCurves.h"	//------ Folger 10/14/08 WRONG_NLF_CURVES_CLASS_IN_PA_MAKES_WRONG_REPORT
///------ End ORIGIN_CRASH_IN_PA_FITTING_WHEN_NEW_PROJECT

//------ Folger 04/29/08 FIX_INPUT_DATA_AND_BASELINE_FAIL_TO_SHOW_IN_PA_REPORT_GRAPH
#define STR_BASELINE_MODE_CONSTATNT_TAGNAME			"Y"
#define STR_BASELINE_MODE_ANCHOR_TAGNAME			"Anchor"
//------ Folger 07/16/08 FIX_BASELINE_MODE_FAIL_TO_DISPLAY_IN_REPORT_GRAPH_DUE_TO_REPORT_SHEET_NODE_CHANGE
//#define STR_BASELINE_MODE_CONNECT_TAGNAME			"Connect"
#define STR_BASELINE_MODE_FUNCTION_ATTRIB			"Function"
//------
#define STR_BASELINE_MODE_ANCHOR_POINTS_TAGNAME		"AnchorPoints"
#define STR_BASELINE_MODE_EXIST_DATASET_TAGNAME		"IDTC2"
//------ End FIX_INPUT_DATA_AND_BASELINE_FAIL_TO_SHOW_IN_PA_REPORT_GRAPH
#define STR_BASELINE_MODE_XPS_METHOD_TAGNAME		"Method"  /// Iris 11/18/2008 PA_FIT_SUPPORT_NEW_BASELINE_MODE_XPS

///Kyle 10/10/08 CLEAN_PFW_TREE_MOVE_CODE_FROM_PFM_UTILS
#define _IDEAL_PEAK_PARAMS_TAGNAME	    "Params"
#define _IDEAL_PEAK_CENTER_MAX_TAGNAME	"CenterMax"
#define _IDEAL_PEAK_CENTROID_X_TAGNAME 	"CenterGrvty"
#define _IDEAL_PEAK_HEIGHT_MAX_TAGNAME 	"MaxHeight"
#define _IDEAL_PEAK_FWHM_TAGNAME      	"FWHM"
///End CLEAN_PFW_TREE_MOVE_CODE_FROM_PFM_UTILS

//#define DEFAULT_FIELD_NUM 	7
//enum{PLOT_PEAK_CURVE, PLOT_CUM_CURVE, PLOT_ALL_CURVE};/// Iris 9/17/2008 NEW_PA move to PFM_utils.h

static bool _operation_output_peak_character_book_event(TreeNode& tr, int nRow, int nType, Dialog& Dlg)
{
	PeakFitOutputGUIManager*	pOutputGUIObj = (PeakFitOutputGUIManager*)get_output_GUI_manager_pointer(tr);
	if( NULL != pOutputGUIObj)
		return pOutputGUIObj->OnPeakCharacterBookChanged(tr);
	return false;
}
 
FitPeak::FitPeak()
{
	m_pPeakFitHelper = NULL;	///------ Folger 01/07/09 QA80-12925-P1 v8.0994b ORIGIN_CRASH_IN_PA_FITTING_WHEN_NEW_PROJECT
	m_bNeedCalculatePeakResults = true;		///------ Folger 03/06/09 SHOULD_NOT_NEW_SHEET_IF_NO_PEAK_PROPERTIES_OUTPUT
}

FitPeak::~FitPeak()
{
	///------ Folger 01/07/09 QA80-12925-P1 v8.0994b ORIGIN_CRASH_IN_PA_FITTING_WHEN_NEW_PROJECT
	if ( m_pPeakFitHelper )
		m_pPeakFitHelper->ResetOperationPtr();
	///------ End ORIGIN_CRASH_IN_PA_FITTING_WHEN_NEW_PROJECT
}

///Jasmine 05/27/08 v8.0871 PA_PLOT_FITCURVE_ON_SRC_GRAPH_ALTHOUGH_HIDE_THIS_NODE
//virtual
bool	FitPeak::IsPlotOnSourceGraph(TreeNode& trOp, int nGraphIndex)// = -1
{
	if(trOp && trOp.GUI && trOp.GUI.PlotCurveTo && PLOT_TO_NONE == trOp.GUI.PlotCurveTo.nVal)
		return false;
		
	if(GRAPH_FIT_CURVE == nGraphIndex)
	{
		TreeNode trGraph = GetGUIGraphNodes(trOp, nGraphIndex);
		if(trGraph && trGraph.PlotFit && DISABLE != trGraph.PlotFit.Enable)
			return tree_is_true(trGraph.PlotFit);
	}
	
	return FitNL::IsPlotOnSourceGraph(trOp, nGraphIndex);
}
///End PA_PLOT_FITCURVE_ON_SRC_GRAPH_ALTHOUGH_HIDE_THIS_NODE

/// Iris 11/12/2008 v8.0969 QA80-12584 OUTPUT_BASELINE_AND_SUBTRACTED_DATA_IN_FIT_PEAK_OP
static bool _fit_peak_output_book_sheet_name_changed(TreeNode& tr, int nRow, int nCol, TreeNode& trNode, DWORD dwCntrl, int nType, WndContainer& theDlg)
{	
	if( !(dwCntrl & GETNEVENT_ON_INIT) || dwCntrl & GETNEVENT_ON_THEME )
	{	
		PeakFitOutputGUIManager*	pOutputGUIObj = (PeakFitOutputGUIManager*)get_output_GUI_manager_pointer(tr);
		if( NULL != pOutputGUIObj)
			return pOutputGUIObj->OnBookSheetNameChanged(trNode);
	}
	return false;
}

static bool _fit_peak_output_subtracted_book_event(TreeNode& tr, int nRow, int nType, Dialog& Dlg)
{
	PeakFitOutputGUIManager*	pOutputGUIObj = (PeakFitOutputGUIManager*)get_output_GUI_manager_pointer(tr);
	if( NULL != pOutputGUIObj)
		return pOutputGUIObj->OnSubtractedBookChanged(tr);
	return false;
}

static bool _fit_peak_output_subtracted_sheet_event(TreeNode& tr, int nRow, int nType, Dialog& Dlg)
{
	PeakFitOutputGUIManager*	pOutputGUIObj = (PeakFitOutputGUIManager*)get_output_GUI_manager_pointer(tr);
	if( NULL != pOutputGUIObj)
		return pOutputGUIObj->OnSubtractedSheetChanged(tr);
	return false;
}

static bool _fit_peak_output_baseline_book_event(TreeNode& tr, int nRow, int nType, Dialog& Dlg)
{
	PeakFitOutputGUIManager*	pOutputGUIObj = (PeakFitOutputGUIManager*)get_output_GUI_manager_pointer(tr);
	if( NULL != pOutputGUIObj)
		return pOutputGUIObj->OnBaselineBookChanged(tr);
	return false;
}

static bool _fit_peak_output_baseline_sheet_event(TreeNode& tr, int nRow, int nType, Dialog& Dlg)
{
	PeakFitOutputGUIManager*	pOutputGUIObj = (PeakFitOutputGUIManager*)get_output_GUI_manager_pointer(tr);
	if( NULL != pOutputGUIObj)
		return pOutputGUIObj->OnBaselineSheetChanged(tr);
	return false;
}
///end OUTPUT_BASELINE_AND_SUBTRACTED_DATA_IN_FIT_PEAK_OP

//virtual
BOOL    FitPeak::Construct(TreeNode& trOperation, int nOption)
{
	/*
	if( WksReportOperation::Construct(trOperation, nOption) )
	{
		TreeNode	trGUI = ConstructAddGUI(trOperation);
		tree_construct_add_input_branch(trGUI, GetDataMode());
		
		constructFitSettings(trGUI);
		
		constructAddFitQuantitiesToCompute(trGUI);		
		
		//initFitSessionPointer(trOperation);
		
		return TRUE;
	}
	*/	
	if( FitNL::Construct(trOperation, nOption) )
	{
		TreeNode trGUI = trOperation.GUI;
		
		//constructFitSettings(trGUI);	///Jasmine 03/11/08 SHOW_FITCONTROL_BRANCH_IN_XF_NOT_IN_PARAMDLG_BY_CP_REQUEST
		
		constructReportOptions(trGUI);
		constructReportFieldOptions(trGUI);
		
		constructOutputOptions(trGUI);///Iris 4/10/2008 PEAK_FIT_REPORT_PEAK_CHARACTERISTICS_TO_SEPARATE_SHEET
		
		GETN_USE(trGUI)
		///Jasmine 02/01/08 PLOT_TO_SOURCE_GRAPH, change default value by requst
		/*1/23 - Bld 793c - ...	by default, the final cumulative curve should be put into the graph they started with. 
		User may not want the more advanced report graph. And really odd to see nothing in the graph one starts with (ER, bld 791b) */
		///Jasmine 05/20/08 REPORT_GRAPH_SHOULD_BE_BE_ABLE_TO_TURN_OFF
		//GETN_LIST(PlotCurveTo, _L("Plot Fitted Curves To"),  1, _L("<Source Graph>|<New Graph>")) GETN_ID(IDE_PFM_PLOT_CURVE_TO)
		GETN_LIST(PlotCurveTo, _L("Create Report Graph"),  PLOT_TO_NEW_GRAPH, REPORT_GRAPH_DESTINATION_LIST) GETN_ID(IDE_PFM_PLOT_CURVE_TO)
		///End REPORT_GRAPH_SHOULD_BE_BE_ABLE_TO_TURN_OFF
		///End PLOT_TO_SOURCE_GRAPH
		GETN_LIST(PLotCurves, _L("Plot Curves"), PLOT_ALL_CURVE, _L("Individual Peak Curve|Cumulative Curve|Both"))	GETN_ID(IDE_PFM_PLOT_CURVES)
		GETN_CHECK(AddBackBaseline, _L("Add Back Baseline"), false) 							GETN_ID(IDE_PFM_ADD_BASELINE)
			GETN_CURRENT_SUBNODE.Show = false;	
			
		modifyFitCurveOptions(trGUI);	///Jasmine 02/01/08 FITCURVE_POINTS_PER_PEAR
		
		return TRUE;
	}
	
	return FALSE;
}

/// Iris 3/26/2008 v8.0832 CLEANUP_OUTPUT_BOOK_SHEET_AREA_TO_CLASS
bool	FitPeak::InitOutputGUIManagerPointer(const TreeNode& trGUI)
{
	if(m_pOutputManager)//already init
		return true;
	
	//------ Folger 04/23/08 SUPPORT_GROUP_SHARED_IN_NANOSIZER
	//m_pOutputManager = new PeakFitOutputGUIManager;
	Tree	trOp;
	GetTree(trOp);
	switch ( GetFitType(trOp) )
	{
	case NLFIT_XYZ_FITTING:
		m_pOutputManager = new SurfaceFitOutputGUIManager;
		break;
	
	default:
		m_pOutputManager = new PeakFitOutputGUIManager;
		break;	
	}
	//------ End SUPPORT_GROUP_SHARED_IN_NANOSIZER

	if(NULL == m_pOutputManager)
		return false;	
	return true;
}
///END CLEANUP_OUTPUT_BOOK_SHEET_AREA_TO_CLASS

	
///Jasmine 11/08/07 ADD_SHARED_TO_PARAMETER_REPORT_TABLE
//virtual 
void	FitPeak::FilterFittingGUI(TreeNode& trOp) 
{
	FitNL::FilterFittingGUI(trOp);	
		
	vector<int> vnNodesToHide = {IDE_REPLICA_NUM, IDE_REPLICA_FROM_NTH_PARAM, IDE_NUM_OF_PARAMS_IN_REPLICA, IDE_FIT_PLOT_TYPE, IDE_FIT_PLOT_FIT_CURVE, IDE_FIT_SET_COLOR};
	// IDE_FIT_SHOW_MARKER in vnNodesToHide initial list caused compile error, need to put into #ifdef ... #endif
	#ifdef	MARKER_VISIBILITY_OPTIONS
	vnNodesToHide.Add(IDE_FIT_SHOW_MARKER);
	#endif //	MARKER_VISIBILITY_OPTIONS
	tree_set_attributes(trOp.GUI, vnNodesToHide, "0");

	vector<int> vnNodesToShow = {IDE_PARAM_SHARED};
	tree_set_attributes(trOp.GUI, vnNodesToShow, "1");
	tree_set_int_value_by_id(trOp.GUI, IDE_PARAM_SHARED, true);
	
	tree_set_int_value_by_id(trOp.GUI, IDE_RESIDUAL_REGULAR, false);		///Jasmine 04/16/08 ADD_RESIDUAL_PLOT_TO_PA_FIT, uncheck by Max request
}
///End ADD_SHARED_TO_PARAMETER_REPORT_TABLE
void	FitPeak::OnAfterCreateReport(TreeNode &trOp, Worksheet& wksReport, DataRange& rngInput, DataRange &rgReportSheetOutput, int nExeMode, bool bNewResultBookCreatedHidden, int nTotalNumData)
{
	FitNL::OnAfterCreateReport(trOp, wksReport, rngInput, rgReportSheetOutput, nExeMode, bNewResultBookCreatedHidden, nTotalNumData);
	if(wksReport)
	{
		OGRIDLIMITS limits;
		limits.col.nMin = 6000;//auto resize column width to fit content
		limits.col.nMax = 6000;
		limits.row.nMin = -1;
		limits.row.nMax = -1;
		wksReport.AutoSize(AS_NOHEIGHT, 0, &limits);	
		
		limits.col.nMin = -1;
		wksReport.AutoSize(AS_NOHEIGHT, 0, &limits);
	}
}
///Jasmine 11/08/07 ADD_SHARED_TO_PARAMETER_REPORT_TABLE
void 	FitPeak::ParameterGetShared(vector<int>& vnShared)
{
	//m_pFitSession->GetParamsSettingIntVector(vnShared, PARMAS_SETTING_SHARE);
	GetFitSession()->GetParamNumericValues(vnShared, PARMAS_SETTING_SHARE);
}
///End ADD_SHARED_TO_PARAMETER_REPORT_TABLE
///Jasmine 11/07/07 ADD_PEAK_NUMBER_TO_PFM_PARAMETERS		
/// Hong 12/23/08 v8.0990 PA_AVOID_NESTED_LOOP_BY_CACHE_LAST_RESULT
//bool	FitPeak::GetPeakNumber(int nIndex, int& nPeakNo, bool& bFuncFirstParam)
bool	FitPeak::GetPeakNumber(int nIndex, int& nPeakNo, bool& bFuncFirstParam, int* pnLastPeakNoWithoutOffset/* = NULL*/, int* pnLastPeaksNum/* = NULL*/)
/// end PA_AVOID_NESTED_LOOP_BY_CACHE_LAST_RESULT
{
	int nPeakOffset = nPeakNo;
	bFuncFirstParam = false;
	int nPeaks = GetFitSession()->GetNumPeaks();
	/// Hong 12/23/08 v8.0990 PA_AVOID_NESTED_LOOP_BY_CACHE_LAST_RESULT
	//for(int nPeak = 0, nNumParas = 0; nPeak < nPeaks; nPeak++)
	int 		nPeak = 0, nNumParas = 0;
	bool		bHasLastResult = false;
	if ( NULL != pnLastPeakNoWithoutOffset && NULL != pnLastPeaksNum && -1 != *pnLastPeakNoWithoutOffset && -1 != *pnLastPeaksNum )
	{
		nPeak = *pnLastPeakNoWithoutOffset;
		nNumParas = *pnLastPeaksNum;		
		bHasLastResult = true;
	}
	for( ; nPeak < nPeaks; nPeak++)
	/// end PA_AVOID_NESTED_LOOP_BY_CACHE_LAST_RESULT
	{
		bFuncFirstParam = nIndex == nNumParas;
		/// Hong 12/23/08 v8.0990 PA_AVOID_NESTED_LOOP_BY_CACHE_LAST_RESULT
		//nNumParas += GetFitSession()->GetNumParameter(nPeak) + GetFitSession()->GetDerivedParamNum(nPeak);
		if ( !(bHasLastResult && nPeak == *pnLastPeakNoWithoutOffset) )
			nNumParas += GetFitSession()->GetNumParameter(nPeak) + GetFitSession()->GetDerivedParamNum(nPeak);
		/// end PA_AVOID_NESTED_LOOP_BY_CACHE_LAST_RESULT
		if(nIndex < nNumParas)
		{
			nPeakNo = nPeak + nPeakOffset;
			/// Hong 12/23/08 v8.0990 PA_AVOID_NESTED_LOOP_BY_CACHE_LAST_RESULT
			if ( NULL != pnLastPeakNoWithoutOffset )
				*pnLastPeakNoWithoutOffset = nPeak;
			if ( NULL != pnLastPeaksNum )
				*pnLastPeaksNum = nNumParas;
			/// end PA_AVOID_NESTED_LOOP_BY_CACHE_LAST_RESULT
			break;
		}
	}
	return true;
}
///End ADD_PEAK_NUMBER_TO_PFM_PARAMETERS

///Sophy 7/9/2008 CLEAN_CODE_FIX_FAIL_TO_GET_INPUT_OUT_DATA_NODE_IN_OUTPUTGUIMANAGER
//virtual
TreeNode	FitPeak::GetInputDataNode( const TreeNode& trGUI )
{
	TreeNode trInput = FitNL::GetInputDataNode( trGUI );
	if( !trInput )
		trInput = trGUI.InputData;
	///Sophy 10/9/2008 FIX_FAIL_TO_GET_OUTPUT_MANAGER_AND_OPERATION_POINTER_IN_OUTPUT_EVENT
	if( !trInput )
		trInput = tree_get_node_by_tagname( trGUI, "InputData", true );
	///end FIX_FAIL_TO_GET_OUTPUT_MANAGER_AND_OPERATION_POINTER_IN_OUTPUT_EVENT
	ASSERT( trInput );
	return trInput;
}

//virtual
TreeNode	FitPeak::GetOutputNode( const TreeNode& trGUI )
{
	TreeNode trOutput =FitNL::GetOutputNode( trGUI );
	///Sophy 11/9/2009 GET_OUTPUT_NODE_BY_BACKUPID_WHEN_FAIL_BY_DATAID
	if ( !trOutput && trGUI )
	{
		///Sophy 11/10/2009 IMPROVE_CODE_TO_GET_OP_GUI_OUTPUT_NODE
		//trOutput = trGUI.FindNodeByAttribute(STR_BACKUP_ID_ATTRIB, IDST_OUTPUT_RESULTS_OPTIONS, true ); //find Output treenode recursively
		trOutput = trGUI.Output;
		///end IMPROVE_CODE_TO_GET_OP_GUI_OUTPUT_NODE
	}
	///end GET_OUTPUT_NODE_BY_BACKUPID_WHEN_FAIL_BY_DATAID
	if( !trOutput )
	{
		TreeNode trResult = trGUI.result;
		if( !trResult )
			trResult = trGUI.XFGUI.result;
		
		trOutput = trResult.Output;
	}
	
	return trOutput;
}
///end CLEAN_CODE_FIX_FAIL_TO_GET_INPUT_OUT_DATA_NODE_IN_OUTPUTGUIMANAGER

///Jasmine 11/05/07 SUBTRACT_BASELINE_BEFORE_PFM_FIT
//virtual 
void 	FitPeak::CumulativeSubtractBaseline(const vector vx, vector& vCumulate, int nNum, double dY0)
{
	///Kyle 10/21/08 CHANGE_FUNCTION_NAME_HASBASELINEPEAK_TO_GETBASELINEFITMODE
	//if(!GetFitSession()->HasBaselinePeak())///Jasmine 12/08/07 ZERO_OFFSET_IF_FIT_WITH_BASELINE
	if(!GetFitSession()->GetBaselineFitMode())///Jasmine 12/08/07 ZERO_OFFSET_IF_FIT_WITH_BASELINE
	///End CHANGE_FUNCTION_NAME_HASBASELINEPEAK_TO_GETBASELINEFITMODE
		FitNL::CumulativeSubtractBaseline(vx, vCumulate, nNum, dY0);
	vector vXBaseline, vYBaseline;
	/// Iris 10/21/2008 FITSESSION_NEED_GETBASELINEDATA_FOR_REPORT
	//GetFitSession()->GetBaselineData(vXBaseline, vYBaseline);
	GetNLFCurvePointer()->GetBaselineData(vXBaseline, vYBaseline);
	///end FITSESSION_NEED_GETBASELINEDATA_FOR_REPORT
	if(vXBaseline.GetSize() && vYBaseline.GetSize())
	{		
		vector vTemp;
		vTemp = vYBaseline * nNum;		
		subtract_baseline(vx, vCumulate, vXBaseline, vTemp);
	}
}
///End SUBTRACT_BASELINE_BEFORE_PFM_FIT
static bool _enable_constraints_event(TreeNode& tr, int nRow, int nCol, TreeNode& trNode, DWORD dwCntrl, int nType, WndContainer& theDlg)
{
	TreeNode trEnable = tree_get_node(tr, nRow);
	if( !trEnable )
		return false;
	
	TreeNode trConstraints = tree_get_node_by_dataid(tr, IDE_PFM_CONSTRAINTS, true);
	if(trConstraints)
	{
		trConstraints.Enable = trEnable.nVal;
		return true;
	}
	return false;

}

static bool _enable_disable_next_node(TreeNode& tr, int nRow, int nCol, TreeNode& trNode, DWORD dwCntrl, int nType, WndContainer& theDlg)
{
	TreeNode trCurrentNode = tree_get_node(tr, nRow);
	if( !trCurrentNode )
		return false;
	
	TreeNode trNextNode = trCurrentNode.NextNode;
	if(trNextNode)
	{
		trNextNode.Enable = trCurrentNode.nVal;
	}
	return true;
	
}

///Jasmine 03/11/08 SHOW_FITCONTROL_BRANCH_IN_XF_NOT_IN_PARAMDLG_BY_CP_REQUEST
/*void	FitPeak::constructFitSettings(TreeNode& trGUI)
{
	GETN_USE(trGUI)
	GETN_BEGIN_BRANCH(FitControl, _L("Fit Control"))	GETN_ID_BRANCH(IDE_PFM_FIT_CONTROLS) GETN_OPTION_BRANCH(GETNBRANCH_OPEN)
		GETN_COMBO(Iter, _L("Iterations"), 100, "2|5|10|20|30|50|100|200") GETN_ID(IDE_PFM_MAX_ITERATIONS)
		GETN_COMBO(Tolerance, _L("Tolerance"), 1e-9, "|1e-15|1e-14|1e-12|1e-10|1e-9|1e-6") GETN_ID(IDE_PFM_TOLERANCE)
		//GETN_NUM(Conf, _L("Confidence"), 0.95) GETN_ID(IDE_PFM_CONFIDENCE)
		//GETN_NUM(Prediction, _L("Prediction"), 0.95) GETN_ID(IDE_PFM_PREDICTION)
		GETN_CHECK(FixPara, _L("Fix Baseline Parameters"), true) GETN_ID(IDE_PFM_FIX_BASELINE_PARAM)
		
		//GETN_LIST(Weight, _L("Weight Method"), 0, _L("no weight|ststistical"))  GETN_ID(IDE_PFM_WEIGHT_METHOD)
		
		GETN_CHECK(EnableConstraints, _L("Enable Constraints"), true)  GETN_ID(IDE_PFM_ENABLE_CONSTRAINTS)  GETN_OPTION_EVENT_EX(_enable_constraints_event)
		
		GETN_MULTILINE_TEXT(Constraints, _L("Constraints"), "")	GETN_ID(IDE_PFM_CONSTRAINTS) GETN_MUTILINE_EDIT_ROLLUP_BUTTON
			GETN_OPTION_DISPLAY_FORMAT(DISPLAY_EDITOR_WRAPPED)
			GETN_MULTILINE_EDIT_DISPLAY_ROW_HEIGHT_RANGE("3-20")
			
	GETN_END_BRANCH(FitControl)
}*/
///End SHOW_FITCONTROL_BRANCH_IN_XF_NOT_IN_PARAMDLG_BY_CP_REQUEST

void 	FitPeak::constructReportOptions(TreeNode& trGUI)
{
	GETN_USE(trGUI)	
	GETN_BEGIN_BRANCH(PeakReport, STR_PEAK_CHARACTERISTICS_REPORT)	GETN_ID_BRANCH(IDE_PFM_REPORT_BRANCH)
		/// Iris 07/23/2007 REMOVE_PLOT_OPTIONS on Sandy's suggestion
		/*
		GETN_BEGIN_BRANCH(ReportGraph, _L("Plot Option")) GETN_ID_BRANCH(IDE_PFM_PLOT_REPORT_BRANCH) GETN_ID_REPEAT_BRANCH(1)
			constructPeakReportOptionTree(GETN_CURRENT_NODE, true);
		GETN_END_BRANCH(ReportGraph)
		
		GETN_BEGIN_BRANCH(ReportSheet, _L("Worksheet Option")) GETN_ID_BRANCH(IDE_PFM_WKS_REPORT_BRANCH) GETN_ID_REPEAT_BRANCH(2)
			constructPeakReportOptionTree(GETN_CURRENT_NODE);
		GETN_END_BRANCH(ReportSheet)
		*/
		constructPeakReportOptionTree(GETN_CURRENT_NODE);	
		//end REMOVE_PLOT_OPTIONS
	GETN_END_BRANCH(PeakReport)	
		
}
void 	FitPeak::constructReportFieldOptions(TreeNode& trGUI)
{
	GETN_USE(trGUI)
	GETN_BEGIN_BRANCH(PeakReportField, STR_PEAK_CHARACTERISTICS_FIELDS)	GETN_ID_BRANCH(IDE_PFM_REPORT_FIELD_BRANCH)
		constructPeakReportFieldTree(trGUI, GETN_CURRENT_NODE);	
	GETN_END_BRANCH(PeakReportField)	
		
}

///Iris 4/10/2008 PEAK_FIT_REPORT_PEAK_CHARACTERISTICS_TO_SEPARATE_SHEET
void 	FitPeak::constructOutputOptions(TreeNode& trGUI)
{
	/// Iris 4/17/2008 INSERT_PEAK_CHAR_NODE_BEFORE_FIT_CURVE
	//GETN_USE(trGUI.Output)
	
	//GETN_BEGIN_BRANCH(PeakCharacter, STR_OUTPUT_PEAKS_TABLE_TO) GETN_ID_BRANCH(IDST_PFM_REPORT_PEAK_CHAR_TO)
	
	TreeNode	trOutput = tree_get_node_by_tagname(trGUI, "Output", true); // in PA GUI, tree struct is trGetN.result.Output
	ASSERT(trOutput);
	
	TreeNode	trPeakCharacter;
	string		strTagname = "PeakCharacter";
	int			nID = TRGP_BRANCH;
	if(trOutput.Data)
	{
		trPeakCharacter = trOutput.InsertNode(trOutput.Data, strTagname, nID);
	}
	else
	{
		trPeakCharacter = trOutput.AddNode(strTagname, nID);
	}
	trPeakCharacter.SetAttribute(STR_LABEL_ATTRIB, STR_OUTPUT_PEAKS_TABLE_TO);	
	trPeakCharacter.DataID = IDST_PFM_REPORT_PEAK_CHAR_TO;
	
	
	GETN_USE(trOutput)
	GETN_BEGIN_USE_BRANCH(PeakCharacter)
	///end INSERT_PEAK_CHAR_NODE_BEFORE_FIT_CURVE
		GETN_STRLIST(Book, _L("Book"), STR_REPORT,  STR_PEAKFIT_PEAK_CHARACTER_BOOK_COMBO ) 		GETN_ID(IDE_PFM_REPORT_PEAK_CHAR_TO_BOOK) GETN_OPTION_EVENT(_operation_output_peak_character_book_event)
		GETN_STR(BookName, _L("Book Name"), E_STR_PEAK_CHARACTER_BOOK_SHORT_NAME) 		GETN_ID(IDE_PFM_REPORT_PEAK_CHAR_TO_BOOKNAME) 
		GETN_STRLIST(Sheet, _L("Sheet"), STR_NEW,  STR_TOKEN_SEP + STR_NEW) 		GETN_ID(IDE_PFM_REPORT_PEAK_CHAR_TO_SHEET) 
		GETN_CURRENT_SUBNODE.Enable = false;
		GETN_STR(SheetName, _L("Sheet Name"), STR_PEAK_CHARACTER_SHEET) 		GETN_ID(IDE_PFM_REPORT_PEAK_CHAR_TO_SHEETNAME)
	/// Iris 4/17/2008 INSERT_PEAK_CHAR_NODE_BEFORE_FIT_CURVE
	//GETN_END_BRANCH(PeakCharacter)
	GETN_END_USE_BRANCH(PeakCharacter)	
	///end INSERT_PEAK_CHAR_NODE_BEFORE_FIT_CURVE
	
	/// Iris 11/12/2008 v8.0969 QA80-12584 OUTPUT_BASELINE_AND_SUBTRACTED_DATA_IN_FIT_PEAK_OP
	GETN_BEGIN_BRANCH(SubtractedData, STR_OUTPUT_SUBTRACTED_DATA_TABLES) GETN_ID_BRANCH(IDE_PFM_OUTPUT_SUBTRACTED_DATA_TO) 
		GETN_STRLIST(Book, _L("Book"), STR_FIT_CURVE,  STR_FIT_CURVE + STR_TOKEN_SEP + STR_NEW + STR_TOKEN_SEP + STR_CUSTOM + STR_THREE_DOTS) GETN_ID(IDE_PFM_SUBTRACTED_DATA_BOOK)  GETN_OPTION_EVENT(_fit_peak_output_subtracted_book_event)
		GETN_STR(BookName, _L("BookName"), _L("")) GETN_ID(IDE_PFM_SUBTRACTED_DATA_BOOK_NAME) GETN_OPTION_EVENT_EX(_fit_peak_output_book_sheet_name_changed)
		GETN_STR(NameForNew, _L(""), _L("")) GETN_ID(IDE_PFM_SUBTRACTED_DATA_BOOK_OLD_NAME) GETN_CURRENT_SUBNODE.Show = false;

		GETN_STRLIST(Sheet, _L("Sheet"), STR_NEW,  STR_NEW + STR_TOKEN_SEP + STR_CUSTOM + STR_THREE_DOTS) GETN_ID(IDE_PFM_SUBTRACTED_DATA_SHEET) GETN_OPTION_EVENT(_fit_peak_output_subtracted_sheet_event)
		GETN_STR(SheetName, _L("SheetName"), _L("")) GETN_ID(IDE_PFM_SUBTRACTED_DATA_SHEET_NAME) GETN_OPTION_EVENT_EX(_fit_peak_output_book_sheet_name_changed)/// Iris 3/28/2008 v8.0829 QA80-10934 ADD_EDITBOX_TO_SPECIFICATION_BOOK_SHEET_NAME_AFTER_CLEAN_OUTPUT_GUI_CODES
		GETN_STR(NameForNew, _L(""), _L("")) GETN_ID(IDE_PFM_SUBTRACTED_DATA_SHEET_OLD_NAME) GETN_CURRENT_SUBNODE.Show = false;
	GETN_END_BRANCH(SubtractedData)
		
	GETN_BEGIN_BRANCH(BaselineData, STR_OUTPUT_BASELINE_DATA_TABLES) GETN_ID_BRANCH(IDE_PFM_OUTPUT_BASELINE_DATA_TO) 
		GETN_STRLIST(Book, _L("Book"), STR_FIT_CURVE,  STR_FIT_CURVE + STR_TOKEN_SEP + STR_NEW + STR_TOKEN_SEP + STR_CUSTOM + STR_THREE_DOTS) GETN_ID(IDE_PFM_BASELINE_DATA_BOOK) GETN_OPTION_EVENT(_fit_peak_output_baseline_book_event)		 	
		GETN_STR(BookName, _L("BookName"), _L("")) GETN_ID(IDE_PFM_BASELINE_DATA_BOOK_NAME) GETN_OPTION_EVENT_EX(_fit_peak_output_book_sheet_name_changed)
		GETN_STR(NameForNew, _L(""), _L("")) GETN_ID(IDE_PFM_BASELINE_DATA_BOOK_OLD_NAME) GETN_CURRENT_SUBNODE.Show = false;

		GETN_STRLIST(Sheet, _L("Sheet"), STR_FIT_CURVE,  STR_FIT_CURVE + STR_TOKEN_SEP + STR_NEW + STR_TOKEN_SEP + STR_CUSTOM + STR_THREE_DOTS) GETN_ID(IDE_PFM_BASELINE_DATA_SHEET) GETN_OPTION_EVENT(_fit_peak_output_baseline_sheet_event)
		GETN_STR(SheetName, _L("SheetName"), _L("")) GETN_ID(IDE_PFM_BASELINE_DATA_SHEET_NAME) GETN_OPTION_EVENT_EX(_fit_peak_output_book_sheet_name_changed)/// Iris 3/28/2008 v8.0829 QA80-10934 ADD_EDITBOX_TO_SPECIFICATION_BOOK_SHEET_NAME_AFTER_CLEAN_OUTPUT_GUI_CODES
		GETN_STR(NameForNew, _L(""), _L("")) GETN_ID(IDE_PFM_BASELINE_DATA_SHEET_OLD_NAME) GETN_CURRENT_SUBNODE.Show = false;
	GETN_END_BRANCH(BaselineData)
	///end OUTPUT_BASELINE_AND_SUBTRACTED_DATA_IN_FIT_PEAK_OP

}
///END PEAK_FIT_REPORT_PEAK_CHARACTERISTICS_TO_SEPARATE_SHEET	

///Jasmine 02/01/08 FITCURVE_POINTS_PER_PEAR
/*1/23 - Bld 793c - The fit curve we generate and plot seems to be fixed to 100 points which is bad. If user has lot more points in raw 
dataset, the fit curve looks like a very bad fit even though the fit was really successful. ..*/
void 	FitPeak::modifyFitCurveOptions(TreeNode& trGUI)
{
	TreeNode trGraph1, trXDataType, trN;
	trGraph1 = trGUI.Graph1;
	if(trGraph1)
		trXDataType = trGraph1.XDataType;
	if(trXDataType)
		trN = trXDataType.N;
	if(trN)
	{
		trXDataType.Use = FIT_CURVE_UNIFORM_LINEAR;
		octree_set_auto_support(&trN);
	}
}
///End FITCURVE_POINTS_PER_PEAR
void 	FitPeak::constructPeakReportFieldTree(const TreeNode trGUI, TreeNode &tr)
{
	string strCombo;
	///Jasmine 03/26/08 SAME_DEFAULT_REPORT_FIELD_ITEM_AS_75
	vector<int> vnDefaultFieldIDs = {	IDE_PFM_PKC_PEAKNUM,  /// Iris 7/06/2009 ADD_PEAK_INDEX_ON_REPORT_GRAPH_SAME_AS_SR5_REPORT
										IDE_PFM_PKC_PEAKTYPE, 
										IDE_PFM_PKC_AREA_INTEGRATE, 
										IDE_PFM_PKC_FWHM, 
										IDE_PFM_PKC_MAXHEIGHT, 
										IDE_PFM_PKC_CENTERGRAVITY, 
										IDE_PFM_PKC_AREA_INTEGRATE_P };
	int nDefaultFieldCount = vnDefaultFieldIDs.GetSize();
	
	vector<int> vnDefaultIndexes;
	vnDefaultIndexes.SetSize(nDefaultFieldCount);
	vnDefaultIndexes = 0;
										
	if(trGUI && trGUI.PeakReport)
	{
		m_trReportCombo.Reset();	//------ Folger 04/10/08 QA80-11364 OPTIMIZE_CALCULATE_OUTPUT_RESULT_FOR_PA_FIT
		
		int ii = 0;
		foreach(TreeNode trNode in trGUI.PeakReport.Children)
		{
			int nID = trNode.DataID;
			if(IDE_PFM_PKC_WIDTHAT_PERCENT == nID || IDE_PFM_PKC_AREAABOVE_PERCENT == nID || IDE_PFM_PKC_CUMAREA_PERCENT == nID || IDE_PFM_PKC_MOMENT_METHOD == nID)	///Jasmine 05/16/08 MOMENTS_COMPUTE_METHOD
				continue;
			
			string strLabel;
			trNode.GetAttribute(STR_LABEL_ATTRIB, strLabel);
			strCombo += strLabel + "|";
			
			//------ Folger 04/10/08 QA80-11364 OPTIMIZE_CALCULATE_OUTPUT_RESULT_FOR_PA_FIT
			TreeNode trNode = m_trReportCombo.AddNode("Item" + ii);
			trNode.DataID = nID;
			//------
			
			vector<uint> vecIndex;
			if( 0 < vnDefaultFieldIDs.Find(vecIndex, nID) )
				vnDefaultIndexes[ vecIndex[0] ] = ii;
			
			ii++;
		}
		if(!tree_get_node_by_id(trGUI.PeakReport, IDE_PFM_PKC_PEAKNUM, true))
		{
			strCombo = _L("Peak Number") + "|" + strCombo;
			vnDefaultIndexes = vnDefaultIndexes + 1;
			vnDefaultIndexes.InsertAt(0, 0);
			nDefaultFieldCount++;
			//------ Folger 04/10/08 QA80-11364 OPTIMIZE_CALCULATE_OUTPUT_RESULT_FOR_PA_FIT
			TreeNode trNode = m_trReportCombo.InsertNode(m_trReportCombo.FirstNode, "PeakNum");
			trNode.DataID = IDE_PFM_PKC_PEAKNUM;
			//------
		}
	}
	strCombo = _L("Display Nothing") + "|" + strCombo;
	
	//------ Folger 04/10/08 QA80-11364 OPTIMIZE_CALCULATE_OUTPUT_RESULT_FOR_PA_FIT
	TreeNode trNode = m_trReportCombo.InsertNode(m_trReportCombo.FirstNode, "Nothing");
	//------

	strCombo.TrimLeft("|");
	strCombo.TrimRight("|");
	vnDefaultIndexes = vnDefaultIndexes + 1;
	
	vector<string> vsItems;
	int nCount = strCombo.GetTokens(vsItems, '|') - 1;//exclude "Display Nothing"
	if(0 == nCount)
		return;
	
	ASSERT(IDE_PFM_REPORT_FIELD_END - IDE_PFM_REPORT_FIELD_BEGIN >= nCount);	///Jasmine 03/26/08 RESERVE_ID_RANGE_FOR_REPORT_FIELD
	
	for(int ii = 0; ii < nCount; ii++)
	{
		int nIndex = ii + 1;
		TreeNode trField = tree_check_get_node(tr, "field" + (string)nIndex, TRGP_ENUM_LIST, STR_LABEL_ATTRIB, _L("Peak report field") + (string)nIndex);
		trField.SetAttribute(STR_COMBO_ATTRIB, strCombo);
		trField.nVal = ii < nDefaultFieldCount ? vnDefaultIndexes[ii] : 0;
		trField.DataID = IDE_PFM_REPORT_FIELD_BEGIN + ii;	///Jasmine 03/26/08 RESERVE_ID_RANGE_FOR_REPORT_FIELD
	}
	///End SAME_DEFAULT_REPORT_FIELD_ITEM_AS_75
}

/// Iris 07/23/2007 REMOVE_PLOT_OPTIONS on Sandy's suggestion
//void 	FitPeak::constructPeakReportOptionTree(TreeNode &tr, bool bReportGraph)// = false
void 	FitPeak::constructPeakReportOptionTree(TreeNode &tr)
{
	/// Iris 07/23/2007 REMOVE_PLOT_OPTIONS on Sandy's suggestion
	/*
	if(bReportGraph) 
	{
		TreeNode trPeakNum = tr.AddNumericNode(1, "PeakNum", TRGP_CHECK);
		trPeakNum.SetAttribute(STR_LABEL_ATTRIB, _L("Peak Number"));
		trPeakNum.DataID = IDE_PFM_PKC_PEAKNUM;
	*/
	///end REMOVE_PLOT_OPTIONS		
		/// Iris 6/29/2009 NEED_PEAK_NO_IN_PEAK_PROPERTIES_REPORT, Joe(US) suggest add peak number back
		TreeNode trPeakNum = tr.AddNumericNode(1, "PeakNum", TRGP_CHECK);
		trPeakNum.SetAttribute(STR_LABEL_ATTRIB, _L("Peak Index"));
		trPeakNum.DataID = IDE_PFM_PKC_PEAKNUM;	
		///------ Folger 07/01/09 THEME_SAVED_IN_SR5_FAILS_TO_BE_APPLIED_AFTER_NEW_RESULTS_NODE_ADDED_IN_PA
		trPeakNum.SetAttribute(STR_DELAY_DATAID_ASSIGN_ATTRIB, PA_DELAY_DATAID_ASSIGN_VER3);
		///------ End THEME_SAVED_IN_SR5_FAILS_TO_BE_APPLIED_AFTER_NEW_RESULTS_NODE_ADDED_IN_PA
		///end NEED_PEAK_NO_IN_PEAK_PROPERTIES_REPORT
		
		TreeNode trPeakType = tr.AddNumericNode(1, "PeakType", TRGP_CHECK);
		trPeakType.SetAttribute(STR_LABEL_ATTRIB, _L("Peak Function Type"));
		trPeakType.DataID = IDE_PFM_PKC_PEAKTYPE;		
	/// Iris 07/23/2007 REMOVE_PLOT_OPTIONS on Sandy's suggestion
	//}
	///end REMOVE_PLOT_OPTIONS
	
	GETN_USE(tr)
		
		GETN_CHECK(AreaFit, _L("Fitted Peak Area"), 1) 											GETN_ID(IDE_PFM_PKC_AREAFIT)
    	GETN_CHECK(AreaFitTruncated, _L("Fitted Peak Area Contained in Fitting Range"), 1) 		GETN_ID(IDE_PFM_PKC_AREAFIT_TRUNCATED)
    	GETN_CHECK(AreaFitPercentage, _L("Fitted Peak Area Contained in Fitting Range(%)"), 1)	GETN_ID(IDE_PFM_PKC_AREAFIT_PERCENTAGE)
    	/// Hong 04/22/08 v8.0847b CHANGE_DEFAULT_REPORT_ITEN_AVOID_SIMILAR_INFO
   		//GETN_CHECK(AreaIntegrate, _L("Peak Area by Integrating Data"), 1) 						GETN_ID(IDE_PFM_PKC_AREA_INTEGRATE)
    	//GETN_CHECK(AreaIntegrateP, _L("Peak Area by Integrating Data(%)"), 1) 					GETN_ID(IDE_PFM_PKC_AREA_INTEGRATE_P)
    	GETN_CHECK(AreaIntegrate, _L("Peak Area by Integrating Data"), 0) 						GETN_ID(IDE_PFM_PKC_AREA_INTEGRATE)
    	GETN_CHECK(AreaIntegrateP, _L("Peak Area by Integrating Data(%)"), 0) 					GETN_ID(IDE_PFM_PKC_AREA_INTEGRATE_P)
    	/// end CHANGE_DEFAULT_REPORT_ITEN_AVOID_SIMILAR_INFO
    	GETN_CHECK(CenterMax, _L("Location for Peak Maximum Height"), 1) 						GETN_ID(IDE_PFM_PKC_CENTERMAX)
    	GETN_CHECK(CenterGravity, _L("Peak Gravity Center"), 1) 								GETN_ID(IDE_PFM_PKC_CENTERGRAVITY)
    	GETN_CHECK(MaxHeight, _L("Peak Maximum Height"), 1) 									GETN_ID(IDE_PFM_PKC_MAXHEIGHT)
    	GETN_CHECK(FWHM, _L("Full Width @ Half Maximum"), 1) 									GETN_ID(IDE_PFM_PKC_FWHM)
    	
    	/// Hong 04/22/08 v8.0847b CHANGE_DEFAULT_REPORT_ITEN_AVOID_SIMILAR_INFO
   		//GETN_CHECK(Resolution, _L("Resolution with Next Adjacent Peak"), 1 ) 					GETN_ID(IDE_PFM_PKC_RESOLUTION)
   		GETN_CHECK(Resolution, _L("Resolution with Next Adjacent Peak"), 0) 					GETN_ID(IDE_PFM_PKC_RESOLUTION)
   		/// end CHANGE_DEFAULT_REPORT_ITEN_AVOID_SIMILAR_INFO
    	
    	GETN_CHECK(WidthAt, _L("Width At"), 0 ) 												GETN_ID(IDE_PFM_PKC_WIDTHAT) 
    		GETN_OPTION_EVENT_EX(_enable_disable_next_node)
    	GETN_NUM(WidthAtPercent, _L("Width At(% of Peak Maximum)"), 10) 						GETN_ID(IDE_PFM_PKC_WIDTHAT_PERCENT)
    	
    	GETN_CHECK(AreaAbove, _L("Area above"), 0 ) 											GETN_ID(IDE_PFM_PKC_AREAABOVE) 
    		GETN_OPTION_EVENT_EX(_enable_disable_next_node)
    	GETN_NUM(AreaAbovePercent, _L("Area above(% of Peak Maximum)"), 10) 					GETN_ID(IDE_PFM_PKC_AREAABOVE_PERCENT)
    	
    	GETN_CHECK(CumArea, _L("Cumulative Area to"), 0 )										GETN_ID(IDE_PFM_PKC_CUMAREA) 
    		GETN_OPTION_EVENT_EX(_enable_disable_next_node)
    	GETN_NUM(CumAreaPercent, _L("Cumulative Area to(Relative to Center)"), 0) 				GETN_ID(IDE_PFM_PKC_CUMAREA_PERCENT)
    	
    	///Jasmine 05/16/08 MOMENTS_COMPUTE_METHOD
    	GETN_CHECK(Variance, _L("Peak Variance"), 0) 											GETN_ID(IDE_PFM_PKC_VARIANCE)				///Jasmine 04/16/08 SET_Variance_SkewExcess_DEFAULT_FALSE_BY_SANDY_REQUEST									GETN_ID(IDE_PFM_PKC_CUMAREA) 
    		GETN_OPTION_EVENT_EX(pa_fit_enable_disable_MomentMethod_node)
    	GETN_CHECK(Skew, _L("Peak Skew"), 0) 													GETN_ID(IDE_PFM_PKC_SKEW)
    		GETN_OPTION_EVENT_EX(pa_fit_enable_disable_MomentMethod_node)
    	GETN_CHECK(Excess, _L("Peak Excess"), 0) 												GETN_ID(IDE_PFM_PKC_EXCESS)
    		GETN_OPTION_EVENT_EX(pa_fit_enable_disable_MomentMethod_node)
    	GETN_CHECK(Moment3,  _L("3rd Order Moment"), 0) 										GETN_ID(IDE_PFM_PKC_MOMENT3)
    		GETN_OPTION_EVENT_EX(pa_fit_enable_disable_MomentMethod_node)
    	GETN_CHECK(Moment4, _L("4th Order Moment"), 0 ) 										GETN_ID(IDE_PFM_PKC_MOMENT4)
   			GETN_OPTION_EVENT_EX(pa_fit_enable_disable_MomentMethod_node)
    	
    	GETN_LIST(MomentMethod, _L("Moments' Computation Method"), MOMENT_METHOD_NUM_INTEGRAL, _L("Speed Mode(Numeric Integral)|Accurate Mode(Function Integral)"))	
    																							GETN_ID(IDE_PFM_PKC_MOMENT_METHOD)
    	///End MOMENTS_COMPUTE_METHOD
}

void FitPeak::InitFitSessionPointer(TreeNode& trOperation)
{
	///Jasmine 04/15/08 GET_FITSESSION_POINTER_IN_InitFitSessionPointer
	bool bUseExisting = false;
	
	if(trOperation && trOperation.FitWorkArea && trOperation.FitWorkArea.FitPointer)
		bUseExisting = true;
	
	if(bUseExisting)
	{
		FitNL::InitFitSessionPointer(trOperation);
		return;
	}
	///End GET_FITSESSION_POINTER_IN_InitFitSessionPointer
	CleanupFitSession("InitFitSessionPointer");
	
	//m_pFitSession = new MulFuncsFitSession(false);
	bool	bSingleFunc = false;
	m_pFitSession = new NLFitSession(bSingleFunc);

}

//MulFuncsFitSession* FitPeak::GetFitSession()
//{
	//return m_pFitSession;
//}

////virtual
//// Got runtime error in FitNL::OperationtoGUI, so overload.
//BOOL	FitPeak::OperationtoGUI(TreeNode& trOperation, bool bInit, string* pstrSelTheme, bool bSetDefaultInputOnInit) //=NULL, = true
//{
	//return TRUE;
//}

bool 	FitPeak::beforeCalcMultiData(TreeNode& trOp)
{
	///---Jasmine 01/17/08 duplicated code, already done in other place
	//TreeNode trOpParams = trOp.GUI.AddNode("Parameters");
	//TreeNode trConstraints = trOpParams.AddNode("LinearConstraints");
	//trConstraints.Replace(trOp.GUI.FitControl.EnableConstraints.Clone(), true, true);	
	//trOp.GUI.Codes.Constraints.strVal = trOp.GUI.FitControl.Constraints.strVal;
	//
	//trOp.GUI.Fit.Iterations.MaxNum.nVal = trOp.GUI.FitControl.Iter.nVal;
	//trOp.GUI.Fit.Iterations.Tolerance.dVal = trOp.GUI.FitControl.Tolerance.dVal;
	///---end
	
	// init data mode to Global Fit
	trOp.GUI.InputData.Use = MDINPUT_INDEPENDENT_CONSOLID; //MDINPUT_GLOBAL_FIT;

	///Jasmine 04/15/08 GET_FITSESSION_POINTER_IN_InitFitSessionPointer
	/*//get FitSession pointer from trOp
	TreeNode trFitPointer = trOp.FitWorkArea.GetNode(STR_FIT_POINTER);
	if(trFitPointer)
	{
		DWORD dw = trFitPointer.nVal;
		m_pFitSession = (NLFitSession*)dw;
	}*/
	///End GET_FITSESSION_POINTER_IN_InitFitSessionPointer

	return true;
}

///---Sim 11-29-2007 ADD_INFO_INTO_REPORT_GRAPH
//TreeNode FitPeak::getInfoPeaksFromPageStorage(GraphPage& gp)
//{
	//TreeNode tr;
	//return tr;
//}

#define PREFIX_PEAK_CONTROL_FIELD	"PKCFIELD"

bool 	FitPeak::addInfoToReportGraph(const TreeNode trResult, const TreeNode trFields, GraphLayer& gl)
{
	if ( !gl || !trResult || !trFields )
		return false;
	
	for(int nIndexField = 0; nIndexField < trFields.GetNodeCount(); nIndexField++)
	{
		TreeNode trField = trFields.Children.Item(nIndexField);
		ASSERT(trField);
		
		string strControl = PREFIX_PEAK_CONTROL_FIELD + (nIndexField+1);
		GraphObject go = gl.GraphObjects(strControl);
		if ( !go )
			return error_report("Peak info graph object don't exist in graph layer!");
											
		int nIndexItem = trField.nVal - 1;
		if ( nIndexItem >= 0 )
		{
			for(int nIndexPeak = 0; nIndexPeak < trResult.GetNodeCount(); nIndexPeak++)
			{
				TreeNode trPeak = trResult.Children.Item(nIndexPeak);
				ASSERT(trPeak);
				
				TreeNode trItem = trPeak.Children.Item(nIndexItem);
				if ( !trItem )
					return error_report("Peak info item index out of range!");
				
				if ( 0 == nIndexPeak )
				{
					string strLabel;
					trItem.GetAttribute(STR_LABEL_ATTRIB, strLabel);
					go.Text = strLabel;
				}
				string strValue;
				if(0 != trItem.tagName.CompareNoCase("PeakNum") && 0 != trItem.tagName.CompareNoCase("PeakType"))
					strValue = ftoa(round(trItem.dVal, 5));
				else
					strValue = trItem.strVal;
				go.Text += "\r\n" + strValue;
			}				
		}
	}
	
	return true;
}
///---END ADD_INFO_INTO_REPORT_GRAPH

//------ Folger 12/04/07 ADD_MORE_INFO_TO_REPORT_GRAPH

static void _add_info_to_report_graph(const TreeNode &trInput, LPCSTR lpcszsTagName, GraphLayer &gl, LPCSTR lpcszObjectName, LPCSTR lpcszSheetName, LPCSTR lpcszDisplayName, bool bRound = false)
{
	GraphObject go = gl.GraphObjects(lpcszObjectName);
	if (!go)
		return;
	
	TreeNode trNode = tree_get_node_by_tagname(trInput, lpcszsTagName, true);
				
	string strPath, strValue;
	if ( !trNode )
		strPath = lpcszsTagName;
	else
		tree_get_level(trNode, strPath);
	//go.Text = (string)lpcszDisplayName + " %(" + lpcszSheetName + ",@WL," + strPath + ")";
	strValue.Format("%s(%s,@WL,%s)", "%", lpcszSheetName, strPath);
	if(bRound)
		strValue.Format("$(%s, %s9.5E)", strValue, "%");
	go.Text = (string)lpcszDisplayName + strValue;
}

bool 	FitPeak::addMoreInfoToReportGraph(const TreeNode &trCalculation, GraphLayer& gl)
{
	Tree tr;
	int nUID;
	trCalculation.GetAttribute(TREE_UID, nUID);
	Datasheet ds;
	Project.GetReportTree(tr, nUID, ds);
	if (!ds)
		return false;
	string strSheet = okutil_make_book_sheet_string(ds.GetPage().GetName(), ds.GetName());
	
	//------ Folger 12/08/07 LOCALIZED_PEAK_FIT_REPORT_TEXT
	//add Text
	GraphObject go = gl.GraphObjects("Text");
	if ( go )
	{
		string str;
		ocu_load_msg_str(PEAK_FIT_REPORT_TEXT, &str);
		go.Text = str;
	}
	//-------
	
	//data set
	TreeNode trInputData = tree_get_node_by_tagname(trCalculation, "Input", true);
	if ( trInputData )
	{
		trInputData = trInputData.Clone();
		_add_info_to_report_graph(trInputData, "IDTC2", gl, "rPkData", strSheet, _L("Data Set:"));
	}
	
	//------ Folger 04/29/08 FIX_INPUT_DATA_AND_BASELINE_FAIL_TO_SHOW_IN_PA_REPORT_GRAPH
	/*
	//base line
	TreeNode trBaseline = tree_get_node_by_tagname(trCalculation, "Baseline", true);
	if ( trBaseline && trBaseline.FirstNode )
	{
		trBaseline = trBaseline.Clone();
		_add_info_to_report_graph(trBaseline, "Y_DATA", gl, "Text1", strSheet, _L("BaseLine:"));
	}
	*/
	
	//base line
	TreeNode trBaseline = tree_get_node_by_tagname(trCalculation, "Baseline", true);
	if ( trBaseline )
	{
		trBaseline = trBaseline.Clone();
		TreeNode trConstant = trBaseline.GetNode(STR_BASELINE_MODE_CONSTATNT_TAGNAME);
		//------ Folger 07/16/08 FIX_BASELINE_MODE_FAIL_TO_DISPLAY_IN_REPORT_GRAPH_DUE_TO_REPORT_SHEET_NODE_CHANGE
		//TreeNode trConnect = trBaseline.GetNode(STR_BASELINE_MODE_CONNECT_TAGNAME);
		TreeNode trAnchor = trBaseline.GetNode(STR_BASELINE_MODE_ANCHOR_POINTS_TAGNAME);
		//--- Iris 11/21/2008 v8.0977c FIX_REPORT_OBJECTS_ALL_EMPTY_IF_BASELINE_FROM_EXSTING_DATA
		//if( !trAnchor )
		//	return error_report("Fail to find treenode " + STR_BASELINE_MODE_ANCHOR_POINTS_TAGNAME + " in FitPeak::addMoreInfoToReportGraph");
		//---
		
		string	strFunction;
		//------
		string strTagName;
		if ( trConstant )
		{
			strTagName = STR_BASELINE_MODE_CONSTATNT_TAGNAME;
		}
		//------ Folger 07/16/08 FIX_BASELINE_MODE_FAIL_TO_DISPLAY_IN_REPORT_GRAPH_DUE_TO_REPORT_SHEET_NODE_CHANGE
		/// because the baseline report table node has changed for user defined mode(which intended to fix a bug when Expand/Collapse
		/// the report table, it became messed up), that makes baseline graph object in report graph fail to display correct info,
		/// so a workaround is needed here which just put a static fit function name text here instead of a link to report table node,
		/// since fit function name info are all in footnotes inside report table
		/*
		else if ( trConnect )
		{
			strTagName = STR_BASELINE_MODE_CONNECT_TAGNAME;
		}
		*/
		//--- Iris 11/21/2008 v8.0977c FIX_REPORT_OBJECTS_ALL_EMPTY_IF_BASELINE_FROM_EXSTING_DATA
		//else if ( trAnchor.GetAttribute(STR_BASELINE_MODE_FUNCTION_ATTRIB, strFunction) )
		else if ( trAnchor && trAnchor.GetAttribute(STR_BASELINE_MODE_FUNCTION_ATTRIB, strFunction) )
		//---
		{
			GraphObject goTmp = gl.GraphObjects("Text1");
			if ( goTmp )
				goTmp.Text = _L("Baseline:") + strFunction;
		}
		//------ End FIX_BASELINE_MODE_FAIL_TO_DISPLAY_IN_REPORT_GRAPH_DUE_TO_REPORT_SHEET_NODE_CHANGE
		///Sophy 12/11/2008 v8.0985 FIX_BASELINE_MODE_FAIL_TO_DISPLAY_IN_REPORT_GRAPH_DUE_TO_REPORT_SHEET_NODE_CHANGE
		else if ( trBaseline.Method ) //XPS mode
		{
			strTagName = STR_BASELINE_MODE_XPS_METHOD_TAGNAME;
		}
		///end FIX_BASELINE_MODE_FAIL_TO_DISPLAY_IN_REPORT_GRAPH_DUE_TO_REPORT_SHEET_NODE_CHANGE
		else
		{
			strTagName = STR_BASELINE_MODE_EXIST_DATASET_TAGNAME;
		}
		//------ Folger 07/16/08 FIX_BASELINE_MODE_FAIL_TO_DISPLAY_IN_REPORT_GRAPH_DUE_TO_REPORT_SHEET_NODE_CHANGE
		if ( !strTagName.IsEmpty() )
		//------
			_add_info_to_report_graph(trBaseline, strTagName, gl, "Text1", strSheet, _L("BaseLine:"));
	}
	//------ End FIX_INPUT_DATA_AND_BASELINE_FAIL_TO_SHOW_IN_PA_REPORT_GRAPH
	else
	{
		GraphObject go = gl.GraphObjects("Text1");
		if (go)
			go.Text = "";
	}
	
	//Statistics
	TreeNode trRegStats = tree_get_node_by_tagname(trCalculation, "RegStats", true);
	if ( trRegStats )
	{
		trRegStats = trRegStats.Clone();
		_add_info_to_report_graph(trRegStats, "ReducedChiSq", gl, "Text6", strSheet, _L("Chi^2="), true);
		_add_info_to_report_graph(trRegStats, "AdjRSq", gl, "Text2", strSheet, _L("Adj. R-Square="), true);
		_add_info_to_report_graph(trRegStats, "N", gl, "Text3", strSheet, _L("# of Data Points="));
		///Kyle 09/24/08 SET_NO_NEED_TO_LOCALIZE
		//_add_info_to_report_graph(trRegStats, "SSR", gl, "Text5", strSheet, _L("SS="), true);
		_add_info_to_report_graph(trRegStats, "SSR", gl, "Text5", strSheet, "SS=", true);
		///End SET_NO_NEED_TO_LOCALIZE
		_add_info_to_report_graph(trRegStats, "DOF", gl, "Text4", strSheet, _L("Degree of Freedom="));
	}
	
	return true;
}

///Sophy 11/25/2008 v8.979 SHOULD_RESCALE_REPORT_RESULT_GRAPH_AFTER_PLOT
//virtual
void 	FitPeak::RescaleReportGraph(TreeNode& trOp, GraphLayer& gl, int nGraphIndex, int nPicRowIndex, int nPicColIndex, int nFirstFittedPlotIndex)
{
	FitNL::RescaleReportGraph(trOp, gl, nGraphIndex, nPicRowIndex, nPicColIndex, nFirstFittedPlotIndex);
	gl.Rescale();
}
///end SHOULD_RESCALE_REPORT_RESULT_GRAPH_AFTER_PLOT

//virtual
bool FitPeak::UpdateSourceGraphFromReport(TreeNode& trOp, const DataRange &rReportSheetOutput, int nTotalNumData, int nExeMode)
{
	/// Hong 11/18/08 QA80-12584 v8.0974 PLOT_BASELINE_IN_SRC_GRAPH_IF_ADD_BACK
	///------ Folger 12/16/08 v8.0987b ONLY_PLOT_BASELINE_DATA_ON_REPORT_GRAPH_WHEN_PEAKS_NOT_FIITING_WITH_BASELINE
	//if ( IsOutputBaselineDataSheet(trOp) )
	/// YuI 06/23/09 QA70-13835 ORIGIN_FREEZE_AFTER_DESCRIPTIVE_STATISTICS
	//	if ( !GetFitSession()->GetBaselineFitMode() && IsOutputBaselineDataSheet(trOp) )
	if ( !GetFitSession()->GetBaselineFitMode() && (REPORT_CREATE == IsOutputBaselineDataSheet(trOp)) )
	/// end ORIGIN_FREEZE_AFTER_DESCRIPTIVE_STATISTICS
	///------ End ONLY_PLOT_BASELINE_DATA_ON_REPORT_GRAPH_WHEN_PEAKS_NOT_FIITING_WITH_BASELINE
	{
		ASSERT(1 == nTotalNumData);
		int				nDataIndex = 0;
		DataPlot 		dp = GetSourceDataPlot(nDataIndex, trOp);
		if ( dp )
		{
			GraphLayer 		glSource;
			dp.GetParent(glSource);
			DataRange		drBaselineData;
			Datasheet		dsBaselineData;							
			if ( GetOutput(drBaselineData, dsBaselineData, GetOutputSlot(nDataIndex, true, OUTPUT_RESULT_BASELINE_DATA_SHEET)) )
			{
				DWORD		dwRules = GetDataRules(trOp);
				int			nPlot = plot_data_range(drBaselineData, glSource, IDM_PLOT_LINE, GAP_USE_TEMPLATE, NULL, true, &dwRules);
				DataPlot	dpAdded;
				if ( nPlot >= 0 )
				{
					dpAdded = glSource.DataPlots(nPlot);
					dpAdded.SetColor(SYSCOLOR_BLUE); // Hong, hardcoded as SR4
				}
			}
		}		
	}
	/// end PLOT_BASELINE_IN_SRC_GRAPH_IF_ADD_BACK
	bool bRet = WksReportOperation::UpdateSourceGraphFromReport(trOp, rReportSheetOutput, nTotalNumData, nExeMode);
	///Jasmine 05/20/08 REPORT_GRAPH_SHOULD_BE_BE_ABLE_TO_TURN_OFF
	//bool bPlotToNewGraph = 0 != trOp.GUI.PlotCurveTo.nVal;
	//if(bPlotToNewGraph)
	if(PLOT_TO_NEW_GRAPH == trOp.GUI.PlotCurveTo.nVal)
	///End REPORT_GRAPH_SHOULD_BE_BE_ABLE_TO_TURN_OFF
	{
		GraphLayer glSource;
		DataPlot dp = GetSourceDataPlot(0, trOp);
		if(dp) dp.GetParent(glSource);
		if(glSource)
		{
			GraphLayer gl = glSource.GetPage().Layers(1);//PKREPORT.otp
			if(gl)
			{
				addMoreInfoToReportGraph(trOp.Calculation, gl);
			}
			glSource.Rescale();///Sophy 11/25/2008 v8.979 SHOULD_RESCALE_REPORT_RESULT_GRAPH_AFTER_PLOT if report to new graph in pa, should recale it
		}
	}	
	return true;			///Jasmine 05/16/08 ADD_BACK_BASELINE_TO_BOTH_FITCURVE_AND_REPORT_GRAPH
	TreeNode trAddBackBaseline = tree_get_node_by_tagname(trOp, "AddBackBaseline", true);
	if(trAddBackBaseline && 0 != trAddBackBaseline.nVal)
	{
		GraphLayer glSource;
		DataPlot dp = GetSourceDataPlot(0, trOp);
		if(dp) dp.GetParent(glSource);
		TreeNode trInputData = tree_get_node_by_tagname( trOp, "Input", true );
		if ( trInputData )
		{
			TreeNode trColX = tree_get_node_by_tagname( trInputData, "IDTC1", true );
			TreeNode trColY = tree_get_node_by_tagname( trInputData, "IDTC2", true );
			if ( trColX && trColY )
			{	
				int nPlotType = dp.GetPlotType();
				Tree tr;
				tr = dp.GetFormat();			
				dp.Destroy();
				XYRange xy;
				xy.Add("X", trColX.strVal);
				xy.Add("Y", trColY.strVal);
				if (check_has_plotted_in_graph(xy, glSource) == 0)
				{
					int nIndex = glSource.AddPlot(xy, nPlotType);
					dp = glSource.DataPlots(nIndex);
					if (dp)
						dp.ApplyFormat(tr);
				}					
			}
		}
		
		///Jasmine 05/14/08 OPERATION_TREE_NEED_BASELINE_RANGE_FOR_ADD_BACK
		//vector 	vBaselineX, vBaselineY;
		int		nBLPlotType;
		Tree 	trBaselineFormat;
		XYRange xyBL;
		if(trOp.GUI.BaselineData)
		{
			TreeNode trBaselineData = trOp.GUI.BaselineData;
			if( okxf_resolve_tree_construct_range(&trBaselineData, &xyBL) )
				//xyBL.GetData(vBaselineY, vBaselineX);
		}
		///End OPERATION_TREE_NEED_BASELINE_RANGE_FOR_ADD_BACK
		
		DataRange rgOut;
		Worksheet wksOut;
		GetOutput(rgOut, wksOut, OUTPUT_RESULT_CURVE_SHEET_RNG_INDEX);
		if(!wksOut)//no fitted data output
			return bRet;
		string strSheetName = wksOut.GetName();
		
		/*Page pg = GetSourcePageName(trOp);
		int nIndex;
		if (pg)
			nIndex = pg.AddLayer(STR_FIT_CURVE_ADD_BASELINE_WKS);
		Worksheet wks = pg.Layers(nIndex);
		
		if (wks)
		{
			
			TreeNode trFitCurves;
			if(trOp.ResultCurves)
				trFitCurves = tree_get_node_by_tagname(trOp.ResultCurves, "FitCurves", true);
			if(trFitCurves)
			{							
				Dataset dsFitX;
					vector vFitX;
				wks.SetSize(-1, trFitCurves.GetNodeCount());
				int nPlot = -1;
				int nCol = 0;
					
				foreach(TreeNode trFit in trFitCurves.Children)
				{
					string strCurves;
					if(0 != trFit.tagName.CompareNoCase("FitX"))
					{
							trFit.GetAttribute(STR_LABEL_ATTRIB, strCurves);
							nPlot = find_plot_index_by_key(glSource, strCurves, strSheetName, nPlot);
							DataPlot dp = glSource.DataPlots(nPlot);
							if (dp)
								{
									if (0 == strCurves.CompareNoCase("Baseline"))
									{
										nBLPlotType = dp.GetPlotType();
										trBaselineFormat = dp.GetFormat();
									}
								dp.Destroy();
								}
							if (0 == strCurves.CompareNoCase("Baseline"))
								continue;
					}
					else
					{
						dsFitX.Attach(wks, nCol);
						dsFitX = trFit.dVals;
						vFitX = dsFitX;
						++nCol;
						continue;
					}		
					Column col(wks, nCol);
					col.SetLongName(strCurves);
					Dataset ds(col);
					ds = trFit.dVals;
					vector vTmp(ds);
					subtract_baseline(vFitX, vTmp, vBaselineX, -vBaselineY);
					ds = vTmp;
					++nCol;
				}
				wks.SetSize(-1, nCol);
			}
			glSource.AddPlot(wks);
		}*/
		
		int nPlot = find_plot_index_by_key(glSource, "Baseline", strSheetName);
		DataPlot dpBL = glSource.DataPlots(nPlot);
		if (dpBL)
		{
			nBLPlotType = dpBL.GetPlotType();
			trBaselineFormat = dpBL.GetFormat();
			dpBL.Destroy();
		}
		if (check_has_plotted_in_graph(xyBL, glSource) == 0)
		{
			int nIndex = glSource.AddPlot(xyBL, nBLPlotType);
			DataPlot dpBaseline = glSource.DataPlots(nIndex);
			if (dpBaseline)
				dpBaseline.ApplyFormat(trBaselineFormat);
		}
	}
	return bRet;
}
///Jasmine 05/15/08 
void 	FitPeak::calcAddMultiPeaksFitCurveTable(TreeNode& trOp, TreeNode& trFC, int index, vector& vX, vector& vFitX, vector& vFitY, const tagFitResultCurveDataOptions& fitOptions, FitParameter *psFitParameter, int nMultiplicity)//= 1
{
	///------ Folger 02/23/09 PLOTTED_CURVES_FAILS_TO_CONTROL_PEAK_PLOTTING_OUTPUT_IN_REPORT_GENERATION
	bool		bPlotIndividual = true;
	bool		bPlotCumulative = true;
	
	TreeNode	trPLotCurves = trOp.GUI.PLotCurves;
	if ( trPLotCurves )
	{
		bPlotIndividual = trPLotCurves.nVal == PLOT_CURVE_INDIVIDUAL || trPLotCurves.nVal == PLOT_CURVE_BOTH;
		bPlotCumulative = trPLotCurves.nVal == PLOT_CURVE_CUMULATIVE || trPLotCurves.nVal == PLOT_CURVE_BOTH;
	}
	///------ End PLOTTED_CURVES_FAILS_TO_CONTROL_PEAK_PLOTTING_OUTPUT_IN_REPORT_GENERATION
	
	///------ Folger 02/04/09 QA80-12962 ADD_OPTION_IN_PA_FIT_TO_SWTICH_BACK_TO_OLD_FIT_CURVE_DATA_GENERATION_MECHANISM
	if ( !GetFitSession()->GetUseSmartX() )
	{
		///------ Folger 02/23/09 PLOTTED_CURVES_FAILS_TO_CONTROL_PEAK_PLOTTING_OUTPUT_IN_REPORT_GENERATION
		/// seems now the only way to control individual and cumulative plotting in base class
		/// is to set PeakCurve and CumulativeCurve checknode under GUI.Replica
		TreeNode	trReplica = get_gui_replica_node(trOp.GUI);
		if ( trReplica )
		{
			trReplica.PeakCurve.nVal = bPlotIndividual;
			trReplica.CumulativeCurve.nVal = bPlotCumulative;
		}
		///------ End PLOTTED_CURVES_FAILS_TO_CONTROL_PEAK_PLOTTING_OUTPUT_IN_REPORT_GENERATION
		FitNL::calcAddMultiPeaksFitCurveTable(trOp, trFC, index, vX, vFitX, vFitY, fitOptions, psFitParameter, nMultiplicity);
	}
	else
	{
	///------ End ADD_OPTION_IN_PA_FIT_TO_SWTICH_BACK_TO_OLD_FIT_CURVE_DATA_GENERATION_MECHANISM
		///------ Folger 01/04/09 QA80-12962 MORE_WORK_ON_GENERATE_INDIVIDUAL_FIT_CURVE_USING_INDEPENDENT_X_IN_PA
		//FitNL::calcAddMultiPeaksFitCurveTable(trOp, trFC, index, vX, vFitX, vFitY, fitOptions, psFitParameter, nMultiplicity);
		ASSERT(trOp.PFWTree);
		bool	bHasBaselinePeak = HasBaselinePeak();
		int		nPeakOffset = bHasBaselinePeak? 0 : 1;
		
		///------ Folger 02/23/09 PLOTTED_CURVES_FAILS_TO_CONTROL_PEAK_PLOTTING_OUTPUT_IN_REPORT_GENERATION
		if ( bPlotIndividual )
		{
		///------ End PLOTTED_CURVES_FAILS_TO_CONTROL_PEAK_PLOTTING_OUTPUT_IN_REPORT_GENERATION
			int			nPeakIndex = 0;
			for(int ii=0; ii<nMultiplicity; ii++)
			{
				vector	vFitX, vFitY;
				SmartXOnPeakShapeOption		stSmartXOpt;
				bool						bSmartX = GetNLFCurvePointer()->CheckGetSmartXOnPeakShapeOption(stSmartXOpt, ii);
				GetNLFCurvePointer()->GetFitX(vFitX, GetFitSession()->GetDataObject(), index, 0, true, true, bSmartX ? &stSmartXOpt : NULL);
				GetNLFCurvePointer()->GetFitY( vFitX, vFitY, GetFitSession()->GetNLParamsMngr(), index, ii);
				
				string 		strLabel;
				int 		nXID, nYID; /// Iris 3/31/2009 QA80-13361 TO_AVOID_USE_SAME_BASE_ID_FOR_BASELINE_AND_FIT_DATA
				if(bHasBaselinePeak && 0 == ii)
				{
					strLabel = STR_LABEL_BASELINE_FIT_CURVE;
					/// Iris 3/31/2009 QA80-13361 TO_AVOID_USE_SAME_BASE_ID_FOR_BASELINE_AND_FIT_DATA
					nXID = IDST_PFM_ONE_BASELINE_DATA_SET;
					nYID = nXID + 1;
					///end TO_AVOID_USE_SAME_BASE_ID_FOR_BASELINE_AND_FIT_DATA
				}
				else
				{
					strLabel.Format("%s %d", STR_LABEL_PEAK_FIT_CURVE, nPeakIndex+1);
					/// Iris 3/31/2009 QA80-13361 TO_AVOID_USE_SAME_BASE_ID_FOR_BASELINE_AND_FIT_DATA
					nXID = make_one_set_ID(IDST_INDIVIDUAL_FIT_X, nPeakIndex); 
					nYID = make_one_set_ID(IDST_FIT_Y, nPeakIndex);
					nPeakIndex++;
					///end TO_AVOID_USE_SAME_BASE_ID_FOR_BASELINE_AND_FIT_DATA
				}
				/// Iris 3/31/2009 QA80-13361 TO_AVOID_USE_SAME_BASE_ID_FOR_BASELINE_AND_FIT_DATA
				//TreeNode	trFitX = check_add_enumerated_node(trFC, "FitX", ii+1, make_one_set_ID(IDST_INDIVIDUAL_FIT_X, ii+1), STR_LABEL_ATTRIB, "");
				//TreeNode	trFitY = check_add_enumerated_node(trFC, "FitY", ii+1, make_one_set_ID(IDST_FIT_Y, ii+1), STR_LABEL_ATTRIB, strLabel);				
				TreeNode	trFitX = check_add_enumerated_node(trFC, "FitX", ii+1, nXID, STR_LABEL_ATTRIB, "");
				TreeNode	trFitY = check_add_enumerated_node(trFC, "FitY", ii+1, nYID, STR_LABEL_ATTRIB, strLabel);
				///end TO_AVOID_USE_SAME_BASE_ID_FOR_BASELINE_AND_FIT_DATA
				trFitX.SetAttribute(STR_COL_DESIGNATION_ATTRIB, OKDATAOBJ_DESIGNATION_X);
				trFitY.SetAttribute(STR_COL_DESIGNATION_ATTRIB, OKDATAOBJ_DESIGNATION_Y);
				trFitX.dVals = vFitX.GetSize() > 0 ? vFitX : NANUM;
				trFitY.dVals = vFitY.GetSize() > 0 ? vFitY : NANUM;
			}
		}	///------ Folger 02/23/09 PLOTTED_CURVES_FAILS_TO_CONTROL_PEAK_PLOTTING_OUTPUT_IN_REPORT_GENERATION
		
		TreeNode trPlotEachPeak = get_gui_replica_node(trOp.GUI).PeakCurve;
		///------ Folger 02/23/09 PLOTTED_CURVES_FAILS_TO_CONTROL_PEAK_PLOTTING_OUTPUT_IN_REPORT_GENERATION
		//if ( trPlotEachPeak )
		
		if ( bPlotCumulative )
		///------ End PLOTTED_CURVES_FAILS_TO_CONTROL_PEAK_PLOTTING_OUTPUT_IN_REPORT_GENERATION
		{
			/// add cumulative fit curve
			trPlotEachPeak.nVal = 0;
			FitNL::calcAddMultiPeaksFitCurveTable(trOp, trFC, index, vX, vFitX, vFitY, fitOptions, psFitParameter, nMultiplicity);
			trPlotEachPeak.nVal = 1;
		}
		///------ End MORE_WORK_ON_GENERATE_INDIVIDUAL_FIT_CURVE_USING_INDEPENDENT_X_IN_PA
	}		///------ Folger 02/04/09 QA80-12962 ADD_OPTION_IN_PA_FIT_TO_SWTICH_BACK_TO_OLD_FIT_CURVE_DATA_GENERATION_MECHANISM
	
	TreeNode trAddBackBaseline = tree_get_node_by_tagname(trOp, "AddBackBaseline", true);
	if(!trAddBackBaseline || false == trAddBackBaseline.nVal)
		return;
	
	vector 	vBaselineX, vBaselineY;	
	XYRange xyBL;
	if(trOp.GUI.BaselineData)
	{
		TreeNode trBaselineData = trOp.GUI.BaselineData;
		if( okxf_resolve_tree_construct_range(&trBaselineData, &xyBL) )
			xyBL.GetData(vBaselineY, vBaselineX);
	}
	
	vector vx, vy;
	foreach(TreeNode trFit in trFC.Children)
	{
		///------ Folger 02/16/09 ADD_BACK_BASELINE_FAILS_WHEN_USING_SAMRT_XDATA_FOR_FIT_CURVE
		//if(0 == trFit.tagName.CompareNoCase("FitX"))
		if(0 == trFit.tagName.Find("FitX"))
		///------ End ADD_BACK_BASELINE_FAILS_WHEN_USING_SAMRT_XDATA_FOR_FIT_CURVE
		{
			vx = trFit.dVals;
			continue;
		}
		else
		{
			string strCurves;
			trFit.GetAttribute(STR_LABEL_ATTRIB, strCurves);
			if (0 == strCurves.CompareNoCase("Baseline"))
				continue;
		}
		
		vy = trFit.dVals;
		subtract_baseline(vx, vy, vBaselineX, -vBaselineY);
		trFit.dVals = vy;
	}
}
///End
//------ End ADD_MORE_INFO_TO_REPORT_GRAPH

///Sophy 10/10/2008 CLEAN_PFW_TREE_MOVE_CODE_FROM_PFM_UTILS
bool	FitPeak::isNeedComputePeaksCharacterization( const PFMPeakCharsRequire xRequireList )
{
	if(xRequireList.bAreaFit||xRequireList.bAreaFitT||xRequireList.bAreaFitTP
		||xRequireList.bAreaIntg||xRequireList.bAreaIntgP||xRequireList.bCenterMax
		||xRequireList.bCenterGrvty||xRequireList.bMaxHeight||xRequireList.bFWHM
		||xRequireList.bVariance||xRequireList.bSkew||xRequireList.bExcess||xRequireList.bResolution
		||xRequireList.bMoment3||xRequireList.bMoment4||xRequireList.bWidthAtP||xRequireList.bAreaAbove
		///------ Folger 03/06/09 SHOULD_NOT_NEW_SHEET_IF_NO_PEAK_PROPERTIES_OUTPUT
		//xRequireList.bCumArea)
		|| xRequireList.bCumArea
		|| xRequireList.bPeakType
		)
		///------ End SHOULD_NOT_NEW_SHEET_IF_NO_PEAK_PROPERTIES_OUTPUT
		return true;

	return false;
}

bool	FitPeak::getFileNameAndParams( const int& nIndex, string& strFullFileName, string& strFuncName, vector& vFitParams )
{
	strFuncName = GetFitSession()->GetFunctionName( NULL, nIndex );
	strFullFileName = GetFitSession()->GetFunctionFileName( nIndex );
	int nNumParams = GetFitSession()->GetNLParamsMngr()->GetParamValues( vFitParams, 0, nIndex, true );
	
	if( strFuncName.IsEmpty() || strFullFileName.IsEmpty() )
		return false;
	return true;
}

void	FitPeak::zeroOffsetParams( vector& vFitParams, vector& vZeroY0Params, TreeNode& trFF )
{
	NLFunctionList nlf;
	vector<string>  vParamNames;
	string 	strParamList = nlf.GetFittingPara(trFF, true, "Names").strVal;
	int nNumParaInFunc = strParamList.GetTokens(vParamNames, ',');

	int nParams = vFitParams.GetSize();
	ASSERT(nParams == nNumParaInFunc);
	vZeroY0Params = vFitParams;
	//Minus peak offset
	int nY0 = vParamNames.Find("y0");
	if(nY0 >= 0 && nY0 < nParams)///Sandy fix Y0 should always be the first parameter and need to reset to zero
		vZeroY0Params[nY0] = 0.0;
}

///end CLEAN_PFW_TREE_MOVE_CODE_FROM_PFM_UTILS

/// Hong 01/13/09 v8.0995d IMPROVE_CODE_OF_MEMORY_CONSUMER_IN_PA
///Kyle 10/10/08 CLEAN_PFW_TREE_MOVE_CODE_FROM_PFM_UTILS
//int FitPeak::calculatePeaksCharacterization( vector& vx, matrix& mPeaksData, /* vector& vXCenters, vector& vXWidth,*/ vector& vyCum,
//         const PFMPeakCharsRequire xRequireList, PFMPeakCharsVaule* pxPFMPeakCharsValueList,
//         double dWidthAtPercent, double dAreaAbovePercent, double dCumAreaTo,
//         int nMomentMethod)	///Jasmine 05/16/08 MOMENTS_COMPUTE_METHOD
/*
{
	if(!isNeedComputePeaksCharacterization(xRequireList))
		return mPeaksData.GetNumCols();

	//prepare data integration result
	IntegrationResult xCumIntg;
	// Jack 05/04/2008 ADD_ERROR_CHECKING_FOR_INTEGRATION
	int nRet = ocmath_integrate(vx, vyCum, 0, vx.GetSize()-1, &xCumIntg, NULL, ABSOLUTE_AREA);
	if (nRet<0)
		{
			return nRet;
		}
	// End ADD_ERROR_CHECKING_FOR_INTEGRATION

	//decompose data
	int nNumPeaks = mPeaksData.GetNumCols();
	
	//Sandy 2008-12-23 move two vector inside this function since there is no use outside
	vector vXCenters, vXWidth;
 	//ASSERT(vXCenters.GetSize() == nNumPeaks);
 	//ASSERT(vXWidth.GetSize() == nNumPeaks);
  	vXCenters.SetSize(nNumPeaks);
 	vXWidth.SetSize(nNumPeaks);
 	//end of 2008-12-23

	double xcLast, wLast;

	//------ Folger 04/10/08 QA80-11364 REDUCE_FDF_LOADING_AND_SETTING_TREE_IN_PEAK_CALCULATION
	string				strLastFuncName;
	Tree				trFF;
	NumericFunction		NF;
	//------

   	//temp workbook for save every infinite peak data
	WorksheetPage wkpTemp;
	wkpTemp.Create("Origin",  CREATE_HIDDEN|CREATE_SET_MISSING_IN_MANAGER);
	Worksheet wks = wkpTemp.Layers(0);
	wks.SetSize(-1, nNumPeaks*2);

	double dIdealCumArea;
	Tree  treeIdealPeaks;
	Tree  treeFitPeaksParams;

	vector<string> vstrFuncName;
	vstrFuncName.SetSize(nNumPeaks);

	///prepare data

	// Jack 05/16/2008 ADD_FUNCTION_INTEGRAL_FOR_AREA_FIT_T
	double dxmin, dxmax;
	vx.GetMinMax(dxmin, dxmax);
	double dAreaFitTCumArea = 0.0;
	vector vAreaFitT(nNumPeaks);
	// End ADD_FUNCTION_INTEGRAL_FOR_AREA_FIT_T
	///Kyle 10/21/08 CHANGE_FUNCTION_NAME_HASBASELINEPEAK_TO_GETBASELINEFITMODE
    //int	nPeakOffset = GetFitSession()->HasBaselinePeak() ? 1 : 0;///Sophy 10/10/2008 CLEAN_PFW_TREE_MOVE_CODE_FROM_PFM_UTILS
    int	nPeakOffset = GetFitSession()->GetBaselineFitMode() ? 1 : 0;///Sophy 10/10/2008 CLEAN_PFW_TREE_MOVE_CODE_FROM_PFM_UTILS
	///End CHANGE_FUNCTION_NAME_HASBASELINEPEAK_TO_GETBASELINEFITMODE
    for( int nIndex = nNumPeaks - 1; nIndex >=0 ; nIndex-- )
    {
       string strFullPathFileName;
       vector vFitParams;

       bool bRet = getFileNameAndParams( nIndex + nPeakOffset, strFullPathFileName, vstrFuncName[nIndex], vFitParams);
       ASSERT(bRet);

	   TreeNode trFitPeak = treeFitPeaksParams.AddNode(("Peak" + nIndex));
	   trFitPeak.dVals = vFitParams;
	   string strFuncName = vstrFuncName[nIndex];
	   if ( strFuncName.CompareNoCase(strLastFuncName) != 0 )
	   {
			strLastFuncName = strFuncName;
			if( !nlsf_FDF_to_tree(strFullPathFileName, &trFF) )
			{
				error_report("Invalid function file");
				continue;
			}
			if (!NF.SetTree(trFF))
			{
				error_report("Invalid function");
				continue;
			}
	   }

       vector vFullPeakX, vFullPeakY;
	   vector vZeroY0Param;
	   zeroOffsetParams(vFitParams, vZeroY0Param, trFF);

		///2008-5-22 Sandy  get NLPEAKPARAMS form NF directly
		NLPEAKPARAMS nlpeakParameters;
		NF.GetPeakParametersIndices(&nlpeakParameters);
		vXCenters[nIndex] = vFitParams[nlpeakParameters.nIndexCenter];
		if(nlpeakParameters.nIndexWidth2>0)
			vXWidth[nIndex] = max(vFitParams[nlpeakParameters.nIndexWidth], vFitParams[nlpeakParameters.nIndexWidth2]);
		else
			vXWidth[nIndex] = vFitParams[nlpeakParameters.nIndexWidth];
		//end
		
		//Sandy 2008-5-30 if width is less than 1/100 of full x datarange, set the width = 1/100 of x range.
		double dLimitMinWidth = abs(dxmax - dxmin)/100.0;
		if(vXWidth[nIndex] < dLimitMinWidth)
		{
			vXWidth[nIndex] = dLimitMinWidth;
		}
		//end

	   int  nInfiniteSize = generate_peak_data(NF, vZeroY0Param, vFullPeakX, vFullPeakY, NANUM, NANUM, vXCenters[nIndex], vXWidth[nIndex]);

	   IntegrationResult xIdealPeakInteg;
	   nRet = ocmath_integrate(vFullPeakX, vFullPeakY, 0, vFullPeakX.GetSize()-1, &xIdealPeakInteg, NULL, ABSOLUTE_AREA);
	   ASSERT(nRet == OE_NOERROR);

	   TreeNode trPeak = treeIdealPeaks.AddNode(("Peak" + nIndex));
	   TreeNode trParams = trPeak.AddNode(_IDEAL_PEAK_PARAMS_TAGNAME);
	   trParams.dVals = vZeroY0Param;
	   trPeak.AddNumericNode(xIdealPeakInteg.xPeak, _IDEAL_PEAK_CENTER_MAX_TAGNAME);
	   trPeak.AddNumericNode(xIdealPeakInteg.xCentroid, _IDEAL_PEAK_CENTROID_X_TAGNAME);
	   trPeak.AddNumericNode(xIdealPeakInteg.yPeak, _IDEAL_PEAK_HEIGHT_MAX_TAGNAME);
	   trPeak.AddNumericNode(xIdealPeakInteg.dxPeak, _IDEAL_PEAK_FWHM_TAGNAME);

	   wks.Columns(nIndex*2).SetType(OKDATAOBJ_DESIGNATION_X);
	   wks.Columns(nIndex*2+1).SetType(OKDATAOBJ_DESIGNATION_Y);

	   XYRange xyPeak;
       xyPeak.Add(wks, nIndex*2, "X");
       xyPeak.Add(wks,nIndex*2+1, "Y");
       xyPeak.SetData(&vFullPeakY, &vFullPeakX);

       //Jack 05/16/2008 ADD_FUNCTION_INTEGRAL_FOR_AREA_FIT_T

       ///Sandy 2008-5-20 Use Integral for speed and it has support precision control
       double dPrecision = 10e-11;
       vAreaFitT[nIndex] = NF.Integral(dxmin, dxmax, vZeroY0Param, dPrecision);
       dIdealCumArea+=abs(vAreaFitT[nIndex]);//sandy 2008-5-26 should use datarange integ.Area

       dAreaFitTCumArea += abs(vAreaFitT[nIndex]);
       //End ADD_FUNCTION_INTEGRAL_FOR_AREA_FIT_T
    }

    double dCumArea = xCumIntg.Area;
    
	//--Sandy 2008-12-17 ADD_PROGRESSBOX_AND_GIVE_USER_FEEDBACK_AND_CANCEL_WHEN_THE_PROGRESS_SLOW
	string strTitle = _L("Calculating Peaks' Properties......");
	string strTips;
	progressBox pb("", PBOX_TOPMOST, nNumPeaks < NLFIT_NUM_PEAKS_THRESHOLD_TO_SHOW_PROGRESSBOX? true:false);
	pb.SetText(strTitle, PBOXT_TITLE);
	pb.SetRange(0,nNumPeaks);
	//--end ADD_PROGRESSBOX_AND_GIVE_USER_FEEDBACK_AND_CANCEL_WHEN_THE_PROGRESS_SLOW

    //calculate
    for(nIndex = nNumPeaks - 1; nIndex >=0 ; nIndex-- )
    {
		//--Sandy 2008-12-17 ADD_PROGRESSBOX_AND_GIVE_USER_FEEDBACK_AND_CANCEL_WHEN_THE_PROGRESS_SLOW
		int nCount =  (nNumPeaks - nIndex);
        strTips.Format(_L("Calculating Peaks' Properties, current peak = %d......"), nCount);
        if(pb.Set(nCount))
        {
            pb.SetText(strTips, PBOXT_MIDCENTER);
        }
        else
        {
            //out_str("User abort!");
            //break;
            return error_report("User abort!");
        }
        //--endADD_PROGRESSBOX_AND_GIVE_USER_FEEDBACK_AND_CANCEL_WHEN_THE_PROGRESS_SLOW    	
    	
    	
	    XYRange xyPeak;
        xyPeak.Add(wks, nIndex*2, "X");
        xyPeak.Add(wks,nIndex*2+1, "Y");
    	vector vFullPeakX, vFullPeakY;
    	xyPeak.GetData(vFullPeakY, vFullPeakX);

    	TreeNode trFitPeak = treeFitPeaksParams.GetNode(("Peak" + nIndex));
    	ASSERT(trFitPeak.IsValid());
	    vector vFitParams;
	    vFitParams = trFitPeak.dVals;

    	TreeNode trIdealPeak = treeIdealPeaks.GetNode(("Peak" + nIndex));
    	ASSERT(trIdealPeak.IsValid());

    	vector vZeroY0Params;
    	TreeNode trParams = trIdealPeak.GetNode(_IDEAL_PEAK_PARAMS_TAGNAME);
    	vZeroY0Params = trParams.dVals;

     	vector vy;
        bool bRet = mPeaksData.GetColumn( vy, nIndex);
   		ASSERT(bRet);

   		/// Jack 9-26-2008 QA-12288 SET_NF_FDF_FOR_EACH_PEAK_FUNCTION
   		// Should set corresponding NF for each peak function to do the moment calculation otherwise NF will always be the first 
   		// peak function  and the analytical formula for the moment will always use this function FDF
   		string strFullPathFileName;
		vector vTempFitParams;

		bool bRet2 = getFileNameAndParams( nIndex + nPeakOffset, strFullPathFileName, vstrFuncName[nIndex], vTempFitParams);
		ASSERT(bRet2);


		string strFuncName = vstrFuncName[nIndex];
	   	if ( strFuncName.CompareNoCase(strLastFuncName) != 0 )
	   	{
			strLastFuncName = strFuncName;
			if( !nlsf_FDF_to_tree(strFullPathFileName, &trFF) )
			{
				error_report("Invalid function file");
				continue;
			}
			if (!NF.SetTree(trFF))
			{
				error_report("Invalid function");
				continue;
			}
	   	}
   		/// End SET_NF_FDF_FOR_EACH_PEAK_FUNCTION
   		
   		
   		//bool bTempSpeedOrAccurateness = true; //temp option, true for speed, false for accurateness (function integral)  Jack 05/15/2008 add temp option to be shown in GUI
        PFMPeakCharsVaule& rxCharsList = pxPFMPeakCharsValueList[nIndex];
	    bRet=cal_peak_characterization(vx, vy, vFullPeakX, vFullPeakY, vXCenters[nIndex], vXWidth[nIndex], vAreaFitT[nIndex],  dCumArea, dAreaFitTCumArea,  vstrFuncName[nIndex], vFitParams, vZeroY0Params,trIdealPeak,
	      								xRequireList, rxCharsList,
	         							dWidthAtPercent, dAreaAbovePercent, dCumAreaTo, xcLast, wLast, NF, nMomentMethod);        		// Jack 05/16/2008 Add dAreaFitTCumArea parameter to the prototype

	    if (false == bRet) return -1; // hard code -1: tobe changed into an error code
    }

    wkpTemp.Destroy();

    return nNumPeaks;
}
///End CLEAN_PFW_TREE_MOVE_CODE_FROM_PFM_UTILS

bool 	FitPeak::calcPFMPeakResults(TreeNode& trOp)
{
	//get fit xy
	vector 	vFitX;
	vector 	vCumulative;
	matrix 	mFitYs;
	
	if( !GetNLFCurvePointer()->GetFitX(vFitX, GetFitSession()->GetDataObject()) )
		return error_report("Fail to Get FitX");
	
	
	int	nNumPeaks = GetFitSession()->GetNumPeaks();
	
	///Sandy 2007-11-20 skip baseline Y if there is baseline
	int nPeak1 = 0;
	///Kyle 10/21/08 CHANGE_FUNCTION_NAME_HASBASELINEPEAK_TO_GETBASELINEFITMODE
	//if(GetFitSession()->HasBaselinePeak())
	if(GetFitSession()->GetBaselineFitMode())
	///End CHANGE_FUNCTION_NAME_HASBASELINEPEAK_TO_GETBASELINEFITMODE
	{
		//nNumPeaks = nNumPeaks - 1; // 2007-11-27 sandy
		nPeak1 = 1;
	}
	//end
	
	for(int nPeak = nPeak1; nPeak < nNumPeaks; nPeak++)
	{
		vector 	vFitY;
		///Kyle 11/26/2008 SUPPORT_GETTING_FIT_Y_WITHOUT_OFFSET_FOR_PA, get fit data not adding back baseline
		//if ( GetNLFCurvePointer()->GetFitY(vFitX, vFitY, GetFitSession()->GetNLParamsMngr(), 0, nPeak) )
		if ( GetNLFCurvePointer()->GetFitYWithoutOffset(vFitX, vFitY, GetFitSession()->GetNLParamsMngr(), 0, nPeak) )
		///End SUPPORT_GETTING_FIT_Y_WITHOUT_OFFSET_FOR_PA
		{
			if(0 == mFitYs.GetNumCols() && 0 < vFitY.GetSize())
				//mFitYs.SetSize(vFitY.GetSize(), nNumPeaks); //2007-11-27 sandy
				mFitYs.SetSize(vFitY.GetSize(), nNumPeaks - nPeak1);
			
			if(mFitYs.GetNumCols() > nPeak - nPeak1)
			{
			//mFitYs.SetColumn(vFitY, nPeak);//2007-11-27 sandy
			mFitYs.SetColumn(vFitY, (nPeak - nPeak1));
			}
			
			if(0 == vCumulative.GetSize())
				vCumulative = vFitY;
			else
				vCumulative += vFitY;
		}
		else
			return error_report("Fail to Get FitY");
			
	}
	//m_pFitSession->GetCumulativeData(vCumulative);
	
	//get PFM tree from trOp
	///Arvin 12/05/07 XOP_NEED_SUPPORT_PFW
	//As jasmine said, tag name of PFW tree node should be PFWTree
	//TreeNode 	trPeaks = trOp.PFMTree.Peaks;
	TreeNode 	trPeaks = trOp.PFWTree.Peaks;
	///end XOP_NEED_SUPPORT_PFW
	
	// get peak report options from GUI to struct
	/// Iris 07/23/2007 REMOVE_PLOT_OPTIONS
	//TreeNode	trReportOptions = trOp.GUI.PeakReport.ReportSheet;
	TreeNode	trReportOptions = trOp.GUI.PeakReport;
	///end REMOVE_PLOT_OPTIONS
	
	PFMPeakCharsRequire stPFMRequireList;
	Tree trPFMRequireAll;//		trPFMStruct;
	trPFMRequireAll += stPFMRequireList;//trPFMStruct += stPFMRequireList;
	//int nn = tree_copy_values_by_id(trReportOptions, trPFMStruct);
	//trPFMRequireAll = trReportOptions.Clone();
	
	//------ Folger 04/10/08 QA80-11364 OPTIMIZE_CALCULATE_OUTPUT_RESULT_FOR_PA_FIT
	//foreach(TreeNode trNode in trPFMRequireAll.Children)
		//trNode.nVal = true;
	tree_copy_values_by_id(trReportOptions, m_trReportCombo);
	int nCount = m_trReportCombo.Children.Count();
	
	if(PLOT_TO_NEW_GRAPH == trOp.GUI.PlotCurveTo.nVal)	///Jasmine 05/20/08 REPORT_GRAPH_SHOULD_BE_BE_ABLE_TO_TURN_OFF
	{
		foreach ( TreeNode trNode in trOp.GUI.PeakReportField.Children )
		{
			if ( trNode.nVal > 0 )
			{
				ASSERT(trNode.nVal < nCount);
				m_trReportCombo.Children.Item(trNode.nVal).nVal = 1;
			}
		}
	}
	tree_copy_values_by_id(m_trReportCombo, trPFMRequireAll);
	//------ End OPTIMIZE_CALCULATE_OUTPUT_RESULT_FOR_PA_FIT
		
	stPFMRequireList = trPFMRequireAll;//trPFMStruct;
	
	double dWidthAtPercent = trReportOptions.WidthAtPercent.dVal;
	double dAreaAbovePercent = trReportOptions.AreaAbovePercent.dVal;
	double dCumAreaTo = trReportOptions.CumAreaPercent.dVal;

	int nMomentMethod = trReportOptions.MomentMethod.nVal;///Jasmine 05/16/08 MOMENTS_COMPUTE_METHOD
	
	PFMPeakCharsVaule* pstResult = (PFMPeakCharsVaule*)malloc( sizeof(PFMPeakCharsVaule) * nNumPeaks );
	
	//do calculation
	
	///Sandy 2007-11-20 remove peak0 for when there is baseline
	Tree trNoBaselinePeaks;
    //TreeNode tr1 = trPeaks.Clone(TRUE);	
    bool flag = trNoBaselinePeaks.AddNode(trPeaks);
    TreeNode trBaseline = tree_get_node_by_tagname(trNoBaselinePeaks, PFM_BASELINE_PEAK_TAG_NAME, true);
    if(trBaseline.IsValid())
    	trBaseline.Remove();
    ///Arvin 12/05/07 XOP_NEED_SUPPORT_PFW
	//As jasmine said, tag name of PFW tree node should be PFWTree
	//bool bHasBaselinePeak = HasBaselinePeak(trOp.PFMTree);
	///Sophy 10/10/2008 CLEAN_PFW_TREE_MOVE_CODE_FROM_PFM_UTILS
	//bool bHasBaselinePeak = HasBaselinePeak(trOp.PFWTree);
	///Kyle 10/21/08 CHANGE_FUNCTION_NAME_HASBASELINEPEAK_TO_GETBASELINEFITMODE
	//bool bHasBaselinePeak = GetFitSession()->HasBaselinePeak();
	bool bHasBaselinePeak = GetFitSession()->GetBaselineFitMode();
	///End CHANGE_FUNCTION_NAME_HASBASELINEPEAK_TO_GETBASELINEFITMODE
	///end CLEAN_PFW_TREE_MOVE_CODE_FROM_PFM_UTILS
	///end XOP_NEED_SUPPORT_PFW
    //end

    // Jack 05/04/2008 AVOID_ZERO_SIZED_VECTOR_PASS 
    if(vFitX.GetSize()<1 || vCumulative.GetSize()<1)
    { 
    	free(pstResult); // todo: Max hope to put missing values to pstResult. 
    	return true;
    }  // check size firstly, and avoid zero-sized vector passed into calculate_peaks_characterization, which causes the runtime error (found by Jasmine)
	// End AVOID_ZERO_SIZED_VECTOR_PASS
	
	///Sandy 2008-5-12 add tow more vector for calculate
	//int nResultNum = calculate_peaks_characterization(vFitX, mFitYs, vCumulative, trNoBaselinePeaks, stPFMRequireList, pstResult, dWidthAtPercent, dAreaAbovePercent, dCumAreaTo);
	///Sandy 2008-12-23 comment out since there is no use anymore
	//vector vXCenters, vXWidths;
	//GetFitSession()->GetPeakCenterOrWidth(vXWidths, false, false);	///Jasmine 05/13/08 NANOSIZER_NEED_GET_X_Y_CENTER_OR_WIDTH_SEPARATELY
	//GetFitSession()->GetPeakCenterOrWidth(vXCenters, true, false);
*/
//	int nResultNum = calculatePeaksCharacterization(vFitX, mFitYs, /*vXCenters, vXWidths,*/ vCumulative, stPFMRequireList, pstResult, dWidthAtPercent, dAreaAbovePercent, dCumAreaTo, nMomentMethod);	///Jasmine 05/16/08 MOMENTS_COMPUTE_METHOD
/*	///end 2008-12-23
	//end 2008-5-12
	
	vector<string> vsFunctions;
	int nFunctionSize = GetFitSession()->GetAllFunctions(vsFunctions);
	
	if(1 > nResultNum)
	{
		free(pstResult);
		return true;
	}
	//TreeNodeCollection trColl(trPeaks, "Peak");
	//get result in tree
	Tree trResult;
	int nResult = 0;
	int ii = 0;
	for(nPeak = 0; nPeak < nNumPeaks; nPeak++)
	{
		if(bHasBaselinePeak && 0 == nPeak)
			continue;//exclude baseline 
		TreeNode trOnePeak = trResult.AddNode("Peak"+(string)(++ii));
		TreeNode trPeakNum = tree_check_get_node(trOnePeak, "PeakNum", 0, STR_LABEL_ATTRIB, _L("Peak #"));
		trPeakNum.DataID = IDE_PFM_PKC_PEAKNUM;
		trPeakNum.nVal = ii;
		TreeNode trPeakType = tree_check_get_node(trOnePeak, "PeakType", 0, STR_LABEL_ATTRIB, _L("Peak Type"));
		trPeakType.DataID = IDE_PFM_PKC_PEAKTYPE;
		//TreeNode	trPeak = trColl.Item(nPeak);
		//trPeakType.strVal = trPeak.Function.FuncName.strVal;
		trPeakType.strVal = nPeak < nFunctionSize? vsFunctions[nPeak] : "";
		
		if(nResult >= nResultNum)
			break;
		trOnePeak += pstResult[nResult];
		updateLabelsForPeaksReportTable(trOnePeak);
		/// Hong 04/22/08 v8/0847b SET_COL_DESIGNATION_OF_PEAKS_REPORT_SHEET
		tree_set_attribute_to_all_nodes(trOnePeak, STR_COL_DESIGNATION_ATTRIB, (string)OKDATAOBJ_DESIGNATION_Y);
		trPeakType.SetAttribute(STR_COL_DESIGNATION_ATTRIB, OKDATAOBJ_DESIGNATION_NONE);
		/// end SET_COL_DESIGNATION_OF_PEAKS_REPORT_SHEET
		nResult++;
	}
	
	//add peaks characterization field
	///Jasmine 05/20/08 REPORT_GRAPH_SHOULD_BE_BE_ABLE_TO_TURN_OFF
	//if(0 != trOp.GUI.plotCurveTo.nVal)
	if(PLOT_TO_NEW_GRAPH == trOp.GUI.PlotCurveTo.nVal)
	{
		GraphLayer glSource, glFields;
		DataPlot dp = GetSourceDataPlot(0, trOp);
		if(dp) dp.GetParent(glSource);
		if(glSource)
			glFields = glSource.GetPage().Layers(1);//PKREPORT.otp		
		if(glFields)
			addInfoToReportGraph(trResult, trOp.GUI.PeakReportField, glFields);
	}
	///End REPORT_GRAPH_SHOULD_BE_BE_ABLE_TO_TURN_OFF
	
	//do report
	TreeNode 	trPeaksTable = tree_check_get_node(trOp.Calculation, "PFM", IDST_PFM_TABLE, STR_LABEL_ATTRIB, STR_PEAK_CHARACTERISTICS_REPORT);
	/// Hong 04/10/08 v8.0840c PEAK_FIT_REPORT_PEAK_CHARACTERISTICS_TO_SEPARATE_SHEET
	trPeaksTable.Show = false; // defualt not show in report sheet, as it eill put in separate flat sheet
	/// end PEAK_FIT_REPORT_PEAK_CHARACTERISTICS_TO_SEPARATE_SHEET
	trPeaksTable.SetAttribute(TREE_Table, GetTableStringMain(false));
	///Jasmine 11/14/07 FIT_BASELINE_AS_WELL_AS_OTHER_PEAKS
	int nPeakOffset = bHasBaselinePeak? 0 : 1;
	nResult = 0;
	for(nPeak = 0; nPeak < nNumPeaks; nPeak++)
	{
		if(bHasBaselinePeak && 0 == nPeak)
			continue;//Sandy said should exclude baseline 
		string		strRowName = (bHasBaselinePeak && 0 == nPeak)? "Baseline" : "Peak" + (nPeak + nPeakOffset);
		string		strRowLabel = (bHasBaselinePeak && 0 == nPeak)? _L("Baseline") : _L("Peak")+" " + (nPeak + nPeakOffset);
	///End FIT_BASELINE_AS_WELL_AS_OTHER_PEAKS
		TreeNode 	trRow = tree_check_get_node(trPeaksTable, strRowName, IDST_TEMP_ONE_SET, STR_LABEL_ATTRIB, strRowLabel);
		
		if(nResult >= nResultNum)
			break;
		TreeNode trOnePeakResult = trResult.Children.Item(nResult);
		trRow.Replace(trOnePeakResult.Clone(), true, true);
		trRow.SetAttribute(STR_LABEL_ATTRIB, strRowLabel);
		
		foreach(TreeNode trNode in trRow.Children)
		{
			if(tree_get_int_value_by_id(trReportOptions, trNode.DataID))
				continue;
			trNode.Remove();
		}
		trRow.ID =  make_one_set_ID(IDST_PFM_ONE_PEAK_RESULT, nPeak + 1);
		nResult++;
	}
	tree_copy_values_to_attributes(trReportOptions, trPeaksTable);//, STR_LABEL_ATTRIB);
	
	free(pstResult);
	return true;
}
*/
bool 		FitPeak::calculatePeaksCharacterization(vector& vX, vector& vY, int nPeakIndex, const IntegrationResult& xCumIntg, const PFMPeakCharsRequire& xRequireList, 
				const PFMPeakCharsVaule& xPFMPeakCharsValueList, double dWidthAtPercent, double dAreaAbovePercent, double dCumAreaTo, int nMomentMethod, 
				double& dAreaFitTCumArea, double& dLastXC, double& dLastWidth, string& strLastFuncName, TreeNode& trLastFDF, NumericFunction& nfLast)
{
	int			n1stPeak = GetFitSession()->GetBaselineFitMode() ? 1 : 0;
	if ( nPeakIndex < n1stPeak )
		return false;
	int			nPeakIndexWithoutBaselineOffset = nPeakIndex - n1stPeak;
	
   	string				strFuncName, strFullPathFileName;   	
   	vector 				vFitParams;
   	bool 				bRet = getFileNameAndParams(nPeakIndex, strFullPathFileName, strFuncName, vFitParams);
   	ASSERT(bRet);
   	if ( strFuncName.CompareNoCase(strLastFuncName) != 0 )
   	{
		strLastFuncName = strFuncName;
		if( !nlsf_FDF_to_tree(strFullPathFileName, &trLastFDF) )		
			return error_report("Invalid function file");
		
		if ( !nfLast.SetTree(trLastFDF) )
			return error_report("Invalid function");			
   	}
   	   	
	Tree  				treeFitPeaksParams;
	TreeNode 			trFitPeak = treeFitPeaksParams.AddNode(("Peak" + nPeakIndexWithoutBaselineOffset));
	trFitPeak.dVals = vFitParams;
	
	vector 				vZeroY0Param;
	zeroOffsetParams(vFitParams, vZeroY0Param, trLastFDF);
	
	///2008-5-22 Sandy  get NLPEAKPARAMS form NF directly
	double				dXCenter, dXWidth;
	NLPEAKPARAMS 		nlpeakParameters;
	nfLast.GetPeakParametersIndices(&nlpeakParameters);
	dXCenter = vFitParams[nlpeakParameters.nIndexCenter];
	if ( nlpeakParameters.nIndexWidth2 > 0 )
		dXWidth = max(vFitParams[nlpeakParameters.nIndexWidth], vFitParams[nlpeakParameters.nIndexWidth2]);
	else
		dXWidth = vFitParams[nlpeakParameters.nIndexWidth];
	//end	
	double 				dxmin, dxmax;
	vX.GetMinMax(dxmin, dxmax);
	//Sandy 2008-5-30 if width is less than 1/100 of full x datarange, set the width = 1/100 of x range.
	double 				dLimitMinWidth = abs(dxmax - dxmin)/100.0;
	if ( dXWidth < dLimitMinWidth)
	{
		dXWidth = dLimitMinWidth;
	}
	//end
	
	vector 				vFullPeakX, vFullPeakY;
	int  				nInfiniteSize = generate_peak_data(nfLast, vZeroY0Param, vFullPeakX, vFullPeakY, NANUM, NANUM, dXCenter, dXWidth);
	
	IntegrationResult xIdealPeakInteg;
	
	///Sandy 2009-1-25 QA80-12999&13019 OCMATH_INTEGRATE_COMPUTED_WRONG_VALUE_FOR_FWHM_WITH_MULTIPLE_PEAKS_DATA
	//int					nRet = ocmath_integrate(vFullPeakX, vFullPeakY, 0, vFullPeakX.GetSize()-1, &xIdealPeakInteg, NULL, ABSOLUTE_AREA);
	int					nRet = ocmath_integrate(vFullPeakX, vFullPeakY, 0, vFullPeakX.GetSize()-1, &xIdealPeakInteg, NULL, ABSOLUTE_AREA, NULL, false, SEARCH_FROM_PEAK);
	ASSERT(nRet == OE_NOERROR);
		
	Tree  				treeIdealPeaks;
	TreeNode 			trIdealPeak = treeIdealPeaks.AddNode(("Peak" + nPeakIndexWithoutBaselineOffset));	
	TreeNode 			trParams = trIdealPeak.AddNode(_IDEAL_PEAK_PARAMS_TAGNAME);
	trParams.dVals = vZeroY0Param;
	trIdealPeak.AddNumericNode(xIdealPeakInteg.xPeak, _IDEAL_PEAK_CENTER_MAX_TAGNAME);
	trIdealPeak.AddNumericNode(xIdealPeakInteg.xCentroid, _IDEAL_PEAK_CENTROID_X_TAGNAME);
	trIdealPeak.AddNumericNode(xIdealPeakInteg.yPeak, _IDEAL_PEAK_HEIGHT_MAX_TAGNAME);
	trIdealPeak.AddNumericNode(xIdealPeakInteg.dxPeak, _IDEAL_PEAK_FWHM_TAGNAME);
	
	///Sandy 2008-5-20 Use Integral for speed and it has support precision control
	double 				dPrecision = 10e-11;
	double				dAreaFitT = nfLast.Integral(dxmin, dxmax, vZeroY0Param, dPrecision);	
	dAreaFitTCumArea += abs(dAreaFitT);
	//End ADD_FUNCTION_INTEGRAL_FOR_AREA_FIT_T		
    return cal_peak_characterization(vX, vY, vFullPeakX, vFullPeakY, dXCenter, dXWidth, dAreaFitT,  xCumIntg.Area, dAreaFitTCumArea,
    									strFuncName, vFitParams, vZeroY0Param, trIdealPeak, xRequireList, xPFMPeakCharsValueList,
         								dWidthAtPercent, dAreaAbovePercent, dCumAreaTo, dLastXC, dLastWidth, nfLast, nMomentMethod);        		// Jack 05/16/2008 Add dAreaFitTCumArea parameter to the prototype		
}

bool 	FitPeak::calcPFMPeakResults(TreeNode& trOp)
{
	vector		vFitX, vFitY, vCumulative;
	
	if ( !GetNLFCurvePointer()->GetFitX(vFitX, GetFitSession()->GetDataObject()) )
		return error_report("Fail to Get Fit X");
	
	bool 		bHasBaselinePeak = GetFitSession()->GetBaselineFitMode();
	int			nNumPeaks = GetFitSession()->GetNumPeaks();
	int			n1stPeak = bHasBaselinePeak ? 1 : 0; ///Sandy 2007-11-20 skip baseline Y if there is baseline
	// get cumulative data without subtract baseline
	int 		iPeak = n1stPeak;
	for ( ; iPeak < nNumPeaks; iPeak++ )
	{
		///------ Folger 03/24/10 QA81-15237 GENERATE_FITY_BASED_ON_BASELINE_FOR_BETTER_PEAK_PROPERTIES_CALCULATION
		//if ( !GetNLFCurvePointer()->GetFitYWithoutOffset(vFitX, vFitY, GetFitSession()->GetNLParamsMngr(), 0, iPeak) )
		if ( !GetNLFCurvePointer()->GetFitYWithoutOffset(vFitX, vFitY, GetFitSession()->GetNLParamsMngr(), 0, iPeak, TRUE) )
		///------ End GENERATE_FITY_BASED_ON_BASELINE_FOR_BETTER_PEAK_PROPERTIES_CALCULATION
			return error_report("Fail to Get FitY");
		
		/// Iris 2/24/2010 QA81-15140 FIT_NOT_CONVERGE_BAD_PARAM_VALUE_CAUSE_BAD_REPORT
		// if fit not converged, bad param values cause the value in vFitY all are missing, add vFitY to vCumulative will cause vCumulative all are missing.
		//vCumulative += vFitY;
		int nNumMissing = ocmath_d_minmax(vFitY, 0, vFitY.GetSize());
		if( nNumMissing != vFitY.GetSize() ) // if all data are missing in vFitY, not add fit data to vCumulative
		{
			vCumulative += vFitY;
		}
		///End FIT_NOT_CONVERGE_BAD_PARAM_VALUE_CAUSE_BAD_REPORT
	}
	
	//TreeNode 	trPeaks = trOp.PFWTree.Peaks;
	TreeNode	trReportOptions = trOp.GUI.PeakReport;
	
	PFMPeakCharsRequire 	stPFMRequireList;
	Tree 		trPFMRequireAll;
	trPFMRequireAll += stPFMRequireList;
	
	//------ Folger 04/10/08 QA80-11364 OPTIMIZE_CALCULATE_OUTPUT_RESULT_FOR_PA_FIT
	//foreach(TreeNode trNode in trPFMRequireAll.Children)
		//trNode.nVal = true;
	tree_copy_values_by_id(trReportOptions, m_trReportCombo);
	
	///------ Folger 03/06/09 SHOULD_NOT_NEW_SHEET_IF_NO_PEAK_PROPERTIES_OUTPUT
	tree_copy_values_by_id(m_trReportCombo, trPFMRequireAll);
	stPFMRequireList = trPFMRequireAll;
	m_bNeedCalculatePeakResults = isNeedComputePeaksCharacterization(stPFMRequireList);
	///------ End SHOULD_NOT_NEW_SHEET_IF_NO_PEAK_PROPERTIES_OUTPUT
	
	int nCount = m_trReportCombo.Children.Count();
	
	if(PLOT_TO_NEW_GRAPH == trOp.GUI.PlotCurveTo.nVal)	///Jasmine 05/20/08 REPORT_GRAPH_SHOULD_BE_BE_ABLE_TO_TURN_OFF
	{
		foreach ( TreeNode trNode in trOp.GUI.PeakReportField.Children )
		{
			if ( trNode.nVal > 0 )
			{
				ASSERT(trNode.nVal < nCount);
				m_trReportCombo.Children.Item(trNode.nVal).nVal = 1;
			}
		}
	}
	tree_copy_values_by_id(m_trReportCombo, trPFMRequireAll);
	//------ End OPTIMIZE_CALCULATE_OUTPUT_RESULT_FOR_PA_FIT
	stPFMRequireList = trPFMRequireAll;
	
	///////////////////do calculation and report////////////////////////////
	// Jack 05/04/2008 AVOID_ZERO_SIZED_VECTOR_PASS 
    if ( vFitX.GetSize() < 1 || vCumulative.GetSize() < 1 )
    	return true;
    // check size firstly, and avoid zero-sized vector passed into calculate_peaks_characterization, which causes the runtime error (found by Jasmine)
	// End AVOID_ZERO_SIZED_VECTOR_PASS		
			
	TreeNode 	trPeaksTable = tree_check_get_node(trOp.Calculation, "PFM", IDST_PFM_TABLE, STR_LABEL_ATTRIB, STR_PEAK_CHARACTERISTICS_REPORT);
	/// Hong 04/10/08 v8.0840c PEAK_FIT_REPORT_PEAK_CHARACTERISTICS_TO_SEPARATE_SHEET
	trPeaksTable.Show = false; // defualt not show in report sheet, as it eill put in separate flat sheet
	/// end PEAK_FIT_REPORT_PEAK_CHARACTERISTICS_TO_SEPARATE_SHEET
	trPeaksTable.SetAttribute(TREE_Table, GetTableStringMain(false));			
	vector<string>		vsFunctions;
	int 		nFunctionSize = GetFitSession()->GetAllFunctions(vsFunctions);	
	double 		dWidthAtPercent = trReportOptions.WidthAtPercent.dVal;
	double 		dAreaAbovePercent = trReportOptions.AreaAbovePercent.dVal;
	double 		dCumAreaTo = trReportOptions.CumAreaPercent.dVal;
	int 		nMomentMethod = trReportOptions.MomentMethod.nVal;///Jasmine 05/16/08 MOMENTS_COMPUTE_METHOD
	bool		bNeedCalculate = isNeedComputePeaksCharacterization(stPFMRequireList);
	IntegrationResult 	xCumIntg;
	if ( bNeedCalculate )
	{
		//prepare data integration result		
		// Jack 05/04/2008 ADD_ERROR_CHECKING_FOR_INTEGRATION
		
	    ///Sandy 2009-1-25 QA80-12999&13019 OCMATH_INTEGRATE_COMPUTED_WRONG_VALUE_FOR_FWHM_WITH_MULTIPLE_PEAKS_DATA
		//if ( ocmath_integrate(vFitX, vCumulative, 0, vFitX.GetSize() - 1, &xCumIntg, NULL, ABSOLUTE_AREA) )
		if ( ocmath_integrate(vFitX, vCumulative, 0, vFitX.GetSize() - 1, &xCumIntg, NULL, ABSOLUTE_AREA, NULL, false, SEARCH_FROM_PEAK) )
			return error_report("integrate cumulative data fail!");
		// End ADD_ERROR_CHECKING_FOR_INTEGRATION	
		/// Hong, need to calculate bAreaFitT for bAreaFitTP, see comment // Hong, dAreaFitTP need to calculated by cumulative area, so update it again as only until here dAreaFitTCumArea is really ready for use
		// and change this bool is safe as result will not be reported even calculate
		if ( stPFMRequireList.bAreaFitTP )
			stPFMRequireList.bAreaFitT = true;
	}	
	//--Sandy 2008-12-17 ADD_PROGRESSBOX_AND_GIVE_USER_FEEDBACK_AND_CANCEL_WHEN_THE_PROGRESS_SLOW
	string strTitle = _L("Calculating Peaks' Properties......");
	string strTips;
	///------ Folger 03/06/09 SHOULD_NOT_NEW_SHEET_IF_NO_PEAK_PROPERTIES_OUTPUT
	//progressBox pb("", PBOX_TOPMOST, (bNeedCalculate && (nNumPeaks < NLFIT_NUM_PEAKS_THRESHOLD_TO_SHOW_PROGRESSBOX)) ? true : false);
	/// Kenny 12/24/2009 QA81-14875-P2 PROGRESS_BAR_IN_BUILTIN_TOOL_SHOULD_NOT_KEEP_TOPMOST
	//progressBox pb("", PBOX_TOPMOST, (bNeedCalculate && (nNumPeaks >= NLFIT_NUM_PEAKS_THRESHOLD_TO_SHOW_PROGRESSBOX)) ? false : true);
	progressBox pb("", PBOX_DEFAULT_STYLE, (bNeedCalculate && (nNumPeaks >= NLFIT_NUM_PEAKS_THRESHOLD_TO_SHOW_PROGRESSBOX)) ? false : true);
	/// End QA81-14875-P2 PROGRESS_BAR_IN_BUILTIN_TOOL_SHOULD_NOT_KEEP_TOPMOST
	///------ End SHOULD_NOT_NEW_SHEET_IF_NO_PEAK_PROPERTIES_OUTPUT
	pb.SetText(strTitle, PBOXT_TITLE);
	pb.SetRange(0, nNumPeaks);
	//--end ADD_PROGRESSBOX_AND_GIVE_USER_FEEDBACK_AND_CANCEL_WHEN_THE_PROGRESS_SLOW
	double		dLastXC(0.0), dLastWidth(0.0), dAreaFitTCumArea(0.0);
	string		strLastFuncName;
	Tree		trLastFDF;
	NumericFunction		nfLast;
	Tree		trResult;
	string		strPreTagName;
	for ( iPeak = nNumPeaks - 1; iPeak >= n1stPeak; iPeak--) // Hong, loop direction should NOT be changed as calculatePeaksCharacterization require for Resolution calculating
	{		
		int nPeakLT = iPeak - n1stPeak + 1;
		PFMPeakCharsVaule	stResult;
		if ( bNeedCalculate ) //do calculation
		{
			//--Sandy 2008-12-17 ADD_PROGRESSBOX_AND_GIVE_USER_FEEDBACK_AND_CANCEL_WHEN_THE_PROGRESS_SLOW
			int 		nCount =  nNumPeaks - nPeakLT;
	        strTips.Format(_L("Calculating Peaks' Properties, current peak = %d......"), nCount);
	        if ( pb.Set(nCount) )
	            pb.SetText(strTips, PBOXT_MIDCENTER);	        
	        else	        
	            return error_report("User abort!");	        
	        //--endADD_PROGRESSBOX_AND_GIVE_USER_FEEDBACK_AND_CANCEL_WHEN_THE_PROGRESS_SLOW
	        
			///------ Folger 03/24/10 QA81-15237 GENERATE_FITY_BASED_ON_BASELINE_FOR_BETTER_PEAK_PROPERTIES_CALCULATION
			//if ( !GetNLFCurvePointer()->GetFitYWithoutOffset(vFitX, vFitY, GetFitSession()->GetNLParamsMngr(), 0, iPeak) )
			if ( !GetNLFCurvePointer()->GetFitYWithoutOffset(vFitX, vFitY, GetFitSession()->GetNLParamsMngr(), 0, iPeak, TRUE) )
			///------ End GENERATE_FITY_BASED_ON_BASELINE_FOR_BETTER_PEAK_PROPERTIES_CALCULATION
				return error_report("Fail to Get FitY");
						
			if ( calculatePeaksCharacterization(vFitX, vFitY, iPeak, xCumIntg, stPFMRequireList, stResult, dWidthAtPercent, dAreaAbovePercent, dCumAreaTo, nMomentMethod,
													dAreaFitTCumArea, dLastXC, dLastWidth, strLastFuncName, trLastFDF, nfLast) <= 0 )			
				return error_report("calculate peak characterization fail!");
		}		
		string			strTagName("Peak"+(string)(nPeakLT));	
		/// Hong 01/22/09 FIX_PEAK_ORDER_IN_CHARACTERIZATION_FIELD_OPPOSITE
		// Hong, need to keep Peak order in trResult which is used to do report
		//TreeNode 		trOnePeak = trResult.AddNode(strTagName);
		TreeNode 		trOnePeak;
		if ( trResult.FirstNode )					
			trOnePeak = trResult.InsertNode(trResult.FirstNode, strTagName);		
		else
			trOnePeak = trResult.AddNode(strTagName);
		/// end FIX_PEAK_ORDER_IN_CHARACTERIZATION_FIELD_OPPOSITE
		TreeNode 		trPeakNum = trOnePeak.AddNumericNode(nPeakLT, "PeakNum");
		trPeakNum.SetAttribute(STR_LABEL_ATTRIB, _L("Peak Index"));		
		trPeakNum.DataID = IDE_PFM_PKC_PEAKNUM;	
		string			strPeakType = iPeak < nFunctionSize ? vsFunctions[iPeak] : "";
		TreeNode 		trPeakType = trOnePeak.AddTextNode(strPeakType, "PeakType");
		trPeakType.SetAttribute(STR_LABEL_ATTRIB, _L("Peak Type"));
		trPeakType.DataID = IDE_PFM_PKC_PEAKTYPE;
		
		trOnePeak += stResult;
		updateLabelsForPeaksReportTable(trOnePeak);
		/// Hong 04/22/08 v8/0847b SET_COL_DESIGNATION_OF_PEAKS_REPORT_SHEET
		tree_set_attribute_to_all_nodes(trOnePeak, STR_COL_DESIGNATION_ATTRIB, (string)OKDATAOBJ_DESIGNATION_Y);
		trPeakType.SetAttribute(STR_COL_DESIGNATION_ATTRIB, OKDATAOBJ_DESIGNATION_NONE);
		/// end SET_COL_DESIGNATION_OF_PEAKS_REPORT_SHEET
		
		string			strRowLabel = _L("Peak")+ " " + nPeakLT;
		// Hong, need to keep Peak order in trPeaksTable which is used to do report
		TreeNode 		trRow = trPeaksTable.GetNode(trOnePeak.tagName);
		if ( !trRow )
		{			
			TreeNode	trPreRow;
			if ( !strPreTagName.IsEmpty() )
				trPreRow = trPeaksTable.GetNode(strPreTagName);
			if ( trPreRow )
				trRow = trPeaksTable.InsertNode(trPreRow, trOnePeak.tagName);
			else
				trRow = trPeaksTable.AddNode(trOnePeak.tagName);
		}
		strPreTagName = trOnePeak.tagName;
		trRow.Replace(trOnePeak.Clone(), true, true);
		trRow.SetAttribute(STR_LABEL_ATTRIB, strRowLabel);
		trRow.ID =  make_one_set_ID(IDST_PFM_ONE_PEAK_RESULT, nPeakLT);		
	}
	// Hong, dAreaFitTP need to calculated by cumulative area, so update it again as only until here dAreaFitTCumArea is really ready for use
	foreach ( TreeNode trPeakInTable in trPeaksTable.Children )
	{
		if ( trPeakInTable.dAreaFitTP && trPeakInTable.dAreaFitT )
		{
			trPeakInTable.dAreaFitTP.dVal = cal_area_fit_TP(trPeakInTable.dAreaFitT.dVal, dAreaFitTCumArea);
		}
		foreach ( TreeNode trNode in trPeakInTable.Children )
		{
			if ( tree_get_int_value_by_id(trReportOptions, trNode.DataID) )
				continue;
			trNode.Remove();
		}
	}	
	
	//add peaks characterization field
	///Jasmine 05/20/08 REPORT_GRAPH_SHOULD_BE_BE_ABLE_TO_TURN_OFF
	//if(0 != trOp.GUI.plotCurveTo.nVal)
	if(PLOT_TO_NEW_GRAPH == trOp.GUI.PlotCurveTo.nVal)
	{
		GraphLayer 		glSource, glFields;
		DataPlot 		dp = GetSourceDataPlot(0, trOp);
		if(dp) dp.GetParent(glSource);
		if(glSource)
			glFields = glSource.GetPage().Layers(1);//PKREPORT.otp		
		if(glFields)
			addInfoToReportGraph(trResult, trOp.GUI.PeakReportField, glFields);
	}
	///End REPORT_GRAPH_SHOULD_BE_BE_ABLE_TO_TURN_OFF
	return true;
}
/// end IMPROVE_CODE_OF_MEMORY_CONSUMER_IN_PA

//------ Folger 10/14/08 WRONG_NLF_CURVES_CLASS_IN_PA_MAKES_WRONG_REPORT
/// virtual
NLFCurvesBase*	FitPeak::createNLFCurvePointer(TreeNode& trOp)
{
	return new PeakFitCurves(m_pFitSession);
}
//------ End WRONG_NLF_CURVES_CLASS_IN_PA_MAKES_WRONG_REPORT

//------ Folger 11/06/08 QA80-12536 v8.0966 LOWER_AND_UPPER_BOUNDS_FAILS_TO_REPORT_IN_PA
/// virtual
bool	FitPeak::addOneDataLBUBToParametersTable(TreeNode& trOp, vector<string>& vstrFactors, vector<string>& vsParamNames, vector<string>& vsParamNamesPostfix, int nDataFrom/* = 0*/, int nNumMultiplicity/* = 0*/)
{
	TreeNode trParams = trOp.Calculation.Parameters;
	//---- Iris 12-09-2008 FIX_CRASH_IF_NOT_REPORT_ANY_PARAM
	//if ( !trParams )
	if ( !trParams || trParams.IsEmpty() ) 
	//----
		return false;
	
	vector vParamLowerBounds;
	GetFitSession()->GetParamNumericValues(vParamLowerBounds, PARMAS_SETTING_LOWERBOUNDS);
	
	vector<bool> vbParamLowerBoundsEnable;
	GetFitSession()->GetParamNumericValues(vbParamLowerBoundsEnable, PARMAS_SETTING_LOWERBOUNDSENABLE);
	
	vector vParamUpperBounds;
	GetFitSession()->GetParamNumericValues(vParamUpperBounds, PARMAS_SETTING_UPPERBOUNDS);
	
	vector<bool> vbParamUpperBoundsEnable;
	GetFitSession()->GetParamNumericValues(vbParamUpperBoundsEnable, PARMAS_SETTING_UPPERBOUNDSENABLE);
	
	int		nParamIndex = 0;
	int		nRow = 0;
	///------ Folger 07/16/09 NANOSIZER_FAILS_TO_REPORT_PARAMETER_BOUNDS_FROM_2ND_PEAK
	//for ( int nFunc=0; nFunc<GetFitSession()->GetNumberFitFunctions(); ++nFunc )
	//{
		//int		nNumParams = GetFitSession()->GetNumParameter(nFunc);
		//int		nParamOffset = GetFitSession()->GetBaselineFitMode() ? 0 : GetFitSession()->GetNLParamsMngr()->GetFunctionParameterOffset(nFunc);
	for ( int nPeak=0; nPeak<GetFitSession()->GetNumPeaks(); ++nPeak )
	{
		int		nFunc = GetFitSession()->GetFuncIndex(nPeak);
		int		nNumParams = GetFitSession()->GetPeakNumParams(nPeak);
		int		nParamOffset = GetFitSession()->GetBaselineFitMode() ? 0 : GetFitSession()->GetPeakParameterOffset(nPeak);
	///------ End NANOSIZER_FAILS_TO_REPORT_PARAMETER_BOUNDS_FROM_2ND_PEAK
		
		for ( int nParam = 0; nParam<nNumParams + nParamOffset; ++nParam )
		{
			#ifdef	_DEBUG 
			if ( nRow >= trParams.Children.Count() )
			{
				ASSERT(false);
			}
			#endif	//_DEBUG
			
			TreeNode	trRow = trParams.Children.Item(nRow++);
			int			nIndex = nParam < nParamOffset ? nParam : nParamIndex++;
			
			TreeNode trLB = tree_check_get_node( trRow, "LowerBound", 0, STR_DATAID_ATTRIB, (string)IDE_PARAM_LOWER_BOUND );
			trLB.dVal = vbParamLowerBoundsEnable[nIndex]? vParamLowerBounds[nIndex] : NANUM;
				
			TreeNode trUB = tree_check_get_node( trRow, "UpperBound", 0, STR_DATAID_ATTRIB, (string)IDE_PARAM_UPPER_BOUND );
			trUB.dVal = vbParamUpperBoundsEnable[nIndex]? vParamUpperBounds[nIndex] : NANUM;
		}
		
		int		nNumDerivedParams = GetFitSession()->GetDerivedParamNum(nFunc);
		nRow += nNumDerivedParams;
	}
	
	return true;
}
//------ End LOWER_AND_UPPER_BOUNDS_FAILS_TO_REPORT_IN_PA

///Jasmine 11/10/07 ADD_PFW_FIT_FUNCTIONS_TABLE
/*
void 	FitPeak::addFitFuncTable(TreeNode& trOp, bool bDataLabelAsTableMainHeader)
{
	if(!trOp)
		return;
	TreeNode trOldFunction, trOldEquation;
	octree_get_node_by_id(&trOp, &trOldFunction, IDE_NOTES_MODEL, true);
	if(trOldFunction)
		trOldFunction.Remove();
	octree_get_node_by_id(&trOp, &trOldEquation, IDE_NOTES_EQUATION, true);
	if(trOldEquation)
		trOldEquation.Remove();
	
	TreeNode trCal, trFitFuncTable;
	if(trOp.Calculation && trOp.Calculation.Parameters)
	{
		trCal = trOp.Calculation;
		trFitFuncTable = trCal.InsertNode(trCal.Parameters, "FitFunctions");
	}
	if(!trFitFuncTable)
		return;
	trFitFuncTable.DataID = IDST_PFM_FIT_FUNCTIONS;
	trFitFuncTable.SetAttribute(STR_LABEL_ATTRIB, _L("Fit Functions"));
	trFitFuncTable.SetAttribute(TREE_Table, GetTableStringMain(false));

	string strDataLabel;
	GetEscapedMainDataString(trOp, strDataLabel, 1);
	ConvertEscapedString(strDataLabel);
	if(bDataLabelAsTableMainHeader && strDataLabel.IsEmpty())
	{
		error_report("empty str lable and trying to add as table main header");
		bDataLabelAsTableMainHeader = false;
	}
	
	if(!trOp.PFMTree && !trOp.PFMTree.Peaks)
		return;
	TreeNode trPFM = trOp.PFMTree;
	TreeNodeCollection trColl(trPFM.Peaks, "Peak");	
	///Jasmine 11/14/07 FIT_BASELINE_AS_WELL_AS_OTHER_PEAKS
	bool bHasBaselinePeak = HasBaselinePeak(trPFM);
	int nPeakOffset = bHasBaselinePeak? 0 : 1;
	
	int	nNumPeaks = m_pFitSession->GetNumPeaks();
	for(int nPeak = 0; nPeak < nNumPeaks; nPeak++)
	{
		TreeNode trPeak = trColl.Item(nPeak);
		string strRowName = (bHasBaselinePeak && 0 == nPeak)? "Baseline" : "Peak" + ftoa(nPeak + nPeakOffset);
		string strTableLabel = (bHasBaselinePeak && 0 == nPeak)? _L("Baseline") : _L("Peak") + ftoa(nPeak + nPeakOffset) + "(" + strDataLabel +")";
	///End FIT_BASELINE_AS_WELL_AS_OTHER_PEAKS
		TreeNode trRow = tree_check_get_node(trFitFuncTable, strRowName);
		if(bDataLabelAsTableMainHeader)
			tree_add_one_label(trRow, strTableLabel);
		
		//function
		TreeNode trFunction = tree_check_get_node(trRow, "Function", IDE_NOTES_MODEL, STR_LABEL_ATTRIB, _L("Function"));
		trFunction.strVal = trPeak.Function.FuncName.strVal;
		////equation
		//string strFullPath = trPeak.Function.FullPath.strVal;
		//Tree trFF;
		//nlsf_load_FDF_to_tree(strFullPath, &trFF);
		//TreeNode trEquation = tree_check_get_node(trRow, "Equation", IDE_NOTES_EQUATION, STR_LABEL_ATTRIB, _L("Equation"));
		//trEquation.strVal = nlsf_get_formula(trFF);
		
		trRow.ID = make_one_set_ID(IDST_PFM_ONE_FUNCTION + nPeak, 0); 
	}
}*/
///End ADD_PFW_FIT_FUNCTIONS_TABLE

//------ Folger 11/27/07 ADD_OTHER_IMFORMATION_TABLE
void	FitPeak::addOtherInformationTable(TreeNode& trOp)
{	
	TreeNode trCalculation = trOp.Calculation;	
	
	TreeNode trPFWInputData = tree_get_node_by_tagname(trCalculation, "PFWInputData", true);
	//------ Folger 04/29/08 FIX_INPUT_DATA_AND_BASELINE_FAIL_TO_SHOW_IN_PA_REPORT_GRAPH
	//string strTable;
	//if(trPFWInputData && !trPFWInputData.GetAttribute(TREE_Table, strTable))
		//trPFWInputData.SetAttribute(TREE_Table, GetTableStringMain(false));
	if ( trPFWInputData )
	{
		///Sophy 12/5/2008 v8.0982 PA_REPORT_WEIGHT_INFO_IN_INPUTDATA_TABLE_AS_NLFIT
		TreeNode trWeightType = tree_get_node_by_tagname(trCalculation.Input, "C4", true);
		if( trWeightType )
		{
			TreeNode trPFWInputWeightType = tree_check_get_node(trPFWInputData.IDTR1, "IDTC4");
			trPFWInputWeightType.Replace(trWeightType, true, true);
		}
		TreeNode trWeightData = tree_get_node_by_tagname(trCalculation.Input, "C5", true);
		if( trWeightData )
		{
			TreeNode trPFWInputWeightData = tree_check_get_node(trPFWInputData.IDTR1, "IDTC5");
			trPFWInputWeightData.Replace(trWeightData, true, true);
		}
		///end PA_REPORT_WEIGHT_INFO_IN_INPUTDATA_TABLE_AS_NLFIT
		trCalculation.Input.Replace(trPFWInputData, true, true);
		trPFWInputData.Remove();			//hide Fit Data
	}
	//------ End FIX_INPUT_DATA_AND_BASELINE_FAIL_TO_SHOW_IN_PA_REPORT_GRAPH
	
	//add X-Function table
	vector<string> vstrXFList, vstrDesc;
	TreeNode trXFInfo = tree_get_node_by_tagname(trOp, "XFInfo", true);
	if (trXFInfo && trXFInfo.GetNodeCount() == 2)
	{
		vstrXFList = trXFInfo.XF.strVals;
		vstrDesc = trXFInfo.Description.strVals;
		trXFInfo.Reset();
		
		trXFInfo.DataID = IDST_PFM_XF_INFO_TABLE;
		trXFInfo.SetAttribute(STR_LABEL_ATTRIB, _L("X-Functions"));
		trXFInfo.SetAttribute(TREE_Table, GetTableStringMain(false));
		
		for (int ii=0; ii<vstrXFList.GetSize(); ++ii)
		{
			TreeNode trRow = tree_check_get_node(trXFInfo, "XF" + ii, IDST_PFM_XF_INFO_TABLE_ROW + ii, STR_LABEL_ATTRIB, (string)(ii + 1));
			TreeNode trXF = tree_check_get_node(trRow, "XF", IDE_PFM_XF_NAME, STR_LABEL_ATTRIB, _L("X-Function"));
			trXF.strVal = vstrXFList[ii];
			TreeNode trDesc = tree_check_get_node(trRow, "Description", IDE_PFM_XF_DECSCRIPTION, STR_LABEL_ATTRIB, _L("Description"));
			trDesc.strVal = vstrDesc[ii];
		}
	}
	
	//------ Folger 12/07/07 ADD_BASELINE_INFO_AND_FIT_INFO_TABLE
	//add Baseline table	
	//------ Folger 12/07/07 ADD_BASELINE_INFO_AND_FIT_INFO_TABLE
	TreeNode trBaseline = trCalculation.InsertNode(trCalculation.Input, "Baseline");
	trBaseline.DataID = IDST_PFM_BASELINE_INFO_TABLE;
	trBaseline.SetAttribute(STR_LABEL_ATTRIB, _L("Baseline"));
	trBaseline.SetAttribute(TREE_Table, GetTableStringMain(false));
	//------
	
	TreeNode trBLInfo = tree_get_node_by_tagname(trOp, "BLInfo", true);
	if (trBLInfo && trBLInfo.GetNodeCount() == 2)
	{
		string strX = trBLInfo.X.strVal;
		string strY = trBLInfo.Y.strVal;
		
		//------ Folger 12/07/07 ADD_BASELINE_INFO_AND_FIT_INFO_TABLE
		//trBLInfo.Reset();
		trBLInfo.Remove();
		trBLInfo = trBaseline.AddNode("BLInfo");
		//------
		
		trBLInfo.DataID = IDST_PFM_BASELINE_TABLE;
		trBLInfo.SetAttribute(STR_LABEL_ATTRIB, _L("Baseline Data"));
		trBLInfo.SetAttribute(TREE_Table, GetTableStringMain(false));
		
		TreeNode trX = tree_check_get_node(trBLInfo, "BL_X", IDST_PFM_BASELINE_TABLE_ROW_X, STR_LABEL_ATTRIB, "x");
		TreeNode trXData = tree_check_get_node(trX, "X_DATA", IDE_PFM_BASELINE_DATA, STR_LABEL_ATTRIB, _L("Data"));
		trXData.strVal = strX;
		TreeNode trY = tree_check_get_node(trBLInfo, "BL_Y", IDST_PFM_BASELINE_TABLE_ROW_Y, STR_LABEL_ATTRIB, "y");
		TreeNode trYData = tree_check_get_node(trY, "Y_DATA", IDE_PFM_BASELINE_DATA, STR_LABEL_ATTRIB, _L("Data"));
		trYData.strVal = strY;
	}
	else	
	{
		if(trBLInfo)
			trBLInfo.Remove();	///Jasmine 03/24/08 MAKECUSTOMTABLETHEME_REQUIRE_TREETABLE_ATTRIB_AND_NODEID
	}
	
	TreeNode trFitBaseline = tree_get_node_by_tagname(trOp, "FitBaseline", true);
	if(trFitBaseline)
	{
		string strFunction;
		TreeNode trParameters = tree_get_node_by_tagname(trFitBaseline, "Parameters", true);
		TreeNode trFunction = tree_get_node_by_tagname(trFitBaseline, "FuncName", true);
		if(trFunction)
			strFunction = trFunction.strVal;		
		
		TreeNode trPFW = trOp.GetNode("PFWTree");
		TreeNode trPeak0 = tree_get_node_by_tagname(trPFW, PFM_BASELINE_PEAK_TAG_NAME, true);
		if (trPeak0)
		{
			if (strFunction.CompareNoCase(trPeak0.Function.FuncName.strVal) == 0)
			{
				trFitBaseline.Remove();
				return;
			}
		}
		
		trFitBaseline.DataID = IDST_PFM_BASELINE_FIT_TABLE;
		trFitBaseline.SetAttribute(STR_LABEL_ATTRIB, _L("Baseline Parameters(Separate Fit)"));
		trFitBaseline.SetAttribute(TREE_Table, GetTableStringMain(false));
		int nPara = 1;
		foreach(TreeNode trPara in trParameters.Children)
		{
			string strRowName = trPara.tagName;
			TreeNode trRow = tree_check_get_node(trFitBaseline, strRowName);
			tree_add_one_label(trRow, strFunction);
			tree_add_one_label(trRow, strRowName, 0);
			int nItem = 1;
			foreach(TreeNode trItem in trPara.Children)
			{
				TreeNode trOneValue = tree_check_get_node(trRow, trItem.tagName, IDST_PFM_BASELINE_ONE_FIT + nItem, STR_LABEL_ATTRIB, _L(trItem.tagName));
				trOneValue.strVal = trItem.strVal;			
			}
			trRow.ID = make_one_set_ID(IDST_PFM_BASELINE_FIT_TABLE + nPara, 0); 
			nPara++;
		}
		trParameters.Remove();
		trFitBaseline.Function.Remove();
		
		//------ Folger 12/07/07 ADD_BASELINE_INFO_AND_FIT_INFO_TABLE
		trBaseline.AddNode( trFitBaseline.Clone() );
		trFitBaseline.Remove();
		//------
	}
	
	if( trBaseline && trBaseline.IsEmpty() )
		trBaseline.Remove();	///Jasmine 03/24/08 MAKECUSTOMTABLETHEME_REQUIRE_TREETABLE_ATTRIB_AND_NODEID
	
	/*//add Fit Table
	TreeNode trFit = trCalculation.InsertNode(trCalculation.Input, "FitInfo");
	trFit.DataID = IDST_PFM_FIT_INFO_TABLE;
	trFit.SetAttribute(STR_LABEL_ATTRIB, _L("Fit"));
	trFit.SetAttribute(TREE_Table, GetTableStringMain(false));
	
	vector<string> vsTagName = { "Input", "Parameters" };
	for (int ii=0; ii<vsTagName.GetSize(); ++ii)
	{
		TreeNode trNode = trCalculation.GetNode(vsTagName[ii]);
		if ( trNode )
		{
			int nTable;
			if ( !trNode.GetAttribute( TREE_Table, nTable ) )
				trNode.SetAttribute( TREE_Table, GetTableStringMain(false) );
			trFit.AddNode( trNode.Clone() );
			trNode.Remove();
		}
	}
	//------
	*/
	///Sophy 11/10/2008 CLEAN_CODE_ADD_BASELINE_INFO_TO_REPORT_TABLE
	//########################  Baseline Info Table  Begin  #####################//
	//------ Folger 04/21/08 ADD_BASELINE_MODE_TABLE_TO_OUTPUT_REPORT
	//knowledge kept in PeakFitHelper::addBaselineInfo
	TreeNode trBL = tree_get_node_by_tagname(trCalculation, "Baseline", true);

	if ( trBL && trBL.FirstNode )
	{
		string strTableLabel;
		string strFootNote = trBL.Subtracted.nVal == 0 ? _L("Baseline was not subtracted") : _L("Baseline was subtracted"); 		//------ Folger 05/16/08 IMPROVE_BASELINE_MODE_TABLE
		switch ( trBL.Mode.nVal )
		{
		case PA_BM_CONSTANT:
			{
				//------ Folger 05/14/08 HIDE_BASE_MODE_TABLE_WHEN_BASELINE_IS_CONSTANT
				if ( trBL.Subtracted.nVal )
				{
				double	rConstant = trBL.Constant.dVal;
					
				trBL.Reset();
					strTableLabel = _L("Baseline Mode(Constant)");
				
				TreeNode trY = tree_check_get_node(trBL, STR_BASELINE_MODE_CONSTATNT_TAGNAME, IDST_PFM_BASELINE_TABLE_ROW_Y, STR_LABEL_ATTRIB, "Y = ");
				trY.dVal = rConstant;
				}
				else
				{
				trBL.Remove();
				}
				//------
			}
			break;
			
		case PA_BM_USERDEF:
			{
				string	strConnect = trBL.Connect.strVal;
				string	strFunction = trBL.Function.strVal;
				vector	vx, vy;
				vx = trBL.X.dVals;
				vy = trBL.Y.dVals;
				
				//------ Folger 05/16/08 IMPROVE_BASELINE_MODE_TABLE
				TreeNode		trParams = trBL.GetNode( STR_BASELINE_PARAM_TREE );
				vector<string>	vsLabels;
				vector			vParamValues;
				if ( trParams )
				{
					foreach ( TreeNode trNode in trParams.Children )
					{
						string strLabel;
						trNode.GetAttribute(STR_LABEL_ATTRIB, strLabel);
						vsLabels.Add(strLabel);
						vParamValues.Add(trNode.dVal);
					}
				}
				//------
				
				trBL.Reset();
				strTableLabel = _L("Baseline Mode(User Defined)");
				
				//------ Folger 05/15/08 USE_FOOTNOTE_TO_REPRESENT_NUMBER_OF_ANCHOR_AND_CONNECT_FUNCTION
				//TreeNode trAnchor = tree_check_get_node(trBL, STR_BASELINE_MODE_ANCHOR_TAGNAME, IDST_PFM_BASELINE_TABLE_ROW_ANCHOR, STR_LABEL_ATTRIB, _L("Number of Baseline Anchor"));
				//trAnchor.nVal = vx.GetSize();
				//TreeNode trConnect = tree_check_get_node(trBL, STR_BASELINE_MODE_CONNECT_TAGNAME, IDST_PFM_BASELINE_TABLE_ROW_CONNECT, STR_LABEL_ATTRIB, _L("Connected by") + ' ' + strConnect);
				//trConnect.strVal = strFunction;
				//------
				
				TreeNode trAnchorPoints = trBL.AddNode(STR_BASELINE_MODE_ANCHOR_POINTS_TAGNAME);
				trAnchorPoints.DataID = IDST_PFM_BASELINE_TABLE_ANCHOR_POINTS;
				trAnchorPoints.SetAttribute(STR_LABEL_ATTRIB, _L("Baseline Anchor Points"));
				trAnchorPoints.SetAttribute(TREE_Table, GetTableStringMain(false));
				//------ Folger 07/16/08 FIX_BASELINE_MODE_FAIL_TO_DISPLAY_IN_REPORT_GRAPH_DUE_TO_REPORT_SHEET_NODE_CHANGE
				trAnchorPoints.SetAttribute(STR_BASELINE_MODE_FUNCTION_ATTRIB, strFunction);
				//------
				
				TreeNode trX = tree_check_get_node(trAnchorPoints, "X", IDST_PFM_BASELINE_TABLE_ROW_X, STR_LABEL_ATTRIB, "X");
				//trX.dVals = vx;		//------ Folger 05/04/08 FIX_ANCHOR_POINTS_TABLE_USE_NORMAL_CELL_VALUE_INSTEAD_OF_VECTOR
				TreeNode trY = tree_check_get_node(trAnchorPoints, "Y", IDST_PFM_BASELINE_TABLE_ROW_Y, STR_LABEL_ATTRIB, "Y");
				//------ Folger 05/04/08 FIX_ANCHOR_POINTS_TABLE_USE_NORMAL_CELL_VALUE_INSTEAD_OF_VECTOR
				//trY.dVals = vy;
				int nNumPoints = IDST_PFM_BASELINE_TABLE_ANCHOR_POINTS_INDEX_END - IDST_PFM_BASELINE_TABLE_ANCHOR_POINTS_INDEX_BEGIN + 1;
				if ( vx.GetSize() < nNumPoints )
					nNumPoints = vx.GetSize();
				for ( int ii=0; ii<nNumPoints; ++ii )
				{
					TreeNode trXCol = tree_check_get_node(trX, "X" + ii, IDST_PFM_BASELINE_TABLE_ANCHOR_POINTS_INDEX_BEGIN + ii, STR_LABEL_ATTRIB, (string)(ii+1));
					trXCol.dVal = vx[ii];
					TreeNode trYCol = tree_check_get_node(trY, "Y" + ii, IDST_PFM_BASELINE_TABLE_ANCHOR_POINTS_INDEX_BEGIN + ii, STR_LABEL_ATTRIB, (string)(ii+1));
					trYCol.dVal = vy[ii];
				}
				//------
				
				//------ Folger 05/16/08 IMPROVE_BASELINE_MODE_TABLE
				int		nSize = vsLabels.GetSize();
				if ( nSize > 0 )
				{
					int 	nActualSize = nSize;
					if ( nSize > IDST_PFM_BASELINE_TABLE_PARAMETERS_ITEM_END - IDST_PFM_BASELINE_TABLE_PARAMETERS_ITEM_BEGIN + 1 )
					{
						ASSERT(FALSE);
						nActualSize = IDST_PFM_BASELINE_TABLE_PARAMETERS_ITEM_END - IDST_PFM_BASELINE_TABLE_PARAMETERS_ITEM_BEGIN + 1;
					}
					
					trParams = trBL.AddNode("Parameters");
					trParams.DataID = IDST_PFM_BASELINE_TABLE_PARAMETERS;
					trParams.SetAttribute(STR_LABEL_ATTRIB, _L("Baseline Parameters"));
					trParams.SetAttribute(TREE_Table, GetTableStringMain(false));
										
					for ( ii=0; ii<nActualSize; ++ii )
					{
						TreeNode trParam = tree_check_get_node(trParams, "P" + ii, IDST_PFM_BASELINE_TABLE_PARAMETERS_ITEM_BEGIN + ii, STR_LABEL_ATTRIB, vsLabels[ii]);
						TreeNode trValue = tree_check_get_node(trParam, "Value", IDST_PFM_BASELINE_TABLE_PARAMETERS_VALUE, STR_LABEL_ATTRIB, _L("Value"));
						trValue.dVal = vParamValues[ii];
					}
				}
				
				string strFootNoteEx;
				strFootNoteEx.Format("\r\n%s : %d\r\n%s %s : %s", _L("Number of Baseline Anchor"), vx.GetSize(), _L("Connected by"), strConnect, strFunction);
				strFootNote += strFootNoteEx;
				//------ End IMPROVE_BASELINE_MODE_TABLE
			}
			break;
			
		case PA_BM_USE_EX:
			///Sophy 11/12/2008 SUPPORT_USE_EXISTING_DATARANGE_AS_BASELINE_IN_NEW_PA
			TreeNode	trXYRange = trBL.Range1;
			string		strX = trXYRange.X.strVal;
			string		strY = trXYRange.Y.strVal;
			string		strRange = trBL.Range.strVal;
			double		rOffset = trBL.Offset.dVal;		//------ Folger 05/16/08 IMPROVE_BASELINE_MODE_TABLE
			///end SUPPORT_USE_EXISTING_DATARANGE_AS_BASELINE_IN_NEW_PA

			
			trBL.Reset();
			strTableLabel = _L("Baseline Mode(Existing Dataset)");
			
			TreeNode trX = tree_check_get_node(trBL, "X", IDST_PFM_BASELINE_TABLE_ROW_X, STR_LABEL_ATTRIB, "X");
			trX.strVal = strX;
			TreeNode trY = tree_check_get_node(trBL, "Y", IDST_PFM_BASELINE_TABLE_ROW_Y, STR_LABEL_ATTRIB, "Y");
			trY.strVal = strY;
			TreeNode trRange = tree_check_get_node(trBL, "Range", IDST_PFM_BASELINE_TABLE_RANGE, STR_LABEL_ATTRIB, "Range");
			trRange.strVal = strRange;
						
			//------ Folger 05/16/08 IMPROVE_BASELINE_MODE_TABLE
			string strFootNoteEx;
			strFootNoteEx.Format("\r\n%s : %g", _L("Baseline had offset"), rOffset);
			strFootNote += strFootNoteEx;
			//------
			break;
				
		/// Iris 11/18/2008 PA_FIT_SUPPORT_NEW_BASELINE_MODE_XPS
		#ifdef PA_WITH_XPS_BASELINE 
		case PA_BM_XPS:
			string strMethod = trBL.Method.strVal;
			
			trBL.Reset();
			if( !strMethod.IsEmpty() )
			{
				TreeNode trMethod = tree_check_get_node(trBL, STR_BASELINE_MODE_XPS_METHOD_TAGNAME, IDST_PFM_BASELINE_TABLE_ROW_XPS_METHOD, STR_LABEL_ATTRIB, _L("Method"));
				trMethod.strVal = strMethod;			
			}
			strTableLabel = _L("Baseline Mode(XPS)");			
			break;
		#endif //PA_WITH_XPS_BASELINE
		///end PA_FIT_SUPPORT_NEW_BASELINE_MODE_XPS
			
		default:
			break;
		}
		trBL.DataID = IDST_PFM_BASELINE_TABLE;
		trBL.SetAttribute(TREE_Table, GetTableStringMain(false));
		trBL.SetAttribute(STR_LABEL_ATTRIB, strTableLabel);			
		
		//------ Folger 05/16/08 IMPROVE_BASELINE_MODE_TABLE
		TreeNode 	trFootNote = tree_check_get_node(trBL, "Footnote", IDE_FOOTNOTE_BEGIN, TREE_Footnote, "1"); 
		trFootNote.strVal = strFootNote;
		//------
		
	}
	//------ End ADD_BASELINE_MODE_TABLE_TO_OUTPUT_REPORT

	//########################  Baseline Info Table  End  ######################//
	///end CLEAN_CODE_ADD_BASELINE_INFO_TO_REPORT_TABLE
}
//------

///Jasmine 11/14/07 FIT_BASELINE_AS_WELL_AS_OTHER_PEAKS
bool 	FitPeak::HasBaselinePeak(/*TreeNode trPFM*/)	///Jasmine 06/15/09 NO_NEED_PFM_TREE
{
	///Kyle 10/20/08 SHOULD_GET_BASELINE_CONDITION_FROM_NLFSESSION
	//return 0 == trPFM.Peaks.FirstNode.tagName.CompareNoCase(PFM_BASELINE_PEAK_TAG_NAME);
	///Kyle 10/21/08 CHANGE_FUNCTION_NAME_HASBASELINEPEAK_TO_GETBASELINEFITMODE
	//return GetFitSession()->HasBaselinePeak();
	return GetFitSession()->GetBaselineFitMode();
	///End CHANGE_FUNCTION_NAME_HASBASELINEPEAK_TO_GETBASELINEFITMODE
	///End SHOULD_GET_BASELINE_CONDITION_FROM_NLFSESSION
}
///End FIT_BASELINE_AS_WELL_AS_OTHER_PEAKS
void 	FitPeak::updateLabelsForPeaksReportTable(TreeNode& trOneResult)
{
	trOneResult.dAreaFit.SetAttribute(STR_LABEL_ATTRIB, _L("Area Fit"));
	trOneResult.dAreaFitT.SetAttribute(STR_LABEL_ATTRIB, _L("Area FitT"));
	trOneResult.dAreaFitTP.SetAttribute(STR_LABEL_ATTRIB, _L("Area FitTP"));
	trOneResult.dAreaIntg.SetAttribute(STR_LABEL_ATTRIB, _L("Area Intg"));
	trOneResult.dAreaIntgP.SetAttribute(STR_LABEL_ATTRIB, _L("Area IntgP"));
	trOneResult.dCenterMax.SetAttribute(STR_LABEL_ATTRIB, _L("Center Max"));
	trOneResult.dCenterGrvty.SetAttribute(STR_LABEL_ATTRIB, _L("Center Grvty"));
	trOneResult.dMaxHeight.SetAttribute(STR_LABEL_ATTRIB, _L("Max Height"));
	///Kyle 09/24/08 SET_NO_NEED_TO_LOCALIZE
	//trOneResult.dFWHM.SetAttribute(STR_LABEL_ATTRIB, _L("FWHM"));
	trOneResult.dFWHM.SetAttribute(STR_LABEL_ATTRIB, "FWHM");
	///End SET_NO_NEED_TO_LOCALIZE
	trOneResult.dVariance.SetAttribute(STR_LABEL_ATTRIB, _L("Variance"));
	trOneResult.dSkew.SetAttribute(STR_LABEL_ATTRIB, _L("Skew"));
	trOneResult.dExcess.SetAttribute(STR_LABEL_ATTRIB, _L("Excess"));
	trOneResult.dResolution.SetAttribute(STR_LABEL_ATTRIB, _L("Resolution"));
	trOneResult.dMoment3.SetAttribute(STR_LABEL_ATTRIB, _L("Moment3"));
	trOneResult.dMoment4.SetAttribute(STR_LABEL_ATTRIB, _L("Moment4"));
	
	///Jasmine 05/14/08 dWidthAtPercent_VALUES_ARE_MISSING_IN_REPORT
	string strPercent;
	if(trOneResult.dWidthAtPP)
	{
		strPercent.Format("(%s%%)", ftoa(trOneResult.dWidthAtPP.dVal) );
		trOneResult.dWidthAtPP.Remove();
	}
	trOneResult.dWidthAtP.SetAttribute(STR_LABEL_ATTRIB, _L("WidthAtP") + strPercent);
	
	if(trOneResult.dAreaAboveP)
	{
		strPercent.Format("(%s%%)", ftoa(trOneResult.dAreaAboveP.dVal) );	
		trOneResult.dAreaAboveP.Remove();
	}
	trOneResult.dAreaAbove.SetAttribute(STR_LABEL_ATTRIB, _L("AreaAbove") + strPercent);
	
	if(trOneResult.dCumAreaP)
	{
		strPercent.Format("(%s)", ftoa(trOneResult.dCumAreaP.dVal) );
		trOneResult.dCumAreaP.Remove();
	}
	trOneResult.dCumArea.SetAttribute(STR_LABEL_ATTRIB, _L("CumArea") + strPercent);
	///End dWidthAtPercent_VALUES_ARE_MISSING_IN_REPORT
}
///Jasmine 10/27/07 QA70-10543 PFM_TREE_STRUCTURE_CHANGE
//virtual 
bool 	FitPeak::insertDerivedParamsNames(vector<string>& vstrParameterNames, vector<string>& vsDerivedParamNames, bool bIncPostfix, vector<bool>& vnTarget, int index)
{
	if(NULL == GetFitSession())
		return error_report("found invalid m_pFitSession in insertDerivedParamsNames");
	int nInsertPlace = 0;
	int nPeaks = GetFitSession()->GetNumPeaks();
	int			iDerivedParamName = 0; /// Hong 01/20/09 FIX_PA_DERIVED_PARAM_NAME_NOT_CORRECT_EXCEPT_FIRST_PEAK_IN_REPORT
	for(int nPeak = 0; nPeak < nPeaks; nPeak++)
	{
		///Jasmine 08/13/08 QA80-12009 PARAM_HAS_SAME_NOTATION_AS_75_FOR_MULTI_DS_AND_REPLICA_AND_PEAK
		int nPostfix = nPeak+1;//offset
		///Kyle 10/21/08 CHANGE_FUNCTION_NAME_HASBASELINEPEAK_TO_GETBASELINEFITMODE
		//if( GetFitSession()->HasBaselinePeak() )
		if( GetFitSession()->GetBaselineFitMode() )
		///End CHANGE_FUNCTION_NAME_HASBASELINEPEAK_TO_GETBASELINEFITMODE
			nPostfix--;//skip baseline peak
		///End PARAM_HAS_SAME_NOTATION_AS_75_FOR_MULTI_DS_AND_REPLICA_AND_PEAK
		int nParaInOnePeak = GetFitSession()->GetNumParameter(nPeak);
		int nNumDerivedParamOnePeak = GetFitSession()->GetDerivedParamNum(nPeak);
		nInsertPlace += nParaInOnePeak;
		for(int ii = 0; ii < nNumDerivedParamOnePeak; ii++)
		{
			/// Hong 01/20/09 FIX_PA_DERIVED_PARAM_NAME_NOT_CORRECT_EXCEPT_FIRST_PEAK_IN_REPORT
			//string strDerivedParam = vsDerivedParamNames[ii];
			if ( iDerivedParamName >= vsDerivedParamNames.GetSize() )
				return error_report("Index out of range.");
			string strDerivedParam = vsDerivedParamNames[iDerivedParamName++];
			/// end FIX_PA_DERIVED_PARAM_NAME_NOT_CORRECT_EXCEPT_FIRST_PEAK_IN_REPORT
			if(0 < nPeak && bIncPostfix)
				//strDerivedParam += "__" + (string)(nPeak + 1);	///Jasmine 08/13/08 QA80-12009 PARAM_HAS_SAME_NOTATION_AS_75_FOR_MULTI_DS_AND_REPLICA_AND_PEAK
				strDerivedParam = GetFitSession()->GetPeakParamIndexedName(strDerivedParam, nPostfix);
			vstrParameterNames.InsertAt(nInsertPlace, strDerivedParam);	
			vnTarget.InsertAt(nInsertPlace, true);
			nInsertPlace++;
		}
	}
	return true;
}
///End PFM_TREE_STRUCTURE_CHANGE

///Kyle 08/10/2009 QA80-14077 ADD_PARAMETER_UNIT_TO_FITTING_REPORT
bool FitPeak::insertDerivedParamsUnits(vector<string>& vstrParameterUnits, vector<string>& vsDerivedParamUnits, vector<bool>& vnTarget, int index)
{
	if(NULL == GetFitSession())
		return error_report("found invalid m_pFitSession in insertDerivedParamsUnits");
	int nInsertPlace = 0;
	int nPeaks = GetFitSession()->GetNumPeaks();
	int			iDerivedParamUnit = 0;
	for(int nPeak = 0; nPeak < nPeaks; nPeak++)
	{
		int nPostfix = nPeak+1;//offset
		if( GetFitSession()->GetBaselineFitMode() )
			nPostfix--;//skip baseline peak

		int nParaInOnePeak = GetFitSession()->GetNumParameter(nPeak);
		int nNumDerivedParamOnePeak = GetFitSession()->GetDerivedParamNum(nPeak);
		nInsertPlace += nParaInOnePeak;
		for(int ii = 0; ii < nNumDerivedParamOnePeak; ii++)
		{
			if ( iDerivedParamUnit >= vsDerivedParamUnits.GetSize() )
				return error_report("Index out of range.");
			vstrParameterUnits.InsertAt(nInsertPlace, vsDerivedParamUnits[iDerivedParamUnit++]);
			vnTarget.InsertAt(nInsertPlace, true);
			nInsertPlace++;
		}
	}
	return true;
}
///End ADD_PARAMETER_UNIT_TO_FITTING_REPORT

///Jasmine 12/17/07 SHOULD_UPDATE_PFW_TREE_AFTER_FITTING
bool 	FitPeak::updatePFWTreeAfterFit(TreeNode& trOp)
{
	if(NULL == GetFitSession())
		return error_report("cannot find m_pFitSession in updatePFWTreeAfterFit");
	
	Tree 		trPFM;
	TreeNode 	trOpPFM = tree_check_get_node(trOp, PFW_TREE_TAG_NAME);
	if(trOpPFM && GetFitSession()->GetResultPFWTree(trPFM))
	{
		trOpPFM.Replace(trPFM.Clone(), true, true);	
		return true;
	}	
	return false;
}
///End SHOULD_UPDATE_PFW_TREE_AFTER_FITTING
bool	FitPeak::CalcMultiData(TreeNode& trOp, DataRange& dr, int &nNumData, int nExeMode, DWORD dwExecCntrl)
{	
	// copy values from pkfitDlg xf GUI tree to trOp.GUI treenodes
	beforeCalcMultiData(trOp);
	
	// init MulFuncsFitSession pointer
	//if(NULL == GetFitSession())
	if ( NULL == m_pFitSession )
	{
		InitFitSessionPointer(trOp); 
	}
	GetFitSession()->SetAutoInitParams(false); //no need init param by param init codes, should read param init value directly from PFM Tree
	///Arvin 12/05/07 XOP_NEED_SUPPORT_PFW
	//As jasmine said, tag name of PFW tree node should be PFWTree
	//m_pFitSession->SetFitInfoTree(trOp.PFMTree);
	GetFitSession()->SetFitInfoTree(trOp.PFWTree);
	///end XOP_NEED_SUPPORT_PFW
	
	
	if( FitNL::CalcMultiData(trOp, dr, nNumData, nExeMode, dwExecCntrl) )
	{	
		/*
		///Jasmine 08/23/07 SPFM_NO_NEED_CALC_PFM_PEAK_RESULTS
		string strCate;
		//m_pFitSession->GetFunctionName(&strCate);	///Jasmine 01/24/08 BASELINE_CATECORY_IS_DIFF
		strCate = m_pFitSession->GetCategoryName();
		if(0 == strCate.CompareNoCase(STR_CATE_NAME_SPFM))
			return true;
		///End SPFM_NO_NEED_CALC_PFM_PEAK_RESULTS
		*/
		if(!updatePFWTreeAfterFit(trOp))	///Jasmine 12/17/07 SHOULD_UPDATE_PFW_TREE_AFTER_FITTING
			error_report("updatePFWTreeAfterFit fail");
		
		/// Iris 2/24/2010 QA81-15140 FIT_NOT_CONVERGE_BAD_PARAM_VALUE_CAUSE_BAD_REPORT
		// fit result not good should not cause cannot add more XF related information to report tree
		//if( calcPFMPeakResults(trOp) )
		//{
		if( !calcPFMPeakResults(trOp) )
			error_report("calcPFMPeakResults return false");		
		///End FIT_NOT_CONVERGE_BAD_PARAM_VALUE_CAUSE_BAD_REPORT
		
			//addFitFuncTable(trOp);	///Jasmine 11/10/07 ADD_PFW_FIT_FUNCTIONS_TABLE
			TreeNode trOldFunction, trOldEquation;
			///Jasmine 04/16/08 MODEL_SHOW_MULTI_FUNCS_OR_FITFUNC_IF_ONLY_ONE_IN_FITPEAK
			/*octree_get_node_by_id(&trOp, &trOldFunction, IDE_NOTES_MODEL, true);
			if(trOldFunction)
				trOldFunction.Remove();*/
			///End MODEL_SHOW_MULTI_FUNCS_OR_FITFUNC_IF_ONLY_ONE_IN_FITPEAK
			octree_get_node_by_id(&trOp, &trOldEquation, IDE_NOTES_EQUATION, true);
			if(trOldEquation)
				trOldEquation.Remove();
			addOtherInformationTable(trOp);		//------ Folger 11/27/07 ADD_OTHER_IMFORMATION_TABLE
			//return true;  /// Iris 11/12/2008 v8.0969 QA80-12584 OUTPUT_BASELINE_AND_SUBTRACTED_DATA_IN_FIT_PEAK_OP, need do more calculation below
			
		/// Iris 2/24/2010 QA81-15140 FIT_NOT_CONVERGE_BAD_PARAM_VALUE_CAUSE_BAD_REPORT
		/*
		}
		/// Iris 11/12/2008 v8.0969 QA80-12584 OUTPUT_BASELINE_AND_SUBTRACTED_DATA_IN_FIT_PEAK_OP
		else
			error_report("calcPFMPeakResults return false");
		*/
		///End FIT_NOT_CONVERGE_BAD_PARAM_VALUE_CAUSE_BAD_REPORT
		
		/// Iris 11/12/2008 v8.0969 QA80-12584 OUTPUT_BASELINE_AND_SUBTRACTED_DATA_IN_FIT_PEAK_OP
		if( !calcConstructSubtractedDataResultCurveTable(trOp) )
			error_report("calcConstructSubtractedDataResultCurveTable return false");
			
		if( !calcConstructBaselineDataResultCurveTable(trOp) )
			error_report("calcConstructBaselineDataResultCurveTable return false");
		
		return true;
		///end OUTPUT_BASELINE_AND_SUBTRACTED_DATA_IN_FIT_PEAK_OP
	}
	
	return false;
}

///Jasmine 04/16/08 MODEL_SHOW_MULTI_FUNCS_OR_FITFUNC_IF_ONLY_ONE_IN_FITPEAK
//virtual
string FitPeak::GetResultModel(const TreeNode& trOperation)
{
	string strFunc = _L("Multiple Functions");
	if(NULL != GetFitSession())
	{
		//vector<int> vnPeakTypes;
		vector<string> vsPeakFuncs;
		if( GetFitSession()->GetParamStringValues(vsPeakFuncs, NLPARAMGRIDCOLTYPE_FUNC_NAME) )
		{
			/*
			int nFunc = 0;
			int nSize = vnPeakTypes.GetSize();
			if(	GetFitSession()->HasBaselinePeak() && 0 < nSize )
			{
				vnPeakTypes.RemoveAt(0);
				nSize--;
				nFunc++;
			}
			
			if(0 < nSize)
			{
				vector<int> vnTemp(nSize);
				int nPeakType = vnPeakTypes[0];
				vnTemp = nPeakType;
				if( oc_is_same(&vnPeakTypes, &vnTemp) )
					strFunc	= GetFitSession()->GetFunctionName(NULL, nFunc);
			}
			*/
		}
		///------ Folger 09/24/09 SHOW_FUNCTION_NAME_IN_REPORT_NOTES_TABLE_WHEN_PA_FITTING_WITH_ONE_SAME_FUNCTION
		int		nFunc = GetFitSession()->GetBaselineFitMode() ? 1 : 0;
		string	strFuncSame;
		for ( ; nFunc<GetFitSession()->GetNumberFitFunctions(); ++nFunc )
		{
			string	str = GetFitSession()->GetFunctionName(NULL, nFunc);
			if ( strFuncSame.IsEmpty() )
			{
				strFuncSame = str;
			}
			else if ( strFuncSame.CompareNoCase(str) != 0 )
			{
				strFuncSame.Empty();
				break;
			}
		}
		if ( !strFuncSame.IsEmpty() )
			strFunc = strFuncSame;
		///------ End SHOW_FUNCTION_NAME_IN_REPORT_NOTES_TABLE_WHEN_PA_FITTING_WITH_ONE_SAME_FUNCTION
	}
	
	return strFunc;
}

string FitPeak::GetResultDescription(const TreeNode& trOperation, bool bLong)// = true
{
	string str = _LR("Peak Fit");
	
	if(bLong)
		str += " (" + GetResultModel(trOperation) + ")";
	
	return str;
}
///End MODEL_SHOW_MULTI_FUNCS_OR_FITFUNC_IF_ONLY_ONE_IN_FITPEAK

///Cheney 2007-7-30 ADD_NEW_FUNC_TO_SUPPORT_PFM_LOAD_FDF
//PFM no need to do this, in PKFitDlg has do it already
bool	FitPeak::LoadFDFtoTree(LPCSTR lpcszFuncName)
{
	return true;
}

//PFM has no theme select from menu
//and now not support change fun, so just return now
void	FitPeak::UpdateFDFTreeFromThemeOrChangeFunc(bool bOpenDlg)
{
	return;
}
///end ADD_NEW_FUNC_TO_SUPPORT_PFM_LOAD_FDF

///Cheney 2007-8-1 CORRECT_LOGIC_OF_LOADING_THEME	
void	FitPeak::ThemeUpdateLastUsed(LPCSTR lpcszClassName, TreeNode& tr, bool bThemesTree)
{
	theme_update_last_used(lpcszClassName, tr, bThemesTree);
}
///end CORRECT_LOGIC_OF_LOADING_THEME

///Cheney/Arvin 2007-9-10 XOP_NEED_SUPPORT_PFW
static bool  _get_func_parameters(const string& strFullPath, vector<string>& vsParams)
{
	vsParams.SetSize(0);
	Tree trFDF;
	if( !nlsf_FDF_to_tree(strFullPath, &trFDF ))
		return false;
	
	string	strParamNames = trFDF.FittingParameters.Names.strVal;
	if(strParamNames.IsEmpty())
		return false;
	
	strParamNames.GetTokens(vsParams, ',');
	return vsParams.GetSize() > 0;
}

static void _add_one_param_settings(TreeNode& trOneParam)
{
	if(!trOneParam)
		return;
	trOneParam.Value.dVal = NANUM;
	trOneParam.LowerBounds.dVal = NANUM;
	trOneParam.LowerBounds.dVal = NANUM;
	trOneParam.LowerBoundsExclusive.nVal = 0;
	trOneParam.UpperBoundsExclusive.nVal = 0;
	trOneParam.Fixed.nVal = 0;
	trOneParam.Shared.nVal = 0;
}
/*
static void _copy_one_param_settings(const TreeNode& trOneParamSettings, TreeNode& trParam)
{
	if(trOneParamSettings.Value)
	{
		trParam.Value.dVal = trOneParamSettings.Value.dVal;
	}
	
	if(trOneParamSettings.LowerBounds)
	{
		trParam.LowerBounds.dVal = trOneParamSettings.LowerBounds.dVal;
	}
	
	if(trOneParamSettings.UpperBounds)
	{
		trParam.LowerBounds.dVal = trOneParamSettings.UpperBounds.dVal;
	}
	
	if(trOneParamSettings.LowerBoundsExclusive)
	{
		trParam.LowerBoundsExclusive.nVal = trOneParamSettings.LowerBoundsExclusive.nVal;
	}
	
	if(trOneParamSettings.UpperBoundsExclusive)
	{
		trParam.UpperBoundsExclusive.nVal = trOneParamSettings.UpperBoundsExclusive.nVal;
	}
	
	if(trOneParamSettings.Fixed)
	{
		trParam.Fixed.nVal = trOneParamSettings.Fixed.nVal;
	}
	
	if(trOneParamSettings.Shared)
	{
		trParam.Shared.nVal = trOneParamSettings.Shared.nVal;
	}
}

int	FitPeak::constructPFWTreeByUserSettings(const TreeNode& trUserSettings, TreeNode& trPFW)
{
	TreeNode trPeaks = trUserSettings.Peaks;
	if(!trPeaks)
		return OP_INVALID_INPUT_DATA_NODE;
	
	int iPeak = 0;
	trPFW.AddNode("Peaks");
	TreeNode trPFWPeaks = trPFW.Peaks;
	foreach(TreeNode trPeak in trPeaks.Children)
	{
		string strPeakName = "Peak" + ftoa(iPeak);
		string strTemp = strPeakName;
		string strTagName = trPeak.tagName;
		strTemp.MakeUpper();
		strTagName.MakeUpper();
		if(iPeak == 0 && strTagName.Compare(strTemp) != 0)
		{
			iPeak++;
			strPeakName = "Peak" + ftoa(iPeak);
			strTemp = strPeakName;
			strTemp.MakeUpper();
		}
		
		if(!strTagName.Compare(strTemp))
		{
			trPFWPeaks.AddNode(strPeakName);
		}
		else
			return OP_WRONG_PFW_TREE_PEAKS_NODE;
		
		if( !IsXOPFuncReady(trPeak.Function.FuncName) )
			return OP_NLSF_NOT_SELECT_FUNCTION;
		string strFuncName = trPeak.Function.FuncName.strVal;
		if(strFuncName.IsEmpty())
			return OP_NLSF_NOT_SELECT_FUNCTION;
		
		TreeNode trPFWPeak = trPFWPeaks.GetNode(strPeakName);
		trPFWPeak.AddNode("Function");
		trPFWPeak.Function.AddNode("FuncName");
		TreeNode trPFWFuncName = trPFWPeak.Function.FuncName;
		trPFWFuncName.strVal = strFuncName;		
		string strCateg, strFile, strFullPath;
		if(!nlf_find_category(strFuncName, strCateg, -1) && strCateg.IsEmpty())
		{
			if(!add_pfw_functions_to_folder() || !nlf_find_category(strFuncName, strCateg, -1))
				return OP_CAN_NOT_FIND_FUNC_FDF_FILE;
		}
		
		nlsf_func_to_fdf(strCateg, strFuncName, strFile, false);
		nlsf_func_to_fdf(strCateg, strFuncName, strFullPath, true);	
		TreeNode trFullPath = trPFWPeak.Function.InsertNode(trPFWFuncName, TAG_FULLPATH_IN_PFM_TREE);
		trFullPath.strVal = strFullPath;
		TreeNode trFile = trPFWPeak.Function.InsertNode(trPFWFuncName, TAG_FILE_IN_PFM_TREE);
		trFile.strVal = strFile;
		
		TreeNode trParams = trPeak.Parameters;
		if(!trParams)
			return OP_INVALID_INPUT_DATA_NODE;
		
		vector<string> vsParams;
		trPFWPeak.AddNode("Parameters");
		TreeNode trPFWParams = trPFWPeak.Parameters;
		if(!_get_func_parameters(strFullPath, vsParams))
			return OP_FAILED_GET_FUNC_PARAMS;
		
		foreach(TreeNode trParam in trParams.Children)
		{
			if(trParam.IsEmpty || !trParam.Value || is_missing_value(trParam.Value.dVal))
				return OP_INVALID_PARAMETER_SETTING;
			
			string strParamName;
			string strTagParam = trParam.tagName;
			int nFind = vsParams.Find(strTagParam);
			if(nFind >= 0 && nFind < vsParams.GetSize())
				strParamName = vsParams[nFind];
			else if(iPeak == 1 && strTagParam.CompareNoCase("y0") == 0)
				strParamName = "y0";
			else
				return OP_WRONG_PFW_TREE_PARAMS_SETTINGS;
			
			trPFWParams.AddNode(strParamName);
			TreeNode trOneParam = trPFWParams.GetNode(strParamName);
			_copy_one_param_settings(trParam, trOneParam)
				
		}
		iPeak++;
	}
	
	return OP_NOERROR;
}
*/
static void _remove_redundant_offset(vector<string>& vsParams, int nFitType, bool bHasBaseLine, int iPeak)
{
	string strTemp = "y0";
	if(nFitType != NLFIT_GENERAL_XY_FITTING)
		strTemp = "z0";
	
	int nFind = vsParams.Find(strTemp);
	if( ( (bHasBaseLine && iPeak > 0) || iPeak > 1) && nFind >= 0)
		vsParams.RemoveAt(nFind);		
}

/// Iris 4/24/2008 HIDE_INNER_OUTER_LIMITS_FOR_XYFIT_AND_PA
/*
static int  _get_fit_type(TreeNode &trOp)
{
	TreeNode trFitType = trOp.SpecInfo.FitType;
	if(trFitType) 
		return trFitType.nVal;
	
	return NLFIT_GENERAL_XY_FITTING;
}
*/
///end HIDE_INNER_OUTER_LIMITS_FOR_XYFIT_AND_PA

int	FitPeak::UpdatePFWTreeByUserSettings(TreeNode& trPFW, int nFitType, bool bHasBaseLine)
{
	TreeNode trPeaks = trPFW.Peaks;
	if(!trPeaks)
		return OP_INVALID_INPUT_DATA_NODE;
	
	int iPeak = 1;
	if(nFitType != NLFIT_GENERAL_XY_FITTING)
		bHasBaseLine = false;
	
	if(bHasBaseLine)
		iPeak = 0;
	foreach(TreeNode trPeak in trPeaks.Children)
	{
		TreeNode trFunc = trPeak.Function;
		if(!IsXOPFuncReady(trFunc.FuncName) )
			return OP_NLSF_NOT_SELECT_FUNCTION;
		string strFuncName = trFunc.FuncName.strVal;
		if(strFuncName.IsEmpty())
			return OP_NLSF_NOT_SELECT_FUNCTION;
			
		string strCateg, strFile, strFullPath;
		if(!nlf_find_category(strFuncName, strCateg, -1) && strCateg.IsEmpty())
		{
			/// Folger, to do
			//if(!add_pfw_functions_to_folder() || !nlf_find_category(strFuncName, strCateg, -1))
				return OP_CAN_NOT_FIND_FUNC_FDF_FILE;
		}
		
		nlsf_func_to_fdf(strCateg, strFuncName, strFile, false);
		nlsf_func_to_fdf(strCateg, strFuncName, strFullPath, true);	
		TreeNode trFullPath = tree_check_get_node(trFunc, TAG_FULLPATH_IN_PFM_TREE);
		trFullPath.strVal = strFullPath;
		TreeNode trFile = tree_check_get_node(trFunc, TAG_FILE_IN_PFM_TREE);
		trFile.strVal = strFile;
		
		TreeNode trParams = tree_check_get_node(trPeak, "Parameters");
		if(!trParams)
			return OP_INVALID_INPUT_DATA_NODE;
		
		vector<string> vsParams;
		if(!_get_func_parameters(strFullPath, vsParams))
			return OP_FAILED_GET_FUNC_PARAMS;
		
		_remove_redundant_offset(vsParams, nFitType, bHasBaseLine, iPeak);
		for(int ii = 0; ii < vsParams.GetSize(); ii++)
		{
			TreeNode trOneParam = tree_check_get_node(trParams, vsParams[ii]);
			_add_one_param_settings(trOneParam);
		}
		iPeak++;
	}
	
	return OP_NOERROR;
}

/// Hong 04/10/08 v8.0840c PEAK_FIT_REPORT_PEAK_CHARACTERISTICS_TO_SEPARATE_SHEET
// virtual
void FitPeak::SetOutputBookSheetDefaultName(TreeNode& trGUI)
{
	FitNL::SetOutputBookSheetDefaultName(trGUI);
	
	TreeNode	trOperation = trGUI.Parent();
	bool 		bSeparateSheetForDataset = IsSeparateSheetForDataset(trOperation);
	TreeNode trBookSheetBranch;
	trBookSheetBranch = trGUI.Output.PeakCharacter;
	if ( trBookSheetBranch )
	{
		/// Iris 4/11/2008 SET_BOTH_LONG_NAME_AND_SHORT_NAME_FOR_REPORT_BOOK
		//SetOneOutputBookSheetDefaultName(trGUI, trBookSheetBranch, true, GetResultCurveBookFullName(trOperation, 0, OUTPUT_RESULT_PEAK_CHARACTER_SHEET, bSeparateSheetForDataset));
		//SetOneOutputBookSheetDefaultName(trGUI, trBookSheetBranch, false, GetResultCurveSheetFullName(trOperation, 0, OUTPUT_RESULT_PEAK_CHARACTER_SHEET));
		SetOneOutputBookSheetDefaultName(trGUI, trBookSheetBranch, true, GetResultCurveBookShortName(trOperation, 0, OUTPUT_RESULT_PEAK_CHARACTER_SHEET));
		SetOneOutputBookSheetDefaultName(trGUI, trBookSheetBranch, false, GetResultCurveSheetFullName(trOperation, 0, OUTPUT_RESULT_PEAK_CHARACTER_SHEET));
		///end SET_BOTH_LONG_NAME_AND_SHORT_NAME_FOR_REPORT_BOOK
	}
	
	/// Iris 11/12/2008 v8.0969 QA80-12584 OUTPUT_BASELINE_AND_SUBTRACTED_DATA_IN_FIT_PEAK_OP
	trBookSheetBranch = trGUI.Output.SubtractedData;
	if ( trBookSheetBranch )
	{
		SetOneOutputBookSheetDefaultName(trGUI, trBookSheetBranch, true, GetResultCurveBookShortName(trOperation, 0, OUTPUT_RESULT_SUBTRACTED_DATA_SHEET));
		SetOneOutputBookSheetDefaultName(trGUI, trBookSheetBranch, false, GetResultCurveSheetFullName(trOperation, 0, OUTPUT_RESULT_SUBTRACTED_DATA_SHEET));
	}
	
	trBookSheetBranch = trGUI.Output.BaselineData;
	if ( trBookSheetBranch )
	{
		SetOneOutputBookSheetDefaultName(trGUI, trBookSheetBranch, true, GetResultCurveBookShortName(trOperation, 0, OUTPUT_RESULT_BASELINE_DATA_SHEET));
		SetOneOutputBookSheetDefaultName(trGUI, trBookSheetBranch, false, GetResultCurveSheetFullName(trOperation, 0, OUTPUT_RESULT_BASELINE_DATA_SHEET));
	}
	///end OUTPUT_BASELINE_AND_SUBTRACTED_DATA_IN_FIT_PEAK_OP	
}

//virtual 
string FitPeak::GetResultCurveBookShortName(TreeNode& trOperation, int nIndex, int nOption)
{
	///Sophy 4/21/2008 MAKE_SURE_PEAKFIT_FITTED_VALUES_BOOKNAME_IS_PROPER
	//return E_STR_PEAK_CHARACTER_BOOK_SHORT_NAME;
	if( OUTPUT_RESULT_PEAK_CHARACTER_SHEET == nOption )
		return E_STR_PEAK_CHARACTER_BOOK_SHORT_NAME;
	
	/// Iris 11/12/2008 v8.0969 QA80-12584 OUTPUT_BASELINE_AND_SUBTRACTED_DATA_IN_FIT_PEAK_OP
	if(OUTPUT_RESULT_SUBTRACTED_DATA_SHEET == nOption)
		return E_STR_SUBTRACTED_DATA_BOOK_SHORT_NAME;
	if(OUTPUT_RESULT_BASELINE_DATA_SHEET == nOption)
		return E_STR_BASELINE_DATA_BOOK_SHORT_NAME;		
	///end OUTPUT_BASELINE_AND_SUBTRACTED_DATA_IN_FIT_PEAK_OP
	return FitNL::GetResultCurveBookShortName(trOperation, nIndex, nOption);
	///end MAKE_SURE_PEAKFIT_FITTED_VALUES_BOOKNAME_IS_PROPER
}

//virtual 
string	FitPeak::GetResultCurveSheetFullName(TreeNode& trOperation, int nIndex, int nOption)// = 0, -1
{
	if(OUTPUT_RESULT_PEAK_CHARACTER_SHEET == nOption)
		return STR_PEAK_CHARACTER_SHEET;
	/// Iris 11/12/2008 v8.0969 QA80-12584 OUTPUT_BASELINE_AND_SUBTRACTED_DATA_IN_FIT_PEAK_OP
	if(OUTPUT_RESULT_SUBTRACTED_DATA_SHEET == nOption)
		return STR_SUBTRACTED_DATA_SHEET;
	if(OUTPUT_RESULT_BASELINE_DATA_SHEET == nOption)
		return STR_BASELINE_DATA_SHEET;
	///end OUTPUT_BASELINE_AND_SUBTRACTED_DATA_IN_FIT_PEAK_OP
	
	return FitNL::GetResultCurveSheetFullName(trOperation, nIndex, nOption);
}

// virtual
string FitPeak::GetResultCurveDefBookName(TreeNode& trOperation, int nDataIndex, int nOption) // = 0, -1
{
	string		strBookName;
	if ( OUTPUT_RESULT_PEAK_CHARACTER_SHEET == nOption )
		strBookName = STR_PEAK_CHARACTER_BOOK_LONG_NAME;
	/// Iris 11/12/2008 v8.0969 QA80-12584 OUTPUT_BASELINE_AND_SUBTRACTED_DATA_IN_FIT_PEAK_OP
	else if(OUTPUT_RESULT_SUBTRACTED_DATA_SHEET == nOption)
		strBookName = STR_SUBTRACTED_DATA_BOOK_LONG_NAME;
	else if(OUTPUT_RESULT_BASELINE_DATA_SHEET == nOption)
		strBookName = STR_BASELINE_DATA_BOOK_LONG_NAME;
	///end OUTPUT_BASELINE_AND_SUBTRACTED_DATA_IN_FIT_PEAK_OP
	else
		strBookName = FitNL::GetResultCurveDefBookName(trOperation, nDataIndex, nOption);	
		
	return strBookName;
}
/// end PEAK_FIT_REPORT_PEAK_CHARACTERISTICS_TO_SEPARATE_SHEET

/// Hong 04/14/08 v8.0840c PEAK_FIT_REPORT_PEAK_CHARACTERISTICS_TO_SEPARATE_SHEET
// virtual 
bool FitPeak::IsOutputPeakCharacterSheet(const TreeNode& trOp)
{
	TreeNode trPeakCharacter = trOp.GUI.Output.PeakCharacter;	
	if ( !trPeakCharacter )
		return error_report("trGUI.Output.PeakCharacter invalid");
	TreeNode trBook = trPeakCharacter.Book;
	if ( !trBook )
		return error_report("trGUI.Output.PeakCharacter.Book invalid");
	
	string strReportBook = trBook.strVal;
	if ( PDS_NONE == str_to_predefined_type(strReportBook) )
		return false;
	
	///------ Folger 03/06/09 SHOULD_NOT_NEW_SHEET_IF_NO_PEAK_PROPERTIES_OUTPUT
	//return true;
	return m_bNeedCalculatePeakResults;
	///------ End SHOULD_NOT_NEW_SHEET_IF_NO_PEAK_PROPERTIES_OUTPUT
}
/// end PEAK_FIT_REPORT_PEAK_CHARACTERISTICS_TO_SEPARATE_SHEET

/// Iris 11/12/2008 v8.0969 QA80-12584 OUTPUT_BASELINE_AND_SUBTRACTED_DATA_IN_FIT_PEAK_OP
bool FitPeak::isOutputSpecialResultCurveSheet(const TreeNode& trBranch)
{
	if( !trBranch )
		return false;
	/// Hong 11/14/08 QA80-12584 v8.0971b DISABLE_OPTIONS_INSTEAD_OF_HIDDEN_IT_FOR_BASELINE_OUTPUT_OPTIONS
	//return trBranch.Show;	
	return tree_is_visible(trBranch) && tree_is_editable(trBranch);
	/// end DISABLE_OPTIONS_INSTEAD_OF_HIDDEN_IT_FOR_BASELINE_OUTPUT_OPTIONS
}

//virtual 
/// Iris 3/24/2009 FIX_CREATE_NEW_NLFIT_FINDXY_REPORT_WHEN_RECALCULATE
//bool FitPeak::IsOutputSubtractedDataSheet(const TreeNode& trOp)
int FitPeak::IsOutputSubtractedDataSheet(const TreeNode& trOp)
///end FIX_CREATE_NEW_NLFIT_FINDXY_REPORT_WHEN_RECALCULATE
{
	//------ Folger 11/21/08 v8.0977 SHOULD_NOT_OUTPUT_SUBTRACTED_DATA_AND_BASELINE_DATA_WHEN_FITTING_WITH_NO_BASELINE
	if ( !GetFitSession()->HasBaseline() )
		/// Iris 3/24/2009 FIX_CREATE_NEW_NLFIT_FINDXY_REPORT_WHEN_RECALCULATE
		//return false;
		return REPORT_NOT_CREATE;
		///end FIX_CREATE_NEW_NLFIT_FINDXY_REPORT_WHEN_RECALCULATE
	//------
	
	TreeNode trSubtractedBranch = trOp.GUI.Output.SubtractedData;
	bool bOutput = isOutputSpecialResultCurveSheet(trSubtractedBranch);	
	/// Iris 3/24/2009 FIX_CREATE_NEW_NLFIT_FINDXY_REPORT_WHEN_RECALCULATE
	//return bOutput;
	return bOutput? REPORT_CREATE : REPORT_NOT_CREATE;
	///end FIX_CREATE_NEW_NLFIT_FINDXY_REPORT_WHEN_RECALCULATE
}

//virtual 
/// Iris 3/24/2009 FIX_CREATE_NEW_NLFIT_FINDXY_REPORT_WHEN_RECALCULATE
//bool FitPeak::IsOutputBaselineDataSheet(const TreeNode& trOp)
int FitPeak::IsOutputBaselineDataSheet(const TreeNode& trOp)
///end FIX_CREATE_NEW_NLFIT_FINDXY_REPORT_WHEN_RECALCULATE
{
	//------ Folger 11/21/08 v8.0977 SHOULD_NOT_OUTPUT_SUBTRACTED_DATA_AND_BASELINE_DATA_WHEN_FITTING_WITH_NO_BASELINE
	if ( !GetFitSession()->HasBaseline() )
		/// Iris 3/24/2009 FIX_CREATE_NEW_NLFIT_FINDXY_REPORT_WHEN_RECALCULATE
		//return false;
		return REPORT_NOT_CREATE;
		///End FIX_CREATE_NEW_NLFIT_FINDXY_REPORT_WHEN_RECALCULATE
	//------
	
	TreeNode trBaselineBranch = trOp.GUI.Output.BaselineData;
	bool bOutput = isOutputSpecialResultCurveSheet(trBaselineBranch);
	
	TreeNode trAddBackBaseline = trOp.GUI.AddBackBaseline;
	bool bAddBackBaseline = trAddBackBaseline && trAddBackBaseline.Show && trAddBackBaseline.nVal;
	/// Iris 3/24/2009 FIX_CREATE_NEW_NLFIT_FINDXY_REPORT_WHEN_RECALCULATE	
	//return bOutput;
	return bOutput ? REPORT_CREATE : REPORT_NOT_CREATE;
	///end FIX_CREATE_NEW_NLFIT_FINDXY_REPORT_WHEN_RECALCULATE
}

bool FitPeak::calcConstructSubtractedDataResultCurveTable(TreeNode& trOp)
{
	//REPORT_CREATE		/// Folger, 06/24/09, no idea why Yuri put the enum here, it should be a mistake
	/// YuI 06/23/09 QA70-13835 ORIGIN_FREEZE_AFTER_DESCRIPTIVE_STATISTICS
	//	if( !IsOutputSubtractedDataSheet(trOp) )
	if( REPORT_CREATE != IsOutputSubtractedDataSheet(trOp) )
	/// end ORIGIN_FREEZE_AFTER_DESCRIPTIVE_STATISTICS
		return true; // no need report 
	
	XYRange dr;
	if( !GetFitSession()->GetSubtractedDataRange(dr) )
		return error_report("Fail to get subtracted data range from NLFitSession");
	
	vector vx, vy;
	if( !dr.GetData(vy, vx) )
		return error_report("Fail to get subtracted data from range");
	
	TreeNode trRC = tree_check_get_node(trOp, "SubtractedData", IDST_PFM_SUBTRACTED_DATA_TABLE, STR_LABEL_ATTRIB, "Subtracted Data");
	trRC.SetAttribute(TREE_Table, GetTableStringMain(true));
	
	TreeNode trX = tree_check_get_node(trRC, "X", make_one_set_ID(IDST_PFM_ONE_SUBTRACTED_DATA_SET, 0), STR_LABEL_ATTRIB, "X");
	trX.dVals = vx;
	trX.SetAttribute(STR_COL_DESIGNATION_ATTRIB, OKDATAOBJ_DESIGNATION_X); /// Hong 11/14/08 v80.971b SET_REPORT_SHEET_COL_DESIGNATION
	
	TreeNode trY = tree_check_get_node(trRC, "Y", make_one_set_ID(IDST_PFM_ONE_SUBTRACTED_DATA_SET, 1), STR_LABEL_ATTRIB, _L("Subtracted Data"));
	trY.dVals = vy;
	trY.SetAttribute(STR_COL_DESIGNATION_ATTRIB, OKDATAOBJ_DESIGNATION_Y); /// Hong 11/14/08 v80.971b SET_REPORT_SHEET_COL_DESIGNATION
	
	return true;
}

bool FitPeak::calcConstructBaselineDataResultCurveTable(TreeNode& trOp)
{
	/// YuI 06/23/09 QA70-13835 ORIGIN_FREEZE_AFTER_DESCRIPTIVE_STATISTICS
	//	if( !IsOutputBaselineDataSheet(trOp) )
	if( REPORT_CREATE != IsOutputBaselineDataSheet(trOp) )
	/// end ORIGIN_FREEZE_AFTER_DESCRIPTIVE_STATISTICS
		return true; // no need report 
	
	vector vx, vy;
	/// Iris 11/15/2008 FIX_ADDBACKBASELINE_FAIL_TO_GET_BASELINE_DATA
	//if( !GetFitSession()->GetBaselineData(vx, vy) )
	if( !GetFitSession()->GetBaselineData(vx, vy, NULL, false) )
	///end FIX_ADDBACKBASELINE_FAIL_TO_GET_BASELINE_DATA
		return error_report("Fail to get baseline data from NLFitSession");
	
	TreeNode trRC = tree_check_get_node(trOp, "BaselineData", IDST_PFM_BASELINE_DATA_TABLE, STR_LABEL_ATTRIB, "Baseline Data");
	trRC.SetAttribute(TREE_Table, GetTableStringMain(true));
	
	TreeNode trX = tree_check_get_node(trRC, "X", make_one_set_ID(IDST_PFM_ONE_BASELINE_DATA_SET, 0), STR_LABEL_ATTRIB, "X");
	trX.dVals = vx;
	trX.SetAttribute(STR_COL_DESIGNATION_ATTRIB, OKDATAOBJ_DESIGNATION_X); /// Hong 11/14/08 v80.971b SET_REPORT_SHEET_COL_DESIGNATION
	
	TreeNode trY = tree_check_get_node(trRC, "Y", make_one_set_ID(IDST_PFM_ONE_BASELINE_DATA_SET, 1), STR_LABEL_ATTRIB, _L("Baseline Data"));
	trY.dVals = vy;
	trY.SetAttribute(STR_COL_DESIGNATION_ATTRIB, OKDATAOBJ_DESIGNATION_Y); /// Hong 11/14/08 v80.971b SET_REPORT_SHEET_COL_DESIGNATION
	
	return true;	
}
///end OUTPUT_BASELINE_AND_SUBTRACTED_DATA_IN_FIT_PEAK_OP

static void _add_one_peak_branch(TreeNode& trPeaks, string& strTagName)
{
	if(!trPeaks)
		return;
	
	TreeNode trPeak = tree_check_get_node(trPeaks, strTagName);
	TreeNode trFunction = tree_check_get_node(trPeak, "Function");
	TreeNode trFullPath = tree_check_get_node(trFunction, "FullPath");
	TreeNode trFile = tree_check_get_node(trFunction, "File");
	TreeNode trFuncName = tree_check_get_node(trFunction, "FuncName");
}

static bool _init_pfw_tree(TreeNode trPFW, int nPeakNum, bool bHasBaseline = false)
{
	if(!trPFW)
		return false;
	
	TreeNode trPeaks = tree_check_get_node(trPFW, "Peaks");
	if(bHasBaseline)
	{
		string strTagName = PFM_BASELINE_PEAK_TAG_NAME;
		_add_one_peak_branch(trPeaks, strTagName);
	}
	
	for(int ii = 0; ii < nPeakNum; ii++)
	{
		string strTagName = "Peak" + ftoa(ii+1);
		_add_one_peak_branch(trPeaks, strTagName);
	}
	
	return true;
}

int 	FitPeak::OnInitOperationTreeFromOCLT(TreeNode &trOp, TreeNode& trOCLT, bool bInitTree)
{
	if(!bInitTree)
	{
		TreeNode trOutGUI = trOCLT.GetNode("GUI");
		DataRange drInputData;
		TreeNode trInputData = trOutGUI.InputData;
		if(trInputData)
		{
			trOp.GUI.InputData.Replace(trInputData.Clone()); //In order to copy all attributes of input data branch
			if(!drInputData.Create(trInputData, FALSE))
				return OP_GET_INPUT_DATARANGE_WRONG;
		}
		else
			return OP_INVALID_INPUT_DATA_NODE;
		
		/// Iris 4/24/2008 HIDE_INNER_OUTER_LIMITS_FOR_XYFIT_AND_PA
		//int nFitType = _get_fit_type(trOp);
		int nFitType = GetFitType(trOp);
		///end HIDE_INNER_OUTER_LIMITS_FOR_XYFIT_AND_PA
		TreeNode trPFW = trOCLT.PFWTree;
		TreeNode trParameters = trPFW.Peaks.Peak1.GetNode("Parameters");
		if(!trParameters)
		{
			bool bHasBaseLine = false;
			TreeNode trHasBaseline = trOCLT.HasBaseline;
			if(trHasBaseline)
				bHasBaseLine = trHasBaseline.nVal;
			return UpdatePFWTreeByUserSettings(trPFW, nFitType, bHasBaseLine);
		}
		
		//update PFM tree to trOp
		TreeNode	trOpPFW = trOp.AddNode("PFWTree");
		trOpPFW.Replace(trPFW.Clone());
		//trOp.GUI.Codes.Constraints.Replace(trOutGUI.FitControl.Constraints, true, true); 	///Jasmine 03/11/08 SHOW_FITCONTROL_BRANCH_IN_XF_NOT_IN_PARAMDLG_BY_CP_REQUEST
		//trOp.GUI.Parameters.LinearConstraints.nVal = trOutGUI.FitControl.EnableConstraints.nVal;
		trOp.FitWorkArea.ID = 1; //create FitWorkArea with ID same in NLFitSession.h
		trOp.FitWorkArea.Parameters.ID = 2;

		
		if(NULL == GetFitSession())
		{
			string strCateg = STR_CATE_NAME_PFM;
			if(nFitType != NLFIT_GENERAL_XY_FITTING)
				strCateg = STR_CATE_NAME_SPFM;
			//m_pFitSession = new MulFuncsFitSession(true, strCateg);
			InitFitSessionPointer(trOp);
		}
		GetFitSession()->SetAutoInitParams(false);
		//m_pFitSession->SetInitData(FALSE);
		GetFitSession()->SetFitInfoTree(trOpPFW);
		GetFitSession()->SetPlotCurveType();
		///Arvin 01/09/2008 QA70-8365 SUPPORT_2D_PEAK_CENTERS_HANDLING
		TreeNode trMultiPeakOptions = trOCLT.MultiPeakOptions;
		if(trMultiPeakOptions)
		{
			int nVal = trMultiPeakOptions.nVal;
			if(nVal)
				GetFitSession()->SetMultipeakOptions(nVal); 
		}
		///end SUPPORT_2D_PEAK_CENTERS_HANDLING
		TreeNode trDataSteps = trOCLT.DataSteps;
		if(trDataSteps)
		{
			int nVal = trDataSteps.nVal;
			if(nVal)
			{
				vector<int> vDataSteps;
				vDataSteps.Add(nVal);
				GetFitSession()->SetDataSteps(vDataSteps);
			}
		}
		
		TreeNode trNumIterWithFixed = trOCLT.NumIterWithFixed;
		if(trNumIterWithFixed)
		{
			int nVal = trNumIterWithFixed.nVal;
			if(nVal)
			{
				GetFitSession()->SetIterationSettings(nVal);
			}
		}
		bool bHasFitGood = false, bParamsReady = false;
		if( !GetFitSession()->InitFromOperationTree(trOp, bHasFitGood, bParamsReady))//, false, bool bAutoInitParams = false, bool bInitData = false, bool bLoadFDF = true);
			return OP_FAILED_INIT_FROM_OPERATION_TREE;
		
		TreeNode	trOpParams = tree_check_get_node(trOp.FitWorkArea, "Parameters");
		if(trOpParams)
			GetFitSession()->GetParams(trOpParams);
		
		//Arvin 01/22/08 SUPPORT_2D_PEAK_FITTING_FROM_SCRIPT
		//trOp.FitWorkArea.SetAttribute(STR_ATTRIB_UNINIT_FIT_SESSION_FROM_OPERATION, 1);
		///end SUPPORT_2D_PEAK_FITTING_FROM_SCRIPT
		//Copy GUI tree from operation tree to OCLT treee 
		trOutGUI.Replace(trOp.GUI.Clone());
		
		TreeNode trPFWTree;
		if(trOCLT.PFWTree)
			trPFWTree = trOCLT.PFWTree;
		else
		{
			trOCLT.AddNode("PFWTree");
			trPFWTree = trOCLT.PFWTree;
		}
		trPFWTree.Replace(trOp.PFWTree.Clone());
		
		TreeNode trFitWorkArea;
		if(trOCLT.FitWorkArea)
			trFitWorkArea = trOCLT.FitWorkArea;
		else
		{
			trOCLT.AddNode("FitWorkArea");
			trFitWorkArea = trOCLT.FitWorkArea;
		}
		trFitWorkArea.Replace(trOp.FitWorkArea.Clone());
	
		return OP_NOERROR;
	}
	else
	{
		int nRet = FitNL::OnInitOperationTreeFromOCLT(trOp, trOCLT, bInitTree);
		if(nRet != OP_NOERROR)
			return nRet;
		int nPeakNum = trOCLT.PeakNum.nVal;
		bool bHasBaseline = trOCLT.HasBaseline.nVal;
		if(nPeakNum < 1)
			return OP_WRONG_PEAK_NUM;
		TreeNode trPFW =  tree_check_get_node(trOCLT, "PFWTree");
		/// Iris 4/24/2008 HIDE_INNER_OUTER_LIMITS_FOR_XYFIT_AND_PA
		//if(_get_fit_type(trOp) != NLFIT_GENERAL_XY_FITTING)
		if(GetFitType(trOp) != NLFIT_GENERAL_XY_FITTING)
		///end HIDE_INNER_OUTER_LIMITS_FOR_XYFIT_AND_PA
			bHasBaseline = false;
		
		_init_pfw_tree(trPFW, nPeakNum, bHasBaseline);
		return OP_NOERROR;
	}
}
///end XOP_NEED_SUPPORT_PFM

///Arvin 12/10/07 WRONG_RESIDUAL_DATA_IN_PFW
bool 	FitPeak::GetCumRegularResidualData(const TreeNode &trOp, const vector& vX, const vector &vY, FitParameter *psFitParameter, vector& vCumRegular, vector& vFitY, int index, int nMultiplicity, vector &vWeights, matrix &mXs, GraphLayer &grLayAppar, matrix& mResiduals)
{
	vector vCumulate;
	for(int ii=0; ii<nMultiplicity; ii++)
	{
		MakeFitY(index, trOp, vX, vFitY, psFitParameter, NULL, ii);
		if(vCumulate.GetSize() == 0)
			vCumulate.SetSize(vFitY.GetSize());
		vCumulate += vFitY;
	}
	///------ Folger 02/03/09 PA_FITTING_WITH_BASELINE_FAILS_TO_GET_CORRECT_RESIDUAL_DATA
	//CumulativeSubtractBaseline(vX, vCumulate, nMultiplicity - 1, GetBaseLineY0(psFitParameter));
	CumulativeSubtractBaseline(vX, vCumulate, GetFitSession()->GetBaselineFitMode() ? nMultiplicity - 1 : nMultiplicity, GetBaseLineY0(psFitParameter));
	///------ End PA_FITTING_WITH_BASELINE_FAILS_TO_GET_CORRECT_RESIDUAL_DATA
	vFitY = vCumulate;
	
	if(vY.GetSize() != vFitY.GetSize())
		return error_report("getResidualData, the size of vY is not same as the size of vFitY");
	
	vCumRegular.SetSize(vFitY.GetSize());
	if (grLayAppar)
	{
		vector		vYTransf(vY.GetSize());
		//vYTransf = vY;
		vector		*pvY;
		if ( grLayAppar.ConvertByAxis(vY, vY.GetSize(), OKAXISTYPE_Y, FALSE, vYTransf) )
			pvY = &vYTransf;
		else
			pvY = &vY;
		
		grLayAppar.ConvertByAxis(vFitY, vFitY.GetSize(), OKAXISTYPE_Y, FALSE);
		vCumRegular = *pvY - vFitY;
	}
	else
		vCumRegular = vY - vFitY;
	
	return true;
}

//virtual 
string 		FitPeak::GetResultBookName(TreeNode& trGUI)
{
	return E_STR_PEAK_FIT_REPORT_TABLE_BOOK_SHORT_NAME;
}

//virtual 
string 		FitPeak::GetResultSheetName(TreeNode& trGUI)
{
	return STR_PEAK_FIT_REPORT_TABLE_SHEET_NAME;
}

/// Iris 10/28/2009 QA81-14546 CHANGE_GUI_REPORT_TABLE_LABEL
/*
/// Iris 4/17/2008 SPECIAL_REPORT_TABLE_NAME_FOR_DIFF_TOOLS
//virtual	
string		FitPeak::GetReportTableGUIName(TreeNode& trGUI)
{
	return STR_OUTPUT_PEAK_FIT_REPORT_TABLE;
}
///end SPECIAL_REPORT_TABLE_NAME_FOR_DIFF_TOOLS
*/
///end CHANGE_GUI_REPORT_TABLE_LABEL

/// Iris 4/25/2008 NANOSIZER_REPORT_COMPLEX_INPUT_DATA_WITH_WEIGHT_INFO
//virtual
bool	  	FitPeak::IsReportComplexInputDataTable(TreeNode& trOp)
{
	if( NLFIT_XYZ_FITTING == GetFitType(trOp) )
	{
		TreeNode 	trSpecInfo = trOp.SpecInfo;
		if( trSpecInfo && trSpecInfo.Categ )
		{
			string	strCateg = trSpecInfo.Categ.strVal;
			if( 0 == strCateg.CompareNoCase("Nanosizer") )
				return true;
		}
	}
	else
		return FitNL::IsReportComplexInputDataTable(trOp);
		
}
///end NANOSIZER_REPORT_COMPLEX_INPUT_DATA_WITH_WEIGHT_INFO

///Jasmine 05/04/08 UPDATE_COLOR_OF_BOTH_REPORT_GRAPH_AND_EMBED_GRAPH_IN_REPORT_SHEET
//virtual 
void 		FitPeak::SetupFittedCurvesPlotDetails(const TreeNode& trOp, GraphLayer& gl, int nFittedPlot, int nNumFittedPlots, int nGraphIndex, bool bIsSourceGraph, int nDataIndex, bool bUpdateExistedReportGraph)//false, 0, false
{
	FitNL::SetupFittedCurvesPlotDetails(trOp, gl, nFittedPlot, nNumFittedPlots, nGraphIndex, bIsSourceGraph, nDataIndex, bUpdateExistedReportGraph);
	
	updateReportGraphColor(trOp, gl);
}

/// Hong 11/15/08 QA80-12584 v8.0972 SBUTRACTED_DATA_IS_FIT_SRC_DATA_AND_SHOULD_REPLACE_DRAW_SRC_DATA
//virtual
bool		FitPeak::PlotSourceDataInLayer(int nDataIndex, TreeNode& trPlotInfo, TreeNode& trOp, GraphLayer& gl, int nGraphIndex/* = 0*/, int nXIndex/* = 0*/, int nYIndex/* = 0*/)
{
	/// YuI 06/23/09 QA70-13835 ORIGIN_FREEZE_AFTER_DESCRIPTIVE_STATISTICS
	//	if ( !IsOutputSubtractedDataSheet(trOp) )
	if ( REPORT_CREATE != IsOutputSubtractedDataSheet(trOp) )
	/// end ORIGIN_FREEZE_AFTER_DESCRIPTIVE_STATISTICS
		return FitNL::PlotSourceDataInLayer(nDataIndex, trPlotInfo, trOp, gl, nGraphIndex, nXIndex, nYIndex);
	
	DataRange		drSubtractedData;
	Datasheet		dsSubtractedData;
	int				nNumdataset = GetFitSession()->GetNumDataset();
	ASSERT(1 == nNumdataset && 0 == nDataIndex);
	if ( 0 != nDataIndex )
		nDataIndex = 0;
	if ( !GetOutput(drSubtractedData, dsSubtractedData, GetOutputSlot(nDataIndex, true, OUTPUT_RESULT_SUBTRACTED_DATA_SHEET)) )
		return false;
	
	int			nPlotType = trPlotInfo.SourcePlotType.nVal;
	DataPlot 	dp;
	dp = GetSourceDataPlot(nDataIndex, trOp);
	Tree		trFmt;
	if ( dp && IsFitCurveFollowSourcePlotType() )
	{
		nPlotType = dp.GetPlotType();		
		trFmt = dp.GetFormat(FPB_ALL, FPB_ALL, TRUE, TRUE);
	}
	
	DWORD		dwRules = GetDataRules(trOp);
	int			nPlot = plot_data_range(drSubtractedData, gl, nPlotType, GAP_USE_TEMPLATE, NULL, true, &dwRules);
	if ( nPlot >= 0 )
	{
		if ( dp && IsFitCurveFollowSourcePlotType() )
		{
			DataPlot 	dpAdded;
			dpAdded = gl.DataPlots(nPlot);
			dpAdded.ApplyFormat(trFmt, TRUE, TRUE);
		}
		legend_append_plot(gl, nPlot, "@LG");
		gl.Rescale();
	}
	return true;
}

//virtual
bool		FitPeak::CheckReplaceSourceDataPlot(TreeNode& trOperation, int nTotalNumData)
{
	/// YuI 06/23/09 QA70-13835 ORIGIN_FREEZE_AFTER_DESCRIPTIVE_STATISTICS
	//	if ( !IsOutputSubtractedDataSheet(trOperation) )
	if ( REPORT_CREATE != IsOutputSubtractedDataSheet(trOperation) )
	/// end ORIGIN_FREEZE_AFTER_DESCRIPTIVE_STATISTICS
		return false;
		
	if ( !trOperation.GUI.PlotCurveTo || PLOT_TO_NEW_GRAPH != trOperation.GUI.PlotCurveTo.nVal )
		return false;
	
	DataRange		drSubtractedData;
	Datasheet		dsSubtractedData;	
	ASSERT(1 == nTotalNumData);
	int				nDataIndex = 0;
	if ( !GetOutput(drSubtractedData, dsSubtractedData, GetOutputSlot(nDataIndex, true, OUTPUT_RESULT_SUBTRACTED_DATA_SHEET)) )
		return false;
	
	DataPlot 	dp;
	dp = GetSourceDataPlot(nDataIndex, trOperation);
	if ( !dp )
	{
		ASSERT(FALSE);
		return error_report("Invalid source dataplot, plx make sure caller is ready for replace.");
	}
		
	GraphLayer		gl;
	dp.GetParent(gl);
	gl.RemovePlot(dp);	
	ASSERT( 0 == gl.DataPlots.Count() ); // Hong, this assumption is necessary to keep dataplot order
	DWORD			dwRules = GetDataRules(trOperation);
	int				nIndex = plot_data_range(drSubtractedData, gl, IDM_PLOT_LINE, GAP_USE_TEMPLATE, NULL, false, &dwRules);
	ASSERT(nIndex >= 0);
	dp = gl.DataPlots(nIndex);
	dp.SetColor(SYSCOLOR_BLACK);
	gl.Rescale();

	XYRange			drPlot;
	bool			bGoodReturn = dp.GetDataRange(drPlot);
	ASSERT(bGoodReturn);
	vector			vX, vY;
	drPlot.GetData(vY, vX, NULL, nDataIndex);
	DWORD			dwPlotUID = dp.GetUID(TRUE);
	SetSourceDataPlot(trOperation, vY, vX, nDataIndex, nTotalNumData, dwPlotUID);
	return true;
}
/// end SBUTRACTED_DATA_IS_FIT_SRC_DATA_AND_SHOULD_REPLACE_DRAW_SRC_DATA

///Sophy 3/5/2009 QA80-12584 v8.0992 FIX_LOSE_SOURCE_CURVE_WHEN_FIT_FROM_GRAPH_ARRANGE_SAME_PLOTS_ON_ONE_GRAPH
//virtual
bool		FitPeak::CheckReplaceSourceRange(TreeNode& trOperation, DataRange& drInput, int nDataIndex) //0
{
	if ( !trOperation || !drInput )
		return false;
	
	DataPlot	dpSrc = GetSourceDataPlot(nDataIndex, trOperation);
	if ( dpSrc )
	{
		DataRange	drSrc;
		if ( dpSrc.GetDataRange(drSrc) )
		{
			drInput = drSrc;
			return true;
		}
	}
	return false;
}
///end FIX_LOSE_SOURCE_CURVE_WHEN_FIT_FROM_GRAPH_ARRANGE_SAME_PLOTS_ON_ONE_GRAPH

void 		FitPeak::updateReportGraphColor(const TreeNode& trOp, GraphLayer& gl)
{	
	vector<string> vsCurves;
	vsCurves.SetSize(6);
	vsCurves[0] = STR_LABEL_PEAK_FIT_CURVE;
	vsCurves[1] = STR_LABEL_CUMULATIVE_FIT_CURVE;
	vsCurves[2] = "LCL";
	vsCurves[3] = "UCL";
	vsCurves[4] = "LPL";
	vsCurves[5] = "UPL";
	vsCurves.Add(STR_LABEL_BASELINE_FIT_CURVE);///Sophy 11/24/2008 SET_BASELINE_PLOT_AS_BLUE_IN_REPORT_GRAPH_AS_SR4
	vector<int> vnColor = {SYSCOLOR_GREEN, SYSCOLOR_RED, SYSCOLOR_GREEN, SYSCOLOR_GREEN, SYSCOLOR_BLUE, SYSCOLOR_BLUE};
	vnColor.Add(SYSCOLOR_BLUE);///Sophy 11/24/2008 SET_BASELINE_PLOT_AS_BLUE_IN_REPORT_GRAPH_AS_SR4
	
	
	string strSheetName;
	
	TreeNode trAddBackBaseline;
	if(trOp.GUI && trOp.GUI.AddBackBaseline)
		trAddBackBaseline = trOp.GUI.AddBackBaseline;
	if(trAddBackBaseline && trAddBackBaseline.nVal && trAddBackBaseline.Show)
		strSheetName = STR_FIT_CURVE_ADD_BASELINE_WKS;
	else 
	{
		DataRange rgOut;
		Worksheet wksOut;
		GetOutput(rgOut, wksOut, OUTPUT_RESULT_CURVE_SHEET_RNG_INDEX);
		strSheetName = wksOut.GetName();
	}		

	/// should get plot from baseline xyrange, Folger, to do
	/*
	DataPlot dpB;
	int nPlotBaseline = -1;
	check_baseline_dataplot(gl, dpB);
	if(dpB.IsValid())
		nPlotBaseline = dpB.GetIndex();
	 else
	 	nPlotBaseline = strSheetName.IsEmpty()? -1 : find_plot_index_by_key(gl, STR_LABEL_BASELINE_FIT_CURVE, strSheetName);
	if(-1 != nPlotBaseline)
		_update_color(gl, nPlotBaseline, SYSCOLOR_BLUE);
	*/
	
	//assume these plots indexes increase ascending
	if(!strSheetName.IsEmpty())
	{
		int nPlot = -1;
		for(int nCurveType = 0; nCurveType < vsCurves.GetSize(); nCurveType++)
		{		
			if(0 == vsCurves[nCurveType].CompareNoCase(STR_LABEL_PEAK_FIT_CURVE))
			{
				for(int nPeak = 1; ; nPeak++)
				{
					string strCurve = vsCurves[nCurveType];
					strCurve += " " + (string)nPeak;
					nPlot = find_plot_index_by_key(gl, strCurve, strSheetName, nPlot);
					if(-1 == nPlot)
						break;
					_update_color(gl, nPlot, vnColor[nCurveType]);
				}
			}
			else
			{			
				string strCurve = vsCurves[nCurveType];
				nPlot = find_plot_index_by_key(gl, strCurve, strSheetName, nPlot);
				if(-1 != nPlot)
					_update_color(gl, nPlot, vnColor[nCurveType]);
			}
		}
	}
	
	//gl.Rescale(ANL_CHK_DATA_OUTSIDE);
}

///------ Folger 01/07/09 QA80-12925-P1 v8.0994b ORIGIN_CRASH_IN_PA_FITTING_WHEN_NEW_PROJECT
/// virtual
void	FitPeak::SetHelperClass(void* pHelper)
{
	m_pPeakFitHelper = (PeakFitHelperBase*)(DWORD)pHelper;
}
///------ End ORIGIN_CRASH_IN_PA_FITTING_WHEN_NEW_PROJECT

static void _update_color(const GraphLayer& gl, int nPlot, int nColor)
{
	DataPlot dp = gl.DataPlots(nPlot);
	if(dp)
		dp.SetColor(nColor);
}
///End UPDATE_COLOR_OF_BOTH_REPORT_GRAPH_AND_EMBED_GRAPH_IN_REPORT_SHEET

/// Iris 04/14/2009 FIX_NUM_PARAMS_IN_NOTE_TABLE_IS_1
// old logic always return the number of parameters of the first fit function, if baseline fit function is const, this number will be 1
// so changed codes to return the number of parameters of the first peak function.
//virtual
bool 	FitPeak::UpdateNumParamsDatasetsNote(TreeNode& trTable, int nTotalNumData, const TreeNode& trOperation)
{
	if( FitNL::UpdateNumParamsDatasetsNote(trTable, nTotalNumData, trOperation) )
	{	
		int nFuncIndex = m_pFitSession->GetBaselineFitMode()? 1 : 0;
		ASSERT( nFuncIndex < m_pFitSession->GetNumberFitFunctions() );
		
		if( trTable.NumFuncParams )
		{
			trTable.NumFuncParams.nVal = m_pFitSession->GetNumParameter(nFuncIndex);
		}
		
		if( trTable.NumDerivParams )
		{
			trTable.NumDerivParams.nVal = m_pFitSession->GetDerivedParamNum(nFuncIndex);
		}	
		return true;
	}
	return false;
}
///end FIX_NUM_PARAMS_IN_NOTE_TABLE_IS_1

///------ Folger 10/28/09 QA81-14552 WRONG_REPORT_STATUS_WHEN_CHANGE_PARAM_IN_PA
/// virtual
string	FitPeak::GetAutoUpdateType(int nExecMode)
{
	if ( m_pPeakFitHelper->IsChangeParam() )
		nExecMode = OEXEM_ON_CHANGEPARAM;

	return FitNL::GetAutoUpdateType(nExecMode);
}
///------ End WRONG_REPORT_STATUS_WHEN_CHANGE_PARAM_IN_PA
