/*------------------------------------------------------------------------------*
 * File Name: PFM_utils.c	 													*
 * Creation: Leo 2005-11-12														*
 * Purpose: OriginC Source C file												*
 * Copyright (c) OriginLab Corp.	2004, 2005, 2006, 2007, 2008, 2009, 2010	*
 * All Rights Reserved															*
 * 																				*
 * Modification Log:															*
 *	Leo 2005-12-05	FIND_PEAKS_HEIGHT											*
 *	Leo 2005-12-16 MOVED_PEAK_AND_BASLINE_FUNCS_TO_PFM_UTILS					*
 *	Raine 2006-04-30 GET_GAUSSIAN_FILTER										*
 *	Hong 04/25/07 v8.0608 MOVE_TO_PFM_UTILS										*
 *	Cloud 4/26/2007 UPDATE_DATAPLOT_FROM_NORMALIZED_CURVE						*
 *	Cloud 4/27/2007 STORE_WIDTH_AND_HEIGHT										*
 *	Cloud 04/27/2007 ADD_FUNCTION_SELECTION_WHEN_FIX_PEAK						*
 *	Jasmine 07/05/07 CENTRALIZE_FIT_PEAK_STORAGE_FUNCTION						*
 *	Arvin 08/01/07 QUIKE_METHOD_OF_PEAK_MOMENTS_AND_INTEGRAL_EVALUATION			*
 *	Cheney/Arvin 2007-9-10 XOP_NEED_SUPPORT_PFM									*
 *	Cloud 11/01/07 FIND_BASELINE_AMONG_DATAPLOTS								*
 *	Arvin 12/05/07 XOP_NEED_SUPPORT_PFW											*
 *	CPY 12/8/2007 QA80-10788 CURVE_UTILS_SHOULD_NOT_NEED_PRO_DLLS				*
 *	Cloud 01/11/08 INTEGRATE_FOR_SEPERATE_PEAK									*
 *	Cloud 01/12/08 SHOULD_SORT_DATA_FIRST_FOR_INTEGRATE							*
 *	Jasmine 01/19/08 SHOULD_GET_SOURCE_LAYER_FROM_STORANGE						*
 *	Jasmine 01/21/08 SHOULD_USE_BFIXED_TO_RETURN_THE_ATTRIBUTE					*
 *	Jasmine 01/22/08 NEW_OPTION_OF_FIX_BASELINE_FOR_EACH_PARA_USING_ITS_OWN_SETTING*
 *	Jasmine 01/22/08 ATTRIBUTE_IS_CHANGE_TO_NODE_VALUE							*
 *	Hong 02/18/08 v8.0806 CHANGE_BTN_BEHAVIOR_BY_EDIT_TEMP_WORKSHEET			*
 *	Folger 04/02/08 QA80-11364 IMRPOVE_PA_FIT_BY_STORE_FIT_FUNCTION_TREE_FOR_LOOP
 *	Folger 04/08/08 QA80-11364 IMPROVE_PA_CREATE_GAUSSIAN_PEAK_MECHANISM		*
 *	Folger 04/10/08 QA80-11364 REDUCE_FDF_LOADING_AND_SETTING_TREE_IN_PEAK_CALCULATION
 *	Jasmine 04/17/08 NEED_PASS_SETTING_INFO_AND_FIT_STATUS_IN_ONE_VARIABLE		*
 *	Folger 04/28/08 CENTRALIZE_CODE_ABOUT_AREA_PARAMETER_CALCULATION			*
 *	Jack 05/04/08	ADD_ERROR_CHECKING_FOR_INTEGRATION							*
 *	Jack 05/04/08	ADD_ERROR_CHECKING_FOR_FIND_INFLECTION_POINT				*
 *	Jack 05/04/08 	ADD_ERROR_CHECKING_FOR_CALCULATE_PEAK_CHARACTERIZATION		*
 *	Jack 05/15/08	CHANGE_TO_FUNCTION_INTEGRAL									*
 *	Jasmine 05/16/08 MOMENTS_COMPUTE_METHOD										*
 *	Jack 05/23/2008 ADD_SPECIAL_SUPPORT_FOR_FUNCTION_WITH_MOMENTS_CALCULABLE_IN_CERTAIN_CASES
 *	Jack 05/29/2008 SEPARATE_MOMENTS_CAL_OUT_FOR_QUICK_METHOD					*
 *	Jack 05/29/2008 ADD_SUPPORT_FOR_INTEGRAL_IN_FUNCTION_DEFINABLE_RANGE		*
 *	Jack  06/07/2008  USE_ZEROPT_FIRST_MOMENT_AS_CENTER_GRVTY_AS_IN_PFM			*
 *  Sandy  2008-9-9 REMOVE_OLD_CODE_OF_PAGE_STORAGE_IN_SR3						*
 *	Jack 9-26-2008 QA-12288 SET_NF_FDF_FOR_EACH_PEAK_FUNCTION					*
 *	Hong 11/04/08 QA80-12526 v8.0965b ADD_BACKWARD_COMPATIABLE					*
 *	Kyle 11/24/2008 CALCULATE_PEAKS_CHARACTERIZATION_HAS_BEEN_MOVED_TO_FITPEAK	*
 *	Folger 12/24/08 v8.0990c SUPPORT_SPECIFIC_NODE_TO_SKIP_EVENT1_IN_PA_FIT		*
 *	Hong 01/13/09 v8.0995d IMPROVE_CODE_OF_MEMORY_CONSUMER_IN_PA				*
 *	Sim 10-12-2009 QA81-14388 IMPROVE_SPEED_OF_PA_FIT							*
 *	Folger 03/30/10 QA81-15237-P2 BETTER_NUMERIC_PRECISION_WHEN_CALCULATE_PEAK_PROPERTIES
 *------------------------------------------------------------------------------*/

#include <Origin.h>
#include <Profiler.h>
#include <xfutils.h>
#include <GetNBox.h>
#include <xfGraph_utils.h>

#include "ocPFM.h"
#include "PFM_utils.h"
//#include <..\OriginLab\blpwiz.h>


//---- CPY 12/8/2007 QA80-10788 CURVE_UTILS_SHOULD_NOT_NEED_PRO_DLLS
#include <ocmsp.h>
//----


#include <..\OriginLab\grobj_utils.h> /// Hong 04/25/07 v8.0608 MOVE_TO_PFM_UTILS
#include <..\OriginLab\NLFitSession.h>
#include <..\OriginLab\graph_utils.h>
#include <..\OriginLab\curve_utils.h>



////////////////////////////////////////////////////////////////////////////////////

///Sandy remove since no used
//#define ADD_ONE_PEAK_EVENT GETNE_ON_CUSTOM_BUTTON1
//#define DEL_ONE_PEAK_EVENT GETNE_ON_CUSTOM_BUTTON2
//#define CLEAR_PEAKS_EVENT GETNE_ON_CUSTOM_BUTTON3

#define _IDEAL_PEAK_PARAMS_TAGNAME	    "Params"
#define _IDEAL_PEAK_CENTER_MAX_TAGNAME	"CenterMax"
#define _IDEAL_PEAK_CENTROID_X_TAGNAME 	"CenterGrvty"
#define _IDEAL_PEAK_HEIGHT_MAX_TAGNAME 	"MaxHeight"
#define _IDEAL_PEAK_FWHM_TAGNAME      	"FWHM"




//#define STR_CATEGORY "PFM"


///Jasmine 04/17/08 NEED_PASS_SETTING_INFO_AND_FIT_STATUS_IN_ONE_VARIABLE
enum{
	EXMSG_PARACHANGE_ALL_SETTING = 1,
	EXMSG_PARACHANGE_SETTING_OFFSET,
};

int pfm_combine_exmsg_parachange_setting(bool bEnbale, int nSetting)//true, -1
{
	if(-1 == nSetting)
		nSetting = EXMSG_PARACHANGE_ALL_SETTING;
	else
		nSetting += EXMSG_PARACHANGE_SETTING_OFFSET;

	if(!bEnbale)
		nSetting *= -1;

	return nSetting;
}

bool pfm_parse_exmsg_parachange_setting(int& nSetting)
{
	int bEnableFit = 0 < nSetting;

	nSetting = abs(nSetting);
	if(EXMSG_PARACHANGE_ALL_SETTING == nSetting)
		nSetting = -1;
	else
		nSetting -= EXMSG_PARACHANGE_SETTING_OFFSET;

	return bEnableFit;
}
///End NEED_PASS_SETTING_INFO_AND_FIT_STATUS_IN_ONE_VARIABLE

///Jasmine 07/05/07 CENTRALIZE_FIT_PEAK_STORAGE_FUNCTION
//TreeNode get_fit_peak_binary_storage_tree(Page& gp, LPCSTR lpcszNodeName)
//{
	//if(!gp)
		//return NULL;
	//Tree trStorage;
	//tree_get_binary_storage(trStorage, gp, STR_FP_STORAGE);
	//TreeNode tr	= tree_get_node_by_tagname(trStorage, lpcszNodeName, true);
	//return tr;
//}
//bool update_fit_peak_binary_storage_tree(Page& gp, TreeNode& trNode, LPCSTR lpcszNodeName)
//{
	//if(!gp)
		//return false;
	//Tree trStorage;
	//tree_get_binary_storage(trStorage, gp, STR_FP_STORAGE);
	//TreeNode tr	= tree_get_node_by_tagname(trStorage, lpcszNodeName, true);
	//if(!tr)
		//tr = trStorage.AddNode(lpcszNodeName);
	//tr.Replace(trNode, true, true);
	//tree_put_binary_storage(trStorage, gp, STR_FP_STORAGE);
	//return true;
//}
//bool clean_fit_peak_binary_storage_tree(Page& gp)
//{
	//if(!gp)
		//return false;
	//Tree trStorage;
	//tree_put_binary_storage(trStorage, gp, STR_FP_STORAGE);
	//return true;
//}
///End CENTRALIZE_FIT_PEAK_STORAGE_FUNCTION
////-----sandy test code
//void test(double value)
//{
	//Worksheet wks = Project.ActiveLayer();
	//if(!wks)
		//return;
	//
	//int iCol=wks.AddCol();
	//
	//if(iCol<0)
		//return;
//
	//Dataset dsX(wks, 0);
	//Dataset dsY(wks, 1);
	//Dataset dsOut;
	//dsOut.Attach(wks, iCol);
	//
	//vector vx = dsX;
	//vector vy = dsY;
	//
	//int nSize;
	//nSize=vx.GetSize();
	//if(nSize!=vy.GetSize())
		//return;
	//
	//int nRet=opfm_tougaard(vx, vy, nSize, 1, value);
	////int nRet=opfm_shirley(vx, vy, nSize, value);
	//dsOut.SetSize(nSize);
	//dsOut = vy;
//}

//--- CPY testing oPFM dll
//void ts()
//{
	//Worksheet wks = Project.ActiveLayer();
	//
	//Dataset ds(wks, 0);
	//vector va = ds;
	//opfm_test_sort(va, va.GetSize());
	//Dataset db(wks, 1);
	//db = va;
//}
//
///Leo 2005-12-16 MOVED_PEAK_AND_BASLINE_FUNCS_TO_PFM_UTILS

//--- CPY 3/19/04
static double curve_spread(const curvebase& crvData)
{
	double xMin, xMax, yMin = 0, yMax = 0;
	Curve_MinMax(&crvData, &xMin, &xMax, FALSE, &yMin, &yMax);
	return yMax - yMin;
}
//---


///Forest 7/29/04 QA70-6067 BASELINE_SECOND_DERIVATIVE_METHOD
// LLOC for finding baseline points using 2nd derivative method
//int find_baseline_2nd_derivative(vector& vxData, vector& vyData, vector& vxBaseline, vector& vyBaseline, double dPercentile, int nSmoothPts)
//{
	//// NOTE: IT IS ASSUMED THAT VECTOR VXDATA IS SORTED.
	//// IF NOT, HLOC SHOULD SORT BEFORE CALLING THIS LLOC.
	//
	//bool bRet;
	//int  iRet;
	//double 	dThresh;
	//
	//Curve	crvData(vxData, vyData);
	//// Smooth the data curve using nSmoothPts-pt adjacent averaging
	//// nSmoothPts = 0 for no smoothing
	//if(nSmoothPts != 0)
		//if( !(bRet = curve_smooth_adjave(crvData,(nSmoothPts-1)/2)) )
			//return -1;
	//
	//if( 1 != (iRet = curve_derivative(crvData)) ) return -2;
	//if( 1 != (iRet = curve_derivative(crvData)) ) return -2;
//
	//// Take the absolute value of the data
	//crvData = abs(crvData);
	//
	//// Get the percentile value
	//Data_percentiles( &crvData, &dPercentile, &dThresh, 1 );
//
	//// Replace points outside threshold with NANUM
	//crvData.Replace(dThresh, NANUM, MATREPL_TEST_GREATER | MATREPL_USE_ABSOLUTE_VALUE_IN_TEST);
	//
	//// Remove all points that do not have a neighbor on either side. This is to ensure
	//// that spurious baseline points that correspond to peaks in the data are removed.
	//// Also get the baseline points
	//int iSize = crvData.GetSize();
	//vxBaseline = vxData;
	//vyBaseline = vyData;
//
	//vector vTemp;
	//vTemp=crvData;
	//vTemp.Replace(NANUM,1,MATREPL_TEST_GREATER | MATREPL_TEST_LESSTHAN); //Replace values that are not equal to NANUM with 1
	//vxBaseline*=vTemp;
	//vyBaseline*=vTemp;
	//vTemp=crvData;
	//vTemp.InsertAt(0,NANUM); 		//Insert row to check previous point
	//vTemp.SetSize(iSize);
	//vTemp.Replace(NANUM,1,MATREPL_TEST_GREATER | MATREPL_TEST_LESSTHAN); //Replace values that are not equal to NANUM with 1
	//vxBaseline*=vTemp;				//Remove spurious baseline points
	//vyBaseline*=vTemp;
	//vTemp=crvData;
	//vTemp.RemoveAt(0,1);			//Remove row to check next point
	//vTemp.InsertAt(iSize-1,NANUM);
	//vTemp.Replace(NANUM,1,MATREPL_TEST_GREATER | MATREPL_TEST_LESSTHAN);
	//vxBaseline*=vTemp;
	//vyBaseline*=vTemp;
	//vxBaseline.Trim();				//Remove NANUM from baseline vector
	//vyBaseline.Trim();
//
	//return vxBaseline.GetSize();
//}
///End BASELINE_SECOND_DERIVATIVE_METHOD


bool find_peaks_2nd_derivative(vector& vxData, vector& vyData, vector& vxPeaks, vector& vyPeaks, vector<int>& vnIndices, int nDir, int nPtsSmooth)
{
	Curve cvData(vxData, vyData);
	if (nPtsSmooth > 3 && !curve_smooth_sg(cvData,(nPtsSmooth-1)/2))
	{
		return false;
	}
	curve_derivative(cvData);
	if (nPtsSmooth > 3 && !curve_smooth_sg(cvData,(nPtsSmooth-1)/2))
	{
		return false;
	}
	curve_derivative(cvData);
	if (nPtsSmooth > 3 && !curve_smooth_sg(cvData,(nPtsSmooth-1)/2))
	{
		return false;
	}

	int iSize = cvData.GetSize();
	vector vTemp1, vTemp2;

	//vnIndices.SetSize(0);		//Vector for peak indexes

	//vector vTempPkInd;
	//vTempPkInd.SetSize(iSize);
	//vTempPkInd.Data(1,iSize,1);
	//
	//cvData.CopyData(vxPeaks, vyPeaks);
	//vyPeaks.Difference(vTemp1);
	//vTemp2 = vTemp1;
	//vTemp1.InsertAt(0,vTemp1[0]);
	//vTemp2.InsertAt(iSize-1,NANUM);
	////if (PEAKS_POSITIVE == nDir)
	//if (nDir &  POSITIVE_DIRECTION)
	//{
		//vTemp1.Replace(0,1,MATREPL_TEST_LESSTHAN | MATREPL_SET_TO_MISSING_VALUE_WHEN_TEST_RESULT_IS_FALSE);
		//vTemp2.Replace(0,1,MATREPL_TEST_GREATER | MATREPL_SET_TO_MISSING_VALUE_WHEN_TEST_RESULT_IS_FALSE);
	//}
	////else if (PEAKS_NEGATIVE == nDir)
	//else if (nDir & NEGATIVE_DIRECTION)
	//{
		//vTemp1.Replace(0,1,MATREPL_TEST_GREATER | MATREPL_SET_TO_MISSING_VALUE_WHEN_TEST_RESULT_IS_FALSE);
		//vTemp2.Replace(0,1,MATREPL_TEST_LESSTHAN | MATREPL_SET_TO_MISSING_VALUE_WHEN_TEST_RESULT_IS_FALSE);
	//}
	//else
		//return false;
//
	 //
	//vxPeaks = vxData * vTemp1 * vTemp2;
	//vyPeaks = vyData * vTemp1 * vTemp2;
	//vTempPkInd *=vTemp1 * vTemp2;
//
	//vxPeaks.Trim();
	//vyPeaks.Trim();
	//vTempPkInd.Trim();
	//vnIndices = vTempPkInd;

	//sandy 2006-3-23 Modify keep same processing as find_peaks_1st_derivative() in curve_utils.c/h

	vxPeaks.SetSize(0);
	vyPeaks.SetSize(0);
	vnIndices.SetSize(0);		//Vector for peak indexes

	vector vTempPkInd;
	vTempPkInd.SetSize(iSize);
	vTempPkInd.Data(1,iSize,1);

	vector vxp, vyp;

	if (nDir &  POSITIVE_DIRECTION)
	{
		cvData.CopyData(vxp, vyp);
		vyp.Difference(vTemp1);
		vTemp2 = vTemp1;
		vTemp1.InsertAt(0, vTemp2[0]);
		vTemp2.InsertAt(iSize-1,NANUM);

		vTemp1.Replace(0, 1, MATREPL_TEST_LESSTHAN | MATREPL_SET_TO_MISSING_VALUE_WHEN_TEST_RESULT_IS_FALSE);
		vTemp2.Replace(0, 1, MATREPL_TEST_GREATER | MATREPL_SET_TO_MISSING_VALUE_WHEN_TEST_RESULT_IS_FALSE);

		vTemp1 *= vTemp2;

		vxp = vxData * vTemp1;
		vyp = vyData * vTemp1;

		vTempPkInd = vTempPkInd * vTemp1;

		vxp.Trim();
		vyp.Trim();
		vTempPkInd.Trim();

		vxPeaks.Append(vxp);	//Append positive peaks
		vyPeaks.Append(vyp);
		vnIndices.Append(vTempPkInd);
	}

	vTempPkInd.SetSize(iSize);  //reset peak indexes
	vTempPkInd.Data(1,iSize,1);


	if (nDir & NEGATIVE_DIRECTION)
	{
		cvData.CopyData(vxp, vyp);
		vyp.Difference(vTemp1);
		vTemp2 = vTemp1;
		vTemp1.InsertAt(0, vTemp2[0]);
		vTemp2.InsertAt(iSize-1,NANUM);

		vTemp1.Replace(0, 1, MATREPL_TEST_GREATER | MATREPL_SET_TO_MISSING_VALUE_WHEN_TEST_RESULT_IS_FALSE);
		vTemp2.Replace(0, 1, MATREPL_TEST_LESSTHAN | MATREPL_SET_TO_MISSING_VALUE_WHEN_TEST_RESULT_IS_FALSE);

		vTemp1 *= vTemp2;

		vxp = vxData * vTemp1;
		vyp = vyData * vTemp1;

		vTempPkInd = vTempPkInd * vTemp1;

		vxp.Trim();
		vyp.Trim();
		vTempPkInd.Trim();

		vxPeaks.Append(vxp);	//Append negative peaks
		vyPeaks.Append(vyp);

		vnIndices.Append(vTempPkInd);
	}

	return true;
}
/*
bool find_peaks_by_deconvolute(const vector& vx,const vector& vy, vector& vxPeaks, vector& vyPeaks, vector<int>& vnIndices, int nDir, int num, int nPtsSmooth)
{
	///Raine 2006-07-07
	//if (!find_peaks_1st_derivative(vx, vy, vxPeaks, vyPeaks, vnIndices, nDir, nPtsSmooth ))
	int nSize = vx.GetSize();
	int nRet = ocmath_find_peaks_1st_derivative(&nSize, vx, vy, vxPeaks, vyPeaks, vnIndices, nDir, nPtsSmooth);
	if(nRet != OE_NOERROR)
	{
		return false;
	}
	vxPeaks.SetSize(nSize);
	vyPeaks.SetSize(nSize);
	vnIndices.SetSize(nSize);

	//restrict the number of peaks to create guass by nlsf, it is too slowly
	//if(num != -1)
		//test_peaks_by_number(vxPeaks, vyPeaks, vnIndices, num);
	//else
		//test_peaks_by_number(vxPeaks, vyPeaks, vnIndices, 10);
	if(num != -1)
		num = 10;
	nRet = ocmath_test_peaks_by_number(vxPeaks.GetSize(), vxPeaks, vyPeaks, vnIndices, num);
	if(nRet != OE_NOERROR)
	{
		return false;
	}
	vxPeaks.SetSize(num);
	vyPeaks.SetSize(num);
	vnIndices.SetSize(num);
	///END

	int nPeakNum = vnIndices.GetSize();
	int iSize = vx.GetSize();

	vector vParams;
	vector vyGauss;


	//for (int ii = 0; ii < nPeakNum; ii++)
	//{
		int nStart, nEnd;
		///Raine 2006-07-07
		//if (!find_peaks_partition(vx, vy, vxPeaks[0], nStart, nEnd, nPtsSmooth))
		nRet = ocmath_find_peaks_partition(vx.GetSize(), vx, vy, vxPeaks[0], &nStart, &nEnd, nPtsSmooth);
		if(nRet != OE_NOERROR)
		{
			//continue;
			return false;
		}
		///END

		int iMid = (nStart + nEnd)/2;
		nStart = iMid - (iMid - nStart)*2;
		nEnd = iMid + (nEnd - iMid)*2;

		if (nStart < 0)
		{
			nStart = 0;
		}
		if (nEnd >= iSize)
		{
			nEnd = iSize - 1;
		}

		vector vxSub(nEnd-nStart), vySub(nEnd-nStart);
		vx.GetSubVector(vxSub, nStart+1, nEnd);
		vy.GetSubVector(vySub, nStart+1, nEnd);
		//create_Gauss_peak_by_nlsf_evluate(vxSub, vySub, vxPeaks[0], vyPeaks[0], nDir, nPtsSmooth, vyGauss, vParams);
		//create_Gauss_peak_by_nlsf_evluate(vx, vy, vxPeaks[ii], vyPeaks[ii], nDir, nPtsSmooth, vyGauss, vParams);

		if (!peak_fit_with_fixed_xc(STR_DEFAULT_PEAK, vxSub, vySub, vxPeaks[0], vParams))
		{
			return false;
		}
	//}

	vector vyDec;
	fft_deconvolute(vy, vyGauss, vyDec, false, false);

	///Raine 2006-07-07
	//if (!find_peaks_1st_derivative(vx, vyDec, vxPeaks, vyPeaks, vnIndices, nDir, nPtsSmooth ))
	//{
		//return false;
	//}
	nSize = vx.GetSize();
	nRet = ocmath_find_peaks_1st_derivative(&nSize, vx, vyDec, vxPeaks, vyPeaks, vnIndices, nDir, nPtsSmooth);
	if(nRet != OE_NOERROR)
	{
		return false;
	}
	vxPeaks.SetSize(nSize);
	vyPeaks.SetSize(nSize);
	vnIndices.SetSize(nSize);

	if(num != -1)
	{
		//test_peaks_by_number(vxPeaks, vyPeaks, vnIndices, num);
		nRet = ocmath_test_peaks_by_number(vxPeaks.GetSize(), vxPeaks, vyPeaks, vnIndices, num);
		if(nRet != OE_NOERROR)
		{
			return false;
		}
		vxPeaks.SetSize(num);
		vyPeaks.SetSize(num);
		vnIndices.SetSize(num);
	}
	///END


	return true;
}
*/
//bool find_peaks_deconvolute(vector &vix, vector &viy, vector &vo, double dC, double dA, double dW)
//{
	//int nSize=viy.GetSize();
//
	//double dmin, dmax, dyrange;
	//double dminx, dmaxx,dmeanx, dxrange;
	//viy.GetMinMax(dmin, dmax);
	//dyrange=dmax-dmin;
	//vix.GetMinMax(dminx, dmaxx);
	//dmeanx=(dminx+dmaxx);
	//dxrange=dmaxx-dminx;
	//
	////standarding
	//viy=viy/dyrange;
	//vix=vix/dxrange;
	//
	//
	//vector vP(3);
	//
	//vP[0]=dC;//center
	//vP[1]=dA;//area
	//vP[2]=dW;//width
	//
	//printf("c=%f  a=%f  w=%f\n", vP[0],vP[1],vP[2] );
	//
	//vector  vyGauss;//vxGauss,
	//
	//vyGauss.SetSize(vix.GetSize());
	//nlsf_evaluate("pfmGaussian", STR_CATEGORY, vix, vyGauss, vP);
	//
	//deconvolute(viy, vyGauss, vo, false, false);
	//
	////compute the peaks of vo and viy
	//vector vxP0, vyP0, vxP1, vyP1;
	//vector<int> vPksInd;
	//int nDir, nPeakNum0=0, nPeakNum1=0;
	//int nPtsSmooth=nSize/100;
	//find_peaks_1st_derivative(vix, viy, vxP0, vyP0, vPksInd, nDir,  nPtsSmooth);
	//find_peaks_1st_derivative(vix, vo, vxP1, vyP1, vPksInd, nDir,  nPtsSmooth);
	//
	//////compute their max-area peak
	////find_peaks_partition(vxP0, vyP0, vxSub0, vySub0, dxPeak, nDir, nPtsSmooth);
	//
	//double dPeakest0y;
	//double dPeakest1y;
	//double temp;
	//int indexmin0, indexmax0;
	//int indexmin1, indexmax1;
	//vyP0.GetMinMax(temp,dPeakest0y,&indexmin0,&indexmax0);
	//vyP1.GetMinMax(temp,dPeakest1y,&indexmin1,&indexmax1);
	//
	//double diff=vxP1[indexmax1]-vxP0[indexmax0];
	//int offset=diff*(nSize-1);
	//if(offset<0)
	//{
		//vo.InsertAt(0,0,-offset);
	//}
	//else
	//{
		//vo.RemoveAt(0,offset);
	//}
	//
	////move the base
	//diff=vyP1[indexmax1]-vyP0[indexmax0];
	//
	//vo=vo-diff;
	//
	////processing
	//vo=vo*dyrange;
	//return true;
//}
//
////bool find_peaks_partition(vector& vxData, vector& vyData, vector& vxSub, vector& vySub, double dxPeak, int nDir, int nPtsSmooth)
//bool find_peaks_partition(vector& vxData, vector& vyData, vector& vxSub, vector& vySub, double dxPeak, int nPtsSmooth)
//{
	//Curve cvData(vxData, vyData);
	//if (!curve_smooth_sg(cvData,(nPtsSmooth-1)/2))
	//{
		//return false;
	//}
	//curve_derivative(cvData);
	//if (!curve_smooth_sg(cvData,(nPtsSmooth-1)/2))
	//{
		//return false;
	//}
	//curve_derivative(cvData);
	//if (!curve_smooth_sg(cvData,(nPtsSmooth-1)/2))
	//{
		//return false;
	//}
//
	//int iSize = cvData.GetSize();
	//
	//vector vxKnod, vyTemp, vyTemp2;
	//cvData.CopyData(vxKnod, vyTemp);
	//vyTemp2 = vyTemp;
	//vyTemp2.InsertAt(0, vyTemp[0]);
	//vyTemp2.SetSize(iSize);
	//vyTemp *= vyTemp2;
	//vyTemp.Replace(0,1,MATREPL_TEST_LESSTHAN | MATREPL_SET_TO_MISSING_VALUE_WHEN_TEST_RESULT_IS_FALSE);
	//vxKnod *= vyTemp;
	//vxKnod.Trim();
	//
	//vxKnod.InsertAt(0, dxPeak);
	//vxKnod.Sort();
//
	//int iPeak, iLeft, iRight;
	//vector<uint> vIndex;
	//vxKnod.Find(vIndex, dxPeak);
	//iPeak = vIndex[0];
	//if (iPeak == 0)
	//{
		//iLeft = 0;
	//}
	//else
	//{
		//vxData.Find(vIndex, vxKnod[iPeak-1]);
		//iLeft = vIndex[0];
	//}
	//if (iPeak == vxKnod.GetSize()-1)
	//{
		//iRight = iSize-1;
	//}
	//else
	//{
		//vxData.Find(vIndex, vxKnod[iPeak+1]);
		//iRight = vIndex[0];
	//}
//
	//vxData.GetSubVector(vxSub, iLeft, iRight);
	//vyData.GetSubVector(vySub, iLeft, iRight);
	//return true;
//}
	//
