#include <origin.h>
#include <GetNBox.h>
#include <xfutils.h>
enum{
	type_gauss,
	type_lorentz,
	type_voigt,
};
#include <GetNBox.h>

#include <ReportTree.h>
#include <..\OriginLab\nlsf_utils.h>
#include <..\OriginLab\NLFitSession.h>
#include <event_utils.h>
///////////////////////////////////////////////////
// Modification log
/// Jasmine 08/14/07 QA80-10207 REPORT_SHEET_CHECK_CONFLICT
/// Hong 11/04/08 QA80-12526 v8.0965b ADD_BACKWARD_COMPATIABLE
/// Kyle 08/04/2009 UPDATE_LEGEND_AFTER_ADDING_PLOTS_TO_SOURCE_GRAPH
/// Kenny 08/25/2009 QA81-14203 RESET_PAGE_NAME_IF_CREATED_FROM_OC
/// Iris 9/27/2009 QA80-14360 WANT_REPORT_DERIVED_PARAMS_IN_FIT_PEAKS
/// Sophy 3/30/2010 QA81-15243 ADD_VOIGT_FUNCTION_FOR_FIT_MULTI_PEAKS
///////////////////////////////////////////////////
enum
{
	FITCURVES_REPORT_TABLE = 101,
};

//enum {
	//ERR_INVALID_INPUT = XF_LOCAL_ERR_BEGIN,
	//ERR_SET_FUNCTION,
	//ERR_SET_DATA,
	//ERR_SET_PARAMETER,
	//ERR_PERFORM_FITTING,
	//ERR_GET_PARAMETERS,
	//ERR_GET_SUMMARY,
	//ERR_USER_CANCEL_PICK_PEAK,
//};

