/*------------------------------------------------------------------------------*
 * File Name:	NLFCurves.h														*
 * Creation: 	Iris															*
 * Purpose: OriginC Source H file												*
 * Copyright (c) ABCD Corp.	2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010		*
 * All Rights Reserved															*
 * 																				*
 * Modification Log:  															*
 *	Jasmine 08/13/08 QA80-12010 X_IS_COL_WHILE_Y_IS_ROW_IN_MATRIX				*
 *	Hong 10/17/08 QA80-10624 NLFIT_SUPPORT_FIT_SWAPPED_POLAR_PLOT				*
 *	Sophy 10/30/08 FIX_FAIL_TO_SHOW_RESIDUAL_GRAPH_ON_MATRIXFIT_PREVIEW			*
 *	Sophy 10/30/08 FIX_FAIL_TO_GET_CORRECT_NUM_OF_DATAPLOT_IN_CASE_WITH_REPLICA	*
 *	Sophy 10/31/2008 v8.963b QA80-12498 FIX_SOURCE_DATAPLOT_DISAPPEAR_WHEN_SELECT_MULTI_DATASET_FROM_ONE_COLUMN
 *	Sophy 10/31/2008 GROUP_CUMULATIVE_CURVE_WITH_FITTED_CURVES					*
 *	Sophy 11/1/2008 NLFIT_FITPLOT_ON_PREVIEW_GRAPH_SHOULD_NOT_DEPEND_ON_TEMPLATE_SETTINGS
 *	CPY 11/06/08 CHANGE_PARAM_OPEN_NLFIT_SAW_ASSERT								*
 *	Sophy 11/11/2008 v8.968 QA80-10599-P1 NLFIT_PREVIEW_UPDATE_CLEANUP			*
 *	Kyle 11/18/2008 QA80-12591 ADD_MORE_OPTION_FOR_INPUT_DATA_TYPE_IN_FITTING_TOOLS
 *	Sophy 11/20/2008 QA80-10599-P6 FIX_FITCURVE_GRAPH_AXES_RESCALE_PROBLEM		*
 *	Sophy 11/21/2008 v8.976 QA80-12591-P3 ADD_ERRMSG_WHEN_FITCURVE_XDATATYPE_IS_LOG_WITH_NEGATIVE_INPUT
 *	Sophy 11/25/2008 v8.979 SELF_MAINTAIN_WHETHER_TO_SORT_AS_OLD_LOGIC			*
 *	Kyle 11/26/2008 SUPPORT_GETTING_FIT_Y_WITHOUT_OFFSET_FOR_PA					*
 *	Sophy 1/12/2009 v8.0995c QA80-12613-P3 FIX_NLFIT_SHOW_WRONG_CUSTOMIZED_Y_MIN_MAX_ON_SURFACEFIT
 *	Sophy 1/12/2009 v8.0995c QA80-12613-P4 SHOULD_ONLY_SHOW_UNIFORM_LINEAR_ON_DATATYPE_FOR_3D_FITTING
 *	Folger 01/04/09 QA80-12962 GENERATE_INDIVIDUAL_FIT_CURVE_USING_INDEPENDENT_X_IN_PA
 *  Iris 01/15/2009 CENTRALIZE_NEW_X_DATA_TYPE_AND_LOG_TYPE_CODES				*
 *	Folger 01/04/09 QA80-12962 MORE_WORK_ON_GENERATE_INDIVIDUAL_FIT_CURVE_USING_INDEPENDENT_X_IN_PA
 *	Sophy 1/16/2009 v8.0957 SWTICH_DATA_AND_FUNCTION_SHOULD_RESET_FITCURVE_SCALE
 *	Sophy 2/16/2009 v8.0979b QA80-13121 CUSTOM_LEGEND_NEED_SIMPLER_LINE_SUPPORT	*
 *	Sophy 3/3/2009 v8.0990 FIX_RUNTIME_ERROR_WHEN_USE_CHEBYSHEV2D_AS_FUNCTION_IN_MATRIX_FITTING
 *	Sophy 4/27/2009 v8.0987 QA80-13178 UPDATE_FITCURVE_RESIDUAL_PLOTS_SETTINGS_FOR_UPDATE_3D_RESIDUAL_PREVIEW
 *	Folger 05/06/09 QA80-13544 IMPROVE_PA_SPEED_WHEN_GO_FROM_FIND_PEAK_TO_FIT_PEAK
 *  Will 06/24/2009 QA80-13783 CHANGE_PROTOTYPE_AND_ALGORITHM_FOR_EXAMINATION
 *	Sim 09-25-2009 QA80-13783 CHANGE_PROTOTYPE_AND_ALGORITHM_FOR_EXAMINATION	*
 *	Hong 07/03/09 QA80-13590-P6 FIX_FAIL_LOAD_USER_DEFINE_FDF_FURMULA_PREVIEW	*
 *	Jasmine 07/03/09 QA80-12613-P4 NEED_ROW_COL_TO_GENERATE_MATRIX_EVEN_XY_SAME_AS_INPUT
 *	Folger 07/28/09 QA80-14021 PREIVEW_UPDATE_IN_MATRIX_FIT_AND_SURFACE_FIT_MUCH_SLOWER_THAN_SR5
 *  Iris 9/18/2009 QA70-9093-P3 FITCURVE_PREVEW_BAD_FOR_WILLBUL3_FUNC			*
 *	Folger 03/24/10 QA81-15237 GENERATE_FITY_BASED_ON_BASELINE_FOR_BETTER_PEAK_PROPERTIES_CALCULATION
 *	Folger 09/16/2010 ORG-1057-P1 MATRIX_FITTING_FAILED_TO_CLOSE_DIALOG_AFTER_FIT_WITH_EMPTY_DATA
 *------------------------------------------------------------------------------*/

#ifndef	_NLF_CURVES_H_
#define	_NLF_CURVES_H_

#include <wks2mat.h>

#define			CURVE_DEFAULT_MARGIN		0.08

enum
{
	NLF_GRAPH_FIT_CURVE = 0,
	NLF_GRAPH_RESIDUAL
};

#define	NLSF_FIT_CURVE_GRAPH_TEMPLATE		"ReportFit"
#define NLSF_RESIDUAL_GRAPH_TEMPLATE		"ReportResidual"
///Sophy 7/28/2008 CLEAN_MATRIXFIT_PREVIEW_CONTROL
#define NLSF_MAT_FIT_CURVE_GRAPH_TEMPLATE	"CONTOUR"
#define NLSF_XYZ_FIT_CURVE_GRAPH_TEMPLATE	"TRICONTOUR"
///Sophy 2/16/2009 v8.0979b QA80-13121 CUSTOM_LEGEND_NEED_SIMPLER_LINE_SUPPORT
//#define NLSF_MAT_RESIDUAL_GRAPH_TEMPLATE	"CONTOUR"
//#define NLSF_XYZ_RESIDUAL_GRAPH_TEMPLATE	"TRICONTOUR"
#define NLSF_MAT_RESIDUAL_GRAPH_TEMPLATE	"ReportContourRes"
#define NLSF_XYZ_RESIDUAL_GRAPH_TEMPLATE	"ReportTricontourRes"
///end CUSTOM_LEGEND_NEED_SIMPLER_LINE_SUPPORT
///end CLEAN_MATRIXFIT_PREVIEW_CONTROL

//----CPY 3/24/2008 NO_NEED_TO_REDUCE_NUMBER_OF_FIT_CONTOUR_LINES
//#define FIT_CONTOUR_LEVEL_REDUCTION_FROM_DATA_LEVELS 2 // number of contour levels on the fit surface is less then the data level by this factor
#define FIT_CONTOUR_LEVEL_REDUCTION_FROM_DATA_LEVELS 1
//---- end NO_NEED_TO_REDUCE_NUMBER_OF_FIT_CONTOUR_LINES
//--- end


class NLFCurvesBase
{
public:	
	NLFCurvesBase(NLFitSession* pNLFSession)
	{
		ASSERT(pNLFSession);
		m_pNLFSession = pNLFSession;
	}
	
	// Data relative
	///------ Folger 01/04/09 QA80-12962 GENERATE_INDIVIDUAL_FIT_CURVE_USING_INDEPENDENT_X_IN_PA
	//bool			GetFitX(vector& vFitX, NLFDataBase* pDataObj, int nDatasetIndex = 0, int nIndependent = 0, bool bSetCustomInput = true, bool bSort = true);
	bool			GetFitX(vector& vFitX, NLFDataBase* pDataObj, int nDatasetIndex = 0, int nIndependent = 0, bool bSetCustomInput = true, bool bSort = true, SmartXOnPeakShapeOption* pSmartXOpt = NULL);
	///------ End GENERATE_INDIVIDUAL_FIT_CURVE_USING_INDEPENDENT_X_IN_PA
	///------ Folger 03/24/10 QA81-15237 GENERATE_FITY_BASED_ON_BASELINE_FOR_BETTER_PEAK_PROPERTIES_CALCULATION
	//virtual	bool	GetFitY(const vector& vX, vector& vFitY, NLParametersManager* pParamMngr, int nDatasetIndex = 0, int nPeakIndex = 0);
	virtual	bool	GetFitY(const vector& vX, vector& vFitY, NLParametersManager* pParamMngr, int nDatasetIndex = 0, int nPeakIndex = 0, BOOL bZeroY0 = FALSE);
	///------ End GENERATE_FITY_BASED_ON_BASELINE_FOR_BETTER_PEAK_PROPERTIES_CALCULATION
	///Kyle 11/26/2008 SUPPORT_GETTING_FIT_Y_WITHOUT_OFFSET_FOR_PA
	///------ Folger 03/24/10 QA81-15237 GENERATE_FITY_BASED_ON_BASELINE_FOR_BETTER_PEAK_PROPERTIES_CALCULATION
	//virtual bool 	GetFitYWithoutOffset(const vector& vX, vector& vFitY, NLParametersManager* pParamMngr, int nDatasetIndex = 0, int nPeakIndex = 0){return false;}
	virtual bool 	GetFitYWithoutOffset(const vector& vX, vector& vFitY, NLParametersManager* pParamMngr, int nDatasetIndex = 0, int nPeakIndex = 0, BOOL bZeroY0 = FALSE) {return false;}
	///------ End GENERATE_FITY_BASED_ON_BASELINE_FOR_BETTER_PEAK_PROPERTIES_CALCULATION
	///End SUPPORT_GETTING_FIT_Y_WITHOUT_OFFSET_FOR_PA
	///Sophy
	///------ Folger 01/04/09 QA80-12962 GENERATE_INDIVIDUAL_FIT_CURVE_USING_INDEPENDENT_X_IN_PA
	//virtual bool	GetFit( vector& vFitX, vector& vFitY, int nDatasetIndex = 0, int nPeak = 0);
	virtual bool	GetFit( vector& vFitX, vector& vFitY, int nDatasetIndex = 0, int nPeak = 0, SmartXOnPeakShapeOption* pSmartXOpt = NULL);
	///------ End GENERATE_INDIVIDUAL_FIT_CURVE_USING_INDEPENDENT_X_IN_PA

	// for multiple indeps and multiple deps
	///Sophy 11/25/2008 v8.979 SELF_MAINTAIN_WHETHER_TO_SORT_AS_OLD_LOGIC
	//bool			GetFitX(matrix& mFitXs, NLFDataBase* pDataObj, int nDatasetIndex = 0, int nNumIndeps = 1, bool bSetCustomInput = true, bool bSort = true);
	///------ Folger 01/04/09 QA80-12962 GENERATE_INDIVIDUAL_FIT_CURVE_USING_INDEPENDENT_X_IN_PA
	//bool			GetFitX(matrix& mFitXs, NLFDataBase* pDataObj, int nDatasetIndex = 0, int nNumIndeps = 1, bool bSetCustomInput = true);
	bool			GetFitX(matrix& mFitXs, NLFDataBase* pDataObj, int nDatasetIndex = 0, int nNumIndeps = 1, bool bSetCustomInput = true, SmartXOnPeakShapeOption* pSmartXOpt = NULL);
	///------ End GENERATE_INDIVIDUAL_FIT_CURVE_USING_INDEPENDENT_X_IN_PA
	///end SELF_MAINTAIN_WHETHER_TO_SORT_AS_OLD_LOGIC
	///Sophy 12/22/2008 v8.0989c SUPPORT_MULTI_DATASET_FOR_MULTI_INDEPS_AND_DEPS_FITTING
	//bool 			GetFitY(const matrix& mFitXs, matrix& mFitYs, NLParametersManager* pParamMngr, int nDatasetIndex = 0, int nNumDeps = 1);
	bool 			GetFitY(const matrix& mFitXs, matrix& mFitYs, NLParametersManager* pParamMngr, int nDatasetIndex = 0, int nNumDeps = 1, int nPeakIndex = 0);
	///end SUPPORT_MULTI_DATASET_FOR_MULTI_INDEPS_AND_DEPS_FITTING

	//bool			GetFitYWithoutOffset(vector& vx, vector& vy, int nIndependent, int nPeakIndex = 0);

	bool 			GetFitZ(const vector& vx, const vector& vy, vector& vFitZ, NLParametersManager* pParamMngr, int nDatasetIndex = 0);

	bool			GetResidualData(vector& vResidual, NLFDataBase* pDataObj, NLParametersManager* pParamMngr, int index = 0, vector& vInX = NULL, vector& vInY = NULL, vector& vInZ = NULL, vector& vFitZ = NULL); 
	
	// for Matrix Fit or Nanosizer
	bool 			GetFitXY(vector& vX, vector& vY, bool bSetCustomInput, bool bNeedGrid = false, int* pnRows = NULL, int* pnCols = NULL);
	bool			GetXYGriding( vector& vX, vector& vY, int& nRow, int& nCol );///Sophy 7/28/2008 CLEAN_MATRIXFIT_PREVIEW_CONTROL
	bool 			GetFitZ(const vector& vX, const vector& vY, matrix& mFitZ, NLParametersManager* pParamMngr, int nDatasetIndex = 0);
	bool			GetFit( vector& vX, vector& vY, matrix& mat, NLParametersManager* pParamMngr, int nDatasetIndex = 0, int& nRows = NULL, int& nCols = NULL, int nIndependent = 0, bool bSetCustomInput = true );///Sophy 7/28/2008 CLEAN_MATRIXFIT_PREVIEW_CONTROL
	///Sophy 10/13/2008 QA80-12365 FIX_FAIL_TO_REPORT_RESIDUAL_IN_MATRIX_FIT
	///Sophy 3/3/2009 v8.0990 FIX_RUNTIME_ERROR_WHEN_USE_CHEBYSHEV2D_AS_FUNCTION_IN_MATRIX_FITTING
	//bool			GetMatResidualData(matrix& matResidual, int& nRows, int& nCols, double& dXmin, double& dYmin, double& dXmax, double& dYmax);
	///end FIX_RUNTIME_ERROR_WHEN_USE_CHEBYSHEV2D_AS_FUNCTION_IN_MATRIX_FITTING
	///end FIX_FAIL_TO_REPORT_RESIDUAL_IN_MATRIX_FIT
	