bool peak_fit_with_fixed_xc(string strFuncName, vector& vX, vector& vY, double xc, vector& vParams, double dCOD)
{
	/// 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, STR_NLSF_CAT_PFM))
	{
		return false;
	}
	if (!fit.SetData(vY, vX))
	{
		return false;
	}
	if (!fit.ParamsInitValues())
	{
		return false;
	}
	vector vErrors;
	if (!fit.GetFitResultsParams(vParams, vErrors))
	{
		return false;
	}
	vParams[0] = xc;
	if (vParams[2] == NANUM)
	{
		double dxMin, dxMax;
		vX.GetMinMax(dxMin, dxMax);
		vParams[2] = (dxMax - dxMin)/2;

	}
	if (0 != fit.SetParamValues(vParams))
	{
		return false;
	}
	if (!fit.SetParamFix(0, true))
	{
		return false;
	}
	int nFitOutcome;
	if (!fit.Fit(&nFitOutcome))
	{
		return true;
	}
	RegStats sRegStats;
	NLSFFitInfo sNLSFFitInfo;
	if (!fit.GetFitResultsStats(&sRegStats, &sNLSFFitInfo))
	{
		return false;
	}
	if (sRegStats.RSqCOD >= dCOD)
	{
		if (!fit.GetFitResultsParams(vParams, vErrors))
		{
			return false;
		}
	}
	return true;
}
//bool peak_fit_with_fixed_xc(string strFuncName, vector& vX, vector& vY, double xc, vector& vParams, double dCOD)
//{
//	vector<bool> vbFixed(3);	//xc, A, w
//	vector vInitParams;
//
//	//Sandy 11/30/05 MODIFY_NLSF_INIT_TO_GET_PARAM_NAME
////	if (!nlsf_init(strFuncName, vX, vY, vParams))
//	vector <string> vstrParamNames;
//	if (!nlsf_init(strFuncName, vX, vY, vstrParamNames, vParams))
//	{
//		return false;
//	}
//	vParams[0] = xc;
//	if (vParams[2] == NANUM)
//	{
//		double dxMin, dxMax;
//		vX.GetMinMax(dxMin, dxMax);
//		vParams[2] = (dxMax - dxMin)/2;
//	}
//	vbFixed[0] = true;
//	vInitParams = vParams;
//
//	RegStats sRegStats;
//	if (!nlsf_fit(strFuncName, vX, vY, vParams, vbFixed, &sRegStats))
//	{
//		return false;
//	}
//
//	if (sRegStats.RSqCOD < dCOD)
//	{
//		vParams = vInitParams;
//	}
//	return true;
//}

///Sandy 2007-6-21 there should be no number constrain in finding peaks
//bool find_peaks_by_residuals(const vector& vx,const vector& vy, vector& vxPeaks, vector& vyPeaks, vector<int>& vnIndices, int nDir, int& num, int nPtsSmooth)
//bool find_peaks_by_residuals(const vector& vX,const vector& vY, vector& vxPeaks, vector& vyPeaks, vector<int>& vnIndices, int nDir, int nPtsSmooth)
//---Sandy 2008-11-18 APPLY_NEW_OCMATH_FUNCTION_PROTOTYPE_WITH_SG_DERIV
//int find_peaks_by_residuals(const vector& vX,const vector& vY, vector& vxPeaks, vector& vyPeaks, vector<int>& vnIndices, int nDir, int nPtsSmooth)
int find_peaks_by_residuals(const vector& vX,const vector& vY, vector& vxPeaks, vector& vyPeaks, vector<int>& vnIndices, int nDir, bool bUseSG, int nPtsSmooth, int nPloyDeg)
{
	///Raine 2006-07-07
	//if (!find_peaks_1st_derivative(vx, vy, vxPeaks, vyPeaks, vnIndices, nDir, nPtsSmooth ))
		//return false;
	/// Cloud 01/12/08 SHOULD_SORT_DATA_FIRST_FOR_INTEGRATE
	vector vx, vy;
	vx = vX;
	vy = vY;
	int nSize = vx.GetSize();
	vector<uint> vRef;
	vx.Sort(SORT_ASCENDING, TRUE, vRef);
	vy.Reorder(vRef);
	/// End SHOULD_SORT_DATA_FIRST_FOR_INTEGRATE
	
	//Sandy 2008-11-18 APPLY_NEW_OCMATH_FUNCTION_PROTOTYPE_WITH_SG_DERIV
	//int nRet = ocmath_find_peaks_1st_derivative(&nSize, vx, vy, vxPeaks, vyPeaks, vnIndices, nDir, nPtsSmooth);
	int nRet = ocmath_find_peaks_1st_derivative(&nSize, vx, vy, vxPeaks, vyPeaks, vnIndices, nDir, bUseSG, nPtsSmooth, nPloyDeg);
	
	if(nRet != OE_NOERROR || nSize <= 0)
	{
		return nRet;
	}
	vxPeaks.SetSize(nSize);
	vyPeaks.SetSize(nSize);
	vnIndices.SetSize(nSize);

	///Sandy 2007-6-21 there should be no number constrain in finding peaks
	/*
	//restrict the number of peaks to create guass by nlsf, it is too slowly
	//if(num != -1)
		//test_peaks_by_number(vxPeaks, vyPeaks, vnIndices, num);
	//else
		//test_peaks_by_number(vxPeaks, vyPeaks, vnIndices, 10);
	//if(num == -1)
		//num = 10;
	if(num < nSize)
	{
		nRet = ocmath_test_peaks_by_number(vxPeaks.GetSize(), vxPeaks, vyPeaks, vnIndices, num);
		if(nRet != OE_NOERROR)
		{
			return false;
		}
		vxPeaks.SetSize(num);
		vyPeaks.SetSize(num);
		vnIndices.SetSize(num);
	}
	///END
	*/

	///Sandy 2006-6-21 add for prepare improve to gaussian
	IntegrationResult sResult;

	/// Cloud 01/11/08 INTEGRATE_FOR_SEPERATE_PEAK
	//ocmath_integrate(vx, vy, 0, vx.GetSize()-1, &sResult, NULL, ABSOLUTE_AREA);
	//if (sResult.dxPeak < 0)
	//{
		//sResult.dxPeak *= -1;
		//sResult.Area *= -1;
	//}
	////vnIndices.Sort(SORT_ASCENDING, TRUE, vn);
	////vxPeaks.Reorder(vn);
	//vxPeaks.Sort(SORT_ASCENDING, TRUE, vn);
	//vnIndices.Reorder(vn);
	//vyPeaks.Reorder(vn);
	vector<int> vMarkInd(2*nSize);
	double dMin, dMax;
	vx.GetMinMax(dMin, dMax);
	nRet = ocmath_find_markers_of_peaks_by_height_and_width(vx.GetSize(), vx, vy, nSize, vnIndices, 2*nSize, vMarkInd, 0, dMax-dMin, 0);
	

	//double dSumHeight;
	//vyPeaks.Sum(dSumHeight);
	//double dWholeWidth = sResult.Area/dSumHeight/sqrt(PI/(4*ln(2)));
	//double dWholeWidth = sResult.Area/dSumHeight/sqrt(PI/2);
	///add end


	int nPeakNum = vnIndices.GetSize();
	int nPoint = vx.GetSize();
	vector vyCum;
	vyCum.SetSize(nPoint);
	vyCum = 0;
	for (int ii = 0; ii < nPeakNum; ii++)
	{
		ocmath_integrate(vx, vy, vMarkInd[ii*2], vMarkInd[ii*2+1], &sResult, NULL);
		vector vParams;
		vector vyGauss;

		///Sandy 2006-6-21 improve to gaussian
		//bool bRet = create_Gauss_peak_by_nlsf_evluate(vx, vy, vxPeaks[ii], vyPeaks[ii], nDir, nPtsSmooth, vyGauss, vParams);
		//bool bRet = create_Gaussian_peak_by_nlsf_evluate(vx, vy, dWholeWidth, vxPeaks[ii], vyPeaks[ii], nDir, nPtsSmooth, vyGauss, vParams);
		//------ Folger 04/08/08 QA80-11364 IMPROVE_PA_CREATE_GAUSSIAN_PEAK_MECHANISM
		//bool bRet = create_Gaussian_peak_by_nlsf_evluate(vx, vy, sResult.dxPeak, vxPeaks[ii], vyPeaks[ii], nDir, nPtsSmooth, vyGauss, vParams);
		bool bRet = create_Gaussian_peak_by_nlsf_evluate(vx, sResult.dxPeak, vxPeaks[ii], vyPeaks[ii], vParams, vyGauss);
		//------
	/// End INTEGRATE_FOR_SEPERATE_PEAK
		if(!bRet)
			return OE_UNKOWN_ERROR;
		vyCum += vyGauss;

	}

	vector<uint> vnTemp;
	if(0!=vyCum.Find(vnTemp, NANUM))
		return OE_UNKOWN_ERROR;

	//calculate the residual.
	vector vyRes(nPoint);
	vyRes = vy - vyCum;

	//vyRes.Replace(0,0,MATREPL_TEST_LESSTHAN);
	//Sandy 2007-6-21 Add for support both direction
	if(nDir == POSITIVE_DIRECTION)
		vyRes.Replace(0,0,MATREPL_TEST_LESSTHAN);
	else if(nDir == NEGATIVE_DIRECTION)
		vyRes.Replace(0,0,MATREPL_TEST_GREATER);

	///Raine 2006-07-07
	//find in the residual data
	//vector vxResPeaks, vyResPeaks;
	//vector<int> vnResIndices;
	//if (!find_peaks_1st_derivative(vx, vyRes, vxResPeaks, vyResPeaks, vnResIndices, nDir, nPtsSmooth ))
	int nResSize = vyRes.GetSize();
	vector vxResPeaks(nResSize), vyResPeaks(nResSize);
	vector<int> vnResIndices(nResSize);
	
	//Sandy 2008-11-18 APPLY_NEW_OCMATH_FUNCTION_PROTOTYPE_WITH_SG_DERIV
	//nRet = ocmath_find_peaks_1st_derivative(&nResSize, vx, vyRes, vxResPeaks, vyResPeaks, vnResIndices, nDir, nPtsSmooth);
	nRet = ocmath_find_peaks_1st_derivative(&nResSize, vx, vyRes, vxResPeaks, vyResPeaks, vnResIndices, nDir, false, nPtsSmooth);
	if(nRet != OE_NOERROR)
	{
		return nRet;
	}
	//vxResPeaks.SetSize(nResSize);
	//vyResPeaks.SetSize(nResSize);
	vnResIndices.SetSize(nResSize);

	//vxPeaks.Append(vxResPeaks);
	//vyPeaks.Append(vyResPeaks);
	vnIndices.Append(vnResIndices);
	vxPeaks.SetSize(nSize+nResSize);
	vyPeaks.SetSize(nSize+nResSize);
	for(ii = 0; ii<nResSize; ii++)
	{
		vxPeaks[nSize+ii] = vx[vnResIndices[ii]];
		/// Cloud 01/11/08 INTEGRATE_FOR_SEPERATE_PEAK
		//vyPeaks[nSize+ii] = vy[vnResIndices[ii]];
		vyPeaks[nSize+ii] = vyRes[vnResIndices[ii]];
		/// End INTEGRATE_FOR_SEPERATE_PEAK
	}

	///Sandy 2007-6-21 there should be no number constrain in finding peaks
	/*
	//if(num != -1)
	if(num < vxPeaks.GetSize())
	{
		//test_peaks_by_number(vxPeaks, vyPeaks, vnIndices, num);
		nRet = ocmath_test_peaks_by_number(vxPeaks.GetSize(), vxPeaks, vyPeaks, vnIndices, num);
		if(nRet != OE_NOERROR)
		{
			return false;
		}
		vxPeaks.SetSize(num);
		vyPeaks.SetSize(num);
		vnIndices.SetSize(num);
	}
	*/

	//vxPeaks.Append(vxResPeaks);
	//vyPeaks.Append(vyResPeaks);
	//vnIndices.Append(vnResIndices);

	vector<uint> vn;
    vxPeaks.Sort(SORT_ASCENDING, true, vn);//

	//vxPeaks.Sort();
	vyPeaks.Reorder(vn);
	vnIndices.Reorder(vn);

	//remove the same index
	vector<int> vecDiff;
	BOOL bRet = vnIndices.Difference(vecDiff);
	for(ii = vecDiff.GetSize() - 1; ii>= 0; ii--)
	{
		if(vecDiff[ii] == 0)
		{
			vnIndices.RemoveAt(ii);
			vyPeaks.RemoveAt(ii);
			vxPeaks.RemoveAt(ii);
		}
	}

	/// Cloud 01/12/08 SHOULD_SORT_DATA_FIRST_FOR_INTEGRATE
	nPeakNum = vxPeaks.GetSize();
	for (ii=0; ii<nPeakNum; ii++)
	{
		vnIndices[ii] = vRef[vnIndices[ii]];
	}
	/// End SHOULD_SORT_DATA_FIRST_FOR_INTEGRATE

	//num = vxPeaks.GetSize();
	return 0;
}

// this function only support only one peak in the data section and have determinate peak direction
bool is_hidden_peak(const vector& vy, int nDir)
{
	double dMax, dMin;
	vy.GetMinMax(dMin, dMax);
	int nSize = vy.GetSize();
	if(nDir == POSITIVE_DIRECTION)
	{
		if(dMax == vy[0] || dMax == vy[nSize-1])
			return true;
		else
			return false;
	}
	else if(nDir == NEGATIVE_DIRECTION)
	{
		if(dMin == vy[0] || dMin == vy[nSize-1])
			return true;
		else
			return false;
	}

	return false;
}


//------ Folger 04/02/08 QA80-11364 IMRPOVE_PA_FIT_BY_STORE_FIT_FUNCTION_TREE_FOR_LOOP
///////Sandy add 2007-6-21 for improve same thing in create_Gauss_peak_by_nlsf_evluate
//bool create_Gaussian_peak_by_nlsf_evluate(const vector& vx, const vector& vy, double dWholeWidth,
				//double xc, double yc, int nDir, int nPtsSmooth, vector& vGaussianPeak, vector& vParams)
//{
	//
	///*
	////xc, a. w
	//vParams.SetSize(3);
	//vParams[0] = xc;
	//vParams[2] = dWholeWidth;
	//vParams[1] = yc*vParams[2]*sqrt(PI/(4*ln(2)));
	//*/
	////y0, xc, a. w
	//vParams.SetSize(4);
	//vParams[0] = 0;
	//vParams[1] = xc;
	//vParams[3] = dWholeWidth;
	//vParams[2] = yc*vParams[3]*sqrt(PI/(4*ln(2)));
	////if(!nlsf_evaluate("Gaussian", "PFM", vx, vGaussianPeak, vParams))
	//if(!nlsf_evaluate(STR_DEFAULT_PEAK, STR_NLSF_CAT_PFM, vx, vGaussianPeak, vParams))
		//return false;
	//
	//
	//return true;
//}

//------ Folger 04/08/08 QA80-11364 IMPROVE_PA_CREATE_GAUSSIAN_PEAK_MECHANISM
/*
bool	create_Gaussian_peak_by_nlsf_evluate(const vector& vx, const vector& vy, double dWholeWidth,
				double xc, double yc, int nDir, int nPtsSmooth, vector& vGaussianPeak, vector& vParams
				, TreeNode &trGaussianFF)
{
	static const double l_dSqrt = sqrt(PI/(4*ln(2)));

	vParams.SetSize(4);
	vParams[0] = 0;
	vParams[1] = xc;
	vParams[3] = dWholeWidth;
	vParams[2] = yc*vParams[3] * l_dSqrt;
*/
bool create_Gaussian_peak_by_nlsf_evluate(const vector& vx, double dWholeWidth, double xc, double yc, vector& vParams, vector& vGaussianPeak, TreeNode &trGaussianFF)
{
	pfm_init_Gaussian_parameters(vParams, xc, yc, dWholeWidth);

	if ( vGaussianPeak == NULL )
		return true;

//------ End IMPROVE_PA_CREATE_GAUSSIAN_PEAK_MECHANISM

	if ( trGaussianFF )
		return nlsf_evaluate(trGaussianFF, vx, vGaussianPeak, vParams);

	return nlsf_evaluate(STR_PA_DEFAULT_FUNC, STR_NLSF_CAT_PFM, vx, vGaussianPeak, vParams);
}
//------ End IMRPOVE_PA_FIT_BY_STORE_FIT_FUNCTION_TREE_FOR_LOOP

//------ Folger 04/08/08 QA80-11364 IMPROVE_PA_CREATE_GAUSSIAN_PEAK_MECHANISM
void	pfm_init_Gaussian_parameters(vector& vParams, double xc, double yc, double dWholeWidth)
{
	//------ Folger 04/28/08 CENTRALIZE_CODE_ABOUT_AREA_PARAMETER_CALCULATION
	//static const double l_dSqrt = sqrt(PI/(4*ln(2)));
	static const double l_dSqrt = NLFIT_AREA_PARAMETER_CALCULATION_FACTOR;
	//------

	vParams.SetSize(4);
	vParams[0] = 0;
	vParams[1] = xc;
	vParams[3] = dWholeWidth;
	vParams[2] = yc*vParams[3] * l_dSqrt;
}
//------

/*
bool create_Gauss_peak_by_nlsf_evluate(const vector& vx, const vector& vy, double xc, double yc, int nDir, int nPtsSmooth,
///Sandy 2007-6-13 this xf should create with Guass always, don't sent function name to it, i roll back the code before Cloud's
/// Cloud 04/27/2007 add a parameter of strFuncName for future
		//vector& vGaussPeak, vector& vParams, int* pPeakStart, int* pPeakEnd)
		//vector& vGaussPeak, vector& vParams, int* pPeakStart, int* pPeakEnd, string strFuncName)
		vector& vGaussPeak, vector& vParams, int* pPeakStart, int* pPeakEnd)
{
	vector vxSub, vySub;

	//2006-4-4 Sandy MODIFY_THE_PROTOTYPE_TO_OUTPUT_THE_INDEX_OF_PEAKS_ENDING
	int nStart, nEnd;
	//if (!find_peaks_partition(vx, vy, vxSub, vySub, xc, nPtsSmooth))

	//if (!find_peaks_partition(vx, vy, xc, nStart, nEnd, nPtsSmooth))
	int nRet = ocmath_find_peaks_partition(vx.GetSize(), vx, vy, xc, &nStart, &nEnd, nPtsSmooth);
	if(nRet != OE_NOERROR)
	{
		return false;
	}

	vx.GetSubVector(vxSub, nStart, nEnd);
	vy.GetSubVector(vySub, nStart, nEnd);

	//2006-4-13 ADD_TEST_FOR_HIDDEN_PEAKS
	if(is_hidden_peak(vySub, nDir) && nDir != BOTH_DIRECTION)
	{
		vxSub.SetSize(3);
		vySub.SetSize(3);
		vxSub[0] = vx[nStart];
		vySub[0] = 0;
		vxSub[1] = xc;
		vySub[1] = yc;
		vxSub[2] = vx[nEnd];
		vySub[2] = 0;

		//vector vsy(nPtsSmooth), vsx(nPtsSmooth);
		//int nResult = ocmath_interpolate(vsx, vsy, nPtsSmooth, vxSub, vySub, 3, INTERP_TYPE_LINEAR);
		//if( nResult != OE_NOERROR )
		//{
			//string strErr  ="Interpolation hidden peak failed. Error code: " + nResult;
			//xf_error_out(strErr);
			//return false;
		//}
		//
		//vxSub = vsx;
		//vySub = vsy;
	}
	//else if (vxSub.GetSize() < nPtsSmooth)
	   //return false;

	//end of MODIFY_THE_PROTOTYPE_TO_OUTPUT_THE_INDEX_OF_PEAKS_ENDING

	//if (vxSub.GetSize() < nPtsSmooth)
		//return false;

	//make sure the subvector include some part of baseline
	//double y0, dyMax;
	//vySub.GetMinMax(y0, dyMax);
	//if(nDir == POSITIVE_DIRECTION)
		//vySub -= y0;
	//else
		//vySub -=dyMax;

	///Sandy 2007-6-13 roll back
	/// Cloud 04/27/2007 ADD_FUNCTION_SELECTION_WHEN_FIX_PEAK
	//if (!peak_fit_with_fixed_xc(STR_DEFAULT_PEAK, vxSub, vySub, xc, vParams))
	//if (!peak_fit_with_fixed_xc(strFuncName, vxSub, vySub, xc, vParams))
	if (!peak_fit_with_fixed_xc(STR_DEFAULT_PEAK, vxSub, vySub, xc, vParams))
	{
		return false;
	}

	///Sandy 2007-6-13 roll back
	//if (!nlsf_evaluate(STR_DEFAULT_PEAK, STR_CATEGORY, vx, vGaussPeak, vParams))
	//if (!nlsf_evaluate(strFuncName, STR_CATEGORY, vx, vGaussPeak, vParams))
	if (!nlsf_evaluate(STR_DEFAULT_PEAK, STR_CATEGORY, vx, vGaussPeak, vParams))
	{
		return false;
	}
	/// End ADD_FUNCTION_SELECTION_WHEN_FIX_PEAK

	if(pPeakStart&&pPeakEnd)
	{
		*pPeakStart = nStart;
		*pPeakEnd = nEnd;
	}
	return true;
}
*/
/*
///Raine 2006-04-30 GET_GAUSSIAN_FILTER
bool get_gaussian_filter(vector& vxData, vector& vyData, vector& vGaussian)
{
	vector vxPeaks, vyPeaks, vGaussPeak, vParams(3);
	vector<int> vnIndices;
	int ii;

	///Raine 2006-07-07
	//bool bRet = find_peaks_1st_derivative(vxData, vyData, vxPeaks, vyPeaks, vnIndices);
	int nSize = vxData.GetSize();
	int nRet = ocmath_find_peaks_1st_derivative(&nSize, vxData, vyData, vxPeaks, vyPeaks, vnIndices);
	//if(!bRet)
	if(nRet != OE_NOERROR)
	{
		return false;
	}
	vxPeaks.SetSize(nSize);
	vyPeaks.SetSize(nSize);
	vnIndices.SetSize(nSize);
	///END

	double dSumFWHM = 0.0;
	double dfwhm = 0.0;
	int nStart, nEnd, jj, kk;
	double dxHalfStart, dxHalfEnd, dHalfAmplitude;
	double dCenter, dArea, dWidth;
	for(ii = 0; ii< vxPeaks.GetSize(); ii++)
	{
		create_Gauss_peak_by_nlsf_evluate(vxData, vyData, vxPeaks[ii], vyPeaks[ii],
				POSITIVE_DIRECTION, 11, vGaussPeak, vParams, &nStart, &nEnd);

		dCenter = vParams[0];
		dArea = vParams[1];
		dWidth = vParams[2];

		for(jj = nStart; jj <= nEnd; jj++)
		{
			if(vxData[jj] == dCenter)
			{
				break;
			}
		}

		if(jj > nEnd)
		{
			return false;
		}

		dHalfAmplitude = vGaussPeak[jj]/2.0;
		for(jj = nStart, kk = nEnd; jj < kk; jj++, kk--)
		{
			if(vGaussPeak[jj] == dHalfAmplitude)
			{
				dxHalfStart = vxData[jj];
			}
			if(vGaussPeak[kk] == dHalfAmplitude)
			{
				dxHalfEnd = vxData[kk];
			}
		}
		dfwhm = dxHalfEnd - dxHalfStart;
		dSumFWHM += dfwhm;
	}

	dfwhm = dSumFWHM / vxPeaks.GetSize();

	///get gaussian window by fwhm
	///formula in matlab is exp((-0.5)*pow((x/sigma), 2.0))
	/// fwhm = 2*sqrt(2*ln(2))*sigma
	double sigma = dfwhm/(2.0*sqrt(2.0*ln(2)));
	int nLength = vyData.GetSize()/vxPeaks.GetSize();
	vGaussian.SetSize(nLength);
	vGaussian.Data(-nLength/2, nLength/2);
	for(ii = 0; ii < nLength; ii++)
	{
		vGaussian[ii]= exp( pow( (vGaussian[ii]/(2.0*sigma)), 2) * (-0.5) );
	}
	///end get gaussian window

	return true;
}

*/

///GET_GAUSSIAN_FILTER