/// Iris 9/27/2009 QA80-14360 WANT_REPORT_DERIVED_PARAMS_IN_FIT_PEAKS
//static bool update_report_tree(XYRange& y, vector& vParamsValue, vector& vParamsError, RegStats sRegStats,
static bool update_report_tree(XYRange& y, vector& vParamsValue, vector& vParamsError, vector<string>& vsDerivedParamNames, vector& vDerivedParamVals, RegStats sRegStats,
///end WANT_REPORT_DERIVED_PARAMS_IN_FIT_PEAKS
	int numParamsInFunction, int numPeaks, string strFunction, vector<string> vParamNames, ReportTree& outTree,
	int type = type_gauss)
{
	/*
	outTree.ID = 12345;
	string strLabel = _L("Multipeaks Fit");
	time_t ltime;
	time(&ltime);
	
	SYSTEMTIME st;
	TM tmLocal;
	double dDate;
	convert_time_to_local(&ltime , &tmLocal);
    tm_to_systemtime(&tmLocal, &st);
	SystemTimeToJulianDate(&dDate, &st);
		
	strLabel += " (" + get_date_str(dDate) + ")";
	outTree.SetAttribute(STR_LABEL_ATTRIB, strLabel);
	//////////////////////////////////////////////////////////////////
	// notes
	//////////////////////////////////////////////////////////////////
	ReportTable rtNotes = outTree.CreateTable("Notes", _L("Notes"), IDST_REPORT_NOTES);		
	rtNotes.AddRow("Description", _L("Description"), _L("Multipeaks Fit"), IDE_NOTES_DESCRIPTION);
	char szUserName[MAX_PATH];
	DWORD dwSize = MAX_PATH;
	if( GetUserName(szUserName, &dwSize) )
		rtNotes.AddRow("User", _L("User Name"), szUserName, IDE_NOTES_USERNAME);
	
	rtNotes.AddRow("Time", _L("Time"), get_date_str(dDate), IDE_NOTES_CREATION_TIME);
	*/
	if(!outTree.IsValid())
		return false;
	
	init_report_tree_common_tables(outTree, _L("Multipeaks Fit"), "fitPeaks", "iy");
	
	///Sophy 6/19/2009 QA80-13805 SHOW_PEAK_FUNCTION_TYPE_IN_NOTES_TABLE_FOR_FIT_MULTIPLE_PEAKS_TOOL
	//For init_report_tree_common_tables seems for common use, so I'd like to keep this code separately.
	TreeNode trNotes = tree_get_node_by_id(outTree, IDST_REPORT_NOTES, true);
	if ( trNotes )
	{
		ReportTable rtNotes(trNotes);
		rtNotes.AddRow("Model", _L("Peak Type"), strFunction, IDE_NOTES_MODEL);
	}
	///end SHOW_PEAK_FUNCTION_TYPE_IN_NOTES_TABLE_FOR_FIT_MULTIPLE_PEAKS_TOOL
	
	
	//////////////////////////////////////////////////////////////////
	// Parameters
	//////////////////////////////////////////////////////////////////
	ReportTable rtParameters = outTree.CreateTable("Parameters", _L("Parameters"), IDST_FIT_PARAMETER);
	
	int ii;
	vector<string>	vecLabel ={"Value", "Error"};
	vector	vecPP(vecLabel.GetSize());
	//y0
	vecPP[0] = vParamsValue[0];
	vecPP[1] = vParamsError[0];
	
	///Sandy 2006-6-13 use new prototype of AddRow() 
	//rtParameters.AddRow(vecPP,_L(vParamNames[0]),vecLabel, make_one_set_ID(IDST_FIT_PARAMETER_ONE_SET, 0));
	/// Hong 11/07/07 v.8.0742 FIX_ERROR_LOCALIZED
	//rtParameters.AddRow(_L(""), vecPP, _L(vParamNames[0]), vecLabel, NULL, make_one_set_ID(IDST_FIT_PARAMETER_ONE_SET, 0));
	rtParameters.AddRow("", vecPP, vParamNames[0], vecLabel, NULL, make_one_set_ID(IDST_FIT_PARAMETER_ONE_SET, 0));
	/// end FIX_ERROR_LOCALIZED
	//xc, w, A
	for (ii = 1; ii <= (numParamsInFunction-1) * numPeaks; ii++)
	{
		/// Iris 9/27/2009 QA80-14360 WANT_REPORT_DERIVED_PARAMS_IN_FIT_PEAKS
		//vecPP[0] = vParamsValue[ii];
		//vecPP[1] = vParamsError[ii];
		vecPP.RemoveAll();
		vecPP.Add( vParamsValue[ii] );
		vecPP.Add( vParamsError[ii] );
		///end WANT_REPORT_DERIVED_PARAMS_IN_FIT_PEAKS
		
		///Sandy 2006-6-13 use new prototype of AddRow() 
		//rtParameters.AddRow(vecPP,_L(vParamNames[(ii-1)%(numParamsInFunction-1)+1]+((ii-1)/(numParamsInFunction-1)+1)),vecLabel, make_one_set_ID(IDST_FIT_PARAMETER_ONE_SET+ii, 0));
		/// Hong 11/07/07 v.8.0742 FIX_ERROR_LOCALIZED
		//rtParameters.AddRow(_L(""), vecPP, _L(vParamNames[(ii-1)%(numParamsInFunction-1)+1]+((ii-1)/(numParamsInFunction-1)+1)), vecLabel, NULL, make_one_set_ID(IDST_FIT_PARAMETER_ONE_SET+ii, 0));
		rtParameters.AddRow("", vecPP, vParamNames[(ii-1)%(numParamsInFunction-1)+1]+((ii-1)/(numParamsInFunction-1)+1), vecLabel, NULL, make_one_set_ID(IDST_FIT_PARAMETER_ONE_SET+ii, 0));
		/// end FIX_ERROR_LOCALIZED
		
		/// Iris 9/27/2009 QA80-14360 WANT_REPORT_DERIVED_PARAMS_IN_FIT_PEAKS
		if( 0 == ii % ( numParamsInFunction-1) )// the last one parameter of each peak
		{
			int nNumDerivedParamsInOneFunc = vDerivedParamVals.GetSize() / numPeaks;
			int nPeakIndex =  ii / ( numParamsInFunction-1) - 1;
			
			for(int jj = nPeakIndex * nNumDerivedParamsInOneFunc; jj < (nPeakIndex+1) * nNumDerivedParamsInOneFunc; jj++)
			{
				vecPP.RemoveAll();
				vecPP.Add( vDerivedParamVals[jj] );
				
				vector<string> vsLabelsEx;
				vsLabelsEx.Add( vecLabel[0] );
				int id = make_one_set_ID( (numParamsInFunction-1) * numPeaks + 1 + jj, 0);
				rtParameters.AddRow("", vecPP, vsDerivedParamNames[jj]+(nPeakIndex+1), vsLabelsEx, NULL, id);
			}
		}
		///end WANT_REPORT_DERIVED_PARAMS_IN_FIT_PEAKS
	}

	//////////////////////////////////////////////////////////////////
	// Peaks
	//////////////////////////////////////////////////////////////////
	ReportTable rtPeaks = outTree.CreateTable("Peaks", _L("Peaks"), IDST_FIT_PEAKS);
	vector<string>	vecLabel2 ={"Area", "Center", "Width", "Height"};
	///Sophy 4/1/2010 QA81-15243-P3 ADD_VOIGT_FUNCTION_FOR_FIT_MULTI_PEAKS
	if ( type_voigt == type )
	{
		vecLabel2[2] = "Gaussian Width";
		vecLabel2[3] = "Lorentzian Width";
	}
	///end ADD_VOIGT_FUNCTION_FOR_FIT_MULTI_PEAKS
	vecPP.SetSize(vecLabel2.GetSize());
	for (ii = 0; ii < numPeaks; ii++)
	{
		///Sophy 4/1/2010 QA81-15243-P3 ADD_VOIGT_FUNCTION_FOR_FIT_MULTI_PEAKS
		//vecPP[0] = vParamsValue[ii*(numParamsInFunction-1)+3]; 
		//vecPP[1] = vParamsValue[ii*(numParamsInFunction-1)+1];
		//vecPP[2] = vParamsValue[ii*(numParamsInFunction-1)+2];
		if ( type_voigt == type )
		{
			vecPP[0] = vParamsValue[ii*(numParamsInFunction-1) + 2];  //A
			vecPP[1] = vParamsValue[ii*(numParamsInFunction-1) + 1]; //xc
			vecPP[2] = vParamsValue[ii*(numParamsInFunction-1) + 3]; //wG
			vecPP[3] = vParamsValue[ii*(numParamsInFunction-1) + 4]; //wL
		}
		else
		{
			vecPP[0] = vParamsValue[ii*(numParamsInFunction-1) + 3]; //A
			vecPP[1] = vParamsValue[ii*(numParamsInFunction-1) + 1]; //xc
			vecPP[2] = vParamsValue[ii*(numParamsInFunction-1) + 2]; //w
			///Sandy 2008-6-6 Fix Height of Lorentz peak is wrong by Larry reported 
			//vecPP[3] = vecPP[0]/vecPP[2]/sqrt(PI/2.0);
			if(type == type_gauss)
				vecPP[3] = vecPP[0]/vecPP[2]/sqrt(PI/2.0);
			else if(type == type_lorentz)
				vecPP[3] = 2*vecPP[0]/(vecPP[2]*PI);
			//end
		}
		
		///Sandy 2006-6-13 use new prototype of AddRow() 
		//rtPeaks.AddRow(vecPP,_L(""+(ii+1)),vecLabel2, make_one_set_ID(IDST_FIT_PARAMETER_ONE_SET+numParamsInFunction*numPeaks+ii, 0));
		/// Hong 11/07/07 v.8.0742 FIX_ERROR_LOCALIZED
		//rtPeaks.AddRow(_L(""),vecPP,_L(""+(ii+1)),vecLabel2,NULL, make_one_set_ID(IDST_FIT_PARAMETER_ONE_SET+numParamsInFunction*numPeaks+ii, 0));
		rtPeaks.AddRow("", vecPP,""+(ii+1), vecLabel2, NULL, make_one_set_ID(IDST_FIT_PARAMETER_ONE_SET+numParamsInFunction*numPeaks+ii, 0));
		/// end FIX_ERROR_LOCALIZED
	}

	//////////////////////////////////////////////////////////////////
	// Statistics
	//////////////////////////////////////////////////////////////////
	ReportTable rtStats = outTree.CreateTable("Statistics", _L("Statistics"), IDST_REG_STATS_RESULTS);
	//rtStats.AddRow("DOF", _L("DOF"), sRegStats.DOF, IDE_FIT_DOF); /// Max 8/17/07 USE_DF_INSTEAD_OF_DOF_FOR_CONSISTENCY
	rtStats.AddRow("DF", _L("DF"), sRegStats.DOF, IDE_FIT_DOF);
	rtStats.AddRow("COD", _L("COD (R^2)"), sRegStats.RSqCOD, IDE_FIT_RSQUARE_COD);
	rtStats.AddRow("ReducedChiSq", _L("ReducedChiSq"), sRegStats.ReducedChiSq, IDE_FIT_REDUCED_CHI_SQUARE);
	return true;
}