	/// Hong 10/17/08 QA80-10624 NLFIT_SUPPORT_FIT_SWAPPED_POLAR_PLOT
	bool			IsSwappedPolarPlot(NLFDataBase* pDataObj) { ASSERT(pDataObj); return pDataObj->IsSwappedPolarPlot() }
	uint			GetFitCurvePlotCtrl(NLFDataBase* pDataObj);
	/// end NLFIT_SUPPORT_FIT_SWAPPED_POLAR_PLOT
	
	//virtual
	bool			GetResidualData(matrix& matResidual, NLFDataBase* pDataObj, NLParametersManager* pParamMngr, int& nRows, int& nCols, double& dXmin, double& dYmin, double& dXmax, double& dYmax);
	
	bool			SetFitCurveOptions(const TreeNode& trFitCurveOpts);
	bool			SetSrcFromAndTo(GraphLayer& gl, int nIndex = -1);	
	///Sophy 10/13/2008 GET_CUMULATIVE_DATA_WHITH_BASELINE_MODE
	//bool			GetCumulativeData(vector& vCumulative, NLParametersManager* pParamMngr, int nDatasetIndex = 0, int nPeaks = 1, bool bHasBaseLinePeak = false);
	///------ Folger 01/04/09 QA80-12962 MORE_WORK_ON_GENERATE_INDIVIDUAL_FIT_CURVE_USING_INDEPENDENT_X_IN_PA
	//virtual	bool	GetCumulativeData(vector& vCumulative, NLParametersManager* pParamMngr, int nDatasetIndex = 0, int nPeaks = 1, bool bHasBaseLinePeak = false);
	virtual	bool	GetCumulativeData(vector& vCumulative, NLParametersManager* pParamMngr, int nDatasetIndex = 0, int nPeaks = 1, bool bHasBaseLinePeak = false, vector* pvXCumulative = NULL);
	///------ End MORE_WORK_ON_GENERATE_INDIVIDUAL_FIT_CURVE_USING_INDEPENDENT_X_IN_PA
	///end GET_CUMULATIVE_DATA_WHITH_BASELINE_MODE

	virtual bool	GetBaselineData( vector& vX, vector& vY ) { return false; } /// Iris 10/21/2008 FITSESSION_NEED_GETBASELINEDATA_FOR_REPORT

	// Plot relative
	int				PlotSourceCurve(GraphLayer& gl, int nDatasetIndex, DWORD* pdwPlotUID = NULL, int nDep = 0, int nIndep = 0, int nPlotType = IDM_PLOT_SCATTER, uint nCntrl = GAP_USE_TEMPLATE, bool bGrayScale = false);
	/// Hong 10/17/08 QA80-10624 NLFIT_SUPPORT_FIT_SWAPPED_POLAR_PLOT
	//int				PlotFitCurve(GraphLayer& gl, DataRange& drFitCurve, bool bCheckIfHasPlot = false, int* pStartPlotIndex = NULL, DWORD *pdwDataRules = NULL); //pStartPlotIndex should be changed to vnPlotIndices later
	///Sophy 10/31/2008 GROUP_CUMULATIVE_CURVE_WITH_FITTED_CURVES
	//int				PlotFitCurve(GraphLayer& gl, DataRange& drFitCurve, NLFDataBase* pDataObj, bool bCheckIfHasPlot = false, int* pStartPlotIndex = NULL, DWORD *pdwDataRules = NULL); //pStartPlotIndex should be changed to vnPlotIndices later
	int				PlotFitCurve(GraphLayer& gl, DataRange& drFitCurve, NLFDataBase* pDataObj, bool bCheckIfHasPlot = false, int* pStartPlotIndex = NULL, DWORD *pdwDataRules = NULL, int nCumulativeIndex = -1 ); //pStartPlotIndex should be changed to vnPlotIndices later , nCumulativeIndex = -1 stands for no cumulative in drFitCurve
	///end GROUP_CUMULATIVE_CURVE_WITH_FITTED_CURVES
	/// end NLFIT_SUPPORT_FIT_SWAPPED_POLAR_PLOT
	int				PlotResidual(GraphLayer& gl, DataRange& drResidual);	
	
	virtual string	GetTemplate(bool bIsResidual);
	
	//copy legend mode, axis type from source graph
	bool			CopyFormatFromSourceGraph(GraphLayer& gl);
	bool			UpdateLegend(GraphLayer& gl);
	///Sophy 11/11/2008 v8.968 QA80-10599-P1 NLFIT_PREVIEW_UPDATE_CLEANUP
	//bool			Rescale(GraphLayer& gl);
	bool			Rescale(GraphLayer& gl, bool bFitCurveGraph = false );
	///end NLFIT_PREVIEW_UPDATE_CLEANUP
	
	///Sophy 11/20/2008 QA80-10599-P6 FIX_FITCURVE_GRAPH_AXES_RESCALE_PROBLEM
	void			SetFitCurveScaleRange(const vector& vFit, bool bFitY);
	bool			GetFitCurvesScaleRange(double& dXMin, double& dXMax, double& dYMin, double& dYMax);
	void			ResetFitCurvesScaleRange();
	///end FIX_FITCURVE_GRAPH_AXES_RESCALE_PROBLEM
	
	///------ Folger 01/04/09 QA80-12962 MORE_WORK_ON_GENERATE_INDIVIDUAL_FIT_CURVE_USING_INDEPENDENT_X_IN_PA
	virtual	bool	CheckGetSmartXOnPeakShapeOption(SmartXOnPeakShapeOption& stSmartXOpt, int nPeak)		{ return false; }
	///------ End MORE_WORK_ON_GENERATE_INDIVIDUAL_FIT_CURVE_USING_INDEPENDENT_X_IN_PA
	
	virtual	bool	SetResidualLimits(const double& dIRL, const double& dORL){ASSERT(FALSE); return false;}///Sophy 4/27/2009 v8.0987 QA80-13178 UPDATE_FITCURVE_RESIDUAL_PLOTS_SETTINGS_FOR_UPDATE_3D_RESIDUAL_PREVIEW

	
protected:
	bool			GetXAxisFromAndTo(NLFDataBase* pDataObj, double& dXFrom, double& dXTo, int nIndex = 0, double dMargin = CURVE_DEFAULT_MARGIN);
	bool 			GetYAxisFromAndTo(NLFDataBase* pDataObj, double& dYFrom, double& dYTo, int nIndex = 0, double dMargin = CURVE_DEFAULT_MARGIN);

	/// Iris 10/24/2008 v8.0960b FIX_FAIL_NOT_SETUP_PLOT_FOR_ALL_PEAK_CURVES
	//int				AddCurvePlot(GraphLayer& gl, DataRange& dr, int nPlotType, uint nCntrl, bool bCheckIfHasPlot = false, DWORD *pdwDataRules = NULL, int* pStartPlotIndex = NULL);
	int				AddCurvePlot(GraphLayer& gl, DataRange& dr, int nPlotType, uint nCntrl, bool bCheckIfHasPlot = false, DWORD *pdwDataRules = NULL, vector<int> *pvnPlotIndices = NULL);
	///end FIX_FAIL_NOT_SETUP_PLOT_FOR_ALL_PEAK_CURVES
	int				AddCurvePlot(GraphLayer& gl, DWORD dwPlotUID);

private:
	virtual int		plotSourceCurve(GraphLayer& gl, int nDatasetIndex, DWORD* pdwPlotUID = NULL, int nDep = 0, int nIndep = 0, bool bGrayScale = false) { ASSERT(false); return -1; }

	//---- Iris 01/15/2009 CENTRALIZE_NEW_X_DATA_TYPE_AND_LOG_TYPE_CODES
	int 			getGraphScaleType(const GraphLayer& gl, bool bIsX);
	int 			getSourceGraphScaleType(NLFDataBase* pDataObj, int nIndex, bool bIsX);
	//----
	
	/// Iris 10/24/2008 v8.0960b FIX_FAIL_NOT_SETUP_PLOT_FOR_ALL_PEAK_CURVES
	///// Hong 10/17/08 QA80-10624 NLFIT_SUPPORT_FIT_SWAPPED_POLAR_PLOT
	////virtual	int		plotFitCurve(GraphLayer& gl, DataRange& drFitCurve, bool bCheckIfHasPlot = false, int* pStartPlotIndex = NULL, DWORD *pdwDataRules = NULL) { ASSERT(false); return -1; } //pStartPlotIndex should be changed to vnPlotIndices later
	//virtual	int		plotFitCurve(GraphLayer& gl, DataRange& drFitCurve, bool bCheckIfHasPlot = false, int* pStartPlotIndex = NULL, DWORD *pdwDataRules = NULL, DWORD dwPlotCtrl = 0) { ASSERT(false); return -1; } //pStartPlotIndex should be changed to vnPlotIndices later
	///// end NLFIT_SUPPORT_FIT_SWAPPED_POLAR_PLOT
	virtual	int		plotFitCurve(GraphLayer& gl, DataRange& drFitCurve, bool bCheckIfHasPlot = false, DWORD *pdwDataRules = NULL, DWORD dwPlotCtrl = 0, vector<int> *pnPlotIndices = NULL) { ASSERT(false); return -1; }
	///end FIX_FAIL_NOT_SETUP_PLOT_FOR_ALL_PEAK_CURVES
	
	virtual int		plotResidual(GraphLayer& gl, DataRange& drResidual) { ASSERT(false); return -1; }

	virtual bool	setupSourcePlot(DataPlot& dp, bool bGrayScale = false);
	
	/// Iris 10/24/2008 v8.0960b FIX_FAIL_NOT_SETUP_PLOT_FOR_ALL_PEAK_CURVES
	//virtual bool 	setupFitPlot(DataPlot& dp) { return false; }
	///Sophy 10/31/2008 GROUP_CUMULATIVE_CURVE_WITH_FITTED_CURVES
	//virtual bool 	setupFitPlot(GraphLayer& gl, const vector<int> &vnPlotIndices) { return false; }
	virtual bool 	setupFitPlot(GraphLayer& gl, const vector<int> &vnPlotIndices, int nCumulativeIndex = -1 ) { return false; }
	///end GROUP_CUMULATIVE_CURVE_WITH_FITTED_CURVES
	///end FIX_FAIL_NOT_SETUP_PLOT_FOR_ALL_PEAK_CURVES
	
	virtual bool 	setupResidualPlot(DataPlot& dp) { return false; }
	///Sophy 11/11/2008 v8.968 QA80-10599-P1 NLFIT_PREVIEW_UPDATE_CLEANUP
	virtual	bool	rescaleFitCurvesGraph( GraphLayer& gl, DWORD dwCtrl );
	///end NLFIT_PREVIEW_UPDATE_CLEANUP
	
	void 			setLayerFromTo(double dFrom, double dTo, vector &vecFrom, vector &vecTo, int nIndex);


	void			copyLegendModeFromSourceGraph(GraphPage& gpSource, GraphLayer& gl);
	void			copyAxisTypeFromSourceGraph(GraphPage& gpSource, GraphLayer& gl);
	//matrix fit relative
	///Sophy 1/12/2009 v8.0995c QA80-12613-P4 SHOULD_ONLY_SHOW_UNIFORM_LINEAR_ON_DATATYPE_FOR_3D_FITTING moved to nlfitsession.h
	//bool			checkXYZRegularData( int& nRows = NULL, int& nCols = NULL);///Sophy 7/28/2008 CLEAN_MATRIXFIT_PREVIEW_CONTROL
	///end SHOULD_ONLY_SHOW_UNIFORM_LINEAR_ON_DATATYPE_FOR_3D_FITTING

protected:
	NLFitSession*					m_pNLFSession;

	FitResultCurveOptions  		m_fitCurveOpts;
	FitResultCurveDataOptions	m_fitCurveDataOptsX;
	FitResultCurveDataOptions	m_fitCurveDataOptsY;
	
private:	
	vector					m_vSrcXFrom;
	vector					m_vSrcXTo;	
	vector					m_vSrcYFrom;
	vector					m_vSrcYTo;
	
	///Sophy 11/20/2008 QA80-10599-P6 FIX_FITCURVE_GRAPH_AXES_RESCALE_PROBLEM
	vector					m_vFitXMin;
	vector					m_vFitXMax;
	vector					m_vFitYMin;
	vector					m_vFitYMax;
	///end FIX_FITCURVE_GRAPH_AXES_RESCALE_PROBLEM
	
};

class NLFCurves : public NLFCurvesBase
{
public:
	NLFCurves(NLFitSession* pNLFSession) : NLFCurvesBase(pNLFSession)
	{
	}

private:
	virtual int		getSourcePlotType(){ return	IDM_PLOT_SCATTER; }
	virtual int		getFitCurvePlotType(){ return IDM_PLOT_LINE; }
	virtual int		getResidualPlotType(){ return IDM_PLOT_SCATTER; }
	
	//virtual 
	int				plotSourceCurve(GraphLayer& gl, int nDatasetIndex, DWORD* pdwPlotUID = NULL, int nDep = 0, int nIndep = 0, bool bGrayScale = false);
	
	/// Iris 10/24/2008 v8.0960b FIX_FAIL_NOT_SETUP_PLOT_FOR_ALL_PEAK_CURVES
	///// Hong 10/17/08 QA80-10624 NLFIT_SUPPORT_FIT_SWAPPED_POLAR_PLOT
	////virtual	
	////int				plotFitCurve(GraphLayer& gl, DataRange& drFitCurve, bool bCheckIfHasPlot = false, int* pStartPlotIndex = NULL, DWORD *pdwDataRules = NULL);
	////virtual	
	//int				plotFitCurve(GraphLayer& gl, DataRange& drFitCurve, bool bCheckIfHasPlot = false, int* pStartPlotIndex = NULL, DWORD *pdwDataRules = NULL, DWORD dwPlotCtrl = 0);
	///// end NLFIT_SUPPORT_FIT_SWAPPED_POLAR_PLOT
	int				plotFitCurve(GraphLayer& gl, DataRange& drFitCurve, bool bCheckIfHasPlot = false, DWORD *pdwDataRules = NULL, DWORD dwPlotCtrl = 0, vector<int> *pnPlotIndices = NULL);
	///end FIX_FAIL_NOT_SETUP_PLOT_FOR_ALL_PEAK_CURVES

	//virtual 
	int				plotResidual(GraphLayer& gl, DataRange& drResidual);