/*  //Sandy 2008-3-18  remove pfmControlLine
/// Hong 04/19/07 v8.0604 NEW_LINE_CONTROL_CLASS_FOR_PFM_XF_NEEDED_BY_SANDY
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////member functons of pfmLineControl////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
pfmLineControl::pfmLineControl(const GraphObject & goOriginal)
{
	m_nPlotIndex = -1;

	Init(goOriginal);
}

pfmLineControl::pfmLineControl(const GraphLayer& gl, LPCSTR lpcszName)
{
	m_nPlotIndex = -1;

	if(gl)
	{
		GraphObject gr;
		gr = gl.GraphObjects(lpcszName);

		Init(gr);
	}
}

bool pfmLineControl::Init(const GraphObject & goOriginal)
{
	if ( goOriginal )
	{
		m_goLine = goOriginal;
		string strLineName = goOriginal.GetName();
		string strIndex = strLineName.GetToken(1, '_');
		m_nPlotIndex = atoi(strIndex);

		GraphLayer gl;
		m_goLine.GetParent(gl);
		m_goHorizonLine = gl.GraphObjects(strLineName + "_Horiz");

		///Sandy 2007-7-9 change one half line to two for better controling.
		//m_goHalfLine = gl.GraphObjects(strLineName + "_Half");
		m_goHalfLeftLine = gl.GraphObjects(strLineName + "_HalfL");
		m_goHalfRightLine = gl.GraphObjects(strLineName + "_HalfR");
		//end

		vector<uint> vnUIDs;
		if(m_goLine.GetConnectedObjects(vnUIDs) > 0)
		{
			GraphObject goText;
			goText = Project.GetObject(vnUIDs[0]);

			if (goText)
				m_goLabel = goText;
		}
	}

	return IsValid();
}


///Sandy 2007-4-26 delete trSetting since the infomation can be create from dataplot
//bool pfmLineControl::Create(const GraphLayer& gl, LPCSTR lpcszNameBase, const DataPlot& dp, const TreeNode& trSetting, LPCSTR lpcszLabel)
//bool pfmLineControl::Create(const GraphLayer& gl, LPCSTR lpcszNameBase, const DataPlot& dp, LPCSTR lpcszLabel)
bool pfmLineControl::Create(const GraphLayer& gl, LPCSTR lpcszNameBase, const DataPlot& dp, LPCSTR lpcszLabel, const DataPlot& dpBase)
{
	if ( !gl || !dp )
		return false;

	m_nPlotIndex = dp.GetIndex();

	string strObjName(lpcszNameBase);
	strObjName = strObjName + "_" + m_nPlotIndex;

	gl.RemoveGraphObject(strObjName);
	gl.RemoveGraphObject(strObjName + "_Label");
	gl.RemoveGraphObject(strObjName + "_Horiz");

	//gl.RemoveGraphObject(strObjName + "_Half");
	gl.RemoveGraphObject(strObjName + "_HalfL");
	gl.RemoveGraphObject(strObjName + "_HalfR");

	double dX, dY, dHalfWidth;

	///Sandy 2007--6-11 add for centralize code
	getDataPlotControlsPos(dp, dX, dY, dHalfWidth, dpBase);

	add_line(gl, m_goLine, dX, dY, ATTACH_TO_SCALE, LN_VERTICAL, true, false);
	m_goLine.Info.System.Parameters.MousePointer = GOMP_OBJECT_WITH_SCRIPT;
	disable_go_move(m_goLine, false);
	m_goLine.SetName(strObjName);

	string strLTScript;
	strLTScript.Format("events_from_pka_control_line_go(%d, %%1)", m_nPlotIndex);
	//string strLTScript = "";
	//if(trSetting.LTScript)
	//{
		//// for any event, %1 from LT will have the event id
		//strLTScript.Format("%s(%d, %%1)", trSetting.LTScript.strVal, m_nPlotIndex);
	//}

	///Sandy 2007-4-26 remove trSetting
	//int nEvent = (trSetting.EventID ? trSetting.EventID.nVal : GRCT_ANY_EVENT);
	int nEvent = GRCT_ANY_EVENT;

	set_LT_script(m_goLine, strLTScript, nEvent);

	string strText;
	if (lpcszLabel != NULL)
		strText = lpcszLabel;
	else
		strText.Format(" %d ", m_nPlotIndex);

	///Sandy move the lable under the cross
	//add_label(gl, m_goLabel, dX , dY, strText);
	add_label(gl, m_goLabel, dX , dY/2.0, strText);

	m_goLabel.SetName(strObjName + "_Label");
	set_go_selectable(m_goLabel, false);
	m_goLabel.ConnectTo(m_goLine, -1, -1, false);

	// horizontal control line
	double dX1, dY1;
	dX1 = dX;
	dY1 = dY;

	//add_line(gl, m_goHorizonLine, dX, dY, ATTACH_TO_SCALE, LN_HORIZONTAL, true, false);
	add_line(gl, m_goHorizonLine, dX-dHalfWidth, dY, ATTACH_TO_SCALE, LN_HORIZONTAL, false, false, dX+dHalfWidth, dY);
	m_goHorizonLine.Info.System.Parameters.MousePointer = GOMP_MOVE_VERTICAL;

	disable_go_move(m_goHorizonLine, true, false);
	m_goHorizonLine.SetName(strObjName + "_Horiz");
	set_LT_script(m_goHorizonLine, strLTScript, nEvent);
	m_goHorizonLine.Show(false); // default hidden


	//Half width control line
	double dX0 = dX - dHalfWidth/2.0;
	//double dX0 = dX;
	dX1 = dX + dHalfWidth/2.0;
	dY1 = dY/2.0;

	///Sandy 2007-7-9 change one half line to two for better controling.
	//add_line(gl, m_goHalfLine, dX0, dY1, ATTACH_TO_SCALE, LN_HORIZONTAL, false, false, dX1, dY1);
	//m_goHalfLine.Info.System.Parameters.MousePointer = GOMP_MOVE_SQUARE_HORIZONTAL;
	////m_goHalfLine.Info.System.Parameters.MousePointer = MAKELONG(GOMP_OBJECT_WITH_SCRIPT, GOMP_MOVE_SQUARE_HORIZONTAL);

	//m_goHalfLine.SetName(strObjName + "_Half");
	//set_LT_script(m_goHalfLine, strLTScript, nEvent);
	//m_goHalfLine.Show(false); // default hidden

	add_line(gl, m_goHalfLeftLine, dX0, dY1, ATTACH_TO_SCALE, LN_HORIZONTAL, false, false, dX, dY1);
	//m_goHalfLeftLine.Info.System.Parameters.MousePointer = MAKELONG(GOMP_NONE, GOMP_MOVE_SQUARE_HORIZONTAL);
	m_goHalfLeftLine.Info.System.Parameters.MousePointer = GOMP_MOVE_SQUARE_HORIZONTAL;
	add_line(gl, m_goHalfRightLine, dX, dY1, ATTACH_TO_SCALE, LN_HORIZONTAL, false, false, dX1, dY1);
	//m_goHalfRightLine.Info.System.Parameters.MousePointer = MAKELONG(GOMP_NONE, GOMP_MOVE_SQUARE_HORIZONTAL);
	m_goHalfRightLine.Info.System.Parameters.MousePointer = GOMP_MOVE_SQUARE_HORIZONTAL;

	m_goHalfLeftLine.SetName(strObjName + "_HalfL");
	strLTScript.Format("events_from_pka_control_line_go(%d, %%1, 1)", m_nPlotIndex); // 1 : Left Half Line
	set_LT_script(m_goHalfLeftLine, strLTScript, nEvent);
	m_goHalfLeftLine.Show(false); // default hidden

	m_goHalfRightLine.SetName(strObjName + "_HalfR");
	strLTScript.Format("events_from_pka_control_line_go(%d, %%1, 2)", m_nPlotIndex); // 2 : Right Half Line
	set_LT_script(m_goHalfRightLine, strLTScript, nEvent);
	m_goHalfRightLine.Show(false); // default hidden
	//end







	// setting state of half line, this maybe utility function in grobj_utils
	Tree tr;
	//tr = m_goHalfLine.GetFormat(FPB_OTHER, FOB_ALL, true, true);
	//
	/////Sandy 2007-6-11 debug and improve
	////tr.Root.States.nVal |= GOC_NO_MOVE|GOC_NO_ROTATE|GOC_NO_SKEW|GOC_NO_EDIT;
	//tr.Root.States.nVal |= GOC_NO_MOVE|GOC_NO_ROTATE|GOC_NO_SKEW;
	//tr.Root.Arrow.Begin.Style.nVal = 12;
	//tr.Root.Arrow.End.Style.nVal = 12;
	//tr.Root.Arrow.Begin.Width.nVal = 5;
	//tr.Root.Arrow.Begin.Length.nVal = 5;
	//tr.Root.Arrow.End.Width.nVal = 5;
	//tr.Root.Arrow.End.Length.nVal = 5;
	//int nErr = m_goHalfLine.UpdateThemeIDs(tr.Root);
	//if(nErr == 0)
	//{
		//m_goHalfLine.ApplyFormat(tr, true, true);
	//}

	///Sandy 2007-7-9 change one half line to two for better controling.
	tr = m_goHalfLeftLine.GetFormat(FPB_OTHER, FOB_ALL, true, true);

	tr.Root.States.nVal |= GOC_NO_MOVE|GOC_NO_ROTATE|GOC_NO_SKEW;
	tr.Root.Arrow.Begin.Style.nVal = 12;
	tr.Root.Arrow.End.Style.nVal = 0;
	tr.Root.Arrow.Begin.Width.nVal = 5;
	tr.Root.Arrow.Begin.Length.nVal = 5;
	tr.Root.Arrow.End.Width.nVal = 5;
	tr.Root.Arrow.End.Length.nVal = 5;
	int nErr = m_goHalfLeftLine.UpdateThemeIDs(tr.Root);
	if(nErr == 0)
	{
		m_goHalfLeftLine.ApplyFormat(tr, true, true);
	}

	tr = m_goHalfRightLine.GetFormat(FPB_OTHER, FOB_ALL, true, true);

	tr.Root.States.nVal |= GOC_NO_MOVE|GOC_NO_ROTATE|GOC_NO_SKEW;
	tr.Root.Arrow.Begin.Style.nVal = 0;
	tr.Root.Arrow.End.Style.nVal = 12;
	tr.Root.Arrow.Begin.Width.nVal = 5;
	tr.Root.Arrow.Begin.Length.nVal = 5;
	tr.Root.Arrow.End.Width.nVal = 5;
	tr.Root.Arrow.End.Length.nVal = 5;
	nErr = m_goHalfRightLine.UpdateThemeIDs(tr.Root);
	if(nErr == 0)
	{
		m_goHalfRightLine.ApplyFormat(tr, true, true);
	}

	///////the format of horizon line at the peaks top
	tr = m_goHorizonLine.GetFormat(FPB_OTHER, FOB_ALL, true, true);
	tr.Root.States.nVal |= GOC_NO_ROTATE|GOC_NO_SKEW;
	tr.Root.Arrow.Begin.Style.nVal = 0;
	tr.Root.Arrow.Begin.Width.nVal = 5;
	tr.Root.Arrow.Begin.Length.nVal = 5;
	tr.Root.Arrow.End.Style.nVal = 0;
	tr.Root.Arrow.End.Width.nVal = 5;
	tr.Root.Arrow.End.Length.nVal = 5;

	nErr = m_goHorizonLine.UpdateThemeIDs(tr.Root);
	if(nErr == 0)
	{
		m_goHorizonLine.ApplyFormat(tr, true, true);
	}

	////the format of vertical central line in the middle of peaks
	tr = m_goLine.GetFormat(FPB_OTHER, FOB_ALL, true, true);
	tr.Root.States.nVal |= GOC_NO_ROTATE|GOC_NO_SKEW;
	tr.Root.Arrow.End.Style.nVal = 6;
	tr.Root.Arrow.End.Width.nVal = 7;
	tr.Root.Arrow.End.Length.nVal = 15;
	tr.Root.Color.nVal = 5;

	nErr = m_goLine.UpdateThemeIDs(tr.Root);
	if(nErr == 0)
	{
		m_goLine.ApplyFormat(tr, true, true);
	}

	return true;
}

bool pfmLineControl::getDataPlotControlsPos(DataPlot& dp, double& dX, double& dY, double& dHalfWidth, const DataPlot& dpBase)
{
	vector vx, vy;
	if(!get_plot_data_xy(dp, vx, vy))
		return false;

	vector vxTemp, vyTemp;
	vxTemp = vx;
	vyTemp = vy;
    ///add by sandy 2007-11-29 for add support for no subtract baseline and update control position
	long lSize = vx.GetSize();
	vector vbx, vby;
	if(dpBase.IsValid())
	{
		if(!get_plot_data_xy(dpBase, vbx, vby))
			return false;
		double dxMin, dxMax;
		vbx.GetMinMax(dxMin, dxMax);
		long lBSize = vbx.GetSize();
		vector vxbTemp, vybTemp;
		vxbTemp.Data(dxMin, dxMax, (dxMax-dxMin)/(lSize-1));
		vybTemp.SetSize(lSize);
		if(0 != ocmath_interpolate(vxbTemp, vybTemp, lSize, vbx, vby, lBSize, INTERP_TYPE_LINEAR))
		{
			return false;
		}
		vxTemp = vx;
		vyTemp = vy - vybTemp;
	}
	///end/////

	///detect the direction of peak
	double dYMax, dYMin, dYSum;
	uint nIndexMin, nIndexMax, nSize;
	nSize = vyTemp.GetSize();
	vyTemp.GetMinMax(dYMin, dYMax,  &nIndexMin, &nIndexMax);
	vyTemp.Sum(dYSum);
	//bool bPositive = (( (dYSum/nSize)>=(vy[0]+vy[nSize-1])/2)  ? true: false);
	//bool bPositive = (( (dYSum/nSize)>=0)  ? true: false); ///need to improve, should use baseline to justify
	//bool bPositive = (( (dYSum/nSize)>=(vy[0]+vy[vy.GetSize()-1])/2)  ? true: false);
	//bool bPositive = ((abs((int)(nSize/2 - nIndexMax)) < abs((int)(nSize/2 - nIndexMin)))? true: false);
	bool bPositive;
	if( (abs(vyTemp[nSize-1]-dYMin) + abs(vyTemp[0]-dYMin)) < ( abs(vyTemp[nSize-1]-dYMax)) + abs(vyTemp[0]-dYMax ) )
		bPositive = true;
	else
		bPositive = false;
	//end

	uint nMIndex = (bPositive? nIndexMax : nIndexMin);
	dX = vx[nMIndex];
	dY = vyTemp[nMIndex];

	vector<uint> vecIndex;

	int nFound;
	if(bPositive)
	{
		nFound = vyTemp.Find(vecIndex, dY/2.0, dY, 8, 0, nMIndex);
	}
	else
	{
		nFound = vyTemp.Find(vecIndex,  dY, dY/2.0, 8, 0, nMIndex);
	}
	if(-1 ==  nFound|| vecIndex.GetSize() == 0)
	{
		return false;
	}
	int d = nMIndex - vecIndex[0];
	int nStart = (nMIndex - d)<0? 0:(nMIndex - d);
	int nEnd = (nMIndex + d)>=nSize? nSize-1:(nMIndex + d);
	dHalfWidth = vx[nEnd] - vx[nStart];


	return true;
}

///Sandy 2007-6-11 move the control lines to attach the dataplot
bool pfmLineControl::updateControlsPos(double dX, double dY, double dHalfWidth)
{
	///Sandy 2007-7-9 change one half line to two for better controling.
	//if(m_goHalfLine.IsValid())
	//{
		//move_hline(m_goHalfLine, dX-dHalfWidth, dX+dHalfWidth, dY/2.0);
	//}

	if(m_goHalfLeftLine.IsValid())
	{
		move_hline(m_goHalfLeftLine, dX-dHalfWidth, dX, dY/2.0);
	}

	if(m_goHalfRightLine.IsValid())
	{
		move_hline(m_goHalfRightLine, dX, dX+dHalfWidth, dY/2.0);
	}
	//end

	if(m_goHorizonLine.IsValid())
	{
		move_hline(m_goHorizonLine, dX-dHalfWidth, dX+dHalfWidth, dY);
	}

	if(m_goLine.IsValid())
	{
		m_goLine.X = dX;
	}

	return true;
}



bool pfmLineControl::UpdateObjectName(LPCSTR lpcszName, LPCSTR lpcszLabel)
{
	if (!IsValid())
		return false;

	m_goLine.SetName(lpcszName);
	string strName = lpcszName;

	m_goHorizonLine.SetName(strName + "_Horiz");

	///Sandy 2007-7-9 change one half line to two for better controling.
	//m_goHalfLine.SetName(strName + "_Half");
	m_goHalfLeftLine.SetName(strName + "_HalfL");
	m_goHalfRightLine.SetName(strName + "_HalfR");

	/// Hong 04/24/07 v8.0607 NEED_UPDATE_SCRIPT_IF_HAVE
	string strPlotIndex;
	strPlotIndex = strName.GetToken(1, '_');
	m_nPlotIndex = atoi(strPlotIndex);

	string strLTScript;
	int nEven = GRCT_ANY_EVENT, nPos;
	if ( get_go_LTScript_event(m_goLine, strLTScript, nEven) )
	{
		nPos = strLTScript.Find('(');
		strLTScript = strLTScript.Left(nPos);
		strLTScript.Format("%s(%d, %%1)", strLTScript, m_nPlotIndex);

		set_LT_script(m_goLine, strLTScript, nEven);
		set_LT_script(m_goHorizonLine, strLTScript, nEven);

		//set_LT_script(m_goHalfLine, strLTScript, nEven);
		set_LT_script(m_goHalfLeftLine, strLTScript, nEven);
		set_LT_script(m_goHalfRightLine, strLTScript, nEven);
	}
	/// end NEED_UPDATE_SCRIPT_IF_HAVE

	string strLabel;
	if (lpcszLabel != NULL)
		strLabel = lpcszLabel;
	else
		strLabel = " " + strName.GetToken(1, '_') + " ";

	strName = strName + "_Label";
	m_goLabel.SetName(strName);
	m_goLabel.Text = strLabel;

	return true;
}

*/ //end of remove pfmControlLine


//bool get_func_info_from_dp(DataPlot dp, string& strFuncName, string& strFuncFDFName, string strCategory, bool bSetDefaultPeakFuncIfNone)
//{
//
//
	//Tree tr;
//
	//if(!dp.GetBinaryStorage("OriginStorage", tr) && !bSetDefaultPeakFuncIfNone)
		//return false;
//
	//if(tr.IsEmpty() && !bSetDefaultPeakFuncIfNone)
	//{
		//return false;
	//}
//
//
	//TreeNode trFunction = tree_check_get_node(tr, BRANCH_FUNCTION_IN_PFM_TREE, 0, NULL, NULL);
//
	//TreeNode trFullPath  = tree_check_get_node(trFunction, TAG_FULLPATH_IN_PFM_TREE, 0, NULL, NULL);
	//TreeNode trFile  = tree_check_get_node(trFunction, TAG_FILE_IN_PFM_TREE, 0, NULL, NULL);
	//TreeNode trFuncName  = tree_check_get_node(trFunction, TAG_FUNCNAME_IN_PFM_TREE, 0, NULL, NULL);
//
	//strFuncFDFName = trFile.strVal;
	//strFuncName = trFuncName.strVal;
//
	//if((strFuncName == "" || strFuncFDFName == "") && !bSetDefaultPeakFuncIfNone)
	//{
		//return false;
	//}
	//else if (strFuncName == "" || strFuncFDFName == "")
	//{
		//strFuncFDFName = STR_PA_DEFAULT_FDF;//"pfmGaussian";
		//strFuncName = STR_PA_DEFAULT_FUNC;//"Gaussian";
//
		//string strFullPath;
		//nlsf_func_to_fdf(strCategory, strFuncName, strFullPath,  true);
//
		//trFile.strVal = strFuncFDFName;
		//trFuncName.strVal = strFuncName ;
		//trFullPath.strVal = strFullPath;
//
		//dp.PutBinaryStorage("OriginStorage", tr);
	//}
//
	//return true;
//}

//void construct_pfw_tree_peak_params_node(TreeNode& tr, vector<string>& vstrParam, vector& vParams)
//{
	////save the parameter to the dataplot
	//TreeNode trParams = tree_check_get_node(tr, BRANCH_PARAMS_IN_PFM_TREE, 0, NULL, NULL);
	//trParams.Reset();
	//if(vstrParam != NULL && vParams!=NULL)
	//{
//
		//for (int jj = 0; jj < vParams.GetSize(); jj++)
		//{
			//TreeNode trPara = trParams.AddNode(cvt_str_to_tag_name(vstrParam[jj]));
			//TREE_SET_DVAL(trPara, "Value", vParams[jj]);
		//}
	//}
//}


//void set_params_info_to_dp(DataPlot dp, vector<string>& vstrParam, vector& vParams)
//{
	//Tree tr;
//
	//if(dp.IsValid())
	//{
		//dp.GetBinaryStorage("OriginStorage", tr);
		//construct_pfw_tree_peak_params_node(tr, vstrParam, vParams);
		//dp.PutBinaryStorage("OriginStorage", tr);
	//}
//
//}
//
//void construct_pfw_tree_peak_func_node(TreeNode& tr, string strFullPath, string strFileName, string strFuncName)
//{
	//TreeNode trFunction = tree_check_get_node(tr, BRANCH_FUNCTION_IN_PFM_TREE, 0, NULL, NULL);
//
	//TreeNode trFullPath  = tree_check_get_node(trFunction, TAG_FULLPATH_IN_PFM_TREE, 0, NULL, NULL);
	//TreeNode trFile  = tree_check_get_node(trFunction, TAG_FILE_IN_PFM_TREE, 0, NULL, NULL);
	//TreeNode trFuncName  = tree_check_get_node(trFunction, TAG_FUNCNAME_IN_PFM_TREE, 0, NULL, NULL);
//
	//trFullPath.strVal = strFullPath;
	//trFile.strVal = strFileName;
	//trFuncName.strVal = strFuncName;
//}


//void set_func_info_to_dp(DataPlot dp, string strFuncName, string strFileName, string strCategory)
//{
	//string strFullPath;
	//nlsf_func_to_fdf(strCategory, strFuncName, strFullPath,  true);
//
	//Tree tr;
	//if(dp.IsValid())
	//{
		//dp.GetBinaryStorage("OriginStorage", tr);
		//construct_pfw_tree_peak_func_node(tr, strFullPath, strFileName, strFuncName);
		////TreeNode trFunction = tree_check_get_node(tr, BRANCH_FUNCTION_IN_PFM_TREE, 0, NULL, NULL);
		////
		////TreeNode trFullPath  = tree_check_get_node(trFunction, TAG_FULLPATH_IN_PFM_TREE, 0, NULL, NULL);
		////TreeNode trFile  = tree_check_get_node(trFunction, TAG_FILE_IN_PFM_TREE, 0, NULL, NULL);
		////TreeNode trFuncName  = tree_check_get_node(trFunction, TAG_FUNCNAME_IN_PFM_TREE, 0, NULL, NULL);
	////
		////trFullPath.strVal = strFullPath;
		////trFile.strVal = strFileName;
		////trFuncName.strVal = strFuncName;
//
		//dp.PutBinaryStorage("OriginStorage", tr);
	//}
//}


//
//bool pfmLineControl::Update(bool bFromControls , double xc, double w, double h, string func)
//{
	//
	//if ( !IsValid() )
		//return false;
	//
	//GraphLayer gl;
	//m_goLine.GetParent(gl);
	//
	//DataPlot dp;
	//dp = gl.DataPlots(m_nPlotIndex);
	//
	//XYRange drXY;
//
	//if(!dp.GetDataRange(drXY))
		//return false;
	//
	//vector vy;
	//vector vx;
	//drXY.GetData(vy, vx);
	////int iSize = vy.GetSize();
	////
	////if(iSize <= 0)
		////return false;
//
	//
	//double dX, dY, dHalfWidth;
	//if(bFromControls)
	//{
		//dX = m_goLine.X;
		//dY = m_goHorizonLine.Y;
		//dHalfWidth = m_goHalfLeftLine.DX;
	//}
	//else
	//{
		//dX = xc;
		//dY = h;
		//dHalfWidth = w/2.0;
	//}
//
	//updateControlsPos(dX, dY, dHalfWidth);
	//
	//
	//string strFuncFDFName, strFuncName;
//
	//if(bFromControls)
		//get_func_info_from_dp(dp, strFuncName, strFuncFDFName);
	//else
	//{
		//nlsf_func_to_fdf(STR_NLSF_CAT_PFM, func, strFuncFDFName,  false);
		//strFuncName = func;
	//}
	//
	//vector voGaussian;
	//vector voGuassianParams;
	//
	//GraphPage gp = gl.GetPage();
	//pfw8_update_peak_data_by_Gaussian(gp, drXY, dX, dHalfWidth, dY, voGaussian, voGuassianParams);
///*
	//vector vGuassianParams(4);//y0, xc, a. w
	//vGuassianParams[0] = 0;
	//vGuassianParams[1] = dX;
	//vGuassianParams[3] = dHalfWidth*2;
	//vGuassianParams[2] = dY*vGuassianParams[3]*sqrt(PI/(4*ln(2)));
//
	//vector vyGaussian;
	//vector vxGaussian;
//
	//if(!nlsf_evaluate(STR_DEFAULT_PEAK, STR_NLSF_CAT_PFM, vx, vyGaussian, vGuassianParams))
		//return false;
	//
	//vector vyFunc;
	//vyFunc = vyGaussian;
	//
	//Page pg = gl.GetPage();
	//vector vbx, vby;
	//if(check_baseline_data(pg, vbx, vby, true))
	//{
		//bool bIsSame;
		//if((vbx.GetSize() != vx.GetSize()) || OE_NOERROR != ocmath_compare_data(vbx.GetSize(), vbx, vx, &bIsSame) || !bIsSame)
		//{
			//int nSize = vx.GetSize();
			//vector vbyNew(nSize), vxBase;
			//vxBase = vx;
			//int nRet = ocmath_interpolate(vxBase, vbyNew, nSize, vbx, vby, vbx.GetSize(), INTERP_TYPE_LINEAR);
			//if(OE_NOERROR != nRet)
			//{
				//return false;
			//}
			//
			//vby = vbyNew;
		//}
		//vyFunc = vyFunc + vby;
	//}
//
	//drXY.SetData(&vyFunc, &vx);
//*/
	//
	////init parameter for user appointed function and save to dataplot
	//if(strFuncName != STR_DEFAULT_PEAK)
	//{
		//vector<string> vstrParam;
		//vector vParams;
//
		//if(!nlsf_init(strFuncFDFName, vx, voGaussian, vstrParam, vParams))
			//return false;
		//
		//set_func_info_to_dp(dp, strFuncName, strFuncFDFName);
		//set_params_info_to_dp(dp, vstrParam, vParams);
	//}
	//else
	//{
		//set_func_info_to_dp(dp, strFuncName, strFuncFDFName);
		//vector<string> vstrGuassianParams = {"y0", "xc", "a", "w"};
		//set_params_info_to_dp(dp, vstrGuassianParams, voGuassianParams);
	//}
//
//
	//return true;
//}
//
//bool pfmLineControl::UpdateParams(const vector& vParams)
//{
	//if ( !IsValid() )
		//return false;
	//
	//GraphLayer gl;
	//m_goLine.GetParent(gl);
	//
	//DataPlot dp;
	//dp = gl.DataPlots(m_nPlotIndex);
	//
	//
	//
	//XYRange drXY;
	//vector vy;
	//vector vx;
	//dp.GetDataRange(drXY);
	//drXY.GetData(vy, vx);
	//int iSize = vy.GetSize();
	//
	//string strFuncName, strFuncFDFName;
	//get_func_info_from_dp(dp, strFuncName, strFuncFDFName);
		//
	//vector<string> vstrParam();
	//vector vInitParams;
	//if(!nlsf_init(strFuncFDFName, vx, vy, vstrParam, vInitParams))
		//return false;
	//
	//if(vParams.GetSize()!=vInitParams.GetSize())
	    //return false;
	//
	//vector vyFunc;
	//vParams[0] = 0;
	//if(!nlsf_evaluate(strFuncName, STR_NLSF_CAT_PFM, vx, vyFunc, vParams))
		//return false;
		//
	//drXY.SetData(&vyFunc, &vx);
	//
	//set_params_info_to_dp(dp,vstrParam, vParams);
	//return true;
//}
//
//bool pfmLineControl::ShowEditControls(bool bShow)
//{
	//if ( !IsValid() )
		//return false;
	//
	//bool bMainObj = m_goLine.Show;
	//m_goHorizonLine.Show(bShow && bMainObj);
	//
	/////Sandy 2007-7-9 change one half line to two for better controling.
	////m_goHalfLine.Show(bShow && bMainObj);
	//m_goHalfLeftLine.Show(bShow && bMainObj);
	//m_goHalfRightLine.Show(bShow && bMainObj);
	////end
	//
	//return true;
//}
//
//void pfmLineControl::UpdateHalfLine(int nActiveHalf)
//{
	//double dX = m_goLine.X;
	//double dY = m_goHorizonLine.Y;
	//
	//double d1 = m_goHalfLeftLine.DX;
	//double d2 = m_goHalfRightLine.DX;
	//if(nActiveHalf == 1) // Left Half is active
	//{
		//move_hline(m_goHalfRightLine, dX, dX + m_goHalfLeftLine.DX, dY/2.0);
	//}
	//else if(nActiveHalf == 2) //Right Half is active
	//{
		//move_hline(m_goHalfLeftLine, dX - m_goHalfRightLine.DX, dX, dY/2.0);
	//}
	//
	//d1 = m_goHalfLeftLine.DX;
	//d2 = m_goHalfRightLine.DX;
//}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////member functons of pfmLineControlList////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//pfmLineControlList::pfmLineControlList(const GraphLayer& gl, LPCSTR lpcszNameBase)
//{
	//m_glTarget = gl;
	//m_strNameBase = lpcszNameBase;
	////m_nCount = 0;
	////m_vnPlotIndex.SetSize(0);
	//initList();
	////m_nActivePlotIndex = m_vnPlotIndex[0];
//}
//
/////Sandy 2007-4-26 Remove trSetting
////int pfmLineControlList::CreateList(const GraphLayer& gl, LPCSTR lpcszNameBase, const TreeNode& trSetting, int nNum, int nPlotOffset)
//int pfmLineControlList::CreateList(const GraphLayer& gl, LPCSTR lpcszNameBase, int nNum, int nPlotOffset)
//{
	//Reset();
	//
	//if (!gl || nNum < -1 )
		//return m_nCount;
	//
	//m_glTarget = gl;
	//m_strNameBase = lpcszNameBase;
//
	//// remove axist objects, maybe move to a function
	//int nPlotNum = gl.DataPlots.Count();
	//int nCount = nPlotNum - nPlotOffset;
	//
	//if ( -1 == nNum ) // if default
		//nNum = nPlotNum;
	//
	//nCount = nNum < nCount ? nNum : nCount;
	//
	////for (int ii=nOffset; ii < nEnd; ii++)
	////{
		////string strTempName;
		////strTempName = m_strNameBase + "_" + ii;
		////gl.RemoveGraphObject(strTempName);
	////}
	//
	//for (int jj=nPlotOffset; jj< nCount + nPlotOffset; jj++)
	//{
		//// remove graphobject if exist
		//string strTempName;
		//strTempName = m_strNameBase + "_" + jj;
		//gl.RemoveGraphObject(strTempName);
		//
		//
		/////Sandy 2007-4-26 Remove trSetting
		////Add(gl.DataPlots(jj), trSetting);
		//Add(gl.DataPlots(jj));
	//}
	//
	////m_nActivePlotIndex = m_vnPlotIndex[0];
	//
	//return m_nCount;
//}
//
/////Sandy 2007-4-26 Remove trSetting
////int pfmLineControlList::CreateList(const GraphLayer& gl, LPCSTR lpcszNameBase, const TreeNode& trSetting, const vector<int> vnPlotIndex)
///// Cloud 04/27/2007 ADD_CUMULATE_INDEX
//int pfmLineControlList::CreateList(const GraphLayer& gl, LPCSTR lpcszNameBase,  const vector<int> vnPlotIndex)
////int pfmLineControlList::CreateList(const GraphLayer& gl, LPCSTR lpcszNameBase,  const vector<int> vnPlotIndex, const int nCumIndex)
//{
	//Reset();
//
	//if (!gl || vnPlotIndex.GetSize() < 0)
		//return m_nCount;
//
	//m_glTarget = gl;
	//m_strNameBase = lpcszNameBase;
//
	//int nPlotNum = gl.DataPlots.Count();
//
	//for (int ii=0; ii < vnPlotIndex.GetSize(); ii++)
	//{
		//// remove graphobject if exist
		//if ( vnPlotIndex[ii] > nPlotNum )
			//continue;
		//
		//string strTempName;
		//strTempName = m_strNameBase + "_" + vnPlotIndex[ii];
		//gl.RemoveGraphObject(strTempName);
		//
		/////Sandy 2007-4-26 Remove trSetting
		////Add(gl.DataPlots(vnPlotIndex[ii]), trSetting);
		//Add(gl.DataPlots(vnPlotIndex[ii]));
	//}
//
	///// Cloud 04/27/2007 ADD_CUMULATE_INDEX
	////if (nCumIndex <= nPlotNum)
	////{
		////string strTempName;
		////strTempName = m_strNameBase + "_" + nCumIndex;
		////gl.RemoveGraphObject(strTempName);
		////Add(gl.DataPlots(nCumIndex));
	////}
	///// End ADD_CUMULATE_INDEX
	//
	////m_nActivePlotIndex = m_vnPlotIndex[0];
//
	//return m_nCount;
//}
//
//pfmLineControl pfmLineControlList::GetAt(int nIndex)
//{
	//pfmLineControl lctrlInvalid;
	////if ( !IsValid() || nIndex > m_nCount )
	//if ( !IsValid() || nIndex > m_nCount || nIndex < 0  )
		//return lctrlInvalid;
	//
	//string strName = m_strNameBase + "_" + m_vnPlotIndex[nIndex];
//
	//pfmLineControl lineCtrl(m_glTarget, strName);
	//
	//return lineCtrl;
//}
//
//pfmLineControl pfmLineControlList::GetByPlotIndex(int nPlotIndex)
//{
	//int nIndex = find_in_list(nPlotIndex, m_vnPlotIndex, true);
//
	//return GetAt(nIndex);
//}
//
//int pfmLineControlList::RemoveAt(int nIndex)
//{
	//if ( !IsValid() || m_nCount < nIndex || nIndex < 0 )
		//return -1;
	//
	//int nPlotIndex = m_vnPlotIndex[nIndex];
	//
	//string strTempName;
	//strTempName = m_strNameBase + "_" + nPlotIndex;
	//m_glTarget.RemoveGraphObject(strTempName);
	//
	/////Sandy add to delete label
	//m_glTarget.RemoveGraphObject(strTempName + "_Label");
	//
	/////Sandy add to delete contol lines
	//m_glTarget.RemoveGraphObject(strTempName + "_Horiz");
	//m_glTarget.RemoveGraphObject(strTempName + "_HalfL");
	//m_glTarget.RemoveGraphObject(strTempName + "_HalfR");
	//
	//DataPlot dp = m_glTarget.DataPlots(nPlotIndex);