static bool update_report_data(XYRange& in, ReportData& out, string strFuncName, int npeaks, int numParamsInFunction, vector& vResultParams, vector& vX)
{
	/// Hong 11/04/08 QA80-12526 v8.0965b ADD_BACKWARD_COMPATIABLE
	//NLFitSessionBase fit(false);
	NLFitSession 		fit;
	fit.SetAutoInitParams(false);
	/// end ADD_BACKWARD_COMPATIABLE
	if (!fit.SetFunction(strFuncName))
	{
		return false;
	}
	
	int nRet;
	int ii, jj;
	out.ID = IDST_RESULT_CURVES;

	ReportTable rtFitCurves;
	rtFitCurves = out.CreateTable("FittedCurves", NULL, FITCURVES_REPORT_TABLE);
	rtFitCurves.AddColumn(vX, "X", IDST_FIT_X, NULL, OKDATAOBJ_DESIGNATION_X);
	
	vector vSumOfPeaks;
	vector vParamsInFunction(numParamsInFunction);
	for (ii = 0; ii < npeaks; ii++)
	{
		vector vFitY(vX.GetSize());
		vParamsInFunction[0] = vResultParams[0];
		for (jj = 1; jj < numParamsInFunction; jj++)
		{
			vParamsInFunction[jj] = vResultParams[ii*(numParamsInFunction-1)+jj];
		}
		if (0 != fit.SetParamValues(vParamsInFunction))
		{
			return false;
		}
		/// Hong 11/04/08 QA80-12526 v8.0965b ADD_BACKWARD_COMPATIABLE
		//if (!fit.GetFitY(vX, vFitY, 0))
		NLFCurvesBase		nlfCurve(&fit);
		if ( !nlfCurve.GetFitY(vX, vFitY, fit.GetNLParamsMngr(), 0) )
		/// end ADD_BACKWARD_COMPATIABLE
		{
			return false;
		}
		///Sandy 2007-1-19 add column long name
		//rtFitCurves.AddColumn(vFitY, "Peak"+(ii+1), IDST_FIT_Y+ii, NULL, OKDATAOBJ_DESIGNATION_Y);
		rtFitCurves.AddColumn(vFitY, "Peak"+(ii+1), IDST_FIT_Y+ii, "Peak"+(string)(ii+1), OKDATAOBJ_DESIGNATION_Y);
		vSumOfPeaks += vFitY;
	}
	vSumOfPeaks -= (npeaks-1)*vResultParams[0];
	///Sandy 2007-1-19 add column long name
	//rtFitCurves.AddColumn(vSumOfPeaks, "Sum", IDST_FIT_Y+ii, NULL, OKDATAOBJ_DESIGNATION_Y);
	rtFitCurves.AddColumn(vSumOfPeaks, "Sum", IDST_FIT_Y+ii, "PeakSum", OKDATAOBJ_DESIGNATION_Y);
	return true;
}
static bool init_params_1st(vector& vX, vector& vY, vector& vXPeaks, int numPeaks, int numParamsInFunction, vector& vInitParams, int nType = type_gauss)
{
	///Sandy 2006-9-29 ADD_Y_BASE_AS_THE_FIRST_VARIABLE
	int ii; 
	vector vTempY;
	vTempY = vY;
	double dBase = (vY[0] + vY[vY.GetSize()-1])/2.0;
	vTempY = vTempY - dBase;
	
	
	IntegrationResult sResult;
	
	///Sandy 2006-9-29 ADD_OPTION_ABSOLUTE_AREA
	//ocmath_integrate(vX, vY, 0, vX.GetSize()-1, &sResult);
	ocmath_integrate(vX, vTempY, 0, vX.GetSize()-1, &sResult, NULL, ABSOLUTE_AREA);
	
	///Sandy 2006-9-25 change for user always can decide the width of peaks when user did not agree with our initialize.
	//if (sResult.dxPeak == NANUM)
	//{
		//sResult.dxPeak = atoi(InputBox("Please roughly estimate the width of peaks."));
	//}
	//else if (sResult.dxPeak < 0)
	//{
		//sResult.dxPeak *= -1;	
		//sResult.Area *= -1;
	//}

	if (sResult.dxPeak < 0)
	{
		sResult.dxPeak *= -1;	
		sResult.Area *= -1;	
	}
	
	
	double dUserWidth;
	//dUserWidth = sResult.Area/numPeaks/sResult.yPeak;
	
	///Sandy2007-9-19 QA-10366 V8.0704 initial width with different way for different function.
	if(nType == type_gauss)
	 	//dUserWidth = sResult.Area/numPeaks/sResult.yPeak;
	 	dUserWidth = abs(sResult.Area/numPeaks/sResult.yPeak);
	else
		dUserWidth = abs(sResult.dxPeak/numPeaks);
	/// Max 12/27/07 CALCULATION_ON_DOUBLE_VARIABLE_SHOULD_NOT_USE_FTOA 
	//dUserWidth = atof(InputBox(_L("Please roughly validate the width of peaks."), ftoa(dUserWidth)));
	dUserWidth = InputBox(dUserWidth, _L("Please roughly validate the width of peaks."));
	/// END CALCULATION_ON_DOUBLE_VARIABLE_SHOULD_NOT_USE_FTOA
	//vInitParams[0] = sResult.yPeakBase;
	///Sandy 2006-9-29 ADD_YO_TO_PARAM
	vInitParams[0] = dBase;
	for (ii = 0; ii < numPeaks; ii++)
	{
		
		vInitParams[ii*(numParamsInFunction-1)+1] = vXPeaks[ii]; //xc
		///Sandy 2006-9-25 User has agreed with this width
		//vInitParams[ii*(numParamsInFunction-1)+2] = sResult.dxPeak/numPeaks;
		///Sophy 3/30/2010 QA81-15243 ADD_VOIGT_FUNCTION_FOR_FIT_MULTI_PEAKS
		//vInitParams[ii*(numParamsInFunction-1)+2] = dUserWidth;
		if ( type_voigt == nType )
		{
			vInitParams[ii*(numParamsInFunction - 1) + 3] = dUserWidth; //wG
			vInitParams[ii*(numParamsInFunction - 1) + 4] = dUserWidth; //wL
		}
		else
		{
			vInitParams[ii*(numParamsInFunction - 1) + 2] = dUserWidth; //w
		}
		///end ADD_VOIGT_FUNCTION_FOR_FIT_MULTI_PEAKS
		
		///Sandy 2007-9-19 QA-10366 V8.0704 Add polarity of area.
		double dYPeak = dBase, dArea, dPolarity = 1;
		int nRet = ocmath_interpolate(&vXPeaks[ii], &dYPeak, 1, vX, vY, vX.GetSize());

		if(nRet == 0 && dYPeak<dBase)
			dPolarity = -1;
		///Sophy 3/30/2010 QA81-15243 ADD_VOIGT_FUNCTION_FOR_FIT_MULTI_PEAKS
		//vInitParams[ii*(numParamsInFunction-1)+3] = dPolarity * sResult.Area/numPeaks;
		if ( type_voigt == nType )
		{
			vInitParams[ii*(numParamsInFunction-1) + 2] = dPolarity * sResult.Area/numPeaks; //A
		}
		else
		{
			vInitParams[ii*(numParamsInFunction-1) + 3] = dPolarity * sResult.Area/numPeaks; //A
		}
		///end ADD_VOIGT_FUNCTION_FOR_FIT_MULTI_PEAKS

	}
	return true;
}