	//virtual 
	bool			setupSourcePlot(DataPlot& dp, bool bGrayScale = false);
	
	//virtual 
	/// Iris 10/24/2008 v8.0960b FIX_FAIL_NOT_SETUP_PLOT_FOR_ALL_PEAK_CURVES
	//bool 			setupFitPlot(DataPlot& dp);	
	///Sophy 10/31/2008 GROUP_CUMULATIVE_CURVE_WITH_FITTED_CURVES
	//bool 			setupFitPlot(GraphLayer& gl, const vector<int> &vnPlotIndices);
	bool 			setupFitPlot(GraphLayer& gl, const vector<int> &vnPlotIndices, int nCumulativeIndex = -1 );
	///end GROUP_CUMULATIVE_CURVE_WITH_FITTED_CURVES
	///end FIX_FAIL_NOT_SETUP_PLOT_FOR_ALL_PEAK_CURVES
	
	//virtual
	bool 			setupResidualPlot(DataPlot& dp);
};

class Fit2DCurves : public NLFCurves
{	
public:
	Fit2DCurves(NLFitSession* pNLFSession) : NLFCurves(pNLFSession)
	{
		m_dIRL = 5; 
		m_dORL = 30;
	}
	//virtual
	bool			SetResidualLimits(const double& dIRL, const double& dORL);///Sophy 4/27/2009 v8.0987 QA80-13178 UPDATE_FITCURVE_RESIDUAL_PLOTS_SETTINGS_FOR_UPDATE_3D_RESIDUAL_PREVIEW
	
private:	
	//virtual
	bool			setupSourcePlot(DataPlot& dp, bool bGrayScale = false);
	//virtual	
	/// Iris 10/24/2008 v8.0960b FIX_FAIL_NOT_SETUP_PLOT_FOR_ALL_PEAK_CURVES
	//bool 			setupFitPlot(DataPlot& dp);
	///Sophy 10/31/2008 GROUP_CUMULATIVE_CURVE_WITH_FITTED_CURVES
	//bool 			setupFitPlot(GraphLayer& gl, const vector<int> &vnPlotIndices);
	bool 			setupFitPlot(GraphLayer& gl, const vector<int> &vnPlotIndices, int nCumulativeIndex = -1 );
	///end GROUP_CUMULATIVE_CURVE_WITH_FITTED_CURVES
	///end FIX_FAIL_NOT_SETUP_PLOT_FOR_ALL_PEAK_CURVES
	
	//virtual
	bool 			setupResidualPlot(DataPlot& dp);
	
	///Sophy 11/11/2008 v8.968 QA80-10599-P1 NLFIT_PREVIEW_UPDATE_CLEANUP
	//virtual
	bool			rescaleFitCurvesGraph( GraphLayer& gl, DWORD dwCtrl );
	///end NLFIT_PREVIEW_UPDATE_CLEANUP
private:
	vector			m_vContourLevelInfo;
	double 			m_dIRL;
	double 			m_dORL;	
};

class SurfaceFitCurves : public Fit2DCurves
{
public:
	SurfaceFitCurves(NLFitSession* pNLFSession) : Fit2DCurves(pNLFSession)
	{
	}
	//virtual
	string			GetTemplate(bool bIsResidual);///Sophy 7/28/2008 CLEAN_MATRIXFIT_PREVIEW_CONTROL
	
private:
	// plot relative
	int		getPlotType() { return IDM_PLOT_TRI_CONTOUR; }
	//virtual
	int		plotSourceCurve(GraphLayer& gl, int nDatasetIndex, DWORD* pdwPlotUID = NULL, int nDep = 0, int nIndep = 0, bool bGrayScale = false);///Sophy 9/2/2008 CLEAN_NLFPREVIEW_AND_NLFCURVE
	
	//virtual 
	int		getSourcePlotType(){ return	getPlotType(); }
	
	//virtual 
	int		getFitCurvePlotType(){ return getPlotType(); }
	
	//virtual 
	int		getResidualPlotType(){ return getPlotType(); }
};

class MatrixFitCurves : public Fit2DCurves
{
public:
	MatrixFitCurves(NLFitSession* pNLFSession) : Fit2DCurves(pNLFSession)
	{
	}
	//virtual
	string			GetTemplate(bool bIsResidual);///Sophy 7/28/2008 CLEAN_MATRIXFIT_PREVIEW_CONTROL

private:
	// plot relative
	int		getPlotType() { return IDM_PLOT_CONTOUR; }
	//virtual
	int		plotSourceCurve(GraphLayer& gl, int nDatasetIndex, DWORD* pdwPlotUID = NULL, int nDep = 0, int nIndep = 0, bool bGrayScale = false);///Sophy 9/2/2008 CLEAN_NLFPREVIEW_AND_NLFCURVE

	//virtual 
	int		getSourcePlotType(){ return	getPlotType(); }
	
	//virtual 
	int		getFitCurvePlotType(){ return getPlotType(); }
	
	//virtual 
	int		getResidualPlotType(){ return getPlotType(); }	
};



//////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////NLFCurvesBase Implementation//////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////
///Sophy 11/21/2008 v8.976 QA80-12591-P3 ADD_ERRMSG_WHEN_FITCURVE_XDATATYPE_IS_LOG_WITH_NEGATIVE_INPUT moved to ananlysis_utils.h
//static int _get_fitted_curve_data_type(const TreeNode& trDataType)
//{
	//int 	nSelection = trDataType.Use;
	//
	//string 			strList;
	//vector<string> 	vsList;
	//trDataType.GetAttribute(STR_ATTRIB_BRANCH_COMBO, strList);
	//strList.GetTokens(vsList, '|');
	//
	//if( nSelection < 0 || nSelection >= vsList.GetSize() )
		//return -1;
	//
	//string strSelction = vsList[nSelection];
	//
	//if ( 0 == strSelction.Compare(STR_FITTED_CURVE_DATA_TYPE_SAME_INPUT))
		//return FIT_CURVE_SAME_AS_DATA;
	//
	//if ( 0 == strSelction.Compare(STR_FITTED_CURVE_DATA_TYPE_UNIFORM_LINEAR))
		//return FIT_CURVE_UNIFORM_LINEAR;
		//
	//if ( 0 == strSelction.Compare(STR_FITTED_CURVE_DATA_TYPE_UNIFORM_LOG))
		//return FIT_CURVE_UNIFORM_LOG;
	//
	/////Kyle 11/18/2008 QA80-12591 ADD_MORE_OPTION_FOR_INPUT_DATA_TYPE_IN_FITTING_TOOLS
	//if( 0 == strSelction.Compare(STR_FITTED_CURVE_DATA_TYPE_SAME_SOURCE_GRAPH) )
	//{
		//return FIT_CURVE_SAME_AS_SOURCE_GRAPH;
	//}
	/////End ADD_MORE_OPTION_FOR_INPUT_DATA_TYPE_IN_FITTING_TOOLS
	//
	//return -1;	
//}
///end ADD_ERRMSG_WHEN_FITCURVE_XDATATYPE_IS_LOG_WITH_NEGATIVE_INPUT

///------ Folger 01/04/09 QA80-12962 GENERATE_INDIVIDUAL_FIT_CURVE_USING_INDEPENDENT_X_IN_PA
//bool		NLFCurvesBase::GetFitX(vector& vFitX, NLFDataBase* pDataObj, int nDatasetIndex, int nIndepenment, bool bSetCustomInput, bool bSort) // = 0, = 0, true, true
bool		NLFCurvesBase::GetFitX(vector& vFitX, NLFDataBase* pDataObj, int nDatasetIndex, int nIndepenment, bool bSetCustomInput, bool bSort, SmartXOnPeakShapeOption* pSmartXOpt/* = NULL*/) // = 0, = 0, true, true
///------ End GENERATE_INDIVIDUAL_FIT_CURVE_USING_INDEPENDENT_X_IN_PA
{
	if ( !pDataObj )
		return false;
	
	vector		vX;
	if ( !pDataObj->GetIndependData(vX, nDatasetIndex, nIndepenment) )
		return false;			
		
	double 		dXFrom, dXTo;
	GetXAxisFromAndTo(pDataObj, dXFrom, dXTo, nDatasetIndex);
	///Kyle 11/18/2008 QA80-12591 ADD_MORE_OPTION_FOR_INPUT_DATA_TYPE_IN_FITTING_TOOLS
	//get_data_by_fitted_curve_options(vX, vFitX, m_fitCurveDataOptsX, NULL, &dXFrom, &dXTo, bSort, bSetCustomInput);
	DWORD dwPlotUID = pDataObj->GetSourcePlotUID(nDatasetIndex);
	DataPlot dp;
	dp = (DataPlot) Project.GetObject(dwPlotUID);
	GraphLayer gl;
	if(dp)
		dp.GetParent(gl);
	///------ Folger 01/04/09 QA80-12962 GENERATE_INDIVIDUAL_FIT_CURVE_USING_INDEPENDENT_X_IN_PA
	//get_data_by_fitted_curve_options(vX, vFitX, m_fitCurveDataOptsX, gl, true, &dXFrom, &dXTo, bSort, bSetCustomInput);
	get_data_by_fitted_curve_options(vX, vFitX, m_fitCurveDataOptsX, gl, true, &dXFrom, &dXTo, bSort, bSetCustomInput, pSmartXOpt);
	///------ End GENERATE_INDIVIDUAL_FIT_CURVE_USING_INDEPENDENT_X_IN_PA
	///End ADD_MORE_OPTION_FOR_INPUT_DATA_TYPE_IN_FITTING_TOOLS
	return true;
}

///------ Folger 03/24/10 QA81-15237 GENERATE_FITY_BASED_ON_BASELINE_FOR_BETTER_PEAK_PROPERTIES_CALCULATION
//bool 		NLFCurvesBase::GetFitY(const vector& vX, vector& vFitY, NLParametersManager* pParamMngr, int nDatasetIndex, int nPeakIndex) // = 0, 0
bool 		NLFCurvesBase::GetFitY(const vector& vX, vector& vFitY, NLParametersManager* pParamMngr, int nDatasetIndex, int nPeakIndex, BOOL bZeroY0/* = FALSE*/) // = 0, 0
///------ End GENERATE_FITY_BASED_ON_BASELINE_FOR_BETTER_PEAK_PROPERTIES_CALCULATION
{
	if ( !pParamMngr )
		return false;
	
	NumericFunction	nf;
	/// Hong 07/03/09 QA80-13590-P6 FIX_FAIL_LOAD_USER_DEFINE_FDF_FURMULA_PREVIEW
	// Hong, should be used Tree directly here, as for Tree, root node will always be destroyed no matter refered or not
	//Tree 			trFF;
	Tree			tr;
	TreeNode		trFF = tr.AddNode("Junk");
	/// end FIX_FAIL_LOAD_USER_DEFINE_FDF_FURMULA_PREVIEW
	int				nFuncIndex = pParamMngr->GetFuncIndex(nPeakIndex);
	///------ Folger 05/06/09 QA80-13544 IMPROVE_PA_SPEED_WHEN_GO_FROM_FIND_PEAK_TO_FIT_PEAK
	//if ( pParamMngr->GetFDFTree(trFF, nFuncIndex) || !nf.SetTree(trFF) )
	if ( pParamMngr->GetFDFTree(trFF, nFuncIndex, FALSE) || !nf.SetTree(trFF) )
	///------ End IMPROVE_PA_SPEED_WHEN_GO_FROM_FIND_PEAK_TO_FIT_PEAK
		return false;	
		
	vector		vParamValue;
	///Sophy 9/9/2008 UPDATE_REPLICA_PREVIEW_FOR_NLF_81
	//pParamMngr->GetParamValues(vParamValue, nDatasetIndex);	
	pParamMngr->GetParamValues(vParamValue, nDatasetIndex, nPeakIndex, true ); // force it to ignore offset setttings and get all params
	///end UPDATE_REPLICA_PREVIEW_FOR_NLF_81
		
	///------ Folger 03/24/10 QA81-15237 GENERATE_FITY_BASED_ON_BASELINE_FOR_BETTER_PEAK_PROPERTIES_CALCULATION
	if ( bZeroY0 )
	{
		/// for now, just assume bZeroY0 is only be true for peak function
		vParamValue[0] = 0.0;
	}
	///------ End GENERATE_FITY_BASED_ON_BASELINE_FOR_BETTER_PEAK_PROPERTIES_CALCULATION
	vFitY = nf.Evaluate(vX, vParamValue);	
	
	/// Iris 9/18/2009 QA70-9093-P3 FITCURVE_PREVEW_BAD_FOR_WILLBUL3_FUNC
	vector<int> vnResults(vFitY.GetSize());
	if( ocmath_check_infinity(vFitY, vFitY.GetSize(), vnResults, vnResults.GetSize()) > 0 )
	{
		vector<uint> vnFinds;
		vnResults.Find(vnFinds, 1);
		
		vFitY.Replace(vnFinds, NANUM); // replace all infinity to missing value
	}
	///end FITCURVE_PREVEW_BAD_FOR_WILLBUL3_FUNC
	
	return true;
}