//
	//if(!dp.IsValid())
	//{
		//return -1;
	//}
//
	//XYRange xyr;
	//dp.GetDataRange(xyr);
	//Worksheet wks;
	//int nC1, nC2;
	//xyr.GetRange(wks, nC1, nC2);
	//dp.AttachXFunction("");
	//Column colY;
	//xyr.GetYColumn(colY);
	//wks.DeleteCol(colY.GetIndex());
//
	////end
	//
	//updateObjectsAfterRemoveAt(nIndex + 1);
//
	//m_vnPlotIndex.RemoveAt(nIndex);
	//
	//m_nCount--;
	//
	//return nPlotIndex;
//
//}
//
//int pfmLineControlList::RemoveByPlotIndex(int nPlotIndex)
//{
	//int nIndex = find_in_list(nPlotIndex, m_vnPlotIndex, true);
	//
	//return RemoveAt(nIndex);
//}
//
//int pfmLineControlList::RemoveAll()
//{
	//int nCount = 0;
	//
	//if ( !IsValid() )
		//return 0;
	//
	//for (int ii=m_nCount; ii > 0; ii--) // remove from the end to avoid problem of m_vnPlotIndex size
	//{
		//if ( -1 != RemoveAt(ii - 1) )
			//nCount++;
	//}
	//
	//return nCount;
//}
//
/////Sandy 2007-4-26 remove trSetting
////int pfmLineControlList::Add(const DataPlot& dp, const TreeNode& trSetting, bool bReplace)
//int pfmLineControlList::Add(const DataPlot& dp, bool bReplace)
//{
	//int nPlotIndex = dp.GetIndex();
	//
	//int nIndex = find_in_list(nPlotIndex, m_vnPlotIndex, true);
	//
	//if ( ( bReplace && nIndex != -1 ) || ( !bReplace && -1 == nIndex ) )
	//{
		//pfmLineControl listCtrl;
		/////Sandy 2007-4-26 remove trSetting
		////if ( !listCtrl.Create(m_glTarget, m_strNameBase, dp, trSetting) )
		//if ( !listCtrl.Create(m_glTarget, m_strNameBase, dp) )
			//return -1;
		//
		//if ( -1 == nIndex )
		//{
			//m_vnPlotIndex.Add(nPlotIndex);
			//m_vnPlotIndex.Sort();
			//m_nCount++;
			////update label to index in m_vnPlotIndex ask by Sandy
			//int iLabel = 1+find_in_list(nPlotIndex, m_vnPlotIndex, true);
			//string strName, strLabel;
			//strName = m_strNameBase + "_" + nPlotIndex;
			//strLabel.Format(" %d ", iLabel);
			//listCtrl.UpdateObjectName(strName, strLabel);
		//}
	//}
	//
	//return nPlotIndex;
//}
//
//bool pfmLineControlList::UpdateEditControls(int nPlotIndex)
//{
	//if ( !IsValid() )
		//return false;
	//
	//for (int ii=0; ii < m_nCount; ii++)
	//{
		//pfmLineControl listCtrl;
		//listCtrl = GetAt(ii);
		//listCtrl.ShowEditControls();
	//}
	//
	//pfmLineControl lc;
	//lc = GetByPlotIndex(nPlotIndex);
	//
	//if(lc.IsValid() )
		//lc.ShowEditControls(true);
	//
	//return true;
//}
//
//int pfmLineControlList::updateObjectsAfterRemoveAt(int nIndexOffset)
//{
	//int nCount = 0;
	//for (int ii = nIndexOffset; ii < m_nCount; ii++)
	//{
		//pfmLineControl listCtrl;
		//listCtrl = GetAt(ii);
		//if(listCtrl.IsValid())
		//{
			//m_vnPlotIndex[ii] = m_vnPlotIndex[ii] - 1;
			//string strName, strLabel;
			//strName = m_strNameBase + "_" + m_vnPlotIndex[ii];
			//strLabel.Format(" %d ", ii);
			//if ( !listCtrl.UpdateObjectName(strName, strLabel) )
				//return nCount;
			//
			//nCount++;
		//}
	//}
	//
	//return nCount;
//}
//
//int pfmLineControlList::initList()
//{
	//int nPlotNum = m_glTarget.DataPlots.Count();
	//
	//m_vnPlotIndex.SetSize(0);
	//m_nCount = 0;
//
	//for (int ii=0; ii < nPlotNum; ii++)
	//{
		//string strName = m_strNameBase + "_" + ii;
	//
		//pfmLineControl listCtrl(m_glTarget, strName);
		//
//
		//if (listCtrl.IsValid())
		//{
			//m_vnPlotIndex.Add(ii);
			//m_nCount++;
		//}
	//}
//
	//return m_vnPlotIndex.GetSize();
//}
//
//bool pfmLineControlList::ShowAll(bool bShow)
//{
	//if ( !IsValid() )
		//return false;
	//
	//for (int ii=0; ii < m_nCount; ii++)
	//{
		//pfmLineControl listCtrl;
		//listCtrl = GetAt(ii);
		//listCtrl.ShowControls(bShow);
		//
		/////Sandy 2007-11-10 add to hide and show the dataplot attach on the control
		//DataPlot dp = m_glTarget.DataPlots(m_vnPlotIndex[ii]);
		//if(dp.IsValid())
			//dp.Show(bShow);
		//
	//
	//
	//}
	//return true;
//}
//
//bool pfmLineControlList::DisableControl()
//{
	//if ( !IsValid() )
		//return false;
	//
	//for (int ii=0; ii < m_nCount; ii++)
	//{
		//pfmLineControl listCtrl;
		//listCtrl = GetAt(ii);
		//listCtrl.ShowControls(false);
//
	//}
	//return true;
//}
//
//bool pfmLineControlList::GetPeaksInfoList(vector<int>& vnPlotIndex,
						//vector<int>& vnLabel,
						//vector& vxc,
						//vector& vw,
						//vector& vh,
						//vector<string>& vstrFunc)
//{
	//vnPlotIndex = m_vnPlotIndex;
	//vnLabel.SetSize(m_nCount);
	//vxc.SetSize(m_nCount);
	//vw.SetSize(m_nCount);
	//vh.SetSize(m_nCount);
	//vstrFunc.SetSize(m_nCount);
	//
	//for(int ii = 0; ii<m_nCount; ii++)
	//{
		//pfmLineControl lc;
		//lc = GetByPlotIndex(vnPlotIndex[ii]);
		//if(!lc.IsValid())
			//out_int("peak %d not found", ii+1);
		//
		//vnLabel[ii] = lc.GetLabelNum();
		//vxc[ii] = lc.GetPeakCenter();
		//vw[ii] = lc.GetPeakHalfWidth();
		//vh[ii] = lc.GetPeakHeight();
		//
		//DataPlot dp = m_glTarget.DataPlots(vnPlotIndex[ii]);
		//string strFuncName, strFuncFDFName;
		//get_func_info_from_dp(dp, strFuncName,strFuncFDFName);
		//vstrFunc[ii] = strFuncName;
	//}
	//return true;
//}
//
/// end NEW_LINE_CONTROL_CLASS_FOR_PFM_XF_NEEDED_BY_SANDY


/* ---Sandy 2008-3-18 remove pfmLineControl
/// Hong 04/25/07 v8.0608 MOVE_TO_PFM_UTILS
// move from grobj_utils
/// Hong 04/19/07 v8.0604 NEW_LINE_CONTROL_CLASS_FOR_PFM_XF_NEEDED_BY_SANDY
//---create a new line list class for pfm xfs needed by Sandy
void events_from_pka_control_line_go(int nID, int nEvent, int nHalfLine = 0)
{
	if(nEvent != OE_UPDATE)
	{

		GraphLayer gl = Project.ActiveLayer();

		if (OE_MOVE == nEvent || OE_RESIZE == nEvent || OE_GRAPHOBJ_EDIT == nEvent)
		{

			string strObjName(PEAK_ANCHOR_CONTROL_LINE_NAME);
			strObjName = strObjName + "_" + nID;

			pfmLineControl lc(gl, strObjName);
			if(nHalfLine != 0)
			{
				lc.UpdateHalfLine(nHalfLine);
			}

			if(lc.Update())
			{
				post_getn_dialog_message(WM_USER_ON_GRAPH_OBJECT_CHANGE, -2);//only need to update sum plot
			}
			else
				post_getn_dialog_message(WM_USER_ON_GRAPH_OBJECT_CHANGE, -10);//error



			return ;
		}

		if (OE_SELECT == nEvent)
		{
			//string strName = PEAK_ANCHOR_CONTROL_LINE_NAME+"_"+(string)nID;
			pfmLineControlList lcl(gl, PEAK_ANCHOR_CONTROL_LINE_NAME);
			if(!lcl.IsValid())
				return;

			lcl.UpdateEditControls(nID);

			///Sandy 2007-6-25 for update function type
			post_getn_dialog_message(WM_USER_ON_GRAPH_OBJECT_CHANGE, nID);// load dataplot function

			return ;
		}

	}
}
///--- end of remove pfmLineControl


/// end NEW_LINE_CONTROL_CLASS_FOR_PFM_XF_NEEDED_BY_SANDY
/// end MOVE_TO_PFM_UTILS
*/
static bool _get_filename_and_params_from_pfm_tree(TreeNode trFit, const int nIndex, string& strFullPathFileName, string& strFuncName, vector& vFitParams)
{
	TreeNode& trPeaks = trFit.GetNode(PFM_PEAKS_TREE_TAG_NAME, false);

    if(!trPeaks.IsValid())
    	return false;

	TreeNode& tr = trPeaks.GetNode("Peak"+(string)(nIndex + 1), false);

    if(!tr.IsValid())
    	return false;

	TreeNode trFunction = tr.GetNode(BRANCH_FUNCTION_IN_PFM_TREE, false);
    if(!trFunction.IsValid())
    	return false;

	TreeNode trFullPath = trFunction.GetNode(TAG_FULLPATH_IN_PFM_TREE, false);
	//TreeNode trFile = trFunction.GetNode("File", false);
	TreeNode trFunc = trFunction.GetNode(TAG_FUNCNAME_IN_PFM_TREE, false);

	TreeNode trParams = tr.GetNode(BRANCH_PARAMS_IN_PFM_TREE, false);

	if(!trFullPath ||!trFunc || !trParams)
		return false;

	strFuncName = trFunc.strVal;
	strFullPathFileName = trFullPath.strVal;

	//if(!nlsf_func_to_fdf( "PFM", strFuncName, strFullPathFileName, true))
		//return false;


	int nCount = trParams.GetNodeCount();
	vFitParams.SetSize(nCount);
	int ii = 0;
	foreach( TreeNode trNode in trParams.Children )
	{
		vFitParams[ii] = trNode.Value? trNode.Value.dVal : NANUM;
		ii++;
	}

	///Sandy 2007-11-21 add y0 back if it isn't the first peak
	TreeNode trFirstP = trParams.FirstNode;
	if(trFirstP.tagName != "y0")
	{
		vFitParams.InsertAt(0, 0);
	}

	if(strFuncName == "" || strFullPathFileName == "" || vFitParams.GetSize() == 0)
		return false;


	return true;


}

///Kyle 11/24/2008 CALCULATE_PEAKS_CHARACTERIZATION_HAS_BEEN_MOVED_TO_FITPEAK
//////Sandy 2007-7-4 Peaks' Characterize functions//////////////////
//int calculate_peaks_characterization( vector& vx, matrix& mPeaksData, vector& vXCenters, vector& vXWidth, vector& vyCum,
		 //TreeNode trFitPeaks,
         //const PFMPeakCharsRequire xRequireList, PFMPeakCharsVaule* pxPFMPeakCharsValueList,
         //double dWidthAtPercent, double dAreaAbovePercent, double dCumAreaTo,
         //int nMomentMethod)	///Jasmine 05/16/08 MOMENTS_COMPUTE_METHOD
//{
	//////debug
	////int nT0 = GetTickCount();
	////int nT = nT0;
//
	//if(!_check_if_need_compute_peaks_characterization(xRequireList))
		//return mPeaksData.GetNumCols();
//
	////prepare data integration result
	//IntegrationResult xCumIntg;
	//// Jack 05/04/2008 ADD_ERROR_CHECKING_FOR_INTEGRATION
	//int nRet = ocmath_integrate(vx, vyCum, 0, vx.GetSize()-1, &xCumIntg, NULL, ABSOLUTE_AREA);
	//if (nRet<0)
		//{
			//return nRet;
		//}
	//// End ADD_ERROR_CHECKING_FOR_INTEGRATION
//
	//////debug
	////out_int("Integ Cum curve in:", GetTickCount() - nT);
	////nT =  GetTickCount() ;
//
	////decompose data
	//int nNumPeaks = mPeaksData.GetNumCols();
 	//ASSERT(vXCenters.GetSize() == nNumPeaks);
 	//ASSERT(vXWidth.GetSize() == nNumPeaks);
//
	//double xcLast, wLast;
//
	////------ Folger 04/10/08 QA80-11364 REDUCE_FDF_LOADING_AND_SETTING_TREE_IN_PEAK_CALCULATION
	//string				strLastFuncName;
	//Tree				trFF;
	//NumericFunction		NF;
	////------
	////int nBegin = GetTickCount();// temp
//
	//////Sandy 2008-5-15 move generate infinite peak data outside
	///*
    //for( int nIndex = nNumPeaks - 1; nIndex >=0 ; nIndex-- )
    //{
//
    	//vector vy;
        //if(!mPeaksData.GetColumn( vy, nIndex))
        	//continue;
//
       //string strFullPathFileName,  strFuncName;
       //vector vFitParams;
//
       //if(_get_filename_and_params_from_pfm_tree(trFitPeaks, nIndex, strFullPathFileName, strFuncName, vFitParams))
       //{
       	////------ Folger 04/10/08 QA80-11364 REDUCE_FDF_LOADING_AND_SETTING_TREE_IN_PEAK_CALCULATION
		  //if ( strFuncName.CompareNoCase(strLastFuncName) != 0 )
		  //{
				//strLastFuncName = strFuncName;
				//if( !nlsf_FDF_to_tree(strFullPathFileName, &trFF) )
				//{
					//out_str("Invalid function file");
					//continue;
				//}
				//if (!NF.SetTree(trFF))
				//{
					//out_str("Invalid function");
					//continue;
				//}
		  //}
		  ////------ End REDUCE_FDF_LOADING_AND_SETTING_TREE_IN_PEAK_CALCULATION
          //PFMPeakCharsVaule& rxCharsList = pxPFMPeakCharsValueList[nIndex];
//
          /////Sandy 2008-5-12 add tow more varible for calculate
          ////// Jack 05/04/2008 ADD_ERROR_CHECKING_FOR_CALCULATE_PEAK_CHARACTERIZATION
	      ////bool bRet=cal_peak_characterization(vx, vy, xCumIntg, strFullPathFileName,  strFuncName, vFitParams,
	      //bool bRet=cal_peak_characterization(vx, vy, vXCenters[nIndex], vXWidth[nIndex], xCumIntg, strFuncName, vFitParams,
	      								//xRequireList, rxCharsList,
	         							//dWidthAtPercent, dAreaAbovePercent, dCumAreaTo, xcLast, wLast
	         							////------ Folger 04/10/08 QA80-11364 REDUCE_FDF_LOADING_AND_SETTING_TREE_IN_PEAK_CALCULATION
	         							//, trFF, NF);
	         							////------
//
//
	      //if (false == bRet) return -1; // hard code -1: tobe changed into an error code
//
	      //// End ADD_ERROR_CHECKING_FOR_CALCULATE_PEAK_CHARACTERIZATION
        //}
//
//
//
    //}
    ////out_int("Total Time =", (GetTickCount() - nBegin));//temp
    //*/
//
   	////temp workbook for save every infinite peak data
	//WorksheetPage wkpTemp;
	//wkpTemp.Create("Origin",  CREATE_HIDDEN|CREATE_SET_MISSING_IN_MANAGER);
	//Worksheet wks = wkpTemp.Layers(0);
	//wks.SetSize(-1, nNumPeaks*2);
//
	//double dIdealCumArea;
	//Tree  treeIdealPeaks;
	//Tree  treeFitPeaksParams;
//
	//vector<string> vstrFuncName;
	//vstrFuncName.SetSize(nNumPeaks);
//
	//////debug
	////out_int("Prepare empty wkbook in:", GetTickCount() - nT);
	////nT =  GetTickCount() ;
//
	/////prepare data
//
	//// Jack 05/16/2008 ADD_FUNCTION_INTEGRAL_FOR_AREA_FIT_T
	//double dxmin, dxmax;
	//vx.GetMinMax(dxmin, dxmax);
	//double dAreaFitTCumArea = 0.0;
	//vector vAreaFitT(nNumPeaks);
	//// End ADD_FUNCTION_INTEGRAL_FOR_AREA_FIT_T
//
    //for( int nIndex = nNumPeaks - 1; nIndex >=0 ; nIndex-- )
    //{
       //string strFullPathFileName;
       //vector vFitParams;
//
       //bool bRet = _get_filename_and_params_from_pfm_tree(trFitPeaks, nIndex, strFullPathFileName, vstrFuncName[nIndex], vFitParams);
       //ASSERT(bRet);
//
	   //TreeNode trFitPeak = treeFitPeaksParams.AddNode(("Peak" + nIndex));
	   //trFitPeak.dVals = vFitParams;
	   //string strFuncName = vstrFuncName[nIndex];
	   //if ( strFuncName.CompareNoCase(strLastFuncName) != 0 )
	   //{
			//strLastFuncName = strFuncName;
			//if( !nlsf_FDF_to_tree(strFullPathFileName, &trFF) )
			//{
				//error_report("Invalid function file");
				//continue;
			//}
			//if (!NF.SetTree(trFF))
			//{
				//error_report("Invalid function");
				//continue;
			//}
	   //}
//
       //vector vFullPeakX, vFullPeakY;
	   //vector vZeroY0Param;
	   //_zero_offset_params(vFitParams, vZeroY0Param, trFF);
//
		/////2008-5-22 Sandy  get NLPEAKPARAMS form NF directly
		//NLPEAKPARAMS nlpeakParameters;
		//NF.GetPeakParametersIndices(&nlpeakParameters);
		//vXCenters[nIndex] = vFitParams[nlpeakParameters.nIndexCenter];
		//if(nlpeakParameters.nIndexWidth2>0)
			//vXWidth[nIndex] = max(vFitParams[nlpeakParameters.nIndexWidth], vFitParams[nlpeakParameters.nIndexWidth2]);
		//else
			//vXWidth[nIndex] = vFitParams[nlpeakParameters.nIndexWidth];
		////end
		//
		////Sandy 2008-5-30 if width is less than 1/100 of full x datarange, set the width = 1/100 of x range.
		//double dLimitMinWidth = abs(dxmax - dxmin)/100.0;
		//if(vXWidth[nIndex] < dLimitMinWidth)
		//{
			//vXWidth[nIndex] = dLimitMinWidth;
		//}
		////end
//
	   //int  nInfiniteSize = generate_peak_data(NF, vZeroY0Param, vFullPeakX, vFullPeakY, NANUM, NANUM, vXCenters[nIndex], vXWidth[nIndex]);
//
	   /////temp Sandy 2008-5-21 replace missing for generate data out of valid range.
	   ////vector<uint> vnIndeces;
	   ////vFullPeakY.Sort(SORT_ASCENDING, false, vnIndeces);
	   ////vFullPeakX.Reorder(vnIndeces);
	   ////vFullPeakY.Trim();
	   ////vFullPeakX.SetSize(vFullPeakY.GetSize());
	   ////
	   ////vFullPeakX.Sort(SORT_ASCENDING, true, vnIndeces);
	   ////vFullPeakY.Reorder(vnIndeces);
	   /////end
//
	   //IntegrationResult xIdealPeakInteg;
	   //nRet = ocmath_integrate(vFullPeakX, vFullPeakY, 0, vFullPeakX.GetSize()-1, &xIdealPeakInteg, NULL, ABSOLUTE_AREA);
	   //ASSERT(nRet == OE_NOERROR);
	   ////if(nRet != OE_NOERROR)
			////return false;
	   ////dIdealCumArea+=xIdealPeakInteg.Area;//sandy 2008-5-26 should use datarange integ.Area
	   //TreeNode trPeak = treeIdealPeaks.AddNode(("Peak" + nIndex));
	   //TreeNode trParams = trPeak.AddNode(_IDEAL_PEAK_PARAMS_TAGNAME);
	   //trParams.dVals = vZeroY0Param;
	   //trPeak.AddNumericNode(xIdealPeakInteg.xPeak, _IDEAL_PEAK_CENTER_MAX_TAGNAME);
	   //trPeak.AddNumericNode(xIdealPeakInteg.xCentroid, _IDEAL_PEAK_CENTROID_X_TAGNAME);
	   //trPeak.AddNumericNode(xIdealPeakInteg.yPeak, _IDEAL_PEAK_HEIGHT_MAX_TAGNAME);
	   //trPeak.AddNumericNode(xIdealPeakInteg.dxPeak, _IDEAL_PEAK_FWHM_TAGNAME);
//
	   //wks.Columns(nIndex*2).SetType(OKDATAOBJ_DESIGNATION_X);
	   //wks.Columns(nIndex*2+1).SetType(OKDATAOBJ_DESIGNATION_Y);
//
	   //XYRange xyPeak;
       //xyPeak.Add(wks, nIndex*2, "X");
       //xyPeak.Add(wks,nIndex*2+1, "Y");
       //xyPeak.SetData(&vFullPeakY, &vFullPeakX);
//
       ////Jack 05/16/2008 ADD_FUNCTION_INTEGRAL_FOR_AREA_FIT_T
//
       /////Sandy 2008-5-20 Use Integral for speed and it has support precision control
       //double dPrecision = 10e-11;
       //vAreaFitT[nIndex] = NF.Integral(dxmin, dxmax, vZeroY0Param, dPrecision);
       //dIdealCumArea+=abs(vAreaFitT[nIndex]);//sandy 2008-5-26 should use datarange integ.Area
       ////int nMomentOrder=0;
       ////int nMomentType= PEAK_ZERO_POINT_MOMENT;
       ////int nErr;
       ////double dPrecision = 10e-8;//10e-11; // Note: did not use NF.Integral as no parameter in Integral to set precision so use CalcPeakMoment instead to obtain enough precision
       ////vAreaFitT[nIndex] = NF.CalcPeakMoment(dxmin, dxmax, vZeroY0Param, nMomentOrder, nMomentType, nErr, dPrecision);
       ////if(nErr)
       ////{
       		////return -1;
       ////}
//
       //dAreaFitTCumArea += abs(vAreaFitT[nIndex]);
       ////End ADD_FUNCTION_INTEGRAL_FOR_AREA_FIT_T
    //}
//
    //double dCumArea = xCumIntg.Area;
//
	//////debug
	////out_int("Prepare generate data in:", GetTickCount() - nT);
	////nT =  GetTickCount() ;
    ////calculate
//
    //for(nIndex = nNumPeaks - 1; nIndex >=0 ; nIndex-- )
    //{
	    //XYRange xyPeak;
        //xyPeak.Add(wks, nIndex*2, "X");
        //xyPeak.Add(wks,nIndex*2+1, "Y");
    	//vector vFullPeakX, vFullPeakY;
    	//xyPeak.GetData(vFullPeakY, vFullPeakX);
//
    	//TreeNode trFitPeak = treeFitPeaksParams.GetNode(("Peak" + nIndex));
    	//ASSERT(trFitPeak.IsValid());
	    //vector vFitParams;
	    //vFitParams = trFitPeak.dVals;
//
    	//TreeNode trIdealPeak = treeIdealPeaks.GetNode(("Peak" + nIndex));
    	//ASSERT(trIdealPeak.IsValid());
//
    	//vector vZeroY0Params;
    	//TreeNode trParams = trIdealPeak.GetNode(_IDEAL_PEAK_PARAMS_TAGNAME);
    	//vZeroY0Params = trParams.dVals;
//
     	//vector vy;
        //bool bRet = mPeaksData.GetColumn( vy, nIndex);
   		//ASSERT(bRet);
//
   		///// Jack 9-26-2008 QA-12288 SET_NF_FDF_FOR_EACH_PEAK_FUNCTION
   		//// Should set corresponding NF for each peak function to do the moment calculation otherwise NF will always be the first 
   		//// peak function  and the analytical formula for the moment will always use this function FDF
   		//string strFullPathFileName;
		//vector vTempFitParams;
//
		//bool bRet2 = _get_filename_and_params_from_pfm_tree(trFitPeaks, nIndex, strFullPathFileName, vstrFuncName[nIndex], vTempFitParams);
		//ASSERT(bRet2);
//
//
		//string strFuncName = vstrFuncName[nIndex];
	   	//if ( strFuncName.CompareNoCase(strLastFuncName) != 0 )
	   	//{
			//strLastFuncName = strFuncName;
			//if( !nlsf_FDF_to_tree(strFullPathFileName, &trFF) )
			//{
				//error_report("Invalid function file");
				//continue;
			//}
			//if (!NF.SetTree(trFF))
			//{
				//error_report("Invalid function");
				//continue;
			//}
	   	//}
   		///// End SET_NF_FDF_FOR_EACH_PEAK_FUNCTION
   		//
   		//
   		////bool bTempSpeedOrAccurateness = true; //temp option, true for speed, false for accurateness (function integral)  Jack 05/15/2008 add temp option to be shown in GUI
        //PFMPeakCharsVaule& rxCharsList = pxPFMPeakCharsValueList[nIndex];
	    //bRet=cal_peak_characterization(vx, vy, vFullPeakX, vFullPeakY, vXCenters[nIndex], vXWidth[nIndex], vAreaFitT[nIndex],  dCumArea, dAreaFitTCumArea,  vstrFuncName[nIndex], vFitParams, vZeroY0Params,trIdealPeak,
	      								//xRequireList, rxCharsList,
	         							//dWidthAtPercent, dAreaAbovePercent, dCumAreaTo, xcLast, wLast, NF, nMomentMethod);        		// Jack 05/16/2008 Add dAreaFitTCumArea parameter to the prototype
//
	    //if (false == bRet) return -1; // hard code -1: tobe changed into an error code
    //}
//
	//////debug
	////out_int("calculate all in:", GetTickCount() - nT);
	////nT =  GetTickCount() ;
//
    //wkpTemp.Destroy();
    /////end of 2008-5-15 move generate infinite peak data outside
//
	//////debug
	////out_int("total in:", GetTickCount() - nT0);
//
    //return nNumPeaks;
//
//}
///End CALCULATE_PEAKS_CHARACTERIZATION_HAS_BEEN_MOVED_TO_FITPEAK

///Arvin 08/01/07 QUIKE_METHOD_OF_PEAK_MOMENTS_AND_INTEGRAL_EVALUATION
bool calc_peak_moments(vector& vDestX, vector& vDestY, double* pArea, double* pM1, double* pM2, double* pM3, double* pM4)
{
	int nRet;
	if(pArea)
	{
		nRet = ocmath_calc_peak_moments(vDestX.GetSize(), vDestX, vDestY, pArea, OCMATH_PEAK_ZERO_POINT_MOMENT, 0);
		if(nRet!= OE_NOERROR)
    		return false;
	}

	if(pM1)
	{
		nRet = ocmath_calc_peak_moments(vDestX.GetSize(), vDestX, vDestY, pM1, OCMATH_PEAK_ZERO_POINT_MOMENT, 1);
		if(nRet!= OE_NOERROR)
    		return false;
	}

	if(pM2)
	{
		nRet = ocmath_calc_peak_moments(vDestX.GetSize(), vDestX, vDestY, pM2, OCMATH_PEAK_CENTRAL_MOMENT, 2);
		if(nRet!= OE_NOERROR)
    		return false;
	}

	if(pM3)
	{
		nRet = ocmath_calc_peak_moments(vDestX.GetSize(), vDestX, vDestY, pM3, OCMATH_PEAK_CENTRAL_MOMENT, 3);
		if(nRet!= OE_NOERROR)
    		return false;
	}

	if(pM4)
	{
		nRet = ocmath_calc_peak_moments(vDestX.GetSize(), vDestX, vDestY, pM4, OCMATH_PEAK_CENTRAL_MOMENT, 4);
		if(nRet!= OE_NOERROR)
    		return false;
	}

	return true;
}

/*///Sandy 2008-5-14 rewrite
bool generate_peak_data(const NumericFunction& NF, const vector& vParams, vector& vDestX, vector& vDestY, int nSrcSize, double dFrom, double dTo, double dPeakLeft, double dPeakRight)
{
	vector vTempX, vTempY;
	vTempX.Data(dFrom, dTo, (dTo-dFrom)/(nSrcSize-1));
	vTempY = NF.Evaluate(vTempX, vParams);
	int nDestSize = nSrcSize*10;
	vDestX.SetSize(nDestSize);
	int nRet = ocmath_generate_peak_data(&nDestSize, vDestX, vTempX.GetSize(), vTempX, vTempY, dPeakLeft, dPeakRight);
    //if(nRet!= OE_NOERROR)
    if(nRet!= OE_NOERROR || nDestSize < 2)//Sandy 2008-4-29 if there is too few points generate, return false.
    	return false;
	vDestY.SetSize(nDestSize);
	vDestX.SetSize(nDestSize);//Sandy
    vDestY = NF.Evaluate(vDestX, vParams);
	return true;
}
*/