///Sophy 3/30/2010 QA81-15243 ADD_VOIGT_FUNCTION_FOR_FIT_MULTI_PEAKS
static	string	_get_function_name(int nIndex)
{
	vector<string> vsNames = {
		"Gauss",
		"Lorentz",
		"Voigt"
	};
	if ( nIndex < 0 || nIndex >= vsNames.GetSize() )
	{
		ASSERT(false);
		return "";
	}
	return vsNames[nIndex];
}
///end ADD_VOIGT_FUNCTION_FOR_FIT_MULTI_PEAKS


void fitpeaks(const int& type, const int& npeaks, const XYRange& iy, ReportTree& rt, ReportData& rd, const int& hint)
{
	
	
	
	int ii, jj, nRet;
	
	///Leo 2005-12-13 ACTIVE_LAYER_BREAKS_AUTOUPDATE
	//GraphLayer gl = Project.ActiveLayer();
	GraphLayer gl;
	GraphPage gp;
	
	DataPlot dp;
	if (iy.GetPlot(dp) )
	{
		dp.GetParent(gl);
	}
	if (!gl)
	{
		/// Kenny 08/25/2009 QA81-14203 RESET_PAGE_NAME_IF_CREATED_FROM_OC
		//gp.Create("Origin");
		gp.Create("Origin", CREATE_DEFAULT_OPTIONS | CREATE_ENUM_EXIST_PAGE);
		/// End QA81-14203 RESET_PAGE_NAME_IF_CREATED_FROM_OC
		gl = gp.Layers(0);
		gl.AddPlot(iy, IDM_PLOT_SCATTER);
		gl.Rescale();
	}
	///End ACTIVE_LAYER_BREAKS_AUTOUPDATE
	
			
	///Sandy 2008 Fixed embed graph problem
	Page pg = gl.GetPage();
	pg.SetShow();
	//end
	
	if(hint == 1)
	{
		///---Sim 06-19-2007 IMPROVE_WARNING_MESSAGE_POST_FUNCTION
		//warning_msg_box(XFWAR_SELECT_PEAKS_CENTER, true, false, false); 
		warning_msg_box(XFWAR_SELECT_PEAKS_CENTER, true); 
		///---END IMPROVE_WARNING_MESSAGE_POST_FUNCTION
	}
	
	vector vX, vY, vXPeaks, vYPeaks;
	
	
	
	///sandy 2006-5-31 GetData without missing value.
	//if (!yi.GetData(vY, vX))
	if (!iy.GetData(vY, vX, NULL, 0, DRR_BAD_WEIGHT_TREATMENT))
	{
		XF_THROW(XFERR_INVALID_RANGE);
	}
	
	
	///sandy 2007-3-1 check data size
	if(vY.GetSize() <= 0)
	{
		XF_THROW(CER_NO_DATA);
	}
	
	///Sandy 2008-3-24 QA80-11287 failed on data where X was sorted in descending order
	vector<uint> vn;
	vX.Sort(SORT_ASCENDING, true, vn);
	vY.Reorder(vn);
	
	///Leo 2005-12-9 USE_GETGRAPHPOINTS
	GetGraphPoints gpts;
	gpts.SetCursorPos(0, 0);
	gpts.SetCursor(0);
	if(!gpts.GetPoints(npeaks, gl))
		XF_THROW(XFERR_USER_CANCEL_PICK_PEAK);
	
	gpts.GetData(vXPeaks, vYPeaks);
	///End USE_GETGRAPHPOINTS
	
	///sandy 2007-1-29 temp for unlock page click, waitting for #9326
	LT_execute("page.noclick = 0;");
	
	
	///Sophy 3/30/2010 QA81-15243 ADD_VOIGT_FUNCTION_FOR_FIT_MULTI_PEAKS
	//string strFuncName = (type == type_gauss) ? "Gauss" : "Lorentz";
	string	strFuncName = _get_function_name(type);
	///end ADD_VOIGT_FUNCTION_FOR_FIT_MULTI_PEAKS
	/// Hong 11/04/08 QA80-12526 v8.0965b ADD_BACKWARD_COMPATIABLE
	//NLFitSessionBase fit(false);
	NLFitSession 		fit;
	fit.SetAutoInitParams(false);
	/// end ADD_BACKWARD_COMPATIABLE
	if (!fit.SetFunction(strFuncName, "", npeaks))
	{
		XF_THROW(XFERR_FAIL_SET_FUNCTION);
	}
	int numParamsInFunction;
	vector<string>	vstrParamNames;
	numParamsInFunction = fit.GetParamNamesInFunction(vstrParamNames);
	//int numTotalParams = 1+(numParamsInFunction-1)*npeaks;
	int numTotalParams = fit.GetNumTotalParams();
	vector vInitParams(numTotalParams); //here we have assumed y0 will not be replicated.
	
	if (!fit.SetData(vY, vX))
	{
		XF_THROW(XFERR_NLFIT_FAIL_TO_SET_DATA);
	}
	
	///Sandy 2007-9-19 QA-10366 V8.0704 add type for init params
	//init_params_1st(vX, vY, vXPeaks, npeaks, numParamsInFunction, vInitParams);
	init_params_1st(vX, vY, vXPeaks, npeaks, numParamsInFunction, vInitParams, type);
	if (0 != fit.SetParamValues(vInitParams))
	{
		XF_THROW(XFERR_NLFIT_SET_PARAMETER);
	}
	
	
	 //hold all xc's constants
	for (ii = 0; ii < npeaks; ii++)
	{
		if (!fit.SetParamFix(ii*(numParamsInFunction-1)+1, true))
		{
			XF_THROW(XFERR_NLFIT_SET_PARAMETER);
		}
	}
	fit.Iterate(2);
	// release all holds on xc's
	for (ii = 0; ii < npeaks; ii++)
	{
		if (!fit.SetParamFix(ii*(numParamsInFunction-1)+1, false))
		{
			XF_THROW(XFERR_NLFIT_SET_PARAMETER);
		}
	}
	///Sandy 2007-9-19 QA-10366 V8.0704 add iterate when release hold on xc 
	fit.Iterate(2);
	
	int nFitOutcome;
	if (!fit.Fit(&nFitOutcome))
	{
		string strErr = fit.GetFitOutCome(nFitOutcome);
		MessageBox( GetWindow(), strErr, _L("Error"), MB_OK | MB_ICONEXCLAMATION);
		//return; ///Sandy 2007-9-19 QA-10366 V8.0704 continue to get result anyway
	}
	vector vResultParams(numTotalParams);
	vector vResultError(numTotalParams);
	if (!fit.GetFitResultsParams(vResultParams, vResultError))
	{
		XF_THROW(XFERR_NLFIT_GET_PARAMETERS);
	}
	
	/// Iris 9/27/2009 QA80-14360 WANT_REPORT_DERIVED_PARAMS_IN_FIT_PEAKS
	vector<string> 	vsDerivedParamNames;
	vector			vDerivedParamVals;
	int nNumDerivedParams = fit.GetDerivedParamNum() * npeaks;
	if (!fit.GetDerivedParameters(0, &vsDerivedParamNames, &vDerivedParamVals))
	{
		XF_THROW(XFERR_NLFIT_GET_PARAMETERS);
	}
	///end WANT_REPORT_DERIVED_PARAMS_IN_FIT_PEAKS
	
	RegStats sRegStats;
	NLSFFitInfo sNLSFFitInfo;	
	if (!fit.GetFitResultsStats(&sRegStats, &sNLSFFitInfo))
	{
		XF_THROW(XFERR_NLFIT_GET_SUMMARY);
	}
	
	///Sandy 2008-6-6 Fix Height of Lorentz peak is wrong by Larry reported 
	//update_report_tree(iy, vResultParams, vResultError, sRegStats, numParamsInFunction, npeaks, strFuncName, vstrParamNames, rt);
	/// Iris 9/27/2009 QA80-14360 WANT_REPORT_DERIVED_PARAMS_IN_FIT_PEAKS
	//update_report_tree(iy, vResultParams, vResultError, sRegStats, numParamsInFunction, npeaks, strFuncName, vstrParamNames, rt, type);
	update_report_tree(iy, vResultParams, vResultError, vsDerivedParamNames, vDerivedParamVals, sRegStats, numParamsInFunction, npeaks, strFuncName, vstrParamNames, rt, type);
	///end WANT_REPORT_DERIVED_PARAMS_IN_FIT_PEAKS
	
	update_report_data(iy, rd, strFuncName, npeaks, numParamsInFunction, vResultParams, vX);
	
	///Sandy 2007-8-20 QA-10073 V8.0685 for clean output curve customization gone after recalculate
	//rd.PlotIntoLayer(gl, FITCURVES_REPORT_TABLE, NULL);
	DataRange dr;
	int nXID = IDST_FIT_X;
	//int nYID = IDST_FIT_Y + npeaks - 1;
	int nYID = IDST_FIT_Y;
	if (0 != rd.GetDataRange(dr, FITCURVES_REPORT_TABLE, nXID, &nYID))//
	{
		vector<int> vnPlotIndices;
		if(!check_has_plotted_in_graph(dr, gl, vnPlotIndices))
		{
			rd.PlotIntoLayer(gl, FITCURVES_REPORT_TABLE, NULL);
			int nPlotCount = gl.DataPlots.Count();
			for (ii = nPlotCount - 2; ii >= nPlotCount - 1 - npeaks; ii--)
			{
				gl.DataPlots(ii).SetColor(2);
			}
			gl.DataPlots(nPlotCount-1).SetColor(1);
			legend_update(gl, -1, false, false);	///Kyle 08/04/2009 UPDATE_LEGEND_AFTER_ADDING_PLOTS_TO_SOURCE_GRAPH
			
			LT_execute("doc -uw");
		}
	}
	
	//end
	
	///Sandy 2006-11-8 reuse color plot when xf isn't running in the first time
	//for (ii = 1; ii <= npeaks; ii++)
	//{
		//gl.DataPlots(ii).SetColor(2);
	//}
	//gl.DataPlots(ii).SetColor(1);
	
	///Sandy 2007-8-20 MOVE_TO_UPPER
	//int nPlotCount = gl.DataPlots.Count();
	//for (ii = nPlotCount - 2; ii >= nPlotCount - 1 - npeaks; ii--)
	//{
		//gl.DataPlots(ii).SetColor(2);
	//}
	//gl.DataPlots(nPlotCount-1).SetColor(1);
	//
	//
	//LT_execute("doc -uw");
	///end of MOVE_TO_UPPER
	
	//LT_execute("legend -s");
	//legend_update(gl, ALM_LONGNAME_UNITS);	/// Max 8/17/07 should not update legend in source graph	
	
	return;
}