//virtual , Sophy
///------ Folger 01/04/09 QA80-12962 GENERATE_INDIVIDUAL_FIT_CURVE_USING_INDEPENDENT_X_IN_PA
//bool		NLFCurvesBase::GetFit( vector& vFitX, vector& vFitY, int nDatasetIndex, int nPeak ) // 0, 0
bool		NLFCurvesBase::GetFit( vector& vFitX, vector& vFitY, int nDatasetIndex, int nPeak, SmartXOnPeakShapeOption* pSmartXOpt/* = NULL*/) // 0, 0
///------ End GENERATE_INDIVIDUAL_FIT_CURVE_USING_INDEPENDENT_X_IN_PA
{
	bool bRet;
	///------ Folger 01/04/09 QA80-12962 GENERATE_INDIVIDUAL_FIT_CURVE_USING_INDEPENDENT_X_IN_PA
	//bRet = GetFitX( vFitX, m_pNLFSession->GetDataObject(), nDatasetIndex );
	bRet = GetFitX( vFitX, m_pNLFSession->GetDataObject(), nDatasetIndex, 0, true, true, pSmartXOpt);
	///------ End GENERATE_INDIVIDUAL_FIT_CURVE_USING_INDEPENDENT_X_IN_PA
	bRet &= GetFitY( vFitX, vFitY, m_pNLFSession->GetNLParamsMngr(), nDatasetIndex, nPeak );
	return bRet;
}
///Sophy 11/25/2008 v8.979 SELF_MAINTAIN_WHETHER_TO_SORT_AS_OLD_LOGIC
//bool		NLFCurvesBase::GetFitX(matrix& mFitXs, NLFDataBase* pDataObj, int nDatasetIndex, int nNumIndeps, bool bSetCustomInput, bool bSort) // = 0, 1, true, true
///------ Folger 01/04/09 QA80-12962 GENERATE_INDIVIDUAL_FIT_CURVE_USING_INDEPENDENT_X_IN_PA
//bool		NLFCurvesBase::GetFitX(matrix& mFitXs, NLFDataBase* pDataObj, int nDatasetIndex, int nNumIndeps, bool bSetCustomInput) // = 0, 1, true
bool		NLFCurvesBase::GetFitX(matrix& mFitXs, NLFDataBase* pDataObj, int nDatasetIndex, int nNumIndeps, bool bSetCustomInput, SmartXOnPeakShapeOption* pSmartXOpt/* = NULL*/) // = 0, 1, true
///------ End GENERATE_INDIVIDUAL_FIT_CURVE_USING_INDEPENDENT_X_IN_PA
///end SELF_MAINTAIN_WHETHER_TO_SORT_AS_OLD_LOGIC
{
	if ( !pDataObj )
		return false;
	///Sophy 11/25/2008 v8.979 SELF_MAINTAIN_WHETHER_TO_SORT_AS_OLD_LOGIC
	bool bSort = NLFIT_GENERAL_XY_FITTING != m_pNLFSession->GetFitType() || 1 == nNumIndeps;
	///end SELF_MAINTAIN_WHETHER_TO_SORT_AS_OLD_LOGIC
	for ( int nIndep = 0; nIndep < nNumIndeps; nIndep++ )
	{
		vector		vFitX;
		///------ Folger 01/04/09 QA80-12962 GENERATE_INDIVIDUAL_FIT_CURVE_USING_INDEPENDENT_X_IN_PA
		//if ( !GetFitX(vFitX, pDataObj, nDatasetIndex, nIndep, bSetCustomInput, bSort) )
		if ( !GetFitX(vFitX, pDataObj, nDatasetIndex, nIndep, bSetCustomInput, bSort, pSmartXOpt) )
		///------ End GENERATE_INDIVIDUAL_FIT_CURVE_USING_INDEPENDENT_X_IN_PA
			return false;
		
		mFitXs.SetSize(vFitX.GetSize(), nNumIndeps); // Hong, to do, very confuce of setsize again and again
		mFitXs.SetColumn(vFitX, nIndep);
	}
	
	return true;
}
///Sophy 12/22/2008 v8.0989c SUPPORT_MULTI_DATASET_FOR_MULTI_INDEPS_AND_DEPS_FITTING
//bool 		NLFCurvesBase::GetFitY(const matrix& mFitXs, matrix& mFitYs, NLParametersManager* pParamMngr, int nDatasetIndex, int nNumDeps) // = 0, 1
bool 		NLFCurvesBase::GetFitY(const matrix& mFitXs, matrix& mFitYs, NLParametersManager* pParamMngr, int nDatasetIndex, int nNumDeps, int nPeakIndex) // = 0, 1, 0
///end SUPPORT_MULTI_DATASET_FOR_MULTI_INDEPS_AND_DEPS_FITTING
{
	if ( !pParamMngr )
		return false;
	
	NumericFunction	nf;
	Tree 			trFF;	
	///Sophy 12/22/2008 v8.0989c SUPPORT_MULTI_DATASET_FOR_MULTI_INDEPS_AND_DEPS_FITTING
	//if ( pParamMngr->GetFDFTree(trFF, nDatasetIndex) || !nf.SetTree(trFF) )
		//return false;
	int				nFuncIndex = pParamMngr->GetFuncIndex(nPeakIndex);
	if ( pParamMngr->GetFDFTree(trFF, nFuncIndex) || !nf.SetTree(trFF) )
		return false;
	///end SUPPORT_MULTI_DATASET_FOR_MULTI_INDEPS_AND_DEPS_FITTING
	
	vector		vParamValue;
	pParamMngr->GetParamValues(vParamValue, nDatasetIndex);

	int			nNumPts = mFitXs.GetNumRows();
	mFitYs.SetSize(nNumPts, nNumDeps);
	
	return	nf.Evaluate(vParamValue, nNumPts, mFitYs, mFitXs);
}

///Sophy 7/28/2008 CLEAN_MATRIXFIT_PREVIEW_CONTROL
bool		NLFCurvesBase::GetXYGriding( vector& vX, vector& vY, int& nRows, int& nCols )
{
	double dXMin, dYMin, dXMax, dYMax;
	vX.GetMinMax(dXMin, dXMax);
	vY.GetMinMax(dYMin, dYMax);		
	
	try 
	{
		vX.SetSize( nRows*nCols );
		vY.SetSize( nRows*nCols );
	}
	catch(int nError)
	{
		return error_report("Memory Allocation failure!\n");
	}
	
	int nRet = ocmath_mat_to_regular_xyz(NULL, nRows, nCols, dXMin, dXMax, dYMin, dYMax, vX, vY, NULL, true);		
	if (nRet < 0)
		return error_report("ocmath_mat_to_regular_xyz returns error in NLFitSessionBase::GetXYGriding!\n");	
		
	return true;
}
///end CLEAN_MATRIXFIT_PREVIEW_CONTROL

///------ Folger 09/16/2010 ORG-1057-P1 MATRIX_FITTING_FAILED_TO_CLOSE_DIALOG_AFTER_FIT_WITH_EMPTY_DATA
#define		CHECK_DATA_EMPTY_AND_RETURN		if ( !vX || vX.GetSize() == 0 || !vY || vY.GetSize() == 0 ) return false
///------ End MATRIX_FITTING_FAILED_TO_CLOSE_DIALOG_AFTER_FIT_WITH_EMPTY_DATA

//bool		NLFCurvesBase::GetFitYWithoutOffset(vector& vx, vector& vy, int nIndependent, int nPeakIndex = 0);
bool 		NLFCurvesBase::GetFitZ(const vector& vX, const vector& vY, vector& vFitZ, NLParametersManager* pParamMngr, int nDatasetIndex) //  = 0
{
	///------ Folger 09/16/2010 ORG-1057-P1 MATRIX_FITTING_FAILED_TO_CLOSE_DIALOG_AFTER_FIT_WITH_EMPTY_DATA
	CHECK_DATA_EMPTY_AND_RETURN;
	///------ End MATRIX_FITTING_FAILED_TO_CLOSE_DIALOG_AFTER_FIT_WITH_EMPTY_DATA
	if ( !pParamMngr )
		return false;
	
	int				nSize = vX.GetSize();
	if ( nSize != vY.GetSize() )
		return false;
	
	if ( nSize != vFitZ.GetSize() )
		vFitZ.SetSize(nSize);
	
	vector			vParamValue;
	if ( pParamMngr->GetParamValues(vParamValue) <= 0 )	
		return false;
	
	double			dBaseline = vParamValue[0];
	NumericFunction	nf;
	Tree 			trFF;
	int				nOldFuncIndex = -1; 
	int				nNumMultiplicity = 1;
	///Sophy 7/30/2008 CLEAN_MATRIXFIT_PREVIEW_CONTROL
	//if ( pParamMngr->GetNumMultiplicity(nNumMultiplicity) )
	if ( !pParamMngr->GetNumMultiplicity(nNumMultiplicity) )
	///end CLEAN_MATRIXFIT_PREVIEW_CONTROL
		return false;	
	for ( int nPeak = 0; nPeak < nNumMultiplicity; nPeak++ )
	{				
		int			nCurrFuncIndex = pParamMngr->GetFuncIndex(nPeak);
		if ( nCurrFuncIndex != nOldFuncIndex )
		{
			if ( pParamMngr->GetFDFTree(trFF, nCurrFuncIndex) || !nf.SetTree(trFF) )
				return false;
		}
		nOldFuncIndex = nCurrFuncIndex;
		
		pParamMngr->GetParamValues(vParamValue, nDatasetIndex, nPeak, true);// force it to ignore offset setttings and get all params
		
		vector 		vzTemp;
		vzTemp = vFitZ;
		if ( !nf.Evaluate(vParamValue, vzTemp, vX, vY, nSize) )
			return false;
		
		if ( 0 == nPeak )
		{
			vFitZ = vzTemp;
		}
		else
		{
			vFitZ += vzTemp;
			vFitZ -= dBaseline; //Subtract baseline
		}
	}
	
	return true;
}

bool 		NLFCurvesBase::GetResidualData(vector& vResidual, NLFDataBase* pDataObj, NLParametersManager* pParamMngr, int index, vector& vInX, vector& vInY, vector& vInZ, vector& vFitZ)
{
	vector 		vX, vY, vZ;	
	pDataObj->GetIndependData(vX, 0, 0);
	pDataObj->GetIndependData(vY, 0, 1);
	pDataObj->GetDependData(vZ);	

	vector vFitZTemp(vX.GetSize());
	if( !GetFitZ(vX, vY, vFitZTemp, pParamMngr, index) )
		return false;
	
	if ( vFitZTemp.GetSize() != vZ.GetSize() )
		return false;
	
	vResidual = vZ - vFitZTemp;
	if ( vInX )
		vInX = vX;
	if ( vInY )
		vInY = vY;
	if ( vInZ )
		vInZ = vZ;
	if ( vFitZ )
		vFitZ = vFitZTemp;
	
	return true;
}

bool 		NLFCurvesBase::GetFitXY(vector& vX, vector& vY, bool bSetCustomInput, bool bNeedGrid, int* pnRows, int* pnCols) // = false, NULL, NULL
{
	///Sophy 7/30/2008 CLEAN_MATRIXFIT_PREVIEW_CONTROL
	//return false;
	
	// _NLF_81, Hong, to do	
	//if ( checkXYZRegularData(NULL, nRows, nCols) && FIT_CURVE_SAME_AS_DATA == m_fitOptionsX.DataType && FIT_CURVE_SAME_AS_DATA == m_fitOptionsY.DataType )
	//	return true;	
	//double dXFrom, dXTo; 
	//getXAxisFromAndTo(dXFrom, dXTo);
	//get_data_by_fitted_curve_options(vX, vX, m_fitOptionsX, NULL, &dXFrom, &dXTo, true, bSetCustomInput);
	//double dYFrom, dYTo; 
	//getYAxisFromAndTo(dYFrom, dYTo);
	//get_data_by_fitted_curve_options(vY, vY, m_fitOptionsY, NULL, &dYFrom, &dYTo, true, bSetCustomInput);
	// replace code above by following
	//filterFitX(vX, bSetCustomInput);
	//filterFitY(vY, bSetCustomInput);
	///*
	int nRows, nCols ;
	///Sophy 1/12/2009 v8.0995c QA80-12613-P4 SHOULD_ONLY_SHOW_UNIFORM_LINEAR_ON_DATATYPE_FOR_3D_FITTING
	//if ( checkXYZRegularData( nRows, nCols) && FIT_CURVE_SAME_AS_DATA == m_fitCurveDataOptsX.DataType && FIT_CURVE_SAME_AS_DATA == m_fitCurveDataOptsY.DataType )
	///------ Folger 07/28/09 QA80-14021 PREIVEW_UPDATE_IN_MATRIX_FIT_AND_SURFACE_FIT_MUCH_SLOWER_THAN_SR5
	//if ( m_pNLFSession->CheckXYZRegularData( nRows, nCols) && FIT_CURVE_SAME_AS_DATA == m_fitCurveDataOptsX.DataType && FIT_CURVE_SAME_AS_DATA == m_fitCurveDataOptsY.DataType )
	if ( FIT_CURVE_SAME_AS_DATA == m_fitCurveDataOptsX.DataType && FIT_CURVE_SAME_AS_DATA == m_fitCurveDataOptsY.DataType && m_pNLFSession->CheckXYZRegularData(nRows, nCols) )
	///------ End PREIVEW_UPDATE_IN_MATRIX_FIT_AND_SURFACE_FIT_MUCH_SLOWER_THAN_SR5
	///end SHOULD_ONLY_SHOW_UNIFORM_LINEAR_ON_DATATYPE_FOR_3D_FITTING
	{
		///Jasmine 07/03/09 QA80-12613-P4 NEED_ROW_COL_TO_GENERATE_MATRIX_EVEN_XY_SAME_AS_INPUT
		//Anyway, it should output if return true. 
		if(pnRows)
			*pnRows = nRows;
		if(pnCols)
			*pnCols = nCols;
		///End NEED_ROW_COL_TO_GENERATE_MATRIX_EVEN_XY_SAME_AS_INPUT
		return true;	
	}
	double dXFrom, dXTo; 
	GetXAxisFromAndTo( m_pNLFSession->GetDataObject(), dXFrom, dXTo );
	///Kyle 11/18/2008 QA80-12591 ADD_MORE_OPTION_FOR_INPUT_DATA_TYPE_IN_FITTING_TOOLS
	//get_data_by_fitted_curve_options(vX, vX, m_fitCurveDataOptsX, NULL, &dXFrom, &dXTo, true, bSetCustomInput);
	DWORD dwPlotUID = m_pNLFSession->GetDataObject()->GetSourcePlotUID();
	DataPlot dp;
	dp = (DataPlot) Project.GetObject(dwPlotUID);
	GraphLayer gl;
	if(dp)
		dp.GetParent(gl);
	get_data_by_fitted_curve_options(vX, vX, m_fitCurveDataOptsX, gl, true, &dXFrom, &dXTo, true, bSetCustomInput);
	///End ADD_MORE_OPTION_FOR_INPUT_DATA_TYPE_IN_FITTING_TOOLS
	double dYFrom, dYTo; 
	GetYAxisFromAndTo( m_pNLFSession->GetDataObject(), dYFrom, dYTo );
	///Kyle 11/18/2008 QA80-12591 ADD_MORE_OPTION_FOR_INPUT_DATA_TYPE_IN_FITTING_TOOLS
	//get_data_by_fitted_curve_options(vY, vY, m_fitCurveDataOptsY, NULL, &dYFrom, &dYTo, true, bSetCustomInput);
	get_data_by_fitted_curve_options(vY, vY, m_fitCurveDataOptsY, gl, false, &dYFrom, &dYTo, true, bSetCustomInput);
	///End ADD_MORE_OPTION_FOR_INPUT_DATA_TYPE_IN_FITTING_TOOLS
	// replace code above by following
	//filterFitX(vX, bSetCustomInput);
	//filterFitY(vY, bSetCustomInput);

	//*/
	///end CLEAN_MATRIXFIT_PREVIEW_CONTROL
	/// Jasmine 08/13/08 QA80-12010 X_IS_COL_WHILE_Y_IS_ROW_IN_MATRIX
	//nRows = vX.GetSize();	
	//nCols = vY.GetSize();
	nCols = vX.GetSize();	
	nRows = vY.GetSize();
	/// end X_IS_COL_WHILE_Y_IS_ROW_IN_MATRIX

	if(bNeedGrid)
	{
		///Sophy 7/30/2008 CLEAN_MATRIXFIT_PREVIEW_CONTROL
		/// Hong, to do, after Griding, vector size changed, check which size is pnRows wanted
		//if( !GetXYGriding(vX, vY, nRows, nCols))
			//return error_report("Error to create XY gridding in NLFitSessionBase::GetFitXY!\n");
		if( !GetXYGriding(vX, vY, nRows, nCols))
			return error_report("Error to create XY gridding in NLFitSessionBase::GetFitXY!\n");
		///end CLEAN_MATRIXFIT_PREVIEW_CONTROL
	}
	
	if(pnRows)
		*pnRows = nRows;
	if(pnCols)
		*pnCols = nCols;
	///end CLEAN_PREVIEW_CTRL_CLASSES
	
	return true;
}