///------ Folger 03/30/10 QA81-15237-P2 BETTER_NUMERIC_PRECISION_WHEN_CALCULATE_PEAK_PROPERTIES
static	int		_get_find_precision(const vector& vv)
{
	double	rMin, rMax;
	vv.GetMinMax(rMin, rMax);
	int		nPrecision = log10((abs(rMax) + abs(rMin)) / (rMax - rMin)) + 2;
	return nPrecision > 3 ? nPrecision : 3;
}
///------ End BETTER_NUMERIC_PRECISION_WHEN_CALCULATE_PEAK_PROPERTIES

#define BASE_NUM_POINT_REGION 50
#define TIMES_W_FROM_CENTER_AS_INFINITE 100
int generate_peak_data(const NumericFunction& NF, const vector& vParams, vector& vDestX, vector& vDestY, double dFrom, double dTo, double dxPeakCenter, double dPeakWidth)
{

	double dW = dPeakWidth/2;

	double dPosInfinite = dxPeakCenter+dPeakWidth*TIMES_W_FROM_CENTER_AS_INFINITE;
	double dNegInfinite = dxPeakCenter-dPeakWidth*TIMES_W_FROM_CENTER_AS_INFINITE;
	int    nNumInfiniteRegion = BASE_NUM_POINT_REGION;

	double dPosIn3W = dxPeakCenter+dPeakWidth*3;
	double dNegIn3W = dxPeakCenter-dPeakWidth*3;
	int    nNumIn3WRegion = BASE_NUM_POINT_REGION * 4;

	double dPosIn2W = dxPeakCenter+dPeakWidth*2;
	double dNegIn2W = dxPeakCenter-dPeakWidth*2;
	int    nNumIn2WRegion = BASE_NUM_POINT_REGION * 6;

	double dPosInHalfW = dxPeakCenter+dPeakWidth/2;
	double dNegInHalfW = dxPeakCenter-dPeakWidth/2;
	int    nNumInHalfWRegion = BASE_NUM_POINT_REGION * 15;

	if(dFrom == NANUM)
		dFrom = dNegInfinite;
	else if(dFrom < dNegInfinite)
		dNegInfinite = dFrom;

	if(dTo == NANUM)
		dTo = dPosInfinite;
	else if(dTo > dPosInfinite)
		dPosInfinite = dTo;

	vector vFullDataX, vFullDataY;
	vector vXInHalfW, vXIn2W, vXIn3W, vXInfinite;

	//create negative X-data points
	vXInfinite.Data(dNegInfinite, dNegIn3W, (dNegIn3W-dNegInfinite)/(nNumInfiniteRegion-1) );
	vXIn3W.Data(dNegIn3W,  dNegIn2W, (dNegIn2W-dNegIn3W)/(nNumIn3WRegion-1));
	vXIn2W.Data(dNegIn2W, dNegInHalfW,  (dNegInHalfW-dNegIn2W)/(nNumIn2WRegion-1) );
	vXInHalfW.Data(dNegInHalfW, dxPeakCenter, (dxPeakCenter-dNegInHalfW)/(nNumInHalfWRegion-1) );

	vFullDataX.Append(vXInfinite);
//	vXIn3W.RemoveAt(0);//remove the duplicate of point
//	vFullDataX.Append(vXIn3W);
	if(vXIn3W.GetSize()>0)  // Jack 05/30/2008 should check size before remove to avoid run-time error when zero-size vector encountered as use Voigt in pa fiiting
	{
		vXIn3W.RemoveAt(0);//remove the duplicate of point
		vFullDataX.Append(vXIn3W);
	}
	
	
//	vXIn2W.RemoveAt(0);//remove the duplicate of point
//	vFullDataX.Append(vXIn2W);
	if(vXIn2W.GetSize()>0)  // Jack 05/30/2008 should check size before remove to avoid run-time error when zero-size vector encountered as use Voigt in pa fiiting
	{
		vXIn2W.RemoveAt(0);//remove the duplicate of point
		vFullDataX.Append(vXIn2W);
	}

	
//	vXInHalfW.RemoveAt(0);//remove the duplicate of point
//	vFullDataX.Append(vXInHalfW);
	if(vXInHalfW.GetSize()>0)  // Jack 05/30/2008 should check size before remove to avoid run-time error when zero-size vector encountered as use Voigt in pa fiiting
	{
		vXInHalfW.RemoveAt(0);//remove the duplicate of point
		vFullDataX.Append(vXInHalfW);
	}


	//create positive X-data points
	vXInfinite.Data(dPosIn3W, dPosInfinite, (dPosInfinite - dPosIn3W)/(nNumInfiniteRegion-1) );
	vXIn3W.Data(dPosIn2W, dPosIn3W,  (dPosIn3W - dPosIn2W)/(nNumIn3WRegion-1));
	vXIn2W.Data(dPosInHalfW, dPosIn2W,(dPosIn2W - dPosInHalfW)/(nNumIn2WRegion-1) );
	vXInHalfW.Data(dxPeakCenter, dPosInHalfW, (dPosInHalfW - dxPeakCenter)/(nNumInHalfWRegion-1) );

//	vXInHalfW.RemoveAt(0);//remove the duplicate of point
//	vFullDataX.Append(vXInHalfW);
	if(vXInHalfW.GetSize()>0)  // Jack 05/30/2008 should check size before remove to avoid run-time error when zero-size vector encountered as use Voigt in pa fiiting
	{
		vXInHalfW.RemoveAt(0);//remove the duplicate of point
		vFullDataX.Append(vXInHalfW);
	}


//	vXIn2W.RemoveAt(0);//remove the duplicate of point
//	vFullDataX.Append(vXIn2W);
	if(vXIn2W.GetSize()>0)  // Jack 05/30/2008 should check size before remove to avoid run-time error when zero-size vector encountered as use Voigt in pa fiiting
	{
		vXIn2W.RemoveAt(0);//remove the duplicate of point
		vFullDataX.Append(vXIn2W);
	}


//	vXIn3W.RemoveAt(0);//remove the duplicate of point
//	vFullDataX.Append(vXIn3W);
	if(vXIn3W.GetSize()>0)  // Jack 05/30/2008 should check size before remove to avoid run-time error when zero-size vector encountered as use Voigt in pa fiiting
	{
		vXIn3W.RemoveAt(0);//remove the duplicate of point
		vFullDataX.Append(vXIn3W);
	}

	
//	vXInfinite.RemoveAt(0);//remove the duplicate of point
//	vFullDataX.Append(vXInfinite);
	if(vXInfinite.GetSize()>0)  // Jack 05/30/2008 should check size before remove to avoid run-time error when zero-size vector encountered as use Voigt in pa fiiting
	{
		vXInfinite.RemoveAt(0);//remove the duplicate of point
		vFullDataX.Append(vXInfinite);
	}

	
	vFullDataY = NF.Evaluate(vFullDataX, vParams);

	//Trim data outside of the range(dFrom,dTo)
	///------ Folger 03/30/10 QA81-15237-P2 BETTER_NUMERIC_PRECISION_WHEN_CALCULATE_PEAK_PROPERTIES
	int		nPrecision = _get_find_precision(vFullDataX);
	///------ End BETTER_NUMERIC_PRECISION_WHEN_CALCULATE_PEAK_PROPERTIES
	int nBegin, nEnd;
	vector<uint> vecIndex;
	///------ Folger 03/30/10 QA81-15237-P2 BETTER_NUMERIC_PRECISION_WHEN_CALCULATE_PEAK_PROPERTIES
	//int nFound = vFullDataX.Find(vecIndex, dFrom, _ONAN, 3);
	int nFound = vFullDataX.Find(vecIndex, dFrom, _ONAN, nPrecision);
	///------ End BETTER_NUMERIC_PRECISION_WHEN_CALCULATE_PEAK_PROPERTIES
	if(nFound > 0)
		nBegin = vecIndex[0];
	else
		nBegin = 0;

	///------ Folger 03/30/10 QA81-15237-P2 BETTER_NUMERIC_PRECISION_WHEN_CALCULATE_PEAK_PROPERTIES
	//nFound = vFullDataX.Find(vecIndex, dTo, _ONAN, 3);
	nFound = vFullDataX.Find(vecIndex, dTo, _ONAN, nPrecision);
	///------ End BETTER_NUMERIC_PRECISION_WHEN_CALCULATE_PEAK_PROPERTIES
	if(nFound > 0)
		nEnd = vecIndex[0];
	else
		nEnd = vFullDataX.GetSize() - 1;

 	vFullDataX.GetSubVector(vDestX, nBegin, nEnd);
 	vFullDataY.GetSubVector(vDestY, nBegin, nEnd);

 	int nMinSize = nNumInHalfWRegion + nNumIn2WRegion + nNumIn3WRegion;
	ASSERT( (vDestX.GetSize() >= nMinSize) && (vDestX.GetSize()  ==  vDestY.GetSize()) );

	return vDestX.GetSize();

}
///end QUIKE_METHOD_OF_PEAK_MOMENTS_AND_INTEGRAL_EVALUATION