//nEventID < 0 on event, like GETNE_ON_INIT, GETNE_ON_OK etc, >0 on change from control
//return 0 to do nothing, return PEVENT_GETN_RET_TO_CLOSE to close dialog
//dwEnables = bOKEnable, bBTN1Enable, bBTN2Enable, bBTN3Enable, , can set to false to disable OK/Apply buttons
//lpcszNodeName = the trGetN TreeNode tag name that generates the event, or is  if GETNE_ON_OK etc
//strAux = optional string for XF Wizard Bar, like DLG_NEED_CHANGE_GRID etc, it will be invalid if from internal node value change event
//strErrMsg = allowing messages to be shown
int fitpeaks_event1(TreeNode& trGetN, int nRow, int nEventID, DWORD& dwEnables, LPCSTR lpcszNodeName, WndContainer& DynaCntrlContainer, string& strAux, string& strErrMsg)
{
	if( xf_is_extended_event(nEventID) )
		return fitpeaks_event1_ex(trGetN, nRow, nEventID, dwEnables, lpcszNodeName, DynaCntrlContainer, strAux, strErrMsg);
	DECLARE_BUTTON_ENABLES
	
	if(get_input_xyrange_num(trGetN.iy) != 1)
	{
		strErrMsg = CER_NOT_ONE_XYRANGE;
		bOKEnable = false;
	}
	
	///Sandy 2008-11-6 QA80-11287 TOTALLY_REMOVE_MONO_CHECKING
	//TreeNode trInput = trGetN.iy;
	//XYRange yi;
	//okxf_resolve_tree_construct_range(&trInput, &yi);
	//vector vx, vy;
	//if(yi.GetData(vy, vx))
	//{
		//int iRet = ocmath_is_monotonic(vx, vx.GetSize());
		/////Sandy 2008-3-24 QA80-11287 failed on data where X was sorted in descending order
		////if(iRet != MONO_INCREASE)
		//if(iRet != MONO_INCREASE && iRet != MONO_DECREASE)
		//{				
			//bOKEnable = false;
			//strErrMsg = CER_NONMONOTONIC_X;//XFERR_NONE_MONO_INCREASE;//XFERR_NOT_CONSISTENT;//
			//return true;		
		//}
	//}
		
	///Jasmine 08/14/07 QA80-10207 REPORT_SHEET_CHECK_CONFLICT
	if(bOKEnable && is_same_sheet(trGetN.rd, trGetN.rt))
	{
		bOKEnable = false;
		strErrMsg = XFERR_REPORT_SHEET_CONFLICT;
	}
	///End REPORT_SHEET_CHECK_CONFLICT
	return true;

}

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