bool 		NLFCurvesBase::GetFitZ(const vector& vX, const vector& vY, matrix& mFitZ, NLParametersManager* pParamMngr, int nDatasetIndex) // = 0
{
	///------ Folger 09/16/2010 ORG-1057-P1 MATRIX_FITTING_FAILED_TO_CLOSE_DIALOG_AFTER_FIT_WITH_EMPTY_DATA
	CHECK_DATA_EMPTY_AND_RETURN;
	///------ End MATRIX_FITTING_FAILED_TO_CLOSE_DIALOG_AFTER_FIT_WITH_EMPTY_DATA

	if ( !pParamMngr )
		return false;
	
	int			nSize = vX.GetSize();
	if ( nSize != vY.GetSize() || nSize != mFitZ.GetNumRows() * mFitZ.GetNumCols() )
		return false;
		
	vector			vParamValue;
	if ( pParamMngr->GetParamValues(vParamValue, nDatasetIndex) <= 0 )	
		return false; 
	
	double			dBaseline = vParamValue[0];
	NumericFunction	nf;
	Tree 			trFF;
	int				nOldFuncIndex = -1;
	int				nNumMultiplicity = 1;
	if ( !pParamMngr->GetNumMultiplicity(nNumMultiplicity ) )
		return false;	
	for ( int nPeak = 0; nPeak < nNumMultiplicity; nPeak++ )
	{				
		int			nCurrFuncIndex = pParamMngr->GetFuncIndex(nPeak);
		if ( nCurrFuncIndex != nOldFuncIndex )
		{
			if ( pParamMngr->GetFDFTree(trFF, nCurrFuncIndex) || !nf.SetTree(trFF) )
				return false;
		}
		nOldFuncIndex = nCurrFuncIndex;
		
		pParamMngr->GetParamValues(vParamValue, nDatasetIndex, nPeak);
		
		matrix		matTemp(mFitZ.GetNumRows(), mFitZ.GetNumCols());
		if ( !nf.Evaluate(vParamValue, matTemp, vX, vY, nSize) )
			return false;
		
		if ( 0 == nPeak )
		{
			mFitZ = matTemp;
		}
		else
		{
			mFitZ += matTemp;			
			mFitZ -= dBaseline; //Subtract baseline
		}
	}
	
	return true;
}
///Sophy 7/28/2008 CLEAN_MATRIXFIT_PREVIEW_CONTROL
bool		NLFCurvesBase::GetFit( vector& vX, vector& vY, matrix& mat, NLParametersManager* pParamMngr, int nDatasetIndex, int& nRows, int& nCols, int nIndependent, bool bSetCustomInput )//default : 0, NULL, NULL, 0, true
{
	int nRowNum, nColNum;
	if( !GetFitXY( vX, vY, bSetCustomInput, true, &nRowNum, &nColNum ) )
		return false;
	
	mat.SetSize( nRowNum, nColNum );
	
	if( !GetFitZ( vX, vY, mat, pParamMngr, nDatasetIndex ) )
		return false;
	
	if( NULL != nRows )
		nRows = nRowNum;
	if( NULL != nCols )
		nCols = nColNum;
	
	return true;
}
//end CLEAN_MATRIXFIT_PREVIEW_CONTROL
///Sophy 10/13/2008 QA80-12365 FIX_FAIL_TO_REPORT_RESIDUAL_IN_MATRIX_FIT
///Sophy 3/3/2009 v8.0990 FIX_RUNTIME_ERROR_WHEN_USE_CHEBYSHEV2D_AS_FUNCTION_IN_MATRIX_FITTING remove duplicated code
//bool	NLFCurvesBase::GetMatResidualData(matrix& matResidual, int& nRows, int& nCols, double& dXmin, double& dYmin, double& dXmax, double& dYmax)
//{
	///// NLF_81 Sophy
	/////*
	//vector 	vResidual, vX, vY;
	//if( !GetResidualData(vResidual, m_pNLFSession->GetDataObject(), m_pNLFSession->GetNLParamsMngr(), 0, vX, vY) )
		//return error_report("Fail to get residual data for surface fitting");
	//
	////examine data and do the conversion if data are regular
	//double dXStep, dYStep;
	//ocmath_xyz_examine_data(vX.GetSize(), vX, vY, vResidual, 1.0e-8, NULL, &dXmin, 
				//&dXStep, &dXmax, &dYmin, &dYStep, &dYmax);
	//
	//vector mat;		
	//nCols = dXStep > 0 ? (int)((dXmax - dXmin) / dXStep + 0.5) + 1 : 1; 
	//nRows = dYStep > 0 ? (int)((dYmax - dYmin) / dYStep + 0.5) + 1 : 1; 
	//mat.SetSize(nRows * nCols); // nRows*nCols = nVar, for regular
	//if(ocmath_convert_regular_xyz_to_matrix(vX.GetSize(), vX, vY, vResidual,
				//mat, dXmin, dXStep, nCols, dYmin, dYStep, nRows) != OE_NOERROR)
		//return false;
	//
	//matResidual.SetSize(nRows, nCols);
	//matResidual.SetByVector(mat);
	//return true;
	////*/
	/////end NLF_81
//}
///end FIX_RUNTIME_ERROR_WHEN_USE_CHEBYSHEV2D_AS_FUNCTION_IN_MATRIX_FITTING
///end FIX_FAIL_TO_REPORT_RESIDUAL_IN_MATRIX_FIT

/// Hong 10/17/08 QA80-10624 NLFIT_SUPPORT_FIT_SWAPPED_POLAR_PLOT
uint		NLFCurvesBase::GetFitCurvePlotCtrl(NLFDataBase* pDataObj)
{	
	if ( IsSwappedPolarPlot(pDataObj) )
		return GAP_XY_POLAR_SWAP;
		
	return 0;
}
/// end NLFIT_SUPPORT_FIT_SWAPPED_POLAR_PLOT

//virtual
bool		NLFCurvesBase::GetResidualData(matrix& matResidual, NLFDataBase* pDataObj, NLParametersManager* pParamMngr, int& nRows, int& nCols, double& dXmin, double& dYmin, double& dXmax, double& dYmax)
{
	vector 	vResidual, vX, vY;
	if( !GetResidualData(vResidual, pDataObj, pParamMngr, 0, vX, vY) )
		return error_report("Fail to get residual data for surface fitting");
	
	//examine data and do the conversion if data are regular
	double dXStep, dYStep;
	///---Sim 09-25-2009 QA80-13783 CHANGE_PROTOTYPE_AND_ALGORITHM_FOR_EXAMINATION
	//ocmath_xyz_examine_data(vX.GetSize(), vX, vY, vResidual, 1.0e-8, NULL, &dXmin, 
	//			&dXStep, &dXmax, &dYmin, &dYStep, &dYmax);
	xyz_examine_data(vX.GetSize(), vX, vY, vResidual, 1.0e-8, NULL, &dXmin, 
				&dXStep, &dXmax, &dYmin, &dYStep, &dYmax);
	///---End QA80-13783 CHANGE_PROTOTYPE_AND_ALGORITHM_FOR_EXAMINATION
				
	vector mat;		
	///Sophy 3/3/2009 v8.0990 FIX_RUNTIME_ERROR_WHEN_USE_CHEBYSHEV2D_AS_FUNCTION_IN_MATRIX_FITTING
	//nCols = dXStep > 0 ? (int)((dXmax - dXmin) / dXStep + 0.5) + 1 : 1; 
	//nRows = dYStep > 0 ? (int)((dYmax - dYmin) / dYStep + 0.5) + 1 : 1;
	int	nDatasetIndex = 0; //matrix fit has only one dataset.
	m_pNLFSession->GetDataObject()->GetDimention(nDatasetIndex, nRows, nCols);
	///end FIX_RUNTIME_ERROR_WHEN_USE_CHEBYSHEV2D_AS_FUNCTION_IN_MATRIX_FITTING
	mat.SetSize(nRows * nCols); // nRows*nCols = nVar, for regular
	if(ocmath_convert_regular_xyz_to_matrix(vX.GetSize(), vX, vY, vResidual,
				mat, dXmin, dXStep, nCols, dYmin, dYStep, nRows) != OE_NOERROR)
		return false;
	
	matResidual.SetSize(nRows, nCols);
	matResidual.SetByVector(mat);
	return true;
}

bool		NLFCurvesBase::SetFitCurveOptions(const TreeNode& trFitCurveOpts)
{
	if ( !trFitCurveOpts )
		return false;
	
	TreeNode trX = trFitCurveOpts.XDataType;
	if( !trX )
		return false;	
	ASSERT(trFitCurveOpts.PlotType);
	
	m_fitCurveDataOptsX = trX;
	///Sophy 11/21/2008 v8.976 QA80-12591-P3 ADD_ERRMSG_WHEN_FITCURVE_XDATATYPE_IS_LOG_WITH_NEGATIVE_INPUT
	//m_fitCurveDataOptsX.DataType = _get_fitted_curve_data_type(trX);
	m_fitCurveDataOptsX.DataType = get_fitted_curve_data_type(trX);
	///end ADD_ERRMSG_WHEN_FITCURVE_XDATATYPE_IS_LOG_WITH_NEGATIVE_INPUT
			
	TreeNode trY = trFitCurveOpts.YDataType; // YDataType is existed only for surface fit
	if( trY )
	{
		m_fitCurveDataOptsY = trY;
		///Sophy 11/21/2008 v8.976 QA80-12591-P3 ADD_ERRMSG_WHEN_FITCURVE_XDATATYPE_IS_LOG_WITH_NEGATIVE_INPUT
		m_fitCurveDataOptsY.DataType = get_fitted_curve_data_type(trY);
		//m_fitCurveDataOptsY.DataType = get_fitted_curve_data_type(trY);
		///end ADD_ERRMSG_WHEN_FITCURVE_XDATATYPE_IS_LOG_WITH_NEGATIVE_INPUT
	}
	
	m_fitCurveOpts.CurveColor = 1; //red for default
	m_fitCurveOpts.PlotType = trFitCurveOpts.PlotType.nVal;
	
	return true;
}

void 		NLFCurvesBase::setLayerFromTo(double dFrom, double dTo, vector &vecFrom, vector &vecTo, int nIndex)
{	
	if(-1 < nIndex && vecFrom.GetSize() > nIndex)
	{
		vecFrom[nIndex] = dFrom;
		vecTo[nIndex] = dTo;		
	}
	else
	{
		vecFrom.Add(dFrom);
		vecTo.Add(dTo);
	}		
}

// ! m_vSrcXFrom and m_vSrcXTo will always save X Axis From/To. m_vSrcYFrom, m_vSrcYTo are same too.
bool		NLFCurvesBase::SetSrcFromAndTo(GraphLayer& gl, int nIndex)
{
	if ( !gl )
		return false;	

	setLayerFromTo(gl.X.From, gl.X.To, m_vSrcXFrom, m_vSrcXTo, nIndex);
	setLayerFromTo(gl.Y.From, gl.Y.To, m_vSrcYFrom, m_vSrcYTo, nIndex);	
	return true;
}

///------ Folger 01/04/09 QA80-12962 MORE_WORK_ON_GENERATE_INDIVIDUAL_FIT_CURVE_USING_INDEPENDENT_X_IN_PA
//bool		NLFCurvesBase::GetCumulativeData(vector& vCumulative, NLParametersManager* pParamMngr, int nDatasetIndex, int nPeaks, bool bHasBaseLinePeak)
bool		NLFCurvesBase::GetCumulativeData(vector& vCumulative, NLParametersManager* pParamMngr, int nDatasetIndex, int nPeaks, bool bHasBaseLinePeak, vector* pvXCumulative/* = NULL*/)
///------ End MORE_WORK_ON_GENERATE_INDIVIDUAL_FIT_CURVE_USING_INDEPENDENT_X_IN_PA
{
	///Sophy 9/19/2008 FIX_FAIL_TO_GET_CUMULATIVE_DATA_RANGE
	/////Jasmine 11/05/07 SUBTRACT_BASELINE_BEFORE_PFM_FIT
	vector		vParamValue;
	pParamMngr->GetParamValues(vParamValue, nDatasetIndex);	
	double 		dY0 = (vParamValue.GetSize() && !bHasBaseLinePeak)? vParamValue[0] : 0;//offset
	///end SUBTRACT_BASELINE_BEFORE_PFM_FIT
	
	vCumulative.SetSize(0);
	vector		vX;		///------ Folger 01/04/09 QA80-12962 MORE_WORK_ON_GENERATE_INDIVIDUAL_FIT_CURVE_USING_INDEPENDENT_X_IN_PA
	for(int nPeak = 0; nPeak < nPeaks; nPeak++)
	{
		///------ Folger 01/04/09 QA80-12962 MORE_WORK_ON_GENERATE_INDIVIDUAL_FIT_CURVE_USING_INDEPENDENT_X_IN_PA
		//vector 	vX, vY;
		vector		vY;
		///------ End MORE_WORK_ON_GENERATE_INDIVIDUAL_FIT_CURVE_USING_INDEPENDENT_X_IN_PA
		///Sophy 10/13/2008 GET_CUMULATIVE_DATA_WHITH_BASELINE_MODE
		//if( !GetFitX( vX, m_pNLFSession->GetDataObject(), nDatasetIndex ) || !GetFitY( vX, vY, pParamMngr, nDatasetIndex, nPeak) )
		if( !GetFit( vX, vY, nDatasetIndex, nPeak ) )
		///end GET_CUMULATIVE_DATA_WHITH_BASELINE_MODE
			return error_report("Get error from GetFit method in NLFCurvesBase::GetCumulativeData");
		else
		{
			if(0 == vCumulative.GetSize())
				vCumulative.SetSize(vY.GetSize());
			
			vCumulative += vY;
			
			if(0 < nPeak)	///Jasmine 11/05/07 SUBTRACT_BASELINE_BEFORE_PFM_FIT
				vCumulative -= dY0;
		}
	}
	///end FIX_FAIL_TO_GET_CUMULATIVE_DATA_RANGE
	
	///------ Folger 01/04/09 QA80-12962 MORE_WORK_ON_GENERATE_INDIVIDUAL_FIT_CURVE_USING_INDEPENDENT_X_IN_PA
	if ( pvXCumulative )
	{
		*pvXCumulative = vX;
	}
	///------ End MORE_WORK_ON_GENERATE_INDIVIDUAL_FIT_CURVE_USING_INDEPENDENT_X_IN_PA
	return true;	
}