///Sandy 2008-5-15 create sub-function make clear
static void _zero_offset_params(vector& vFitParams, vector& vZeroY0Param, TreeNode& trFF)
{
	NLFunctionList nlf;
	vector<string>  vParamNames;
	string 	strParamList = nlf.GetFittingPara(trFF, true, "Names").strVal;
	int nNumParaInFunc = strParamList.GetTokens(vParamNames, ',');

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

///Sandy 2008-5-20 for clean up comment and reconstruct the function
////Sandy 2008-5-15 move generate infinite peak data outside
//bool cal_peak_characterization(vector& vx, vector& vy , double dPeakXC, double dPeakWidth, const IntegrationResult xCumIntg,
		///*string strFullPathFileName, */ string strFuncName,  vector& vFitParams,
		//const PFMPeakCharsRequire xRequireList, PFMPeakCharsVaule& xPFMPeakCharsValueList,
         //double dWidthAtPercent, double dAreaAbovePercent, double dCumAreaTo , double& dLastXC, double& dLastWidth
         ////------ Folger 04/10/08 QA80-11364 REDUCE_FDF_LOADING_AND_SETTING_TREE_IN_PEAK_CALCULATION
         //, TreeNode &trFF, NumericFunction &NF)
         ////------
//bool cal_peak_characterization(vector& vx, vector& vy , vector& vFullPeakX, vector& vFullPeakY, double dPeakXC, double dPeakWidth, double dAreaFitT,
		//double dCumArea, double dAreaFitTCumArea, string strFuncName,  vector& vFitParams, vector& vZeroY0Params, TreeNode trIdealPeak,
		//const PFMPeakCharsRequire xRequireList, PFMPeakCharsVaule& xPFMPeakCharsValueList,
        //double dWidthAtPercent, double dAreaAbovePercent, double dCumAreaTo , double& dLastXC, double& dLastWidth,NumericFunction &NF, int nMomentdMode)
         ////------
//{
	////------ Folger 04/10/08 QA80-11364 REDUCE_FDF_LOADING_AND_SETTING_TREE_IN_PEAK_CALCULATION
	///*
	////perpare numeric function
	//Tree			trFF;
	//
	////string		strFDF = okutil_get_origin_path(ORIGIN_PATH_SYSTEM, "FitFunc")+ strFDFFileName +".FDF";
	//if( !nlsf_FDF_to_tree(strFullPathFileName, &trFF) )
	//{
		//out_str("Invalid function file");
		//return false;
	//}
	//*/
	////------ End REDUCE_FDF_LOADING_AND_SETTING_TREE_IN_PEAK_CALCULATION
	//
	////prepare data integration result
	//IntegrationResult xPeakIntg;
	//// Jack 05/04/2008 ADD_ERROR_CHECKING_FOR_INTEGRATION
	//int nRet = ocmath_integrate(vx, vy, 0, vx.GetSize()-1, &xPeakIntg, NULL, ABSOLUTE_AREA);
	//if (nRet<0)
		//{
			//return false;
		//}
	//// End ADD_ERROR_CHECKING_FOR_INTEGRATION
//
	/////Sandy 2008-5-12  use peaks' center and width which pass from outside
	///*
	/////Sandy 2007-11-27 add for support get width of negative peak
	////double dWholeWidth = abs(xPeakIntg.Area/xPeakIntg.yPeak/sqrt(PI/(4*ln(2))));
	//double dWholeWidth = abs(xPeakIntg.Area/xPeakIntg.yPeak/sqrt(PI/(4*ln(2))));
	//if (xPeakIntg.dxPeak < 0)
	//{
		//xPeakIntg.dxPeak = dWholeWidth;
		//xPeakIntg.Area *= -1;
	//}
	//
	////end
	//
	//double dFWHM = dWholeWidth/2.;
	//*/
	//
	////Calculate function peak area and moments
	////vector vZeroY0Param;
	////_zero_offset_params(vFitParams, vZeroY0Param, trFF);
	///*
	//NLFunctionList nlf;
	//vector<string>  vParamNames;
	//string 	strParamList = nlf.GetFittingPara(trFF, true, "Names").strVal;
	//int nNumParaInFunc = strParamList.GetTokens(vParamNames, ',');
	////int nPeakCenter = vParamNames.Find("xc");
	//int nParams = vFitParams.GetSize();
	////if( nPeakCenter < 0 || nPeakCenter >= nParams)
		////return false;
	////
	////double dPeakCenter = vFitParams[nPeakCenter];
	//vector vParamValue;
	//vParamValue = vFitParams;
	////Minus peak offset
	//int nY0 = vParamNames.Find("y0");
	////if(nY0 > 0 && nY0 < nParams)
	//if(nY0 >= 0 && nY0 < nParams)///Sandy fix Y0 should always be the first parameter and need to reset to zero
		//vParamValue[nY0] = 0.0;
	//*/
	//
	/////Sandy 2008-5-12 add generate peak data for find inflection points.
	////Calculate source peak area
	//int nSrcSize;
	//nSrcSize = vx.GetSize();
	//double dxmin, dxmax;
	//vx.GetMinMax(dxmin, dxmax);
	//
	/////Sandy 2008-5-14 new generate_peak_data take missing value as infinite
	////double dFrom 		= dPeakXC - 10*dPeakWidth;//xc - 10*w
	////double dTo 			= dPeakXC + 10*dPeakWidth;//xc + 10*w
	//
	////vector vFullPeakX, vFullPeakY;
	//
	/////Sandy 2008-5-14 rewrite generate_peak_data
    ////bool bRet = generate_peak_data(NF, vParamValue, vFullPeakX, vFullPeakY, nSrcSize, dFrom, dTo, dPeakXC-2*dPeakWidth, dPeakXC+2*dPeakWidth);
	////if(!bRet)
    	////return bRet;
    ////int  nInfiniteSize = generate_peak_data(NF, vZeroY0Param, vFullPeakX, vFullPeakY, NANUM, NANUM, dPeakXC, dPeakWidth);
    ////end
//
//
    /////Sandy 2008-5-20 move to resolution session for reduce the time cost
	////double dFWHM = dPeakWidth/2;
	////double dLeft, dRight, dBottomWidth;
	////// Jack 05/04/2008 ADD_ERROR_CHECKING_FOR_FIND_INFLECTION_POINT
    //////nRet=ocmath_find_inflection_point(vx.GetSize(), vx, vy, xPeakIntg.xPeak, dFWHM, &dLeft, &dRight, &dBottomWidth);
    ////nRet=ocmath_find_inflection_point(vFullPeakX.GetSize(),  vFullPeakX, vFullPeakY, dPeakXC, dFWHM, &dLeft, &dRight, &dBottomWidth);///Sandy 2008-5-12 use outside peak parameters
    ////if (nRet<0)
		////return false;
	//// End ADD_ERROR_CHECKING_FOR_FIND_INFLECTION_POINT
    //
    ////------ Folger 04/10/08 QA80-11364 REDUCE_FDF_LOADING_AND_SETTING_TREE_IN_PEAK_CALCULATION
    ///*
	//NumericFunction	NF;
	//if (!NF.SetTree(trFF))
	//{
		//out_str("Invalid function");
		//return false;
	//}
	//*/
	////------
	//
	/////Arvin 08/01/07 QUIKE_METHOD_OF_PEAK_MOMENTS_AND_INTEGRAL_EVALUATION
	////double d1, d2;
	////d1 =-INFINITY;
	////d2 = INFINITY;
	////double dAreaFit = NF.Integral(d1, d2, vFitParams);
	//
	////double dxmin, dxmax;
	////vx.GetMinMax(dxmin, dxmax);
	////double dAreaFitT = NF.Integral(dxmin, dxmax, vFitParams);
	//
    ////CalcPeakMoment(double dFrom, double dTo, vector& vParamValues, int nMomentOrder = 0, int nMomentType = INTEG_CENTRAL_MOMENT);
    //
	////double m2 = NF.CalcPeakMoment(d1, d2, vFitParams, 2, PEAK_CENTRAL_MOMENT);
	////double m3 = NF.CalcPeakMoment(d1, d2, vFitParams, 3, PEAK_CENTRAL_MOMENT);
	////double m4 = NF.CalcPeakMoment(d1, d2, vFitParams, 4, PEAK_CENTRAL_MOMENT);
	//
	//
////	vector vDestX, vDestY; Jack --- No need to generate data for calculating dAreaFitT use function integral outside
	/////Sandy 2008-5-14 rewrite generate_peak_data
    ///*
	/////Sandy add 2008-5-8 adjust the left and right when the peak's total width is out of data range
	//dLeft = max(dxmin, dLeft);
	//dRight = min(dxmax, dRight);
	////end
    //bRet = generate_peak_data(NF, vFitParams, vDestX, vDestY, nSrcSize, dxmin, dxmax, dLeft, dRight);
    //if(!bRet)
    	//return bRet;
    //*/
	////int  nInRangeSize = generate_peak_data(NF, vFitParams, vDestX, vDestY, dxmin, dxmax, dPeakXC, dPeakWidth);
////	int  nInRangeSize = generate_peak_data(NF, vZeroY0Params, vDestX, vDestY, dxmin, dxmax, dPeakXC, dPeakWidth);//should use y0 = 0 parameters
////   ---Jack  No need to generate data for calculating dAreaFitT use function integral outside
	////end
	//
	///*
    //IntegrationResult SrcPeakInteg;
	//nRet = ocmath_integrate(vDestX, vDestY, 0, vDestX.GetSize()-1, &SrcPeakInteg, NULL, MATHEMATICAL_AREA);
	//if(nRet != OE_NOERROR)
		//return false;
	//double dAreaFitT = SrcPeakInteg.Area;// Sandy 2008-5-6 should use the realy center peak's data
    //*/
    //// Jack AreaFit is calculated outside and passed in
    //
    //
	///* ///Sandy 2008-5-12 move to the top of this function
	////Calculate function peak area and moments
	//NLFunctionList nlf;
	//vector<string>  vParamNames;
	//string 	strParamList = nlf.GetFittingPara(trFF, true, "Names").strVal;
	//int nNumParaInFunc = strParamList.GetTokens(vParamNames, ',');
	//int nPeakCenter = vParamNames.Find("xc");
	//int nParams = vFitParams.GetSize();
	//if( nPeakCenter < 0 || nPeakCenter >= nParams)
		//return false;
	//
	//double dPeakCenter = vFitParams[nPeakCenter];
	//vector vParamValue;
	//vParamValue = vFitParams;
	////Minus peak offset
	//int nY0 = vParamNames.Find("y0");
	//if(nY0 > 0 && nY0 < nParams)
		//vParamValue[nY0] = 0.0;
	//*/
	//
	/////Sandy 2008-5-12 just move to the beginning
	//////double dPeakWidth	= dRight-dLeft;
	////double dFrom 		= dPeakCenter - 10*dPeakWidth;//xc - 10*w
	////double dTo 			= dPeakCenter + 10*dPeakWidth;//xc + 10*w
	//
	/////Sandy 2008-5-14 no need to generate again, since the peak point will be the same of the first time of generating
	///*
	/////Sandy 2008-5-13
	//double dPeakWidth2 = dRight-dLeft;
	/////Sandy 2008-4-16 remove 10 times for speed but need to confirm with Arvin later
    //bRet = generate_peak_data(NF, vParamValue, vDestX, vDestY, nSrcSize, dFrom, dTo, dPeakCenter-2*dPeakWidth2, dPeakCenter+2*dPeakWidth2);
    ////bRet = generate_peak_data(NF, vParamValue, vDestX, vDestY, 10*nSrcSize, dFrom, dTo, dPeakCenter-2*dPeakWidth, dPeakCenter+2*dPeakWidth);
	//if(!bRet)
    	//return bRet;
	//*/
	//
    	///////Sandy 2008-5-6 add for see temp data
	    //////{
	    	////temp for output temp data
	    	////WorksheetPage wkp;
	    	////wkp.Create("Origin",  CREATE_HIDDEN);
	    	////Worksheet wks = wkp.Layers(0);
	    	////Dataset dsX(wks, 0);
	    	////Dataset dsY(wks, 1);
	    	////dsX = vFullPeakX;
	    	////dsY = vFullPeakY;
	    //
	    ////out_int("num:", vFullPeakX.GetSize());
	    //////}
	//
	/////Sandy 2008-5-6 add
	////IntegrationResult fitPeakInteg;
	////nRet = ocmath_integrate(vFullPeakX, vFullPeakY, 0, vFullPeakX.GetSize()-1, &fitPeakInteg, NULL, ABSOLUTE_AREA);
	////if(nRet != OE_NOERROR)
		////return false;
	////end
	//
	//
	///*
    ////Calculate peak moments
    //bool bRet;
	//double dAreaFit, m1, m2, m3, m4;
	//if(xRequireList.bAreaFit)
	//{
		////bRet = calc_peak_moments(vDestX, vDestY, &dAreaFit, NULL, NULL, NULL, NULL);// sandy 2008-5-15 should use generate data
		//bRet = calc_peak_moments(vFullPeakX, vFullPeakY, &dAreaFit, NULL, NULL, NULL, NULL);
	//}
	//if(xRequireList.bVariance || xRequireList.bSkew || xRequireList.bExcess
		//|| xRequireList.bMoment3 || xRequireList.bMoment4)
	//{
		////bRet = calc_peak_moments(vDestX, vDestY, NULL,&m1, &m2, &m3, &m4);// sandy 2008-5-15 should use generate data
		//bRet = calc_peak_moments(vFullPeakX, vFullPeakY, NULL,&m1, &m2, &m3, &m4);
	//}
	//if(!bRet)
		//return bRet;
    /////end QUIKE_METHOD_OF_PEAK_MOMENTS_AND_INTEGRAL_EVALUATION
    //*/
    //
    //
    //// Jack 05/15/2008 CHANGE_TO_FUNCTION_INTEGRAL
    //// bool bTempSpeedOrAccurateness = false;// temp option for choosing Speed or Accurateness method of calculation of dAreafit, m2-m4 integration
//
    //bool bRet;
	//double dAreaFit, m1, m2, m3, m4;
	//
	/////Sandy 2008-5-17 use FDF's moment value if function is analytical
	//vector vMoments(4);
	//StringArray arrMomentNames = {"m1", "m2", "m3", "m4"};
	//nRet = NF.EvaluateMomentsAnalytically(vMoments, arrMomentNames, vZeroY0Params, vZeroY0Params.GetSize());
	//ASSERT(nRet == 0);
	//m1 = vMoments[0];
	//m2 = vMoments[1];
	//m3 = vMoments[2];
	//m4 = vMoments[3];
//
	////Calculate peak moments by numeric function integral for dAreaFit
    //int nMomentOrder=0; // for calculation of theoretical area between fitted curve and baseline (without fitted curve's offset too, see vParamValue)
	//int nMomentType= PEAK_ZERO_POINT_MOMENT;
	//int nErr;
	//double dPrecision = 10e-15;//10e-11;
	//if(xRequireList.bAreaFit)
	//{
		//dAreaFit=NF.CalcPeakMoment(dPeakXC-100*dPeakWidth, dPeakXC+100*dPeakWidth, vZeroY0Params, nMomentOrder, nMomentType, nErr, dPrecision);
		//if(nErr)   // hard code 100 to make it as integratin like to infinite
		//{
			//return false;
		//}
	//}
//
//
	//// need to calculate moment 1 and above
	//if(xRequireList.bVariance || xRequireList.bSkew || xRequireList.bExcess
		//|| xRequireList.bMoment3 || xRequireList.bMoment4)
	//{
		////bRet = calc_peak_moments(vDestX, vDestY, NULL,&m1, &m2, &m3, &m4);// sandy 2008-5-15 should use generate data
		//if(nMomentdMode == MOMENT_METHOD_NUM_INTEGRAL) // for speed calculation of integration of moment m1, m2,m3,m4
		//{
			//if(m2 == NANUM ||m3 == NANUM ||m4 == NANUM )
			//{
				//bRet = calc_peak_moments(vFullPeakX, vFullPeakY, NULL,&m1, &m2, &m3, &m4);
				//if(!bRet)
				//return bRet;
			//}
			/////end QUIKE_METHOD_OF_PEAK_MOMENTS_AND_INTEGRAL_EVALUATION
		//}
		//else // Add Function Integral for accurate calculation
		//{
			//nMomentType = PEAK_CENTRAL_MOMENT;
			//if(m2 == NANUM)//Sandy 2008-5-17 the moment isn't analytical and applicable to compute
			//{
				//nMomentOrder = 2;
				//m2=NF.CalcPeakMoment(dPeakXC-100*dPeakWidth, dPeakXC+100*dPeakWidth, vZeroY0Params, nMomentOrder, nMomentType, nErr, dPrecision);
				//if(nErr)
					//return false;
			//}
			//
			//if(m3 == NANUM)//Sandy 2008-5-17 the moment isn't analytical and applicable to compute
			//{
				//nMomentOrder = 3;
				//m3=NF.CalcPeakMoment(dPeakXC-100*dPeakWidth, dPeakXC+100*dPeakWidth, vZeroY0Params, nMomentOrder, nMomentType, nErr, dPrecision);
				//if(nErr)
					//return false;
			//}
			//
			//if(m4 == NANUM)//Sandy 2008-5-17 the moment isn't analytical and applicable to compute
			//{
				//nMomentOrder = 4;
				//m4=NF.CalcPeakMoment(dPeakXC-100*dPeakWidth, dPeakXC+100*dPeakWidth, vZeroY0Params, nMomentOrder, nMomentType, nErr, dPrecision);
				//if(nErr)
					//return false;
			//}
		//}
		//
		/////Sandy 2008-5-17 if NF return ONLSF8_MOMENT_VALUE_NOT_APPLICABLE, re-set moment to NANUM;
		//m2 = (m2 == ONLSF8_MOMENT_VALUE_NOT_APPLICABLE? NANUM : m2);
		//m3 = (m3 == ONLSF8_MOMENT_VALUE_NOT_APPLICABLE? NANUM : m3);
		//m4 = (m4 == ONLSF8_MOMENT_VALUE_NOT_APPLICABLE? NANUM : m4);
		/////end
//
	//}
    //
    //// End CHANGE_TO_FUNCTION_INTEGRAL
//
	//
	////calculate peaks characterization
	//if(xRequireList.bAreaFit)
	//{
		//xPFMPeakCharsValueList.dAreaFit = dAreaFit;
	//}
    //
	//if(xRequireList.bAreaFitT)
	//{
		//xPFMPeakCharsValueList.dAreaFitT = dAreaFitT;
	//}
//
	//
	//if(xRequireList.bAreaFitTP)
	//{
		////xPFMPeakCharsValueList.dAreaFitTP = dAreaFitT/xCumIntg.Area*100.;
		//xPFMPeakCharsValueList.dAreaFitTP = dAreaFitT/dAreaFitTCumArea*100.;
	//}
	//
	//if(xRequireList.bAreaIntg)
	//{
		//xPFMPeakCharsValueList.dAreaIntg = xPeakIntg.Area;
	//}
	//
	//if(xRequireList.bAreaIntgP)
	//{
		////xPFMPeakCharsValueList.dAreaIntgP = xPeakIntg.Area/xCumIntg.Area*100.;
		//xPFMPeakCharsValueList.dAreaIntgP = xPeakIntg.Area/dCumArea*100.;
	//
	//}
//
//
	//if(xRequireList.bCenterMax)
	//{
		/////Sandy 2008-5-6 should use the realy center peak's data
		////xPFMPeakCharsValueList.dCenterMax =	xPeakIntg.xPeak;
		////xPFMPeakCharsValueList.dCenterMax =	fitPeakInteg.xPeak;
		//
		//TreeNode trNode = trIdealPeak.GetNode(_IDEAL_PEAK_CENTER_MAX_TAGNAME);
		//ASSERT(trNode.IsValid());
		//xPFMPeakCharsValueList.dCenterMax =	trNode.dVal;
		//
	//}
//
	//if(xRequireList.bCenterGrvty)
	//{
		////	xPFMPeakCharsValueList.dCenterGrvty =	xPeakIntg.xCentroid;
		////xPFMPeakCharsValueList.dCenterGrvty =	fitPeakInteg.xCentroid;
		//TreeNode trNode = trIdealPeak.GetNode(_IDEAL_PEAK_CENTROID_X_TAGNAME);
		//ASSERT(trNode.IsValid());
		//xPFMPeakCharsValueList.dCenterGrvty =	trNode.dVal;
	//}
	//
    //if(xRequireList.bMaxHeight)
    //{
    	////xPFMPeakCharsValueList.dMaxHeight =	xPeakIntg.yPeak;
    	////xPFMPeakCharsValueList.dMaxHeight =	fitPeakInteg.yPeak;
		//TreeNode trNode = trIdealPeak.GetNode(_IDEAL_PEAK_HEIGHT_MAX_TAGNAME);
		//ASSERT(trNode.IsValid());
		//xPFMPeakCharsValueList.dMaxHeight =	trNode.dVal;
    //}
    //
    //if(xRequireList.bFWHM)
    //{
    	////xPFMPeakCharsValueList.dFWHM =	xPeakIntg.dxPeak;
    	////xPFMPeakCharsValueList.dFWHM =	fitPeakInteg.dxPeak;
		//TreeNode trNode = trIdealPeak.GetNode(_IDEAL_PEAK_FWHM_TAGNAME);
		//ASSERT(trNode.IsValid());
		//xPFMPeakCharsValueList.dFWHM =	trNode.dVal;
    //}
    //
    //
    //if(xRequireList.bVariance) //m2
    //{
    	 //xPFMPeakCharsValueList.dVariance = m2;
    //}
    //
    //if(xRequireList.bSkew)
    //{
    	//xPFMPeakCharsValueList.dSkew = m3/sqrt(m2*m2*m2);
    //}
    //
    //if(xRequireList.bExcess)
    //{
    	//xPFMPeakCharsValueList.dExcess = m4/(m2*m2) - 3;
    //}
    //
    //double dBottomWidth;
    //if(xRequireList.bResolution)//from cloud's function
    //{
		//double dFWHM = dPeakWidth/2;
		//double dLeft, dRight;
		//// Jack 05/04/2008 ADD_ERROR_CHECKING_FOR_FIND_INFLECTION_POINT
	    ////nRet=ocmath_find_inflection_point(vx.GetSize(), vx, vy, xPeakIntg.xPeak, dFWHM, &dLeft, &dRight, &dBottomWidth);
	    //nRet=ocmath_find_inflection_point(vFullPeakX.GetSize(),  vFullPeakX, vFullPeakY, dPeakXC, dFWHM, &dLeft, &dRight, &dBottomWidth);///Sandy 2008-5-12 use outside peak parameters
	    //if (nRet<0)
			//return false;
    //
    	//if(dLastWidth == 0)
    		//xPFMPeakCharsValueList.dResolution = NANUM;
    	//else
		////	xPFMPeakCharsValueList.dResolution = 2*(dLastXC - xPeakIntg.xPeak)/(dLastWidth + dBottomWidth);
			//xPFMPeakCharsValueList.dResolution = 2*(dLastXC - dPeakXC)/(dLastWidth + dBottomWidth);
//
    //}
//
    //
    //if(xRequireList.bMoment3)
    //{
    	//xPFMPeakCharsValueList.dMoment3 = m3;
    //}
    //
    //if(xRequireList.bMoment4)
    //{
    	//xPFMPeakCharsValueList.dMoment4 = m4;
    //}
    //
    //
    //if(xRequireList.bWidthAtP)
    //{
    	//double dWidthAtY = dWidthAtPercent/100 * (xPeakIntg.yPeak - xPeakIntg.yPeakBase);
		////set how many x should be finded
		//uint nSize = 2;
		//vector vFindx;
		//vector<int> vFindxNum;
		//vFindx.SetSize(nSize);
		//vFindxNum.SetSize(nSize);
		//
		////find _compute_y_by_x function in stats_operations.c
		//string strFile = GetOriginPath() + "OriginC\\OriginLab\\nlsf_utils.c";
		//PFN_STR_INT_DOUBLE_DOUBLE_DOUBLEP pFunc = Project.FindFunction("compute_y_by_x", strFile, true);
		//
		//int nRet = ocmath_find_xs(dWidthAtY, (uint)(vy.GetSize()), vx, vy, nSize, vFindx,
						//strFuncName, vFitParams.GetSize(), vFitParams, pFunc, vFindxNum);
						//
		//if(nRet == OE_NOERROR && vFindx[1] != NANUM && vFindx[0] != NANUM)
		//{
			//xPFMPeakCharsValueList.dWidthAtP = abs(vFindx[1] - vFindx[0]);
		//}
		//else
		//{
			//xPFMPeakCharsValueList.dWidthAtP = NANUM;
		//}
		//
		//xPFMPeakCharsValueList.dWidthAtPP = dWidthAtPercent;//add for output to result
    //}
    //
    //if(xRequireList.bAreaAbove)
    //{
    	//
    	//double dAreaAboveY = dAreaAbovePercent/100 * abs(xPeakIntg.yPeak - xPeakIntg.yPeakBase);
    	//vector vYTemp;
    	//vYTemp = vy;
    	//if(xPeakIntg.yPeak - xPeakIntg.yPeakBase<0)
    		//vYTemp = -1* vYTemp;
    	//
    	//vYTemp = vYTemp - dAreaAboveY;
    	//vYTemp.Replace(0,0,MATREPL_TEST_LESSTHAN);
    	//
		//IntegrationResult xAboveIntg;
		//ocmath_integrate(vx, vYTemp, 0, vx.GetSize()-1, &xAboveIntg, NULL, ABSOLUTE_AREA);
		//
		//xPFMPeakCharsValueList.dAreaAbove = xAboveIntg.Area;
		//
		//
		//xPFMPeakCharsValueList.dAreaAboveP = dAreaAbovePercent;//add for output to result
    //}
    //
    //if(xRequireList.bCumArea)
    //{
    	/////Sandy 2008-5-9 Should use NF.Integral, but the result is bad, so use ocmath_integrate and waitting improvement.
    	////xPFMPeakCharsValueList.dCumArea =  NF.Integral(-INFINITY, xPeakIntg.xPeak + dCumAreaTo, vFitParams);
    	////xPFMPeakCharsValueList.dCumArea =  NF.Integral(-INFINITY, xPeakIntg.xPeak + dCumAreaTo, vParamValue);
    	//xPFMPeakCharsValueList.dCumArea =  NF.Integral(-INFINITY,dPeakXC + dCumAreaTo, vZeroY0Params);
    	//
    	//xPFMPeakCharsValueList.dCumAreaP = dCumAreaTo;//add for output to result
    	//
	    ///*
	    //vector<uint> vecIndex;
	    //double dDelta = vDestX[1] - vDestX[0];
	    //double dLower = (dPeakCenter + dCumAreaTo);//dPeakCenter replace xPeakIntg.xPeak
	    //double dUpper = (dPeakCenter + dCumAreaTo) + dDelta;
	    //int nFound = vDestX.Find(vecIndex, dLower, dUpper, 3);
	    //double dFound = vDestX[vecIndex[0]];
	    //uint nEndInd = vecIndex[0];
		////printf("Find index %d\n", nEndInd );
		////printf("Find Value %g\n", dLower );
		////printf("Found Value %g\n", dFound );
	    //if(nFound > 0)
	    //{
			//IntegrationResult xCumPeakInteg;
			//nRet = ocmath_integrate(vDestX, vDestY, 0, nEndInd, &xCumPeakInteg, NULL, MATHEMATICAL_AREA);
			////nRet = ocmath_integrate(vDestX, vDestY, 0, nM, &xCumPeakInteg, NULL, MATHEMATICAL_AREA);
			//if(nRet != OE_NOERROR)
				//return false;
			//
			//xPFMPeakCharsValueList.dCumArea = xCumPeakInteg.Area;
	    //}
	////end
	//*/
    //}
//
    //dLastXC =  xPeakIntg.xPeak;
    //dLastWidth = dBottomWidth;
	//return true;
//}

/// Hong 01/13/09 v8.0995d IMPROVE_CODE_OF_MEMORY_CONSUMER_IN_PA
double cal_area_fit_TP(double dAreaFitT, double dAreaFitTCumArea)
{
	ASSERT( 0.0 != dAreaFitTCumArea );
	return dAreaFitT/dAreaFitTCumArea*100.;
}
/// end IMPROVE_CODE_OF_MEMORY_CONSUMER_IN_PA

///---Sim 10-12-2009 QA81-14388 IMPROVE_SPEED_OF_PA_FIT
#define MAX_SIZE_MOENTS 5

#ifdef __IMPROVE_PA_FIT_SPEED__
static void _get_need_moments(bool MomentNeeds[MAX_SIZE_MOENTS], const PFMPeakCharsRequire& xRequireList)
{
	for ( int ii = 0; ii < MAX_SIZE_MOENTS; ii++ )
		MomentNeeds[ii] = false;
	
	if ( xRequireList.bAreaFit )
	{
		MomentNeeds[0] = true;
	}
	
	if ( xRequireList.bCenterGrvty )
	{
		MomentNeeds[1] = true;
	}
	
	if ( xRequireList.bVariance )
	{
		MomentNeeds[2] = true;
	}
	
	if ( xRequireList.bSkew )
	{
		MomentNeeds[2] = true;
		MomentNeeds[3] = true;
	}
	
	if ( xRequireList.bExcess )
	{
		MomentNeeds[2] = true;
		MomentNeeds[4] = true;
	}
	
    if(xRequireList.bMoment3)
    {
		MomentNeeds[3] = true;
    }

    if(xRequireList.bMoment4)
    {
		MomentNeeds[4] = true;
    }
}
#endif // __IMPROVE_PA_FIT_SPEED__
///---END QA81-14388 IMPROVE_SPEED_OF_PA_FIT
bool cal_peak_characterization(vector& vx, vector& vy , vector& vFullPeakX, vector& vFullPeakY, double dPeakXC, double dPeakWidth, double dAreaFitT,
		double dCumArea, double dAreaFitTCumArea, string strFuncName,  vector& vFitParams, vector& vZeroY0Params, TreeNode trIdealPeak,
		const PFMPeakCharsRequire xRequireList, PFMPeakCharsVaule& xPFMPeakCharsValueList,
        double dWidthAtPercent, double dAreaAbovePercent, double dCumAreaTo , double& dLastXC, double& dLastWidth,NumericFunction &NF, int nMomentdMode)
         //------
{
	////debug
	//printf("===================\n");
	//int nT0 = GetTickCount();
	//int nT = nT0;

	//prepare data integration result
	IntegrationResult xPeakIntg;
	// Jack 05/04/2008 ADD_ERROR_CHECKING_FOR_INTEGRATION
	//int nRet = ocmath_integrate(vx, vy, 0, vx.GetSize()-1, &xPeakIntg, NULL, ABSOLUTE_AREA);
	int nRet = ocmath_integrate(vx, vy, 0, vx.GetSize()-1, &xPeakIntg, NULL, MATHEMATICAL_AREA);//Sandy 2009-2-9 #13077 Area Intg and Area IntgP of negative peaks are positive in PA¡¯s Fit Peak goal 
	if (nRet<0)
	{
		return false;
	}

	////debug
	//out_int("Integ Src Peak in:", GetTickCount() - nT);
	//nT =  GetTickCount() ;

	//Calculate source peak area
	int nSrcSize;
	nSrcSize = vx.GetSize();
	double dxmin, dxmax;
	vx.GetMinMax(dxmin, dxmax);

    bool bRet;
	double dAreaFit;
	//Calculate peak moments by numeric function integral for dAreaFit
    int nMomentOrder=0; // for calculation of theoretical area between fitted curve and baseline (without fitted curve's offset too, see vParamValue)
	int nMomentType= PEAK_ZERO_POINT_MOMENT;
	int nErr;
	double dPrecision = 10e-15;//10e-11;//

	// Jack 05/23/2008 ADD_SPECIAL_SUPPORT_FOR_FUNCTION_WITH_MOMENTS_CALCULABLE_IN_CERTAIN_CASES
	DWORD dwMoments; // test if NF provide info whether moments are calculable for certain cases    i.e. see PearsonVII pdf
	bool bHasInfoAboutMomentsCalculable = NF.MomentsExist(&dwMoments, vFitParams, vFitParams.GetSize());

	///---Sim 10-12-2009 QA81-14388 IMPROVE_SPEED_OF_PA_FIT
#ifdef __IMPROVE_PA_FIT_SPEED__
	bool MomentNeeds[MAX_SIZE_MOENTS];
	_get_need_moments(MomentNeeds, xRequireList);
	
	if ( !bHasInfoAboutMomentsCalculable ) // For those does not provide info about whether moments are calculable in certain cases then treat them calculable so that the previous logic is followed
		dwMoments = MOMENTEXISTS_0 | MOMENTEXISTS_1 | MOMENTEXISTS_2 | MOMENTEXISTS_3 | MOMENTEXISTS_4;

	// Jack 05/29/2008 ADD_SUPPORT_FOR_INTEGRAL_IN_FUNCTION_DEFINABLE_RANGE     i.e. for Weibull Pulse.function which may only be definable in certain range
	vector vBounds(2);
	StringArray arrBoundNames = {"_mlower","_mupper"};
	nRet = NF.EvaluateMomentsAnalytically(vBounds, arrBoundNames, vFitParams, vFitParams.GetSize()); // to get function definable range if exist
	ASSERT(nRet == 0);
	
	double dLowerBound, dUpperBound;
	dLowerBound = (vBounds[0] == NANUM ? (-INFINITY) : vBounds[0]);
	dUpperBound = (vBounds[1] == NANUM ? INFINITY : vBounds[1]);	
	ASSERT(dLowerBound < dUpperBound); 
	// End ADD_SUPPORT_FOR_INTEGRAL_IN_FUNCTION_DEFINABLE_RANGE
	
	StringArray arrMomentNames = {"mz0", "mz1", "mc2", "mc3", "mc4"};
	ASSERT(MAX_SIZE_MOENTS == arrMomentNames.GetSize());
	int MomentTypes[MAX_SIZE_MOENTS] = {PEAK_ZERO_POINT_MOMENT, PEAK_ZERO_POINT_MOMENT, PEAK_CENTRAL_MOMENT, PEAK_CENTRAL_MOMENT, PEAK_CENTRAL_MOMENT};
	int OMMomentTypes[MAX_SIZE_MOENTS] = {OCMATH_PEAK_ZERO_POINT_MOMENT, OCMATH_PEAK_ZERO_POINT_MOMENT, OCMATH_PEAK_CENTRAL_MOMENT, OCMATH_PEAK_CENTRAL_MOMENT, OCMATH_PEAK_CENTRAL_MOMENT};
	DWORD MomentExists[MAX_SIZE_MOENTS] = {MOMENTEXISTS_0, MOMENTEXISTS_1, MOMENTEXISTS_2, MOMENTEXISTS_3, MOMENTEXISTS_4};	
	
	vector vMoments(MAX_SIZE_MOENTS);
	nRet = NF.EvaluateMomentsAnalytically(vMoments, arrMomentNames, vZeroY0Params, vZeroY0Params.GetSize());
	ASSERT(nRet == 0);
	
	for ( int ii = 0; ii < MAX_SIZE_MOENTS; ii++ )
	{
		//if ( MomentNeeds[ii] && NANUM == vMoments[ii] ) // can't get from fdf moments session
		if ( MomentNeeds[ii] && is_missing_value(vMoments[ii]) ) // can't get from fdf moments session
		{
			if ( !(MomentExists[ii] & dwMoments) )
			{
				//Sim, better to check error and return, but old logic do NOT.
				continue;
			}
			
			nErr = OE_NOERROR;
			
			if ( 0 == ii )
			{
				vMoments[ii] = NF.Integral(-INFINITY, INFINITY, vZeroY0Params, dPrecision);
			}
			else
			if ( 1 == ii )
			{
				vMoments[ii] = NF.CalcPeakMoment(-INFINITY, INFINITY, vZeroY0Params, ii, MomentTypes[ii], nErr, dPrecision);
			}
			else
			{
				if(nMomentdMode == MOMENT_METHOD_NUM_INTEGRAL) // for speed calculation of integration of moment
				{
					int nRet = ocmath_calc_peak_moments(vFullPeakX.GetSize(), vFullPeakX, vFullPeakY, &vMoments[ii], OMMomentTypes[ii], ii);
					if( nRet != OE_NOERROR )
					{
						error_report("ocmath_calc_peak_moments return error:"+nRet);
						return false;
					}
				}
				else
				{
					vMoments[ii] = NF.CalcPeakMoment(dLowerBound, dUpperBound, vZeroY0Params, ii, MomentTypes[ii], nErr, dPrecision);
				}
			}
			
			if( OE_NOERROR != nErr )
			{
				error_report("NF calcPeakMoment return error:"+nErr);
				vMoments[ii] = NANUM;
			}
			
			//if ( ONLSF8_MOMENT_VALUE_NOT_APPLICABLE == vMoments[ii] )
				//vMoments[ii] = NANUM;
		}
		// Fix for Moments isn't applicable, like Lorentz
		if ( ONLSF8_MOMENT_VALUE_NOT_APPLICABLE == vMoments[ii] )
			vMoments[ii] = NANUM;
	}
#else
	///---END QA81-14388 IMPROVE_SPEED_OF_PA_FIT
	if(xRequireList.bAreaFit)
	{
		vector vMoments(1);
		StringArray arrMomentNames = {"mz0"};
		nRet = NF.EvaluateMomentsAnalytically(vMoments, arrMomentNames, vZeroY0Params, vZeroY0Params.GetSize());
		ASSERT(nRet == 0);
		dAreaFit = vMoments[0];


		if(dAreaFit == NANUM)
		{
			// Jack 05/23/2008 ADD_SPECIAL_SUPPORT_FOR_FUNCTION_WITH_MOMENTS_CALCULABLE_IN_CERTAIN_CASES
			if (bHasInfoAboutMomentsCalculable)// For those functions provide info that moments are calculable in certain cases
			{
				if ( MOMENTEXISTS_0 & dwMoments ) // check if moment_0 exists for certain cases     i.e. see PearsonVII pdf
				{
					dAreaFit = NF.Integral(-INFINITY, INFINITY, vZeroY0Params, dPrecision);
				}
				else //  moment_0 not exist, namely, Not Applicable
				{
					dAreaFit == ONLSF8_MOMENT_VALUE_NOT_APPLICABLE;
				}
			}
			else // For those does not provide info about whether moments are calculable in certain cases then treat them calculable so that the previous logic is followed
			{
	  		//  This may still be unacceptable for some special function which does not provide info about whether moments are calculable
			 // End ADD_SPECIAL_SUPPORT_FOR_FUNCTION_WITH_MOMENTS_CALCULABLE_IN_CERTAIN_CASES
				
				///Sandy 2008-5-20 Use Integral for speed and it has support precision control
				dAreaFit = NF.Integral(-INFINITY, INFINITY, vZeroY0Params, dPrecision);
				//dAreaFit=NF.CalcPeakMoment(dPeakXC-100*dPeakWidth, dPeakXC+100*dPeakWidth, vZeroY0Params, nMomentOrder, nMomentType, nErr, dPrecision);
				//if(nErr)   // hard code 100 to make it as integratin like to infinite
				//{
					//return false;
				//}
			}

		}

		dAreaFit = (dAreaFit == ONLSF8_MOMENT_VALUE_NOT_APPLICABLE? NANUM : dAreaFit);
	}

	double m1, m2, m3, m4;
	// need to calculate moment 1 and above
	if(xRequireList.bVariance || xRequireList.bSkew || xRequireList.bExcess
		|| xRequireList.bMoment3 || xRequireList.bMoment4)
	{


		///Sandy 2008-5-17 use FDF's moment value if function is analytical
		vector vMoments(4);
		StringArray arrMomentNames = {"mz1", "mc2", "mc3", "mc4"};
		nRet = NF.EvaluateMomentsAnalytically(vMoments, arrMomentNames, vZeroY0Params, vZeroY0Params.GetSize());
		ASSERT(nRet == 0);
		m1 = vMoments[0];
		m2 = vMoments[1];
		m3 = vMoments[2];
		m4 = vMoments[3];
		//bRet = calc_peak_moments(vDestX, vDestY, NULL,&m1, &m2, &m3, &m4);// sandy 2008-5-15 should use generate data
		if(nMomentdMode == MOMENT_METHOD_NUM_INTEGRAL) // for speed calculation of integration of moment m1, m2,m3,m4
		{

			/*
			if(m2 == NANUM ||m3 == NANUM ||m4 == NANUM )
			{
				bRet = calc_peak_moments(vFullPeakX, vFullPeakY, NULL,&m1, &m2, &m3, &m4);
				if(!bRet)
				return bRet;
			}
			*/
			
			// Jack   05/29/2008  SEPARATE_MOMENTS_CAL_OUT_FOR_QUICK_METHOD
			// Need separate different moments calculation out, as the special function can not always be calculated in one time for all four moments, some lower moments may exist while some higher ones may not
			// otherwise the moments value return by this method are meaningless i.e for pearsonVII moments
			
			if(m2 == NANUM)
			{
				if(bHasInfoAboutMomentsCalculable)
				{
					if ( MOMENTEXISTS_2 & dwMoments ) // check if moment_2 exists for certain cases 
				    {
				    	bRet = calc_peak_moments(vFullPeakX, vFullPeakY, NULL, NULL, &m2, NULL, NULL);
						if(!bRet)
						return bRet;
                    }
                    else
                    {
                    	m2 = ONLSF8_MOMENT_VALUE_NOT_APPLICABLE;
                    }
				}
				else
				{
					bRet = calc_peak_moments(vFullPeakX, vFullPeakY, NULL,NULL, &m2, NULL, NULL);
					if(!bRet)
					return bRet;
				}
			}
			
			
			if(m3 == NANUM)
			{
				if(bHasInfoAboutMomentsCalculable)
				{
					if ( (MOMENTEXISTS_3 & dwMoments) ) // check if moment_3 exists for certain cases 
				    {
				    	bRet = calc_peak_moments(vFullPeakX, vFullPeakY, NULL, NULL,NULL, &m3, NULL);
						if(!bRet)
						return bRet;
                    }
                    else
                    {
                    	m3 = ONLSF8_MOMENT_VALUE_NOT_APPLICABLE;
                    }
				}
				else
				{
					bRet = calc_peak_moments(vFullPeakX, vFullPeakY, NULL, NULL,NULL, &m3, NULL);
					if(!bRet)
					return bRet;
				}
			}
			
			if(m4 == NANUM)
			{
				if(bHasInfoAboutMomentsCalculable)
				{
					if ( (MOMENTEXISTS_4 & dwMoments) ) // check if moment_2 exists for certain cases 
				    {
				    	bRet = calc_peak_moments(vFullPeakX, vFullPeakY, NULL, NULL, NULL,NULL, &m4);
						if(!bRet)
						return bRet;
                    }
                    else
                    {
                    	m4 = ONLSF8_MOMENT_VALUE_NOT_APPLICABLE;
                    }
				}
				else
				{
					bRet = calc_peak_moments(vFullPeakX, vFullPeakY, NULL, NULL, NULL,NULL, &m4);
					if(!bRet)
					return bRet;
				}
			}
			// End SEPARATE_MOMENTS_CAL_OUT_FOR_QUICK_METHOD
			
			
			///end QUIKE_METHOD_OF_PEAK_MOMENTS_AND_INTEGRAL_EVALUATION
		}
		else // Add Function Integral for accurate calculation
		{
			nMomentType = PEAK_CENTRAL_MOMENT;
			
			// Jack 05/29/2008 ADD_SUPPORT_FOR_INTEGRAL_IN_FUNCTION_DEFINABLE_RANGE     i.e. for Weibull Pulse.function which may only be definable in certain range
			vector vBounds(2);
			StringArray arrBoundNames = {"_mlower","_mupper"};
			int nRet = NF.EvaluateMomentsAnalytically(vBounds, arrBoundNames, vFitParams, vFitParams.GetSize()); // to get function definable range if exist
			ASSERT(nRet == 0);
			
			double dLowerBound, dUpperBound;
			dLowerBound = (vBounds[0] == NANUM ? (-INFINITY) : vBounds[0]);
			dUpperBound = (vBounds[1] == NANUM ? INFINITY : vBounds[1]);	
			ASSERT(dLowerBound < dUpperBound); 
			
			// End ADD_SUPPORT_FOR_INTEGRAL_IN_FUNCTION_DEFINABLE_RANGE
			

			if(m2 == NANUM)//Sandy 2008-5-17 the moment isn't analytical and applicable to compute
			{
			    // Jack 05/23/2008 ADD_SPECIAL_SUPPORT_FOR_FUNCTION_WITH_MOMENTS_CALCULABLE_IN_CERTAIN_CASES
				if(bHasInfoAboutMomentsCalculable) // For those functions provide info that moments are calculable in certain cases
				{
				    if ( MOMENTEXISTS_2 & dwMoments ) // check if moment_0 exists for certain cases     i.e. see PearsonVII pdf
				    {
				        nMomentOrder = 2;
				        // m2=NF.CalcPeakMoment(dPeakXC-TIMES_W_FROM_CENTER_AS_INFINITE*dPeakWidth, dPeakXC+TIMES_W_FROM_CENTER_AS_INFINITE*dPeakWidth, vZeroY0Params, nMomentOrder, nMomentType, nErr, dPrecision);
                        m2=NF.CalcPeakMoment(dLowerBound, dUpperBound, vZeroY0Params, nMomentOrder, nMomentType, nErr, dPrecision);
	                    if(nErr)
	                    {
	                    	error_report("NF calcPeakMoment return error:"+nErr);
	                    }
                    }
                    else //  moment_2 not exist, namely, Not Applicable
                    {
                        m2 = ONLSF8_MOMENT_VALUE_NOT_APPLICABLE;
                    }
                }
                else // For those does not provide info about whether moments are calculable in certain cases then treat them calculable so that the previous logic is followed
				//  This may still be unacceptable for some special function which does not provide info about whether moments are calculable
                // End ADD_SPECIAL_SUPPORT_FOR_FUNCTION_WITH_MOMENTS_CALCULABLE_IN_CERTAIN_CASES
                {
                    nMomentOrder = 2;
                    // m2=NF.CalcPeakMoment(dPeakXC-TIMES_W_FROM_CENTER_AS_INFINITE*dPeakWidth, dPeakXC+TIMES_W_FROM_CENTER_AS_INFINITE*dPeakWidth, vZeroY0Params, nMomentOrder, nMomentType, nErr, dPrecision);
                    m2=NF.CalcPeakMoment(dLowerBound, dUpperBound, vZeroY0Params, nMomentOrder, nMomentType, nErr, dPrecision);
                    if(nErr)
                    {
                    	error_report("NF calcPeakMoment return error:"+nErr);
                    }
                }

			}

			if(m3 == NANUM)//Sandy 2008-5-17 the moment isn't analytical and applicable to compute
			{
			    // Jack 05/23/2008 ADD_SPECIAL_SUPPORT_FOR_FUNCTION_WITH_MOMENTS_CALCULABLE_IN_CERTAIN_CASES
			    if(bHasInfoAboutMomentsCalculable) // For those functions provide info that moments are calculable in certain cases
				{
				    if ( MOMENTEXISTS_3 & dwMoments ) // check if moment_0 exists for certain cases     i.e. see PearsonVII pdf
				    {
				        nMomentOrder = 3;
                       // m3=NF.CalcPeakMoment(dPeakXC-TIMES_W_FROM_CENTER_AS_INFINITE*dPeakWidth, dPeakXC+TIMES_W_FROM_CENTER_AS_INFINITE*dPeakWidth, vZeroY0Params, nMomentOrder, nMomentType, nErr, dPrecision);
                        m3 = NF.CalcPeakMoment(dLowerBound, dUpperBound, vZeroY0Params, nMomentOrder, nMomentType, nErr, dPrecision);
	                    if(nErr)
	                    {
	                    	error_report("NF calcPeakMoment return error:"+nErr);
	                    }
                    }
                    else //  moment_2 not exist, namely, Not Applicable
                    {
                        m3 = ONLSF8_MOMENT_VALUE_NOT_APPLICABLE;
                    }
                }
                else // For those does not provide info about whether moments are calculable in certain cases then treat them calculable so that the previous logic is followed
				//  This may still be unacceptable for some special function which does not provide info about whether moments are calculable
                // End ADD_SPECIAL_SUPPORT_FOR_FUNCTION_WITH_MOMENTS_CALCULABLE_IN_CERTAIN_CASES
                {
                    nMomentOrder = 3;
                    // m3=NF.CalcPeakMoment(dPeakXC-TIMES_W_FROM_CENTER_AS_INFINITE*dPeakWidth, dPeakXC+TIMES_W_FROM_CENTER_AS_INFINITE*dPeakWidth, vZeroY0Params, nMomentOrder, nMomentType, nErr, dPrecision);
                    m3 = NF.CalcPeakMoment(dLowerBound, dUpperBound, vZeroY0Params, nMomentOrder, nMomentType, nErr, dPrecision);
                    if(nErr)
                    {
                    	error_report("NF calcPeakMoment return error:"+nErr);
                    }
                }

			}

			if(m4 == NANUM)//Sandy 2008-5-17 the moment isn't analytical and applicable to compute
			{
			    // Jack 05/23/2008 ADD_SPECIAL_SUPPORT_FOR_FUNCTION_WITH_MOMENTS_CALCULABLE_IN_CERTAIN_CASES
			    if(bHasInfoAboutMomentsCalculable) // For those functions provide info that moments are calculable in certain cases
				{
				    if ( MOMENTEXISTS_4 & dwMoments ) // check if moment_0 exists for certain cases     i.e. see PearsonVII pdf
				    {
				        nMomentOrder = 4;
                   //   m4=NF.CalcPeakMoment(dPeakXC-TIMES_W_FROM_CENTER_AS_INFINITE*dPeakWidth, dPeakXC+TIMES_W_FROM_CENTER_AS_INFINITE*dPeakWidth, vZeroY0Params, nMomentOrder, nMomentType, nErr, dPrecision);
                   		m4 = NF.CalcPeakMoment(dLowerBound, dUpperBound, vZeroY0Params, nMomentOrder, nMomentType, nErr, dPrecision);
	                    if(nErr)
	                    {
	                    	error_report("NF calcPeakMoment return error:"+nErr);
	                    }
                    }
                    else //  moment_2 not exist, namely, Not Applicable
                    {
                        m4 = ONLSF8_MOMENT_VALUE_NOT_APPLICABLE;
                    }
                }
                else // For those does not provide info about whether moments are calculable in certain cases then treat them calculable so that the previous logic is followed
				//  This may still be unacceptable for some special function which does not provide info about whether moments are calculable
                // End ADD_SPECIAL_SUPPORT_FOR_FUNCTION_WITH_MOMENTS_CALCULABLE_IN_CERTAIN_CASES
                {
                    nMomentOrder = 4;
            //      m4=NF.CalcPeakMoment(dPeakXC-TIMES_W_FROM_CENTER_AS_INFINITE*dPeakWidth, dPeakXC+TIMES_W_FROM_CENTER_AS_INFINITE*dPeakWidth, vZeroY0Params, nMomentOrder, nMomentType, nErr, dPrecision);
            		m4 = NF.CalcPeakMoment(dLowerBound, dUpperBound, vZeroY0Params, nMomentOrder, nMomentType, nErr, dPrecision);
                    if(nErr)
                    {
                    	error_report("NF calcPeakMoment return error:"+nErr);
                    }
                }


			}
		}

		///Sandy 2008-5-17 if NF return ONLSF8_MOMENT_VALUE_NOT_APPLICABLE, re-set moment to NANUM;
		m2 = (m2 == ONLSF8_MOMENT_VALUE_NOT_APPLICABLE? NANUM : m2);
		m3 = (m3 == ONLSF8_MOMENT_VALUE_NOT_APPLICABLE? NANUM : m3);
		m4 = (m4 == ONLSF8_MOMENT_VALUE_NOT_APPLICABLE? NANUM : m4);
		///end

	}
#endif // __IMPROVE_PA_FIT_SPEED__ ///---Sim 10-12-2009 QA81-14388 IMPROVE_SPEED_OF_PA_FIT

	////debug
	//out_int("Prepare moments if needing in :", GetTickCount() - nT);
	//nT =  GetTickCount() ;

	//calculate peaks characterization
	if(xRequireList.bAreaFit)
	{
		///---Sim 10-12-2009 QA81-14388 IMPROVE_SPEED_OF_PA_FIT
#ifdef __IMPROVE_PA_FIT_SPEED__
		xPFMPeakCharsValueList.dAreaFit = vMoments[0];
#else // __IMPROVE_PA_FIT_SPEED__
		///---END QA81-14388 IMPROVE_SPEED_OF_PA_FIT
		xPFMPeakCharsValueList.dAreaFit = dAreaFit;
#endif // __IMPROVE_PA_FIT_SPEED__ ///---Sim 10-12-2009 QA81-14388 IMPROVE_SPEED_OF_PA_FIT
	}

	if(xRequireList.bAreaFitT)
	{
		xPFMPeakCharsValueList.dAreaFitT = dAreaFitT;
	}


	if(xRequireList.bAreaFitTP)
	{
		/// Hong 01/13/09 v8.0995d IMPROVE_CODE_OF_MEMORY_CONSUMER_IN_PA
		//xPFMPeakCharsValueList.dAreaFitTP = dAreaFitT/dAreaFitTCumArea*100.;
		xPFMPeakCharsValueList.dAreaFitTP = cal_area_fit_TP(dAreaFitT, dAreaFitTCumArea);
		/// end IMPROVE_CODE_OF_MEMORY_CONSUMER_IN_PA		
	}

	if(xRequireList.bAreaIntg)
	{
		xPFMPeakCharsValueList.dAreaIntg = xPeakIntg.Area;
	}

	if(xRequireList.bAreaIntgP)
	{
		xPFMPeakCharsValueList.dAreaIntgP = xPeakIntg.Area/dCumArea*100.;

	}


	if(xRequireList.bCenterMax)
	{
		TreeNode trNode = trIdealPeak.GetNode(_IDEAL_PEAK_CENTER_MAX_TAGNAME);
		ASSERT(trNode.IsValid());
		xPFMPeakCharsValueList.dCenterMax =	trNode.dVal;

	}

	if(xRequireList.bCenterGrvty)
	{
		///---Sim 10-12-2009 QA81-14388 IMPROVE_SPEED_OF_PA_FIT
#ifdef __IMPROVE_PA_FIT_SPEED__
		xPFMPeakCharsValueList.dCenterGrvty = vMoments[1];
#else // __IMPROVE_PA_FIT_SPEED__
		///---END QA81-14388 IMPROVE_SPEED_OF_PA_FIT
//		TreeNode trNode = trIdealPeak.GetNode(_IDEAL_PEAK_CENTROID_X_TAGNAME);
//		ASSERT(trNode.IsValid());
//		xPFMPeakCharsValueList.dCenterGrvty =	trNode.dVal;

		// Jack  06/07/2008  USE_ZEROPT_FIRST_MOMENT_AS_CENTER_GRVTY_AS_IN_PFM
		nMomentOrder = 1;
		nMomentType = PEAK_ZERO_POINT_MOMENT;
//		double dZeroPtMoment1 = NF.CalcPeakMoment(dPeakXC-TIMES_W_FROM_CENTER_AS_INFINITE*dPeakWidth, dPeakXC+TIMES_W_FROM_CENTER_AS_INFINITE*dPeakWidth, vZeroY0Params, nMomentOrder, nMomentType, nErr, dPrecision);
		double dZeroPtMoment1 = NF.CalcPeakMoment(-INFINITY, INFINITY, vZeroY0Params, nMomentOrder, nMomentType, nErr, dPrecision);
		if(nErr)
	    {
          	error_report("NF calcPeakMoment return error:"+nErr);
          	dZeroPtMoment1 = NANUM;
    	}
		xPFMPeakCharsValueList.dCenterGrvty = dZeroPtMoment1;  
		// End USE_ZEROPT_FIRST_MOMENT_AS_CENTER_GRVTY_AS_IN_PFM
#endif // __IMPROVE_PA_FIT_SPEED__ ///---Sim 10-12-2009 QA81-14388 IMPROVE_SPEED_OF_PA_FIT
	}

    if(xRequireList.bMaxHeight)
    {
		TreeNode trNode = trIdealPeak.GetNode(_IDEAL_PEAK_HEIGHT_MAX_TAGNAME);
		ASSERT(trNode.IsValid());
		xPFMPeakCharsValueList.dMaxHeight =	trNode.dVal;
    }

    if(xRequireList.bFWHM)
    {
		TreeNode trNode = trIdealPeak.GetNode(_IDEAL_PEAK_FWHM_TAGNAME);
		ASSERT(trNode.IsValid());
		xPFMPeakCharsValueList.dFWHM =	trNode.dVal;
    }


	///---Sim 10-12-2009 QA81-14388 IMPROVE_SPEED_OF_PA_FIT
#ifdef __IMPROVE_PA_FIT_SPEED__
    if(xRequireList.bVariance) //m2
    {
		xPFMPeakCharsValueList.dVariance = vMoments[2];
    }

    if(xRequireList.bSkew)
    {
    	xPFMPeakCharsValueList.dSkew = vMoments[3]/sqrt(vMoments[2]*vMoments[2]*vMoments[2]);
    }

    if(xRequireList.bExcess)
    {
    	xPFMPeakCharsValueList.dExcess = vMoments[4]/(vMoments[2]*vMoments[2]) - 3;
    }
#else // __IMPROVE_PA_FIT_SPEED__
    if(xRequireList.bVariance) //m2
    {
		xPFMPeakCharsValueList.dVariance = m2;
    }

    if(xRequireList.bSkew)
    {
    	xPFMPeakCharsValueList.dSkew = m3/sqrt(m2*m2*m2);
    }

    if(xRequireList.bExcess)
    {
    	xPFMPeakCharsValueList.dExcess = m4/(m2*m2) - 3;
    }
#endif // __IMPROVE_PA_FIT_SPEED__ ///---Sim 10-12-2009 QA81-14388 IMPROVE_SPEED_OF_PA_FIT

    double dBottomWidth;
    if(xRequireList.bResolution)//from cloud's function
    {
		double dFWHM = dPeakWidth/2;
		double dLeft, dRight;
	    nRet=ocmath_find_inflection_point(vFullPeakX.GetSize(),  vFullPeakX, vFullPeakY, dPeakXC, dFWHM, &dLeft, &dRight, &dBottomWidth);///Sandy 2008-5-12 use outside peak parameters
	    if (nRet<0)
			return false;

    	if(dLastWidth == 0)
    		xPFMPeakCharsValueList.dResolution = NANUM;
    	else
			xPFMPeakCharsValueList.dResolution = 2*(dLastXC - dPeakXC)/(dLastWidth + dBottomWidth);

    }


	///---Sim 10-12-2009 QA81-14388 IMPROVE_SPEED_OF_PA_FIT
#ifdef __IMPROVE_PA_FIT_SPEED__
    if(xRequireList.bMoment3)
    {
    	xPFMPeakCharsValueList.dMoment3 = vMoments[3];
    }

    if(xRequireList.bMoment4)
    {
    	xPFMPeakCharsValueList.dMoment4 = vMoments[4];
    }
#else // __IMPROVE_PA_FIT_SPEED__
    if(xRequireList.bMoment3)
    {
    	xPFMPeakCharsValueList.dMoment3 = m3;
    }

    if(xRequireList.bMoment4)
    {
    	xPFMPeakCharsValueList.dMoment4 = m4;
    }
#endif // __IMPROVE_PA_FIT_SPEED__ ///---Sim 10-12-2009 QA81-14388 IMPROVE_SPEED_OF_PA_FIT


    if(xRequireList.bWidthAtP)
    {
    	double dWidthAtY = dWidthAtPercent/100 * (xPeakIntg.yPeak - xPeakIntg.yPeakBase);
		//set how many x should be finded
		uint nSize = 2;
		vector vFindx;
		vector<int> vFindxNum;
		vFindx.SetSize(nSize);
		vFindxNum.SetSize(nSize);

		//find _compute_y_by_x function in stats_operations.c
		string strFile = GetOriginPath() + "OriginC\\OriginLab\\nlsf_utils.c";
		PFN_STR_INT_DOUBLE_DOUBLE_DOUBLEP pFunc = Project.FindFunction("compute_y_by_x", strFile, true);

		int nRet = ocmath_find_xs(dWidthAtY, (uint)(vy.GetSize()), vx, vy, nSize, vFindx,
						strFuncName, vFitParams.GetSize(), vFitParams, pFunc, vFindxNum);

		if(nRet == OE_NOERROR && vFindx[1] != NANUM && vFindx[0] != NANUM)
		{
			xPFMPeakCharsValueList.dWidthAtP = abs(vFindx[1] - vFindx[0]);
		}
		else
		{
			xPFMPeakCharsValueList.dWidthAtP = NANUM;
		}

		xPFMPeakCharsValueList.dWidthAtPP = dWidthAtPercent;//add for output to result
    }

    if(xRequireList.bAreaAbove)
    {

    	double dAreaAboveY = dAreaAbovePercent/100 * abs(xPeakIntg.yPeak - xPeakIntg.yPeakBase);
    	vector vYTemp;
    	vYTemp = vy;
    	if(xPeakIntg.yPeak - xPeakIntg.yPeakBase<0)
    		vYTemp = -1* vYTemp;

    	vYTemp = vYTemp - dAreaAboveY;
    	vYTemp.Replace(0,0,MATREPL_TEST_LESSTHAN);

		IntegrationResult xAboveIntg;
		ocmath_integrate(vx, vYTemp, 0, vx.GetSize()-1, &xAboveIntg, NULL, ABSOLUTE_AREA);

		xPFMPeakCharsValueList.dAreaAbove = xAboveIntg.Area;


		xPFMPeakCharsValueList.dAreaAboveP = dAreaAbovePercent;//add for output to result
    }

    if(xRequireList.bCumArea)
    {
    	xPFMPeakCharsValueList.dCumArea =  NF.Integral(-INFINITY,dPeakXC + dCumAreaTo, vZeroY0Params);
    	xPFMPeakCharsValueList.dCumAreaP = dCumAreaTo;//add for output to result

    }

    //dLastXC =  xPeakIntg.xPeak;
    dLastXC =  dPeakXC;//Sandy 2009-1-20 More resonable than that of SR4
    dLastWidth = dBottomWidth;


	////debug
	//out_int("calculate all in :", GetTickCount() - nT0);
	//nT =  GetTickCount() ;
	//printf("===================\n");

	return true;
}


bool _check_if_need_compute_peaks_characterization(const PFMPeakCharsRequire xRequireList)
{
	if(xRequireList.bAreaFit||xRequireList.bAreaFitT||xRequireList.bAreaFitTP
		||xRequireList.bAreaIntg||xRequireList.bAreaIntgP||xRequireList.bCenterMax
		||xRequireList.bCenterGrvty||xRequireList.bMaxHeight||xRequireList.bFWHM
		||xRequireList.bVariance||xRequireList.bSkew||xRequireList.bExcess||xRequireList.bResolution
		||xRequireList.bMoment3||xRequireList.bMoment4||xRequireList.bWidthAtP||xRequireList.bAreaAbove
		||xRequireList.bCumArea)
		return true;

	return false;
}

/////////////////////////////////////////////////////////////////////////////////////////////////
////////////////Move From PFMWiz.h//////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////

void events_from_peaks_finding_control_line_go(int nID)
{
	post_getn_dialog_message(WM_USER_ON_GRAPH_OBJECT_CHANGE, 1);
}



//bool create_baseline_events_handler(TreeNode& trGetN, int nEventID, LPCSTR lpcszNodeName, bool& bOKEnable, string& strAux, string& strErrMsg)
//{
	//GraphLayer gl;
	//if(!get_gl_from_xyr_treenode(gl, trGetN.iy))
	//{
		//gl = Project.ActiveLayer();
	//}
	//
	//
	//GraphPage gp = gl.GetPage();
	//DataPlot dpData;
	//if(nEventID == GETNE_ON_INIT || nEventID == GETNE_ON_THEME ||  nEventID == GETNE_ON_NEXT || nEventID == GETNE_ON_RESTORE
		//|| !lstrcmpi(lpcszNodeName, "npts"))
	//{
			//
		//if(is_wizzard_mode(gp, PFM_WIZZARD_MODULE))
		//{
			//if(!o8bpw_replace_input_treenode_by_dataplot(gl, trGetN.iy, PFW_ORIGIN_PLOT_TAGNAME, dpData))
			//{
				//bOKEnable = false;
				//strErrMsg = XFERR_FAILED_GET_DATAPLOT_FROM_XYRANGE;
				//return true;
			//}
			//
		//}
		//
		//XYRange iy;
		//TreeNode& trInput = trGetN.iy;
		//okxf_resolve_tree_construct_range(&trInput, &iy);
		//if(!iy.GetPlot(dpData))
		//{
			//strErrMsg = XFERR_FAILED_GET_DATAPLOT_FROM_XYRANGE;
			//bOKEnable = false;
			//return true;
		//}
		//
		//set_npts_same_x_with_data(trGetN, iy);
	//}
		//
	//DataPlot dpbl;
	//check_baseline_plot(gl, dpbl);
	//
	//switch(nEventID)
	//{
	//case GETNE_ON_NEXT:
		//if(dpbl.IsValid())
			//dpbl.AttachXFunction("");
		//break;
	//
	//case GETNE_ON_APPLY:
		//bOKEnable = false; // for disable apply button to prevent apply function twice
		//break;
	//case GETNE_ON_UNDO:
		//if(dpbl.IsValid())
		//{
			//delete_dataplot_and_clear_from_tree(gl, PFW_BASELINE_PLOT_TAGNAME);
		//}
		//remove_executed_ds_from_new(trGetN, "oy");
		//delete_last_xf_info_from_page();
		//break;
	//default:
		//break;
	//}
	//hide_lengends_of_unshow_dataplots(gl);
	//return true;
//}
//

/*
bool pfm_save_peaks_to_tree(GraphLayer gl, XYRange& xyPeaks)
{
	/// Hong 11/22/07 v8.0753 ADD_VALID_CHECK_AVOID_RUNTIME
	if ( !gl )
		return false;
	/// end ADD_VALID_CHECK_AVOID_RUNTIME

	GraphPage gp = gl.GetPage();
	HWND hwnd;
	Tree trGetN;
	load_GetN_from_page(gp, trGetN,  hwnd, STR_STORAGE_NAME);
	//TreeNode trPeaks, trPeaksPlot;


	//tree_check_get_node_by_dataid(trGetN, trPeaks,"Peaks", IDE_PFM_PEAKS );
	//if(!trPeaks)
	//{
		//return false;
	//}

	if(xyPeaks == NULL)
	{
		return false;
	}

	DataPlot dpPeaksPlot;
	if(!xyPeaks.GetPlot(dpPeaksPlot))
	{
		dpPeaksPlot = xyPeaks.MakePlot(gl);
	}
	dpPeaksPlot.Show(false);
	//tree_check_get_node_by_dataid(trGetN, trPeaksPlot,PFW_PEAKS_PLOT_TAGNAME, IDE_PFM_PEAKS_PLOT);
	TreeNode trPeaksPlot = tree_check_get_node(trGetN, PFW_PEAKS_PLOT_TAGNAME);
	if(!trPeaksPlot || !dataplot_save_to_tree(trPeaksPlot, dpPeaksPlot))
	{
		return false;
	}


	save_GetN_to_page(gp, trGetN,  hwnd, STR_STORAGE_NAME);

	return true;
}
*/
///Sandy 2007-12-3 add
//bool check_peaks_plot(GraphLayer gl, DataPlot& dpPeaksPlot)
//{
	//GraphPage gp = gl.GetPage();
	//HWND hwnd;
	//Tree trGetN;
	//load_GetN_from_page(gp, trGetN,  hwnd, STR_STORAGE_NAME);
	//
	//TreeNode trPeaksPlot = trGetN.GetNode(PFW_PEAKS_PLOT_TAGNAME);
	////trPeaksPlot = tree_find_node_by_dataID(trGetN,  IDE_PFM_PEAKS_PLOT);
	//
	//if(!trPeaksPlot)
		//return false;
	//
	//return dataplot_read_from_tree(gl, trPeaksPlot, dpPeaksPlot);
//}

/* ---Sandy 2008-3-18 remove
///Sandy 2007-4-23 add
bool pfw8_get_peaks_center_from_ctrls(GraphLayer& gl, const vector& vx,const vector& vy, vector& vxNewPeaks, vector& vyNewPeaks)
{


	if(vx.GetSize()== 0|| !gl.IsValid())
		return false;

	vector vxPeaks;
	vector vyPeaks;
	LineControlList lcl(gl, PEAK_CENTER_RED_LINE_NAME);
	if(!lcl.IsValid())
		return false;

	lcl.GetLinePositions(vxPeaks);
	int npeaks = vxPeaks.GetSize();

	if(npeaks<=0)
		return false;

	vxNewPeaks.SetSize(0);
	vyNewPeaks.SetSize(0);

	double dMin, dMax;
	vx.GetMinMax(dMin, dMax);
	double dErr = (dMax - dMin)/vx.GetSize();

	for(int ii = 0; ii<npeaks; ii++)
	{
		vector<uint> vecIndex;

		int nFound = vx.Find(vecIndex, vxPeaks[ii]-dErr, vxPeaks[ii]+dErr);
		if(  nFound >= 1 )
		{
			vxNewPeaks.Add(vxPeaks[ii]);
			vyNewPeaks.Add(vy[vecIndex[0]]);
		}
	}

	if(vxNewPeaks.GetSize() == 0 || vyNewPeaks.GetSize() == 0)
		return false;

	return true;

}

///end

*/


/////////////////////////////////////////////////////////////////////////////////////////////////
////////////////End of PFMWiz.h//////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////



//Sandy need to remove later
//bool is_existed_baseline_in_gp_storage(GraphLayer gl,bool bClean)
//{
	//GraphPage gp = gl.GetPage();
	//HWND hwnd;
	//Tree trGetN;
	//load_GetN_from_page(gp, trGetN,  hwnd, STR_STORAGE_NAME);
	//
	//TreeNode trBaseline;
	//trBaseline = tree_find_node_by_dataID(trGetN,  IDE_O8_BASELINES);
	//
	//if(!trBaseline)
		//return false;
	//
	//TreeNode trBaselineExisted = trBaseline.GetNode(PFW_EXISTED_BASELINE_TAGNAME);
	//if(trBaselineExisted.IsValid() && trBaselineExisted.nVal == 1)
	//{
		//if(bClean)
			//trBaselineExisted.nVal = 0;
		//return true;
	//}
	//else
		//return false;
//}

//bool set_existed_baseline_to_gp_storage(GraphLayer gl,bool bBaselineExisted)
//{
	//
	//
	//GraphPage gp = gl.GetPage();
	//HWND hwnd;
	//Tree trGetN;
	//load_GetN_from_page(gp, trGetN,  hwnd, STR_STORAGE_NAME);
	//TreeNode trBaselines,trBaselineExisted;
	//
	//tree_check_get_node_by_dataid(trGetN, trBaselines,PFW_BRANCH_BASELINE_TAGNAME, IDE_O8_BASELINES);
	//trBaselineExisted = trBaselines.GetNode(PFW_EXISTED_BASELINE_TAGNAME);
	//if(!trBaselineExisted)
	   //trBaselineExisted = trBaselines.AddNode(PFW_EXISTED_BASELINE_TAGNAME);
	//
	//trBaselineExisted.nVal = bBaselineExisted;
//
	//save_GetN_to_page(gp, trGetN,  hwnd, STR_STORAGE_NAME);
	//
	//return true;
//}

//bool auto_find_baseline_points(vector& vx, vector& vy, int npts)
//{
	//if(vx.GetSize()!=vy.GetSize() || npts<=0)
		//return false;
	//
	//int nSize = vy.GetSize(), nRet;
	//
	//vector<int> vLM, vRM;
	//vector vXofPeaks;
	//int nPeaksNum = npts;
	//find_peaks_by_number_full_auto(vx, vy, nPeaksNum, vXofPeaks,NULL, NULL, vLM, vRM);
	//nPeaksNum = vXofPeaks.GetSize();
	//
	//if(nPeaksNum <= 0)
	//{
		//double dMax, dMin;
		//vx.GetMinMax(dMin, dMax);
		//double d = (dMax-dMin)/3;
		//vXofPeaks.Data(dMin+d, dMax-d, d);
		//vLM.SetSize(npts);
		//vRM.SetSize(npts);
		//double dWidth = (dMax - dMin)/(npts*4);
		//for(int jj = 0; jj<npts; jj++)
		//{
			//vLM[jj] = vXofPeaks[jj]-dWidth;
			//vRM[jj] = vXofPeaks[jj]+dWidth;
		//}
	//}
	//
	//vector vxb(npts), vyb(npts);
	//
	//for(int ii = 0; ii<nPeaksNum; ii++)
	//{
		//vxb[ii]= vx[vLM[ii]];
		//vyb[ii]= vy[vLM[ii]];
	//}
	//
	//
	//vxb.SetSize(npts);
	//vyb.SetSize(npts);
	//
	//vx = vxb;
	//vy = vyb;
	//
	//return true;
//}

///need to replace with destroy_pfw_temp_wps later
//void clean_find_peaks_temp_wks()
//{
	////WorksheetPage wp1(PREVIEW_2ND_DERVIA_WORKSHEETPAGE);
	////if(wp1.IsValid())
		////wp1.Destroy();
	////
	////WorksheetPage wp2(PREVIEW_RESIDUAL_WORKSHEETPAGE);
	////if(wp2.IsValid())
		////wp2.Destroy();
		//
	//string strWksList = PREVIEW_2ND_DERVIA_WORKSHEETPAGE + "," +PREVIEW_RESIDUAL_WORKSHEETPAGE + "," + PKINFO_TEMP_WKS_NAME;
	//destroy_pfw_temp_wps(strWksList);
	//
//}
//


//void clean_edit_peaks_temp_wks()
//{
	//string strWksList = PKEDIT_TEMP_WKS_NAME;
	//destroy_pfw_temp_wps(strWksList);
	//
//}



//void back_up_page(const GraphPage& gp)
//{
	//if(!gp.IsValid())
	   //return;
	//GraphPage gpBackup;
	//gpBackup.Create("origin", CREATE_SET_MISSING_IN_MANAGER);
	//if(gpBackup && page_clone(gp, gpBackup))
	//{
		//page_set_storage_str(gp, "BackupCopy", gpBackup.GetName());
	//}
	//else
		//gpBackup.Destroy();
//}

//
//void clean_up_pfw_trace(Page& pg, bool bRecover, bool bShowOriginalData, bool bKeepBaseline, bool bCleanTree)
//{
	////clean_find_peaks_temp_wks();
	//destroy_pfw_temp_wps(PREVIEW_2ND_DERVIA_WORKSHEETPAGE + "," +PREVIEW_RESIDUAL_WORKSHEETPAGE + "," + PKINFO_TEMP_WKS_NAME;);
	//
	//clean_edit_peaks_temp_wks();
	//
	/////Jasmine 01/19/08 SHOULD_GET_SOURCE_LAYER_FROM_STORANGE
	////GraphLayer gl = Project.ActiveLayer();
	//GraphLayer gl;
	//HWND hwnd;
	//Tree trGetN;
	//load_GetN_from_page(pg, trGetN,  hwnd, STR_STORAGE_NAME);
	//TreeNode trNode = trGetN.GetNode(PFW_ORIGIN_PLOT_TAGNAME);
	//if(trNode.IsValid())
		//get_gl_from_xyr_treenode(gl, trNode);
	/////End SHOULD_GET_SOURCE_LAYER_FROM_STORANGE
	//if(gl.IsValid())
	//{
		//pfmLineControlList lcList(gl, PEAK_ANCHOR_CONTROL_LINE_NAME);
		//lcList.RemoveAll();
	//
		//GraphPage gpBackup;
		//string strCopyName;
		//page_get_storage_str(pg, "BackupCopy", strCopyName);
		//if(!strCopyName.IsEmpty())
		//{
			//GraphPage gpTemp(strCopyName);
			//gpBackup = gpTemp;
		//}
		//
		//GraphPage gp = gl.GetPage();
		//
		//if(bRecover)
		//{
			//if(gpBackup && gp)
			//{
				//page_clone(gpBackup, gp, false);
			//}
			//return;
		//}
		//
		//if(gpBackup)
			//gpBackup.Destroy();
		//
		//get_back_page_no_click(gl);
		//
		//GraphObject go = gl.GraphObjects(GO_LEGEND_NAME);
		//if(gpBackup)
		//{
			//GraphObject goBackup = gpBackup.Layers().GraphObjects(GO_LEGEND_NAME);
			//if(go && goBackup)
				//go.Text = goBackup.Text;
		//}
	//}
//
	//if(pg && bCleanTree)
		//clear_tree_attatched_to_page(pg);
//
//}

///Arvin 12/05/07 XOP_NEED_SUPPORT_PFW
//If user haven't add pfw functions to user or system folder,
//when he do multiply peak fit from xop, we need add these functions to folder
//bool add_pfw_functions_to_folder(bool bUserFolder)
//{
	//static vector<string> vstrCategories = {
		//STR_NLSF_CAT_BASELINE,
		//STR_NLSF_CAT_PFM
	//};
//
	//static vector<string> vstrBaselineFileNames = {
		//"Line",
		//"CUBIC",
		//"PARABOLA",
		//"Poly4",
		//"Poly5",
		//"HYPERBL",
		//"EXPONENT",
		//"ExpDec1",
		//"ExpDec2",
		//"ExpGro1",
		//"EXPGROW1",
		//"EXPGROW2",
		//"MMOLECU1"
	//};
//
	//static vector<string> vstrPFMFileNames = {
		///// Cloud 10/22/07 use gauss and lorentz with y0
		//"Gaussian",
		////"pfmGaussian2",
		//"GaussAmp",
		//"BiGaussian",
		////"pfmGaussianMod",
		//"gaussmod",
		////"pfmGramCharlier",
		//"grmcharl",
		////"pfmEdgeworthCramer",
		//"edgwthcr",
		////"pfmCheslerCram",
		//"cheslecr",
		////"pfmLorentzian",
		//"Lorentz",
		////"pfmLogNormal",
		//"lognorm",
		////"pfmVoigt5",
		//"Voigt5",
		////"pfmPseudoVoigt1",
		//"psdvgt1",
		////"pfmPseudoVoigt2",
		//"psdvgt2",
		////"pfmPearsonVII",
		//"Pearson7",
		////"pfmAsymDblSig",
		//"asymdbls",
		////"pfmWeibull3",
		//"Weibull3",
		////"pfmInversePoly",
		//"invspoly",
		////"pfmSine",
		////"pfmSineSqr",
		////"pfmSineDamp",
		//"Sine",
		//"SineSqr",
		//"SineDamp",
		////"pfmPower1",	//without y0, and isn't Peaks function
		////"pfmPower2",	//without y0, and isn't Peaks function
//
		////"pfmPulse",
		//"Pulse",
		//"FraserSuzuki",
		//"DoniachSunjic",
		//"Gaussian_LorenCross",
		//"ConsGaussian",
		//"HVL",
		//"BWF"
	//};
//
	////add by sandy 2006-3-16 for  access user folder
	//int nPathType;
	//if(bUserFolder)
		//nPathType = USER_FOLDER;
	//else
		//nPathType = SYS_FOLDER;
	////add end
//
	//NumFunctionOrganizer nfo;
	//string strOldName;
	//for (int ii = 0; ii < vstrCategories.GetSize(); ii++)
	//{
		//if (!nfo.UpdateCategoryToNLSF(vstrCategories[ii], strOldName, nPathType))
		//{
			//return false;
		//}
		//vector<string> vstrFuncNames;
		//vstrFuncNames = (ii == 0) ? vstrBaselineFileNames : vstrPFMFileNames ;
		//for (int jj = 0; jj < vstrFuncNames.GetSize(); jj++)
		//{
			//Tree trFDF;
			//string strFullPath = GetOriginPath()+"FitFunc\\"+vstrFuncNames[jj]+".FDF";
			//if( !nlsf_FDF_to_tree( strFullPath, &trFDF) )
				//return false;
//
			//string strFuncName = nfo.GetFunctionName(trFDF);
			//if (!nfo.UpdateFunctionToNLSF(vstrCategories[ii], strFuncName, strOldName, strFullPath, nPathType))
			//{
				//return false;
			//}
		//}
	//}
	//return true;
//}
/////end XOP_NEED_SUPPORT_PFW

//----------Sandy 2008-11-18 APPLY_NEW_OCMATH_FUNCTION_PROTOTYPE_WITH_SG_DERIV
/*
//----- CPY 12/8/2007 QA80-10788 CURVE_UTILS_SHOULD_NOT_NEED_PRO_DLLS
int find_peaks_2nd_derivative_ex(UINT* lSize, const vector& vxData,const vector& vyData, vector& vxPeaks, vector& vyPeaks, vector<int>& vnIndices, DWORD dwCtrl, int nPtsSmooth)
{
	return ocmsp_find_peaks_2nd_derivative(lSize, vxData, vyData, vxPeaks, vyPeaks, vnIndices, dwCtrl, nPtsSmooth);
}
//-----
*/

int find_peaks_2nd_derivative_ex(UINT* lSize, const vector& vxData, const vector& vyData, vector& vxPeaks, vector& vyPeaks, vector<int>& vnIndices,  DWORD dwCtrl, int nSmoothDerivativeMethod, vector& v2ndDeriv, int nSGPtsSmooth, double dCutoffFreq, int nPolyOrder)
{
	int nRet;
	
	vector vDerivTemp;
	vDerivTemp.SetSize(vyData.GetSize());

	switch(nSmoothDerivativeMethod)
	{
	case DERIV_SMOOTH_NONE:
			nRet = ocmath_find_peaks_2nd_derivative(lSize, vxData, vyData, vxPeaks, vyPeaks, vnIndices, dwCtrl, DERIVATIVE_WITHOUT_SMOOTH, vDerivTemp);
			break;
	case DERIV_SMOOTH_FFT:
			nRet = ocmsp_find_peaks_2nd_derivative(lSize, vxData, vyData, vxPeaks, vyPeaks, vnIndices, dwCtrl, dCutoffFreq, vDerivTemp);					
			break;
	case DERIV_SMOOTH_ADJ:
			nRet = ocmath_find_peaks_2nd_derivative(lSize, vxData, vyData, vxPeaks, vyPeaks, vnIndices, dwCtrl, DERIVATIVE_WITH_ADJ_SMOOTH, vDerivTemp, nSGPtsSmooth);
			break;
	case DERIV_SMOOTH_SG:
			nRet = ocmath_find_peaks_2nd_derivative(lSize, vxData, vyData, vxPeaks, vyPeaks, vnIndices, dwCtrl, DERIVATIVE_USE_SG_SECOND_DERIV, vDerivTemp,  nSGPtsSmooth, nPolyOrder);
			break;
	case DERIV_SMOOTH_QSG:
			nRet = ocmath_find_peaks_2nd_derivative(lSize, vxData, vyData, vxPeaks, vyPeaks, vnIndices, dwCtrl, DERIVATIVE_WITH_CONTINUOUS_SG_FIRST_DER_SMOOTH, vDerivTemp, nSGPtsSmooth, nPolyOrder);
			break;
	default:
		error_report("Invalid derivative smooth method! in find_peaks_2nd_derivative_ex()");
		break;
	}
	
	if(v2ndDeriv != NULL)
		v2ndDeriv = vDerivTemp;
	
	return nRet;
}
//----------end APPLY_NEW_OCMATH_FUNCTION_PROTOTYPE_WITH_SG_DERIV

//
//TreeNode pfw8_construst_default_baseline_branch_in_pfw_tree(TreeNode trPeaks)
//{
	//
	//if(!trPeaks)
	     //return NULL;
	//
	//TreeNode trPeak0 = trPeaks.GetNode("Peak0");
	//if(trPeak0)
		//trPeak0.Reset();
	//else
		//trPeak0 = trPeaks.InsertNode(trPeaks.FirstNode, "Peak0");
//
//
	//string strDefFunc = "Constant";
	//string strDefCat = "Polynomial";
	//vector<string> vstrParams(1);
	//vstrParams[0]= "y0";
	//string strDefFullPath;
	//nlsf_func_to_fdf(strDefCat, strDefFunc, strDefFullPath,  true);
	//
	//vector  vParams(1);
	//vParams[0] = 0;
	//
	//trPeak0.Reset();
	//construct_pfw_tree_peak_func_node(trPeak0, strDefFullPath, strDefFunc, strDefFunc);
	//construct_pfw_tree_peak_params_node(trPeak0, vstrParams, vParams);
	//
	//return trPeak0;
//}


//int pfw8_add_peaks_data_to_temp_wks(Worksheet& wks, vector& vx, vector& vy,  bool bIsPeakData)//, Page& pgStorage)
//{
	//
	//if(!wks.IsValid())
		//return -1;
	//
	//int n1st , n2nd;
	//if(bIsPeakData)
	//{
		//n2nd = wks.AddCol();
		//wks.Columns(n2nd).SetType(OKDATAOBJ_DESIGNATION_Y);
		//wks.Columns(n2nd).SetLongName(_L("Peak")+(string)(n2nd-1));
		//Dataset dsY(wks, n2nd);
		//dsY = vy;
	//}
	//else//Cumulate data always at the first two cols
	//{
		//wks.SetSize(-1, 0);
		//n1st = wks.AddCol();
		//n2nd = wks.AddCol();
		//wks.Columns(n1st).SetType(OKDATAOBJ_DESIGNATION_X);
		//wks.Columns(n2nd).SetType(OKDATAOBJ_DESIGNATION_Y);
		//wks.Columns(n2nd).SetLongName(_L("Cumulate"));
		//Dataset dsX(wks, n1st), dsY(wks, n2nd);
		//dsX = vx;
		//dsY = vy;
		//
		////if(pgStorage.IsValid())
		////{
			////XYRange xyCum;
			////
			////xyCum.Add(wks, n1st, "X");
			////xyCum.Add(wks, n1st, "Y");
			////
			////update_data_context_to_page(pgStorage, xyCum, PFW_PEAKS_CUM_PLOT_TAGNAME);
		////}
	//}
	//
	//return n2nd;
//
//}

//bool check_peaks_cum_range(Page& pg, XYRange& yc)
//{
	//if(!pg.IsValid())
		//return false;
	//
	//HWND hwnd;
	//Tree trGetN;
	//load_GetN_from_page(pg, trGetN,  hwnd, STR_STORAGE_NAME);
	//
	//TreeNode trCum = trGetN.GetNode(PFW_PEAKS_CUM_PLOT_TAGNAME);
	//
	//if(!trCum)
		//return false;
	//
	//
	//if(!okxf_resolve_tree_construct_range(&trCum, &yc)|| !yc.IsValid())
		//return false;
	//
	//return true;
//}


//bool pfw8_save_curve_fitting_info_to_col(Column& colY, vector<string>& vsParams, vector& vParams, string strFuncName, string strFileName, string strCategory)
//{
	//string strFullPath;
	//nlsf_func_to_fdf(strCategory, strFuncName, strFullPath,  true);
	//
	//Tree tr;
	//if(!colY.IsValid())
	//{
		//return false;
	//}
	//
	//colY.GetBinaryStorage("OriginStorage", tr);
	//construct_pfw_tree_peak_func_node(tr, strFullPath, strFileName, strFuncName);
	//construct_pfw_tree_peak_params_node(tr, vsParams, vParams);
	//colY.PutBinaryStorage("OriginStorage", tr);
//
	//return true;
//}

//bool pfw8_save_curve_fitting_info_to_dateplot(DataPlot& dp, vector<string>& vsParams, vector& vParams, string strFuncName, string strFileName, string strCategory)
//{
	//string strFullPath;
	//nlsf_func_to_fdf(strCategory, strFuncName, strFullPath,  true);
	//
	//Tree tr;
	//if(!dp.IsValid())
	//{
		//return false;
	//}
	//
	//dp.GetBinaryStorage("OriginStorage", tr);
	//construct_pfw_tree_peak_func_node(tr, strFullPath, strFileName, strFuncName);
	//construct_pfw_tree_peak_params_node(tr, vsParams, vParams);
	//dp.PutBinaryStorage("OriginStorage", tr);
//
	//return true;
//}


//bool pfw8_update_peak_data_by_Gaussian(Page& pgStorage, XYRange& xyPeak, double dX, double dHalfWidth, double dY, vector& voGuassian, vector& voGuassianParams)
//{
//
	//vector vy, vx;
	//if(!xyPeak.GetData(vy, vx))
		//return false;
//
//
	//vector vGuassianParams(4);//y0, xc, a. w
	//vGuassianParams[0] = 0;
	//vGuassianParams[1] = dX;
	//vGuassianParams[3] = dHalfWidth*2;
	//vGuassianParams[2] = dY*vGuassianParams[3]*sqrt(PI/(4*ln(2)));
//
	//vector vyGaussian;
	//vector vxGaussian;
//
	//if(!nlsf_evaluate(STR_PA_DEFAULT_FUNC, STR_NLSF_CAT_PFM, vx, vyGaussian, vGuassianParams))
		//return false;
//
	//vector vyFunc;
	//vyFunc = vyGaussian;
//
	//vector vbx, vby;
	//if(check_baseline_data(pgStorage, vbx, vby, true))
	//{
		//bool bIsSame;
		//if((vbx.GetSize() != vx.GetSize()) || OE_NOERROR != ocmath_compare_data(vbx.GetSize(), vbx, vx, &bIsSame) || !bIsSame)
		//{
			//int nSize = vx.GetSize();
			//vector vbyNew(nSize), vxBase;
			//vxBase = vx;
			//int nRet = ocmath_interpolate(vxBase, vbyNew, nSize, vbx, vby, vbx.GetSize(), INTERP_TYPE_LINEAR);
			//if(OE_NOERROR != nRet)
			//{
				//return false;
			//}
//
			//vby = vbyNew;
		//}
		//vyFunc = vyFunc + vby;
	//}
//
	//if(voGuassian != NULL)
		//voGuassian = vyGaussian;
//
	//if(voGuassianParams != NULL)
		//voGuassianParams = vGuassianParams;
//
	//return xyPeak.SetData(&vyFunc, &vx);
//}
/////end


//void pfw8_update_2ndDeriative_preivew_of_findpeak_page(TreeNode trGetN, GraphLayer& gl, int nEventID, string strNode, const vector& vx, const vector& vy,bool bUpdate)
//{
	//bool b2ndDeriative = trGetN.derivative.nVal;
	//if(nEventID == GETNE_ON_INIT || nEventID == GETNE_ON_RESTORE|| bUpdate)
	//{
		//pa8_update_advance_preview_data( vx, vy, NULL,  false, true);
    	//pa8_show_advance_preview_graph(gl, false, b2ndDeriative);
	//}
//
	//if(strNode == "derivative")
	//{
		//pa8_show_advance_preview_graph(gl, false, b2ndDeriative);
	//}
//
	//if(nEventID ==  GETNE_ON_PREVIOUS)
	//{
//
		//pa8_show_advance_preview_graph(gl, false, false);
	//}
//
	//if(nEventID ==  GETNE_ON_NEXT)
	//{
		//pa8_show_advance_preview_graph(gl, false, false);
//
	//}
////
	////LineControlList lcl(gl, PEAK_CENTER_RED_LINE_NAME);
	////
	////if(lcl.IsValid()&&!bUpdate && strNode == "derivative")
		////lcl.RemoveAll();
//}
//
bool  pfw8_get_executed_output_xyrange(TreeNode trGetN, string strTag, XYRange& xy)
{
	if(!trGetN.IsValid())
		return false;

	TreeNode tr = get_external_settings_branch(trGetN, EX_SETTING_EXEC_VALS);
	/// Hong 02/03/08 FIX_RUNTIME_ERROR_WHEN_TRY_WIZ_XFS_IN_LT
	if ( !tr.IsValid() )
		return false;
	/// end FIX_RUNTIME_ERROR_WHEN_TRY_WIZ_XFS_IN_LT
	TreeNode trNode = tr.GetNode(strTag);//ExecutionValues.
	if(!trNode)
		return false;

	string strData = trNode.strVal;
	DataRange dr;
	int nRet = dr.Create(strData, XVT_XYDATARANGE);

	if(dr.IsValid() && nRet == CER_NO_ERROR)
	{
		xy = dr;
		return true;
	}

	return false;

}


/*///Sandy remove since no used
/// Hong 02/18/08 v8.0806 CHANGE_BTN_BEHAVIOR_BY_EDIT_TEMP_WORKSHEET
//bool pfw8_line_controls_handler_of_findpeak_page(GraphLayer& gl, TreeNode& trGetN, int nEventID, string strNode, string& strErrMsg)
bool pfw8_line_controls_handler_of_findpeak_page(GraphLayer& gl, TreeNode& trGetN, int nEventID, string strNode, string& strErrMsg, const XYRange* pyp) // = NULL
/// end CHANGE_BTN_BEHAVIOR_BY_EDIT_TEMP_WORKSHEET
{

	if(!gl.IsValid() || !trGetN)
		return false;

	GraphPage gp = gl.GetPage();

	LineControlList lcl(gl, PEAK_CENTER_RED_LINE_NAME);
	//if(!trGetN.modify.nVal)
	//{
		//lcl.RemoveAll();
	//}
	//else
	//{
		switch(nEventID)
		{
		case GETNE_ON_RESTORE:
			lcl.ShowAll();
			break;
		case GETNE_ON_NEXT:
			lcl.ShowAll(false);
			break;
		case GETNE_ON_PREVIOUS:
			lcl.RemoveAll();
			break;

		case CLEAR_PEAKS_EVENT:
			{
				lcl.RemoveAll();
				XYRange yp;
				/// Hong 02/18/08 v8.0806 CHANGE_BTN_BEHAVIOR_BY_EDIT_TEMP_WORKSHEET
				//if(pfw8_get_executed_output_xyrange(trGetN, "yp", yp))
				if ( pyp )
					yp = *pyp;
				else
					pfw8_get_executed_output_xyrange(trGetN, "yp", yp);
				if ( yp )
				/// end CHANGE_BTN_BEHAVIOR_BY_EDIT_TEMP_WORKSHEET
				{
					vector vx, vy;
					yp.SetData(&vy, &vx);//clean data
				}

			}
			break;
		case ADD_ONE_PEAK_EVENT:
		{
			page_xf_dynadlg_shown_control(gp, 0, false);//close dlg during getting points from graph


			GetGraphPoints gpts;
			gpts.SetCursorPos(0, 0);
			gpts.SetCursor(0);
			if(!gpts.GetPoints(1, gl))
			{
				page_xf_dynadlg_shown_control(gp, 1, false);
				strErrMsg = XFERR_USER_CANCEL_PICK_PEAK;
			}
			vector vX, vY;
			gpts.GetData(vX, vY);

			if(trGetN.modify.nVal)
			{
				if(lcl.GetCount() > 0)
					lcl.Add(vX[0], SCRIPT_PKFIND_GROBJECT_EVENT);
				else
				    lcl.CreateList(gl, PEAK_CENTER_RED_LINE_NAME, vX, SCRIPT_PKFIND_GROBJECT_EVENT);
			}
			//else /// Hong 02/18/08 v8.0806 CHANGE_BTN_BEHAVIOR_BY_EDIT_TEMP_WORKSHEET
			{ // should also keep worksheet updated
				XYRange yp;
				/// Hong 02/18/08 v8.0806 CHANGE_BTN_BEHAVIOR_BY_EDIT_TEMP_WORKSHEET
				//if(pfw8_get_executed_output_xyrange(trGetN, "yp", yp))
				if ( pyp )
					yp = *pyp;
				else
					pfw8_get_executed_output_xyrange(trGetN, "yp", yp);
				if ( yp )
				/// end CHANGE_BTN_BEHAVIOR_BY_EDIT_TEMP_WORKSHEET
				{
					vector vx, vy;
					yp.GetData(vy, vx);
					vy.Append(vY);
					vx.Append(vX);
					yp.SetData(&vy, &vx);//update
				}
			}

			page_xf_dynadlg_shown_control(gp, 1, false);//open again after get points sucessfully

		}
		break;

		case DEL_ONE_PEAK_EVENT:
		{
			GraphObject go;
			go = Selection.Objects();
			/// Hong 02/18/08 v8.0806 CHANGE_BTN_BEHAVIOR_BY_EDIT_TEMP_WORKSHEET
			vector vx, vy;
			XYRange yp;
			if ( pyp )
				yp = *pyp;
			else
				pfw8_get_executed_output_xyrange(trGetN, "yp", yp);
			if ( yp )
			{
				yp.GetData(vy, vx);
			}
			/// end CHANGE_BTN_BEHAVIOR_BY_EDIT_TEMP_WORKSHEET
			do
			{
				if(go.IsValid())
				{
					/// Hong 02/18/08 v8.0806 CHANGE_BTN_BEHAVIOR_BY_EDIT_TEMP_WORKSHEET
					vector<uint> vnIndex;
					if ( vx.Find(vnIndex, go.X) > 0 )
					{
						vx.RemoveAt(vnIndex[0]);
						vy.RemoveAt(vnIndex[0]);
					}
					/// end CHANGE_BTN_BEHAVIOR_BY_EDIT_TEMP_WORKSHEET
					lcl.Remove(go.GetName());
				}
				go = Selection.Objects();
			}
			while(go.IsValid());
			yp.SetData(&vy, &vx, 0, NULL, DRS_SET_COL_DESIGNATIONS); /// Hong 02/18/08 v8.0806 CHANGE_BTN_BEHAVIOR_BY_EDIT_TEMP_WORKSHEET
		}
		break;

		default:
			break;
		}
	//}

	if(strNode == "modify")
	{
		if(!trGetN.modify.nVal)
		{
			lcl.RemoveAll();
		}
		else
		{
			XYRange yp;
			/// Hong 02/18/08 v8.0806 CHANGE_BTN_BEHAVIOR_BY_EDIT_TEMP_WORKSHEET
			//if(pfw8_get_executed_output_xyrange(trGetN, "yp", yp))
			if ( pyp )
				yp = *pyp;
			else
				pfw8_get_executed_output_xyrange(trGetN, "yp", yp);
			if ( yp )
			/// end CHANGE_BTN_BEHAVIOR_BY_EDIT_TEMP_WORKSHEET
			{
				vector vxPeaks, vyPeaks;
				yp.GetData(vyPeaks, vxPeaks);//clean data

				LineControlList lcl;
				lcl.CreateList(gl, PEAK_CENTER_RED_LINE_NAME, vxPeaks, SCRIPT_PKFIND_GROBJECT_EVENT);
			}
		}
	}

	return true;
}
*/

//bool pfw8_clean_apply_result_of_findpeak_page(Page& pg, TreeNode& trGetN)
//{
	//if(!pg.IsValid())
		//return false;
	//
	//destroy_pfw_temp_wps(PKINFO_TEMP_WKS_NAME;);
	//remove_executed_ds_from_new(trGetN, "yp");
	//delete_last_xf_info_from_page(pg);
	//
	////GraphLayer gl = pg.Layers();
	////if (gl.IsValid() )
	////{
		////LineControlList lcl(gl, PEAK_CENTER_RED_LINE_NAME);
		////if(lcl.IsValid())
			////lcl.RemoveAll();
	////}
	////
	//return true;
//}


//bool pfw8_line_controls_to_yp_of_findpeak_page(Page& pg, const vector& vxi,const vector& vyi, XYRange& yp)
//{
	//GraphLayer gl = pg.Layers();
//
	//if(gl.IsValid())
	//{
		//GraphPage gp;
		//gp = gl.GetPage();
	//
		//LineControlList lcl(gl, PEAK_CENTER_RED_LINE_NAME);
		//if(lcl.IsValid())
		//{
			//vector vxNewPeaks, vyNewPeaks;
			//if(pfw8_get_peaks_center_from_ctrls(gl, vxi, vyi,  vxNewPeaks, vyNewPeaks))
			//{
				//yp.SetData(&vyNewPeaks, &vxNewPeaks);
	//
				//if(update_data_context_to_page(pg, yp, PFW_PEAKS_PLOT_TAGNAME))
					//return true;
			//}
		//}
	//}
	//
	//return false;
//}
//





///Jasmine 01/22/08 NEW_OPTION_OF_FIX_BASELINE_FOR_EACH_PARA_USING_ITS_OWN_SETTING
enum{
	fixed_NO,
	fixed_YES,
	fixed_NONE,
};
///End NEW_OPTION_OF_FIX_BASELINE_FOR_EACH_PARA_USING_ITS_OWN_SETTING
//bool pfw8_is_baseline_fixed(const Page& pg, bool& bFixed)
//{
	///// Hong 11/22/07 v8.0753 ADD_VALID_CHECK_AVOID_RUNTIME
	//if ( !pg )
		//return false;
	///// end ADD_VALID_CHECK_AVOID_RUNTIME
	//HWND hwnd;
	//Tree trGetN;
	//load_GetN_from_page(pg, trGetN,  hwnd, STR_STORAGE_NAME);
	/////Jasmine 01/22/08 ATTRIBUTE_IS_CHANGE_TO_NODE_VALUE
	///*
	//TreeNode trBaseline = trGetN.GetNode(PFW_BASELINE_PLOT_TAGNAME);
	////trBaselinePlot = tree_find_node_by_dataID(trGetN,  IDE_O8_BASELINES_BASELINE_PLOT);
//
	//if(!trBaseline)
		//return false;
//
	//int nFixed;
	//if(!trBaseline.GetAttribute(STR_FIX_ATTRIBUTE, nFixed) || fixed_NONE == nFixed)	///Jasmine 01/22/08 NEW_OPTION_OF_FIX_BASELINE_FOR_EACH_PARA_USING_ITS_OWN_SETTING
		//return false;
	//*/
	//TreeNode trFix = trGetN.GetNode(STR_FIX_ATTRIBUTE);
	//if(!trFix.IsValid() || fixed_NONE == trFix.nVal)
		//return false;
	/////Jasmine 01/21/08 SHOULD_USE_BFIXED_TO_RETURN_THE_ATTRIBUTE
	////return nFixed;
	//bFixed = trFix.nVal;//nFixed
	//return true;
	/////End SHOULD_USE_BFIXED_TO_RETURN_THE_ATTRIBUTE
	/////End ATTRIBUTE_IS_CHANGE_TO_NODE_VALUE
//}

/// Iris 9/05/2008 PA_PARAM_DLG_USE_NEW_FIT_CLASS, need passs PeakFitHelper pointer to this dialog, so rewrite this func in pa_fit xfunciton temp, change to static here 
//typedef bool (* PFMDLG_FUNC)(int nMsg, DWORD dwCntrl);
//bool open_params_dlg(int nOption, DWORD dwCntrl)// = 0
typedef bool (* PFMDLG_FUNC_TEMP)(int nMsg, DWORD dwCntrl);
static bool _open_params_dlg(int nOption, DWORD dwCntrl)// = 0
///end PA_PARAM_DLG_USE_NEW_FIT_CLASS
{
	string 	strFile = "Originlab\\PFMParameterDlg";

	PFMDLG_FUNC_TEMP pfm = Project.FindFunction("FitPeakDlg", strFile, true);
	if( pfm )
	{
		return pfm(nOption, dwCntrl);
	}
	return false;
}


#define PREFIX_SECTION_PEAK_INFO	"PEAK"
#define STR_KEY_FUNC_NAME			"FitFunc"
#define STR_KEY_CENTER				"PeakCenter"
#define STR_KEY_HEIGHT				"EstimatedPeakHeight"
bool store_peak_info_ini_file(LPCSTR lpcszINIFile, bool bSave, PEAKINFO& pkinfo)
{
	INIFile iniPeakInfo(lpcszINIFile);

	try{
		if ( bSave )
		{
			// get and assure size
			int nNumPeaks = pkinfo.nNumPeaks;
			string strSection;
			ASSERT(pkinfo.vsFunc.GetSize() >= nNumPeaks);
			ASSERT(pkinfo.vxc.GetSize() >= nNumPeaks);
			ASSERT(pkinfo.vh.GetSize() >= nNumPeaks);

			// save setting value
			for (int ii = 0; ii < nNumPeaks; ii++)
			{
				strSection = PREFIX_SECTION_PEAK_INFO + (ii+1);
				iniPeakInfo.WriteString(strSection, STR_KEY_FUNC_NAME, pkinfo.vsFunc[ii]);
				iniPeakInfo.WriteDouble(strSection, STR_KEY_CENTER, pkinfo.vxc[ii]);
				iniPeakInfo.WriteDouble(strSection, STR_KEY_HEIGHT, pkinfo.vh[ii]);
			}
		}
		else
		{
			// get number of peaks from ini file
			StringArray saSections;
			iniPeakInfo.GetSectionNames(saSections);
			int nNumPeaks = 0;
			string strSection;
			do
			{
				strSection = PREFIX_SECTION_PEAK_INFO + (++nNumPeaks);
			}while (saSections.Find(strSection) >= 0);
			--nNumPeaks;

			// set size
			pkinfo.nNumPeaks = nNumPeaks;
			pkinfo.vsFunc.SetSize(nNumPeaks);
			pkinfo.vxc.SetSize(nNumPeaks);
			pkinfo.vh.SetSize(nNumPeaks);

			// get setting value
			for (int ii = 0; ii < nNumPeaks; ii++)
			{
				strSection = PREFIX_SECTION_PEAK_INFO + (ii+1);
				pkinfo.vsFunc[ii]	= iniPeakInfo.ReadString(strSection, STR_KEY_FUNC_NAME, "");
				pkinfo.vxc[ii]		= iniPeakInfo.ReadDouble(strSection, STR_KEY_CENTER, NANUM);
				pkinfo.vh[ii]		= iniPeakInfo.ReadDouble(strSection, STR_KEY_HEIGHT, NANUM);
			}
		}
	}
	catch(int nErr)
	{
		return false;
	}

	return true;
}
///---END STORE_PEAK_INFO_SETTING_TO_FILE

///Jasmine 05/16/08 MOMENTS_COMPUTE_METHOD
bool pa_fit_enable_disable_MomentMethod_node(TreeNode& tr, int nRow, int nCol, TreeNode& trNode, DWORD dwCntrl, int nType, WndContainer& theDlg)
{
	vector<string> vs = {"Variance", "Skew", "Excess", "Moment3", "Moment4"};

	///------ Folger 12/24/08 v8.0990c SUPPORT_SPECIFIC_NODE_TO_SKIP_EVENT1_IN_PA_FIT
	/*
	string strTagName;
	if(trNode)
		strTagName = trNode.tagName;

	if( !strTagName.IsEmpty() && -1 < vs.Find(strTagName) )
	{
		TreeNode trParent = trNode.Parent();
		if(!trParent)
			return false;

		TreeNode trMomentMethod = trParent.GetNode("MomentMethod");
		if(!trMomentMethod)
			return false;

		bool bEnable = false;
		if(true == trNode.nVal)
			bEnable = true;

		int nSize = vs.GetSize();
		for(int ii = 0; !bEnable && ii < nSize; ii++)
		{
			TreeNode trChild = trParent.GetNode( vs[ii] );
			if(trChild && true == trChild.nVal)
				bEnable = true;
		}

		trMomentMethod.Enable = bEnable;
	}
	*/
	
	TreeNode trParent = trNode.Parent();
	if(!trParent)
		return false;
	
	bool bEnable = false;
	for(int ii = 0; !bEnable && ii < vs.GetSize(); ii++)
	{
		TreeNode trChild = trParent.GetNode( vs[ii] );
		if(trChild && true == trChild.nVal)
			bEnable = true;
	}
	
	TreeNode trMomentMethod = trParent.GetNode("MomentMethod");
	trMomentMethod.Enable = bEnable;
	///------ End SUPPORT_SPECIFIC_NODE_TO_SKIP_EVENT1_IN_PA_FIT
	
	return true;
}
///End MOMENTS_COMPUTE_METHOD

/// Iris 11/11/2008 v8.0968 MOVE_PA_ENUM_TO_NEW_HEADER_PA_UTILS, move to nlsf_utils
/*
string get_function_list(LPCSTR lpcszCategory)
{
	string strFunctions;
	vector<string> 	vsFuncNames;
	vector<string>  vsFileNames;
	if( nslf_get_func_list(vsFuncNames, vsFileNames, lpcszCategory) )
	{
		strFunctions.SetTokens( vsFuncNames, '|' );
	}
	return strFunctions;
}
*/
///end MOVE_PA_ENUM_TO_NEW_HEADER_PA_UTILS