/// Iris 10/24/2008 v8.0960b FIX_FAIL_NOT_SETUP_PLOT_FOR_ALL_PEAK_CURVES
//int			NLFCurvesBase::AddCurvePlot(GraphLayer& gl, DataRange& dr, int nPlotType, uint nCntrl, bool bCheckIfHasPlot, DWORD *pdwDataRules, int* pStartPlotIndex)
int			NLFCurvesBase::AddCurvePlot(GraphLayer& gl, DataRange& dr, int nPlotType, uint nCntrl, bool bCheckIfHasPlot, DWORD *pdwDataRules, vector<int> *pvnPlotIndices)
///end FIX_FAIL_NOT_SETUP_PLOT_FOR_ALL_PEAK_CURVES
{	
	/*
	plotDataRange plot ranges like 
		Range 
			->X:[Book1]Sheet1!A
			->Y:[Book1]Sheet1!B
	plot_data_range plot ranges got from report table, like 
		Range
			->0: [Book1]Sheet1!A:B
	so plot_data_range will change range to the first format, then do plot
	*/	
	///Sophy 9/2/2008 CLEAN_NLFCURVE_ADDPLOT_CODE
	/*
	int	nPlot =	plotDataRange(dr, gl, nPlotType, nCntrl, bCheckIfHasPlot);
	if( nPlot < 0 )
	{
		//int	plot_data_range(DataRange& dr, GraphLayer& gl, int nPlotType, uint nCntrl = GAP_GROUP_PLOTS | GAP_USE_TEMPLATE | GAP_ALLOW_DUPLICATE_COL, int* pDelCol = NULL, bool bCheckIfPlot = false, DWORD *pdwDataRules = NULL, int* pStartPlotIndex = NULL);
		nPlot =	plot_data_range(dr, gl, nPlotType, nCntrl, NULL, bCheckIfHasPlot, NULL, pStartPlotIndex);
	}
	return nPlot;
	*/
	//After add GAP_USE_WKS_DESIGNATION into nCntrl, it can handle both range formats successfully
	/// Iris 10/24/2008 v8.0960b FIX_FAIL_NOT_SETUP_PLOT_FOR_ALL_PEAK_CURVES, nPlot is plot index of first plot, pvnPlotIndices saved all plot indices
	/*
	int nPlot = plotDataRange(dr, gl, nPlotType, nCntrl, bCheckIfHasPlot);
	if( nPlot < 0 )
		nPlot = plotDataRange(dr, gl, nPlotType, nCntrl | GAP_USE_WKS_DESIGNATION, bCheckIfHasPlot);
	*/
	int nPlot = plotDataRange(dr, gl, nPlotType, nCntrl, bCheckIfHasPlot, pvnPlotIndices);
	if( nPlot < 0 )
		nPlot = plotDataRange(dr, gl, nPlotType, nCntrl | GAP_USE_WKS_DESIGNATION, bCheckIfHasPlot, pvnPlotIndices);
	///end FIX_FAIL_NOT_SETUP_PLOT_FOR_ALL_PEAK_CURVES
	ASSERT( nPlot >=0 );
	return nPlot;
	///end CLEAN_NLFCURVE_ADDPLOT_CODE
}

int			NLFCurvesBase::AddCurvePlot(GraphLayer& gl, DWORD dwPlotUID)
{
	DataPlot dp;
	dp = Project.GetObject(dwPlotUID);
	//---- CPY 11/06/08 CHANGE_PARAM_OPEN_NLFIT_SAW_ASSERT
	//ASSERT(dp.IsValid());
	if(!dp.IsValid())
		return -1;
	//----
	
	int nPlot = gl.AddPlot(dp, ADDPLTPFROMPLT_ADD_EVEN_IF_DATASET_PRESENT | ADDPLTPFROMPLT_ERRORBAR);		
	return nPlot;	
}

int		NLFCurvesBase::PlotSourceCurve(GraphLayer& gl, int nDatasetIndex, DWORD* pdwPlotUID, int nDep, int nIndep, int nPlotType, uint nCntrl, bool bGrayScale)
{	
	int		nPlot = -1;
	if(!gl)
		return nPlot;
	
	nPlot = plotSourceCurve(gl, nDatasetIndex, pdwPlotUID, nDep, nIndep, bGrayScale);
	DataPlot dp = gl.DataPlots(nPlot);
	
	if( nPlot < 0 || !dp ) 
		return nPlot;
		
	if( pdwPlotUID )
	{
		*pdwPlotUID = dp.GetUID(true);
	}
	
	///Sophy 7/30/2008 CLEAN_MATRIXFIT_PREVIEW_CONTROL
	//setupSourcePlot(dp);
	setupSourcePlot(dp, bGrayScale );
	///end CLEAN_MATRIXFIT_PREVIEW_CONTROL
	
	return nPlot;
}


bool		NLFCurvesBase::setupSourcePlot(DataPlot& dp, bool bGrayScale)
{
	return true;
}

/// Hong 10/17/08 QA80-10624 NLFIT_SUPPORT_FIT_SWAPPED_POLAR_PLOT
//int			NLFCurvesBase::PlotFitCurve(GraphLayer& gl, DataRange& drFitCurve, bool bCheckIfHasPlot, int* pStartPlotIndex, DWORD *pdwDataRules)
///Sophy 10/31/2008 GROUP_CUMULATIVE_CURVE_WITH_FITTED_CURVES
//int			NLFCurvesBase::PlotFitCurve(GraphLayer& gl, DataRange& drFitCurve, NLFDataBase* pDataObj, bool bCheckIfHasPlot, int* pStartPlotIndex, DWORD *pdwDataRules)
int			NLFCurvesBase::PlotFitCurve(GraphLayer& gl, DataRange& drFitCurve, NLFDataBase* pDataObj, bool bCheckIfHasPlot, int* pStartPlotIndex, DWORD *pdwDataRules, int nCumulativeIndex )
///end GROUP_CUMULATIVE_CURVE_WITH_FITTED_CURVES
/// end NLFIT_SUPPORT_FIT_SWAPPED_POLAR_PLOT
{
	int 	nPlot = -1;
	if(!gl)
		return nPlot;	
	
	
	/// Hong 10/17/08 QA80-10624 NLFIT_SUPPORT_FIT_SWAPPED_POLAR_PLOT
	//nPlot =  plotFitCurve(gl, drFitCurve, bCheckIfHasPlot, pStartPlotIndex, pdwDataRules);	
	/// Iris 10/24/2008 v8.0960b FIX_FAIL_NOT_SETUP_PLOT_FOR_ALL_PEAK_CURVES
	//nPlot =  plotFitCurve(gl, drFitCurve, bCheckIfHasPlot, pStartPlotIndex, pdwDataRules, GetFitCurvePlotCtrl(pDataObj));
	//vector<int> vnPlotIndices; 
	///Sophy 10/30/08 FIX_FAIL_TO_GET_CORRECT_NUM_OF_DATAPLOT_IN_CASE_WITH_REPLICA nNumPlots is not reliable in some case, such as one dataset with multiple peaks(XYY, in case with replica)	
	///Sophy 10/30/08 FIX_FAIL_TO_SHOW_RESIDUAL_GRAPH_ON_MATRIXFIT_PREVIEW
	//int nNumPlots = drFitCurve.GetNumData(DRR_GET_DEPENDENT | DRR_NO_FACTORS);
	//DWORD dwDataRules = m_pNLFSession->GetDataRules();
	//int nNumPlots = drFitCurve.GetNumData( dwDataRules );
	//
	//ASSERT( nNumPlots >=0 );
	//if( nNumPlots < 0 )
		//return -1; //nPlot;
	/////end FIX_FAIL_TO_SHOW_RESIDUAL_GRAPH_ON_MATRIXFIT_PREVIEW
	//vnPlotIndices.SetSize(nNumPlots);
	//vnPlotIndices.SetSize(1); ///Sophy, the size of this vector is not important now, will reset it after plot fitcurves.
	int nNumPlotsBfPlt = gl.DataPlots.Count();//before add plot
	///end FIX_FAIL_TO_GET_CORRECT_NUM_OF_DATAPLOT_IN_CASE_WITH_REPLICA
	///Sophy 10/31/2008 GROUP_CUMULATIVE_CURVE_WITH_FITTED_CURVES
	//nPlot =  plotFitCurve(gl, drFitCurve, bCheckIfHasPlot, pdwDataRules, GetFitCurvePlotCtrl(pDataObj), &vnPlotIndices);
	nPlot =  plotFitCurve(gl, drFitCurve, bCheckIfHasPlot, pdwDataRules, GetFitCurvePlotCtrl(pDataObj) );
	///end GROUP_CUMULATIVE_CURVE_WITH_FITTED_CURVES
	/// end NLFIT_SUPPORT_FIT_SWAPPED_POLAR_PLOT
	if( nPlot< 0)
		return nPlot;
	
	///Sophy 10/30/08 FIX_FAIL_TO_GET_CORRECT_NUM_OF_DATAPLOT_IN_CASE_WITH_REPLICA nNumPlots is not reliable in some case, such as one dataset with multiple peaks
	vector<int> vnPlotIndices; 
	int nNumPlotsAdded = gl.DataPlots.Count() - nNumPlotsBfPlt;//after add plot
	if( nNumPlotsAdded )
		vnPlotIndices.Data( nPlot, nNumPlotsAdded + nPlot - 1, 1 );
	///end FIX_FAIL_TO_GET_CORRECT_NUM_OF_DATAPLOT_IN_CASE_WITH_REPLICA
	
	/// Iris 10/24/2008 v8.0960b FIX_FAIL_NOT_SETUP_PLOT_FOR_ALL_PEAK_CURVES, move this logic to PeakFitCurves::setupFitPlot
	//if( bGroup ) 
	//{
		//gl.UngroupPlots();
		//gl.GroupPlots(nPlot1Index, nPlotLastIndex);
	//}
	///end FIX_FAIL_NOT_SETUP_PLOT_FOR_ALL_PEAK_CURVES
	
	/// Iris 10/24/2008 v8.0960b FIX_FAIL_NOT_SETUP_PLOT_FOR_ALL_PEAK_CURVES
	//DataPlot 	dp = gl.DataPlots(nPlot);
	//setupFitPlot(dp);
	///Sophy 10/31/2008 GROUP_CUMULATIVE_CURVE_WITH_FITTED_CURVES
	//setupFitPlot(gl, vnPlotIndices);
	setupFitPlot( gl, vnPlotIndices, nCumulativeIndex );
	///end GROUP_CUMULATIVE_CURVE_WITH_FITTED_CURVES
	if( pStartPlotIndex )
		*pStartPlotIndex = nPlot;
	///end FIX_FAIL_NOT_SETUP_PLOT_FOR_ALL_PEAK_CURVES
	
	return nPlot;
}

int			NLFCurvesBase::PlotResidual(GraphLayer& gl, DataRange& drResidual)
{
	int 	nPlot =  plotResidual(gl, drResidual);
	if( nPlot >= 0)
	{
		DataPlot dp = gl.DataPlots(nPlot);
		setupResidualPlot(dp);
	}
	return nPlot;		
}


//virtual
string		NLFCurvesBase::GetTemplate(bool bResidual) 
{ 
	if( bResidual )
		return NLSF_RESIDUAL_GRAPH_TEMPLATE;
	else
		return NLSF_FIT_CURVE_GRAPH_TEMPLATE; 
}

void		NLFCurvesBase::copyLegendModeFromSourceGraph(GraphPage& gpSource, GraphLayer& gl)
{		
	string		strCustomFormat;
	int	nLegendMode = get_page_legend_mode(gpSource, strCustomFormat);
	
	GraphPage	gp = gl.GetPage();
	if( set_page_legend_mode(gp, nLegendMode, strCustomFormat) )
		gp.Refresh(true);	
}

/// Iris NLF_81, copy logic from WksReportOperation::setFormatFromSourceGraphToReport
void		NLFCurvesBase::copyAxisTypeFromSourceGraph(GraphPage& gpSource, GraphLayer& gl)
{
	GraphLayer glSource = gpSource.Layers();/// Iris NLF_81, to do , need NLFitSession support GetSourceGraphLayer
	
	// need to copy X & Y Axis type from source graph
	vector<string> 		vsAxisNames = {"X", "Y"};
	for(int ii = 0; ii < vsAxisNames.GetSize(); ii++)
	{
		string strLT;
		strLT.Format("Axis -pg %s S axistype", vsAxisNames[ii]);
		
		if(glSource.LT_execute(strLT))
		{
			double	dType;
			if(LT_get_var("axistype", &dType))
			{
				string str;
				/// Iris 08/06/2007 v8.0674 ALWAYS_COPY_SOURCE_GRAPH_AXIS_TYPE
				//str.Format("Axis -ps X S %.0f", dType);
				str.Format("Axis -ps %s S %.0f", vsAxisNames[ii], dType);
				///end ALWAYS_COPY_SOURCE_GRAPH_AXIS_TYPE
				gl.LT_execute(str);
			}
		}
	}
}

///Sophy 1/12/2009 v8.0995c QA80-12613-P4 SHOULD_ONLY_SHOW_UNIFORM_LINEAR_ON_DATATYPE_FOR_3D_FITTING moved to nlfitsession.h
/////Sophy 7/28/2008 CLEAN_MATRIXFIT_PREVIEW_CONTROL
//bool		NLFCurvesBase::checkXYZRegularData( int& nRows, int& nCols )
//{
	//vector vX, vY, vZ;
	//NLFDataBase*	pDataObj = m_pNLFSession->GetDataObject();
	//ASSERT( pDataObj );
	//if( !pDataObj )
		//return false;
	//
	//pDataObj->GetDependData( vX, 0, 0 );
	//pDataObj->GetDependData( vY, 0, 1 );
	//pDataObj->GetIndependData( vZ, 0, 0 );
	//
	//bool bRegular = false;		
	//if(vX.GetSize() == vY.GetSize() && vX.GetSize() == vZ.GetSize() && vX.GetSize() != 0)
	//{
		//double 	dPrecision = 1E-8;
		//int 	nSize = vX.GetSize();
		//double 	Xmin, Ymin, Xstep, Ystep, Xmax, Ymax;
		//int nRet = ocmath_xyz_examine_data(nSize, vX, vY ,vZ, dPrecision, &nSize, &Xmin,
					//&Xstep, &Xmax, &Ymin, &Ystep, &Ymax, true);			
					//
		//if(NULL != nCols) nCols = Xstep > 0 ? (int)((Xmax - Xmin) / Xstep + 0.5) + 1 : 1; 
		//if(NULL != nRows) nRows = Ystep > 0 ? (int)((Ymax - Ymin) / Ystep + 0.5) + 1 : 1; 
		//if(Examine_XYZ_Regular == nRet)
			//bRegular = true;
	//}	
	//return bRegular;
//}
/////end CLEAN_MATRIXFIT_PREVIEW_CONTROL
///end SHOULD_ONLY_SHOW_UNIFORM_LINEAR_ON_DATATYPE_FOR_3D_FITTING

bool		NLFCurvesBase::CopyFormatFromSourceGraph(GraphLayer& gl)
{
	GraphPage gpSource = m_pNLFSession->GetSrcGraphPage();
	if( !gpSource )
		return false;
	
	copyLegendModeFromSourceGraph(gpSource, gl);	
	
	copyAxisTypeFromSourceGraph(gpSource, gl);
	
	return true;
}

bool		NLFCurvesBase::UpdateLegend(GraphLayer& gl)
{
	///Sophy 7/31/2008 FIX_DONT_CREATE_LEGEND_NAME_IF_NOT_EXIST consistent to 80
	//legend_update(gl,  -1, true, false);	
	legend_update(gl,  -1, false, false);	
	///end FIX_DONT_CREATE_LEGEND_NAME_IF_NOT_EXIST
	return false;
}
///Sophy 11/11/2008 v8.968 QA80-10599-P1 NLFIT_PREVIEW_UPDATE_CLEANUP
//bool		NLFCurvesBase::Rescale(GraphLayer& gl)
bool		NLFCurvesBase::Rescale(GraphLayer& gl, bool bFitCurveGraph )//false
///end NLFIT_PREVIEW_UPDATE_CLEANUP
{
	/// Iris NLF_81 to do, this may move to derived class SurfaceFitCurves later
	/*
	/// Hong 05/05/08 QA80-11511 FIX_SURFACE_FIT_CONTOUR_LEVEL_CHANGED_BY_RESCALE
	//DWORD 	dwCntrl = 0; //default 
	DWORD 	dwCntrl = OKAXISTYPE_Z; //default should NOT rescale Z axis
	/// end FIX_SURFACE_FIT_CONTOUR_LEVEL_CHANGED_BY_RESCALE
	*/
	///Sophy 7/30/2008 CLEAN_MATRIXFIT_PREVIEW_CONTROL
	//DWORD 	dwCntrl = 0; //default 
	DWORD 	dwCntrl = OKAXISTYPE_Z; //default 
	///end CLEAN_MATRIXFIT_PREVIEW_CONTROL
	///end NLF_81
			
	if(FIT_CURVE_SPAN_AXIS == m_fitCurveDataOptsX.Range)
	{
		//Iris NLF_81 copy logic from NLFitPreviewCtrl, but why not do no expand if DataType is Same as Input Data?
		if(FIT_CURVE_UNIFORM_LINEAR == m_fitCurveDataOptsX.DataType || FIT_CURVE_UNIFORM_LOG == m_fitCurveDataOptsX.DataType)
		{
			dwCntrl = ANL_NO_EXPAND;
		}
	}
	if( dwCntrl > 0 )
		dwCntrl |= ANL_CHK_DATA_OUTSIDE;	
	
	int nOutcome;	
	///Sophy 11/11/2008 v8.968 QA80-10599-P1 NLFIT_PREVIEW_UPDATE_CLEANUP
	//return gl.Rescale(dwCntrl, &nOutcome);	
	if( !bFitCurveGraph )
		return gl.Rescale( dwCntrl, &nOutcome );
	else
		return rescaleFitCurvesGraph( gl, dwCntrl );
	///end NLFIT_PREVIEW_UPDATE_CLEANUP
}
///Sophy 11/11/2008 v8.968 QA80-10599-P1 NLFIT_PREVIEW_UPDATE_CLEANUP
bool		NLFCurvesBase::rescaleFitCurvesGraph( GraphLayer& gl, DWORD dwCtrl )
{
	double x1,x2,y1,y2;
	///Sophy 11/20/2008 QA80-10599-P6 FIX_FITCURVE_GRAPH_AXES_RESCALE_PROBLEM
	//if(!GetXAxisFromAndTo( m_pNLFSession->GetDataObject(), x1, x2 ) || !GetYAxisFromAndTo( m_pNLFSession->GetDataObject(), y1, y2 ) )
			//return false;
	if( !GetFitCurvesScaleRange(x1, x2, y1, y2) )
		return false;
	///end FIX_FITCURVE_GRAPH_AXES_RESCALE_PROBLEM
	
	//---- Iris 01/15/2009 CENTRALIZE_NEW_X_DATA_TYPE_AND_LOG_TYPE_CODES, new type is Use Source Graph Scale Type
	//bool bLogXScale = FIT_CURVE_UNIFORM_LOG == m_fitCurveDataOptsX.DataType? true:false;
	//double xInc = get_min_max_inc(x1, x2, bLogXScale,0.08, 10);
	int nXScaleType = getGraphScaleType(gl, true);
	bool bLogXScale = SCALE_TYPE_LOG10 == nXScaleType;
	double xInc = get_min_max_inc(x1, x2, nXScaleType, 0.08, 10);
	//----

	int nYSteps = 10; //Keep same as X steps

	//---- Iris 01/15/2009 CENTRALIZE_NEW_X_DATA_TYPE_AND_LOG_TYPE_CODES, new type is Use Source Graph Scale Type
	//bool bLogYScale = FIT_CURVE_UNIFORM_LOG == m_fitCurveDataOptsY.DataType? true:false;
	//double yInc = get_min_max_inc(y1, y2, bLogYScale,0.08, nYSteps);
	int nYScaleType = getGraphScaleType(gl, false);	
	double bLogYScale = SCALE_TYPE_LOG10 == nYScaleType;;
	double yInc = get_min_max_inc(y1, y2, nYScaleType, 0.08, nYSteps);
	//----
	
	// check to see if input data is too far outside, then we may need to expand to show them
	DataRange drSrc;
	drSrc = m_pNLFSession->GetSrcDataRange();
	if(drSrc) 
	{
		double dx1, dx2, dy1, dy2;
		bool bNeedExpand = false;
		DWORD dwRules = m_pNLFSession->GetDataRules();

		dwRules |= DRR_GET_DEPENDENT;
		
		if(get_data_range_xy_scale(drSrc, dx1, dx2, dy1, dy2, dwRules, NULL, NULL))
		{
			if(dy1 < y1) {bNeedExpand = true; y1 = dy1;}
			if(dy2 > y2) {bNeedExpand = true; y2 = dy2;}
		}
	}	
	gl.X.From = x1;
	gl.X.To = x2;
	if(!bLogXScale)
		gl.X.Inc = xInc;
	gl.Y.From = y1;
	gl.Y.To = y2;
	if(!bLogYScale)
	{
		gl.Y.Inc = yInc;
	}	
	return true;
}
///end NLFIT_PREVIEW_UPDATE_CLEANUP

///Sophy 11/20/2008 QA80-10599-P6 FIX_FITCURVE_GRAPH_AXES_RESCALE_PROBLEM
void		NLFCurvesBase::SetFitCurveScaleRange(const vector& vFit, bool bFitY)
{
	double dMin = 0, dMax = 0;
	vFit.GetMinMax(dMin, dMax);
	
	if( bFitY )
	{
		m_vFitYMin.Add(dMin);
		m_vFitYMax.Add(dMax);
	}
	else
	{
		m_vFitXMin.Add(dMin);
		m_vFitXMax.Add(dMax);
	}
}

bool		NLFCurvesBase::GetFitCurvesScaleRange(double& dXMin, double& dXMax, double& dYMin, double& dYMax)
{
	if( m_vFitXMin.GetSize() < 1 || m_vFitYMin.GetSize() < 1 || m_vFitXMin.GetSize() != m_vFitXMax.GetSize() || m_vFitYMin.GetSize() != m_vFitYMax.GetSize() )
		return false;
	
	///Sophy 6/1/2009 IMPROVE_CODE
	/*
	dXMin = m_vFitXMin[0];
	dXMax = m_vFitXMax[0];
	
	for( int ii = 1; ii < m_vFitXMin.GetSize(); ii++ )
	{
		if( m_vFitXMin[ii] < dXMin )dXMin = m_vFitXMin[ii];
		if( m_vFitXMax[ii] > dXMax )dXMax = m_vFitXMax[ii];
	}
	
	dYMin = m_vFitYMin[0];
	dYMax = m_vFitYMax[0];
	for( ii = 1; ii < m_vFitYMin.GetSize(); ii++ )
	{
		if( m_vFitYMin[ii] < dYMin )dYMin = m_vFitYMin[ii];
		if( m_vFitYMax[ii] > dYMax )dYMax = m_vFitYMax[ii];
	}
	*/
	double dummy;
	m_vFitXMin.GetMinMax(dXMin, dummy);
	m_vFitXMax.GetMinMax(dummy, dXMax);
	
	m_vFitYMin.GetMinMax(dYMin, dummy);
	m_vFitYMax.GetMinMax(dummy, dYMax);
	///end IMPROVE_CODE
	return true;
}

void		NLFCurvesBase::ResetFitCurvesScaleRange()
{
	///Sophy 1/16/2009 v8.0957 SWTICH_DATA_AND_FUNCTION_SHOULD_RESET_FITCURVE_SCALE
	//m_vFitYMin.SetSize(0);
	//m_vFitYMax.SetSize(0);
	m_vFitXMin.SetSize(0);
	m_vFitXMax.SetSize(0);
	///end SWTICH_DATA_AND_FUNCTION_SHOULD_RESET_FITCURVE_SCALE
	m_vFitYMin.SetSize(0);
	m_vFitYMax.SetSize(0);
}
///end FIX_FITCURVE_GRAPH_AXES_RESCALE_PROBLEM

//---- Iris 01/15/2009 CENTRALIZE_NEW_X_DATA_TYPE_AND_LOG_TYPE_CODES
int NLFCurvesBase::getGraphScaleType(const GraphLayer& gl, bool bIsX)
{
	FitResultCurveDataOptions fitOptions;
	fitOptions = bIsX? m_fitCurveDataOptsX : m_fitCurveDataOptsY;
	
	int nScaleType = FIT_CURVE_UNIFORM_LOG == fitOptions.DataType? SCALE_TYPE_LOG10 : SCALE_TYPE_LINEAR;
	
	if(gl && FIT_CURVE_SAME_AS_SOURCE_GRAPH == fitOptions.DataType)
		get_scale_type(gl, nScaleType, bIsX);
	
	return nScaleType;
}

int NLFCurvesBase::getSourceGraphScaleType(NLFDataBase* pDataObj, int nIndex, bool bIsX)
{	
	GraphLayer gl;
	if(pDataObj->IsAllSrcDataFromGraph())
	{
		bool bRet = m_pNLFSession->GetSourceGraphLayer(gl, nIndex);
		ASSERT(bRet);
	}	
	
	return getGraphScaleType(gl, bIsX);
}
//----end CENTRALIZE_NEW_X_DATA_TYPE_AND_LOG_TYPE_CODES

bool		NLFCurvesBase::GetXAxisFromAndTo(NLFDataBase* pDataObj, double& dXFrom, double& dXTo, int nIndex, double dMargin) // = 0, CURVE_DEFAULT_MARGIN
{
	if( FIT_CURVE_SPAN_AXIS == m_fitCurveDataOptsX.Range && pDataObj->IsAllSrcDataFromGraph() )
	{
		if(nIndex < 0 || nIndex >= m_vSrcXFrom.GetSize()||nIndex >= m_vSrcXTo.GetSize())
			return false;
		
		dXFrom = m_vSrcXFrom[nIndex];
		dXTo = m_vSrcXTo[nIndex];
		return true;
	}
	///Sophy 1/12/2009 v8.0995c QA80-12613-P3 FIX_NLFIT_SHOW_WRONG_CUSTOMIZED_Y_MIN_MAX_ON_SURFACEFIT
	//if( pDataObj->GetXMinMax(dXFrom, dXTo) )
	if( pDataObj->GetIndepMinMax(dXFrom, dXTo, nIndex) )
	///end FIX_NLFIT_SHOW_WRONG_CUSTOMIZED_Y_MIN_MAX_ON_SURFACEFIT
	{
		//---- Iris 01/15/2009 CENTRALIZE_NEW_X_DATA_TYPE_AND_LOG_TYPE_CODES, new type is Use Source Graph Scale Type
		//get_min_max_inc(dXFrom, dXTo, FIT_CURVE_UNIFORM_LOG == m_fitCurveDataOptsX.DataType, dMargin);		
		int nScaleType = getSourceGraphScaleType(pDataObj, nIndex, true);
		get_min_max_inc(dXFrom, dXTo, nScaleType, dMargin);
		//----
		return true;
	}	
	return false;	
}

bool		NLFCurvesBase::GetYAxisFromAndTo(NLFDataBase* pDataObj, double& dYFrom, double& dYTo, int nIndex, double dMargin) // = 0, CURVE_DEFAULT_MARGIN
{	
	if( FIT_CURVE_SPAN_AXIS == m_fitCurveDataOptsY.Range && pDataObj->IsAllSrcDataFromGraph() )
	{
		if(nIndex < 0 || nIndex >= m_vSrcYFrom.GetSize()||nIndex >= m_vSrcYTo.GetSize())
			return false;
		
		dYFrom = m_vSrcYFrom[nIndex];
		dYTo = m_vSrcYTo[nIndex];
		return true;
	}
	///Sophy 1/12/2009 v8.0995c QA80-12613-P3 FIX_NLFIT_SHOW_WRONG_CUSTOMIZED_Y_MIN_MAX_ON_SURFACEFIT
	//if( pDataObj->GetYMinMax(dYFrom, dYTo) )
	if( pDataObj->GetDepMinMax(dYFrom, dYTo, nIndex) )
	///end FIX_NLFIT_SHOW_WRONG_CUSTOMIZED_Y_MIN_MAX_ON_SURFACEFIT
	{
		//---- Iris 01/15/2009 CENTRALIZE_NEW_X_DATA_TYPE_AND_LOG_TYPE_CODES, new type is Use Source Graph Scale Type
		//get_min_max_inc(dYFrom, dYTo, FIT_CURVE_UNIFORM_LOG == m_fitCurveDataOptsY.DataType, dMargin);
		int nScaleType = getSourceGraphScaleType(pDataObj, nIndex, false);
		get_min_max_inc(dYFrom, dYTo, nScaleType, dMargin);
		//---- 
		return true;
	}	
	return false;
}

//////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////NLFCurves Implementation//////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////
//virtual
int		NLFCurves::plotSourceCurve(GraphLayer& gl, int nDatasetIndex, DWORD* pdwPlotUID, int nDep, int nIndep, bool bGrayScale)
{
	int nPlot = -1;
	ASSERT(m_pNLFSession);	
	if( NULL == m_pNLFSession )	
		return nPlot; 
	
	NLFDataBase*	pDataObj = m_pNLFSession->GetDataObject();
	DWORD 	dwSourcePlotUID = pDataObj->GetSourcePlotUID(nDatasetIndex);
	
	if( 0 != dwSourcePlotUID )
	{
		nPlot = AddCurvePlot(gl, dwSourcePlotUID);	
	}
	else
	{
		DataRange 	drSub;	
		if( !m_pNLFSession->GetSrcSubDataRange(drSub, nDatasetIndex, nDep, nIndep) || !drSub)
			return error_report("Fail to get sub source data range");
		
		///Sophy 10/31/2008 v8.963b QA80-12498 FIX_SOURCE_DATAPLOT_DISAPPEAR_WHEN_SELECT_MULTI_DATASET_FROM_ONE_COLUMN
		//uint nCntrl = GAP_USE_TEMPLATE;
		uint nCntrl = GAP_USE_TEMPLATE | GAP_ALLOW_DUPLICATE_COL;
		///end FIX_SOURCE_DATAPLOT_DISAPPEAR_WHEN_SELECT_MULTI_DATASET_FROM_ONE_COLUMN
		nPlot = AddCurvePlot(gl, drSub, getSourcePlotType(), nCntrl);
	}
	return nPlot;
}

/// Iris 10/24/2008 v8.0960b FIX_FAIL_NOT_SETUP_PLOT_FOR_ALL_PEAK_CURVES
///// Hong 10/17/08 QA80-10624 NLFIT_SUPPORT_FIT_SWAPPED_POLAR_PLOT
//////virtual
////int			NLFCurves::plotFitCurve(GraphLayer& gl, DataRange& drFitCurve, bool bCheckIfHasPlot, int* pStartPlotIndex, DWORD *pdwDataRules)
////virtual
//int			NLFCurves::plotFitCurve(GraphLayer& gl, DataRange& drFitCurve, bool bCheckIfHasPlot, int* pStartPlotIndex, DWORD *pdwDataRules, DWORD dwPlotCtrl)
///// 	end NLFIT_SUPPORT_FIT_SWAPPED_POLAR_PLOT
int			NLFCurves::plotFitCurve(GraphLayer& gl, DataRange& drFitCurve, bool bCheckIfHasPlot, DWORD *pdwDataRules, DWORD dwPlotCtrl, vector<int> *pvnPlotIndices)
///end FIX_FAIL_NOT_SETUP_PLOT_FOR_ALL_PEAK_CURVES
{
	///Sophy 11/1/2008 NLFIT_FITPLOT_ON_PREVIEW_GRAPH_SHOULD_NOT_DEPEND_ON_TEMPLATE_SETTINGS
	//uint 	nCntrl = GAP_USE_TEMPLATE | GAP_GROUP_PLOTS; //Sophy : add GAP_GROUP_PLOTS to support group multi-peaks fit plot...
	uint nCntrl = GAP_USE_TEMPLATE ;
	///end NLFIT_FITPLOT_ON_PREVIEW_GRAPH_SHOULD_NOT_DEPEND_ON_TEMPLATE_SETTINGS
	nCntrl |= dwPlotCtrl; /// Hong 10/17/08 QA80-10624 NLFIT_SUPPORT_FIT_SWAPPED_POLAR_PLOT
	int		nPlotType = getFitCurvePlotType();
	/// Iris 10/24/2008 v8.0960b FIX_FAIL_NOT_SETUP_PLOT_FOR_ALL_PEAK_CURVES
	//return AddCurvePlot(gl, drFitCurve, nPlotType, nCntrl, bCheckIfHasPlot, pdwDataRules, pStartPlotIndex);
	return AddCurvePlot(gl, drFitCurve, nPlotType, nCntrl, bCheckIfHasPlot, pdwDataRules, pvnPlotIndices);
	///end FIX_FAIL_NOT_SETUP_PLOT_FOR_ALL_PEAK_CURVES
}

int			NLFCurves::plotResidual(GraphLayer& gl, DataRange& drResidual)
{
	uint 	dwCntrl = GAP_USE_TEMPLATE; 
	return AddCurvePlot(gl, drResidual, getResidualPlotType(), dwCntrl);
}

bool		NLFCurves::setupSourcePlot(DataPlot& dp, bool bGrayScale)
{
	/// Iris NLF_81, to do 
	//if(nlfitSessionBase.IsAllSrcDataFromGraph())
	//	SetPlotFormatfromSrcPlot(dp, nPlot, gl);
	///end NLF_81
	return true;
}

/// Iris 10/24/2008 v8.0960b FIX_FAIL_NOT_SETUP_PLOT_FOR_ALL_PEAK_CURVES
/*
bool		NLFCurves::setupFitPlot(DataPlot& dp)
{
	dp.SetColor(SYSCOLOR_RED);
	return true;
}
*/
///Sophy 10/31/2008 GROUP_CUMULATIVE_CURVE_WITH_FITTED_CURVES
//bool 		NLFCurves::setupFitPlot(GraphLayer& gl, const vector<int> &vnPlotIndices)
bool 		NLFCurves::setupFitPlot(GraphLayer& gl, const vector<int> &vnPlotIndices, int nCumulativeIndex ) // -1 , will use it in peakfit
///end GROUP_CUMULATIVE_CURVE_WITH_FITTED_CURVES
{
	if( !gl || vnPlotIndices.GetSize() == 0 )
		return false;	
		
	if( vnPlotIndices.GetSize() > 1 )
	{
		gl.UngroupPlots();
		gl.DataPlots(vnPlotIndices[0]).SetColor(SYSCOLOR_RED);
		gl.GroupPlots(vnPlotIndices[0], vnPlotIndices[vnPlotIndices.GetSize()-1]);
	}
	else if( vnPlotIndices.GetSize() == 1 )
	{
		gl.DataPlots(vnPlotIndices[0]).SetColor(SYSCOLOR_RED);
	}	
	return true;
}
///end FIX_FAIL_NOT_SETUP_PLOT_FOR_ALL_PEAK_CURVES

bool		NLFCurves::setupResidualPlot(DataPlot& dp)
{
	if( !dp )
		return false;
	
	GraphLayer gl;
	dp.GetParent(gl);
	gl.Rescale(); 
	
	dp.SetColor(SYSCOLOR_RED);	
	return true;

}


////////////////////////////////////Fit2DCurves Implementation////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////

///Sophy 4/27/2009 v8.0987 QA80-13178 UPDATE_FITCURVE_RESIDUAL_PLOTS_SETTINGS_FOR_UPDATE_3D_RESIDUAL_PREVIEW
bool		Fit2DCurves::SetResidualLimits(const double& dIRL, const double& dORL)
{
	m_dIRL = dIRL;
	m_dORL = dORL;
	return true;
}
///end UPDATE_FITCURVE_RESIDUAL_PLOTS_SETTINGS_FOR_UPDATE_3D_RESIDUAL_PREVIEW


bool		Fit2DCurves::setupSourcePlot(DataPlot& dp, bool bGrayScale)
{
	if( !dp )
		return false;
	
	int nSteps = 16;
	if(!rescale_init_colormap(dp, &m_vContourLevelInfo, nSteps, bGrayScale))
		return error_report("rescale_init_colormap failed!");	
	return true;	
}

/// Iris 10/24/2008 v8.0960b FIX_FAIL_NOT_SETUP_PLOT_FOR_ALL_PEAK_CURVES
//bool		Fit2DCurves::setupFitPlot(DataPlot& dp)
//{
///Sophy 10/31/2008 GROUP_CUMULATIVE_CURVE_WITH_FITTED_CURVES
//bool		Fit2DCurves::setupFitPlot(GraphLayer& gl, const vector<int> &vnPlotIndices)
bool		Fit2DCurves::setupFitPlot(GraphLayer& gl, const vector<int> &vnPlotIndices, int nCumulativeIndex ) // -1
///end GROUP_CUMULATIVE_CURVE_WITH_FITTED_CURVES
{
	for(int nn = 0; nn < vnPlotIndices.GetSize(); nn++)
	{
		DataPlot dp = gl.DataPlots(vnPlotIndices[nn]);
///end FIX_FAIL_NOT_SETUP_PLOT_FOR_ALL_PEAK_CURVES
		
		if( m_vContourLevelInfo.GetSize() < 3 )
		{
			return error_report("Fail to set contour level info vector");
		}
		
		//--- CPY 3/4/08 QA-11206 XYZ_PREVIEW_NOT_SHOWING
		//m_vContourLevelInfo[2] *= 2;
		m_vContourLevelInfo[2] *= FIT_CONTOUR_LEVEL_REDUCTION_FROM_DATA_LEVELS;
		//---
		
		if(!setup_fit_contour(dp, m_vContourLevelInfo))
			return error_report("setup_fit_contour failed!");
	}
	
	return true;	
}

bool 		Fit2DCurves::setupResidualPlot(DataPlot& dp)
{
	if( m_vContourLevelInfo.GetSize() < 3 )
	{
		return error_report("Fail to set contour level info vector");
	}

	///Sophy 6/30/2009 v8.0987 QA80-13178 UPDATE_FITCURVE_RESIDUAL_PLOTS_SETTINGS_FOR_UPDATE_3D_RESIDUAL_PREVIEW
#ifndef	__UPDATE_IRL_ORL_ON_RESIDUAL_GRAPH__
	double  dIRL = 5, dORL = 30;
	int 	nInnersteps = 8, nOutSteps = 20;
	if(!setup_residual_contour(dp, m_vContourLevelInfo, dIRL, dORL, nInnersteps, nOutSteps))
		return error_report("nlsf_setup_residual_contour failed!");
#else
	int 	nInnersteps = 8, nOutSteps = 20;
	if(!setup_residual_contour(dp, m_vContourLevelInfo, m_dIRL, m_dORL, nInnersteps, nOutSteps))
		return error_report("nlsf_setup_residual_contour failed!");
#endif
	///end UPDATE_FITCURVE_RESIDUAL_PLOTS_SETTINGS_FOR_UPDATE_3D_RESIDUAL_PREVIEW
	return true;	
}

///Sophy 11/11/2008 v8.968 QA80-10599-P1 NLFIT_PREVIEW_UPDATE_CLEANUP surface&matrix fit don't need setup graph from&to
//virtual
bool		Fit2DCurves::rescaleFitCurvesGraph( GraphLayer& gl, DWORD dwCtrl )
{
	if( !gl )
		return false;
	
	int nOutcome;
	gl.Rescale( dwCtrl, &nOutcome );
	return true;
}
///end NLFIT_PREVIEW_UPDATE_CLEANUP
//////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////SurfaceFitCurves Implementation///////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////
///Sophy 7/28/2008 CLEAN_MATRIXFIT_PREVIEW_CONTROL
//virtual
string		SurfaceFitCurves::GetTemplate(bool bIsResidual)
{
	if( bIsResidual )
		return NLSF_XYZ_RESIDUAL_GRAPH_TEMPLATE;
	else
		return NLSF_XYZ_FIT_CURVE_GRAPH_TEMPLATE;
}
///end CLEAN_MATRIXFIT_PREVIEW_CONTROL
//virtual
///Sophy 9/2/2008 CLEAN_NLFPREVIEW_AND_NLFCURVE
int			SurfaceFitCurves::plotSourceCurve(GraphLayer& gl, int nDatasetIndex, DWORD* pdwPlotUID, int nDep, int nIndep, bool bGrayScale)
{
	int nPlot = -1;
	ASSERT(m_pNLFSession);	
	if( NULL == m_pNLFSession )	
		return nPlot; 

	DataRange 	dr;
	dr = m_pNLFSession->GetSrcDataRange();
	if( !dr )
		return error_report("Fail to get sub source data range");
	int	nCntrl = GAP_USE_TEMPLATE;
	nPlot = plotDataRange( dr, gl, getSourcePlotType(), nCntrl, false);

	return nPlot;
}
///end CLEAN_NLFPREVIEW_AND_NLFCURVE

//int			SurfaceFitCurves::plotFitCurve(GraphLayer& gl, DataRange& drFitCurve, bool bCheckIfHasPlot, int* pStartPlotIndex, DWORD *pdwDataRules)
//{	
	//uint nCntrl = GAP_USE_TEMPLATE;
	//int		nPlotType = getFitCurvePlotType();
	//return AddCurvePlot(gl, drFitCurve, nPlotType, nCntrl, bCheckIfHasPlot, pdwDataRules, pStartPlotIndex);
//}

//////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////MatrixFitCurves Implementation///////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////
///Sophy 7/28/2008 CLEAN_MATRIXFIT_PREVIEW_CONTROL
//virtual
string		MatrixFitCurves::GetTemplate(bool bIsResidual)
{
	if( bIsResidual )
		return NLSF_MAT_RESIDUAL_GRAPH_TEMPLATE;
	else
		return NLSF_MAT_FIT_CURVE_GRAPH_TEMPLATE;
}
///end CLEAN_MATRIXFIT_PREVIEW_CONTROL
///Sophy 9/2/2008 CLEAN_NLFPREVIEW_AND_NLFCURVE
//virtual
int			MatrixFitCurves::plotSourceCurve(GraphLayer& gl, int nDatasetIndex, DWORD* pdwPlotUID, int nDep, int nIndep, bool bGrayScale)
{
	int nPlot = -1;
	ASSERT(m_pNLFSession);	
	if( NULL == m_pNLFSession )	
		return nPlot; 

	DataRange 	dr;
	dr = m_pNLFSession->GetSrcDataRange();
	if( !dr )
		return error_report("Fail to get sub source data range");
	int	nCntrl = GAP_USE_TEMPLATE;
	return AddCurvePlot(gl, dr, getSourcePlotType(), nCntrl, true); 
}
///end CLEAN_NLFPREVIEW_AND_NLFCURVE
//int			MatrixFitCurves::plotFitCurve(GraphLayer& gl, DataRange& drFitCurve, bool bCheckIfHasPlot, int* pStartPlotIndex, DWORD *pdwDataRules)
//{
	//uint 	nCntrl = GAP_USE_TEMPLATE;
	//int 	nPlotType = getFitCurvePlotType();
	//return AddCurvePlot(gl, drFitCurve, nPlotType, nCntrl, bCheckIfHasPlot, pdwDataRules, pStartPlotIndex);
//}


#endif	//_NLF_CURVES_H_
