#include <origin.h>
#include <GetNBox.h>
#include <xfutils.h>
enum{
	dir_p,
	dir_n,
	dir_b,
};
enum{
	method_max,
	method_win,
	method_first,
	method_second,
	method_residue,
};
enum{
	option_r,
	option_p,
};
enum{
	filter_none,
	filter_h,
	filter_num,
};
enum{
	lc_x,
	lc_y,
	lc_n,
	lc_xy,
};

//put additional include files here
#include <..\OriginLab\PAWizCore.h>
#include <..\OriginLab\XFWizard_utils.h>
#include <..\Originlab\curve_utils.h>
#include <..\originlab\graph_utils.h>
#include <..\Originlab\grobj_utils.h>
#ifdef _FOR_SMART_LOADING_ONLY
	#include <xfGraph_utils.h>
	#include <..\OriginLab\nlsf_utils.h>

#endif // _FOR_SMART_LOADING_ONLY
#include <ReportTree.h>
#include <o8dlg.h>
#include <..\Originlab\xfdynadlg_utils.h>

//------ Folger 07/02/08 CENTRALIZE_CODE_OF_PEAK_EDIT_DIALOG
#include 	<..\Originlab\PeakEdit.h>
#define		PA_PEAK_EDIT_OPTION_DISABLE		PEAK_EDIT_OPTION_DISABLE
#define		PA_PEAK_EDIT_DISABLE			PEAK_EDIT_DISABLE
//------ End CENTRALIZE_CODE_OF_PEAK_EDIT_DIALOG

///===================end of include headers=============================

/*------------------------------------------------------------------------------*
 * Modification Log:															*
 *  Sim 08-15-2008 REORDER_PEAK_BY_XC											*
 *	Folger 11/01/08 QA80-12509 v8.0964 SUPPORT_PEAK_LABEL_SWITCHING_IN_PA_FIT_CONTROL_DIALOG
 *  Iris 11/01/2008 V8.0963d MOVE_2ND_DERVITIVE_PLOT_CODES_TO_PAWIZCORE			*
 *	Folger 11/25/08 v8.0979 BETTER_SOLUTION_TO_SWITCH_BASELINE_OUTPUT			*
 *	Sim 01-07-2008 QA80-12833 FIX_APPLY_XF_WIZ_XF_TWICE							*
 *	Folger 01/16/09 OPEN_AND_SAVE_AS_DIALOG_INSIDE_PA_SHOULD_BE_MODAL			*
 *	Jasmine 08/24/09 QA81-14165 DISPLAY_BUT_DISABLE_PRO_OPTION_IN_REG_VERSION	*
 *	Jasmine 08/28/09 CENTRALIZE_FIND_PEAK_METHOD_COMBO							*
 *	Folger 09/27/09 QA80-14076-P1 PA_FIND_PEAKS_FAILS_TO_APPLY_THEME_TO_PEAK_CENTERS_OUTPUT
 *	Kyle 03/11/2010 PICK_PEAK_ROI_TOOL_SHARES_UTILS_FUNCTION_WITH_PA			*
 *------------------------------------------------------------------------------*/

#define STR_MODIFY_PEAK_XF	STR_XF_MODIFY_BASE_ANCHORS

///Sandy 2008-2-20 only for rename and separate
#define STR_BUTTON_LIST ("Add|Modify/Del|Clear All")
#define STR_BUTTON_FIND ("Find")
///---Sim 08-15-2008 REORDER_PEAK_BY_XC
#define STR_BUTTON_FILE_LIST ("Save...|Load...|Peaks Info...")//shorten name
//#define STR_BUTTON_FILE_LIST _L("Save...|Load...|Peaks Info...|Reorder Peaks")//shorten name
///---END REORDER_PEAK_BY_XC


#define _STR_DEFAULT_TEXT_FOR_REPORT_DATA_NODE "[<input>]<new>"
//#define _STR_DEFAULT_TEXT_FOR_REPORT_DATA_NODE "[<same>]<new>"


enum
{
	STR_BTN_SAVE,
	STR_BTN_LOAD,
	STR_BTN_LIST,
	//STR_BTN_REORDER, ///---Sim 08-15-2008 REORDER_PEAK_BY_XC
};

enum
{
	FIND_MODE_CUSTOM,
	FIND_MODE_AUTO,
};



typedef bool (*FUNC_HWND_LPCSTR_VN_VN_VS_VD_VD_VD_DW)(HWND hParent,
												LPCSTR		lpcszFunctionCategory,
												vector<int> &vnPlotIndecies,		//rest are input and output
												vector<int> &vnPeakIndecies,
												vector<string> &vsFuncs,
												vector &vCenter,
												vector &vWidth,
												vector &vHeight,
												DWORD	dwOption = 0
												);
											

static bool _auto_method_parameters(TreeNode& trGetN,  string* pstrErrMsg = NULL)
{	
	PAWizCore* paCore = (PAWizCore*)get_xf_core_handler(trGetN);
	ASSERT(paCore);	
	
	vector vx, vy;	
	if(!get_peaks_ascending_data_from_pacore(paCore,  vx, vy))
		return false;
	
	if ( method_win == trGetN.method.nVal )
	{
		double dHeight = 20, dWidth = 50;
		if (trGetN.option.nVal == option_r) //raw size
		{
			double dMin, dMax, dTotalHeight, dTotalWidth;	
			vy.GetMinMax(dMin, dMax);
			dTotalHeight = max(abs(dMax), abs(dMin));
			
			vx.GetMinMax(dMin, dMax);
			//dTotalWidth = abs(vx[vx.GetSize()-1] - vx[0]); 	
			dTotalWidth = abs(dMax - dMin); 	
			
			dHeight *= dTotalHeight/100;
			dWidth *= dTotalWidth/100;
		}		
		TreeNode trNode = trGetN.height;
		if ( 1 == octree_get_auto_support(&trNode) )
		{
			trGetN.height.dVal = dHeight;
		}
		trNode = trGetN.width;
		if ( 1 == octree_get_auto_support(&trNode) )
		{
			trGetN.width.dVal = dWidth;
		}
	}
	return true;
}

static bool _auto_filter_parameter(TreeNode& trGetN, string* pstrErrMsg = NULL)
{
	
	PAWizCore* paCore = (PAWizCore*)get_xf_core_handler(trGetN);
	ASSERT(paCore);	
	
	vector vx, vy;	
	if(!get_peaks_ascending_data_from_pacore(paCore,  vx, vy))
		return false;
	
	TreeNode trNode = trGetN.value;	
	if ( 1 == octree_get_auto_support(&trNode) )
	{
		double dAutoHeightThres;
		double dMin, dMax, dTotalHeight, dDefaultHeightPer = 0.20;	
		vy.GetMinMax(dMin, dMax);
		dTotalHeight = max(abs(dMax), abs(dMin));			
		dAutoHeightThres = dTotalHeight * dDefaultHeightPer;

		switch ( trGetN.filter.nVal )
		{
		case filter_h:
			
			trNode.dVal = 20; // default value
			break;
		case filter_num:
			int iPeakNum = 1;
			///Kyle 03/11/2010 PICK_PEAK_ROI_TOOL_SHARES_UTILS_FUNCTION_WITH_PA
			//if(_compute_peaks_number_by_filter_height(vx, vy, dAutoHeightThres, iPeakNum))
			if(compute_peaks_number_by_filter_height(vx, vy, dAutoHeightThres, iPeakNum))
			///End PICK_PEAK_ROI_TOOL_SHARES_UTILS_FUNCTION_WITH_PA
				trNode.dVal = iPeakNum;

			break;
		}
	}
	return true;
}

static bool _auto_marker_parameters(TreeNode& trGetN, string* pstrErrMsg = NULL)
{
	PAWizCore* paCore = (PAWizCore*)get_xf_core_handler(trGetN);
	ASSERT(paCore);	
	
	vector vx, vy;	
	if(!get_peaks_ascending_data_from_pacore(paCore,  vx, vy) || vx.GetSize() < 1)
		return false;
	
	TreeNode trNode = trGetN.hwidth;	
	if ( 1 == octree_get_auto_support(&trNode) )
	{
		double dTotalWidth, dDefaultWidthPer = 0.25;	
		dTotalWidth = abs(vx[vx.GetSize()-1] - vx[0]); 			
		trNode.dVal = dTotalWidth * dDefaultWidthPer;
	}
	trNode = trGetN.fheight;	
	if ( 1 == octree_get_auto_support(&trNode) )
	{
		vector vySmoothed;
		vySmoothed = vy;		
		if ( trGetN.smooth.nVal > 1 )
		{
			vector vytemp;
			vytemp = vySmoothed;
			ocmath_savitsky_golay(vytemp, vySmoothed, vySmoothed.GetSize(), trGetN.smooth.nVal/2);
		}
		trNode.dVal = get_feet_height_by_percent_of_total_height(vySmoothed, 0.05);
	}
	return true;
}

static bool _auto_smooth_point(TreeNode& trGetN,  string* pstrErrMsg = NULL)
{
	PAWizCore* paCore = (PAWizCore*)get_xf_core_handler(trGetN);
	ASSERT(paCore);	
	
	vector vx, vy;	
	if(!get_peaks_ascending_data_from_pacore(paCore,  vx, vy))
		return false;
	
	return update_smooth_point(trGetN, vy, pstrErrMsg);
}

static bool _update_auto_value_by_input_change(TreeNode& trGetN, string* pstrErrMsg = NULL)
{
	string strErrMsg;
	// update smooth point		
	_auto_smooth_point(trGetN, strErrMsg); 
	// auto method parameters
	_auto_method_parameters(trGetN, strErrMsg);
	// auto filter parameter
	_auto_filter_parameter(trGetN, strErrMsg);
	// auto marker parameters
	_auto_marker_parameters(trGetN, strErrMsg);
	
	if(pstrErrMsg)
		* pstrErrMsg = strErrMsg;
	return true;

}

static void _update_method_params_status(TreeNode& trGetN)
{
	bool bShowPts = (method_max == trGetN.method.nVal) ? true : false;
	trGetN.npts.Show = bShowPts;
	
	bool bShowWinParams = (method_win == trGetN.method.nVal) ? true : false;		
	trGetN.option.Show = bShowWinParams;
	trGetN.height.Show = bShowWinParams;
	trGetN.width.Show = bShowWinParams;
}

static void _update_filter_params_status(TreeNode& trGetN)
{
	bool bEnable = (filter_none == trGetN.filter.nVal) ? false : true;
	string strLabel;
	switch ( trGetN.filter.nVal )
	{
	case filter_h:
		strLabel = _L("Threshold Height(%)");
		break;
	case filter_num:
		strLabel = _L("Number of Peaks");
		break;
	case filter_none:
	default:
		strLabel = _L("Filter Value");
	}
	trGetN.value.Enable = bEnable;
	trGetN.value.SetAttribute(STR_LABEL_ATTRIB, strLabel);
}

static void _update_graph_relative_params_status(TreeNode& trGetN)
{
	PAWizCore* paCore = (PAWizCore*)get_xf_core_handler(trGetN);
	ASSERT(paCore);	
	
	GraphLayer gl;
	if(!paCore->GetPreviewLayer(gl))
		error_report("fail to get preview layer in paCore!");

	bool bShow = gl.IsValid();
	trGetN.derivative.Show = bShow;
}


static void _update_find_params_status(TreeNode& trGetN)
{
	/// Folger, 12/12/08, diable peak modify when change parameter
	PAWizCore* paCore = (PAWizCore*)get_xf_core_handler(trGetN);
	trGetN.btns_manual.Enable = paCore->IsAutoUpdated() || trGetN.mode.nVal ? DISABLE : ENABLE;	

	if( FIND_MODE_AUTO == trGetN.mode.nVal )
	{
		vector<int> vn(1);
		vn[0] = STR_BTN_LOAD;
	    disable_buttons_in_group(vn, trGetN.btns_file);
	}
	else// custom mode
	{
		vector<int> vn;
		disable_buttons_in_group(vn, trGetN.btns_file);
	}
}


static void _update_variables_status(TreeNode& trGetN)
{
	_update_method_params_status(trGetN);
	_update_filter_params_status(trGetN);
	_update_graph_relative_params_status(trGetN);
	_update_find_params_status(trGetN); 
}

//static bool _is_need_undo_node_event(const string& strNode)
//{
	//if ( strNode == "smooth" || strNode == "dir" || strNode == "npts" || strNode == "option" ||strNode == "height" || strNode == "width" 
		//|| strNode == "value" || strNode == "hwidth" || strNode == "fheight" )
		//return true;
	//return false;
//}

static bool _do_peak_list(TreeNode& trGetN, Page& pg, const Window& DynaCntrlContainer)
{
	PAWizCore* paCore = (PAWizCore*)get_xf_core_handler(trGetN);
	ASSERT(paCore);	
	
	XYRange xyPeaksCenter;
	if( !paCore->GetPeaksCenterRange(xyPeaksCenter) )
		return false;		
	vector vxc, vh, vxcEnable, vhEnable, vxcDisable, vhDisable;
	peaks_center_to_tree(trGetN.otr, vxcEnable, vhEnable, false);
	peaks_center_to_tree(trGetN.distr, vxcDisable, vhDisable, false);
	
	vxc = vxcEnable;
	vxc.Append(vxcDisable);
	vh = vhEnable;
	vh.Append(vhDisable);
	
	int nEnablePeaks = vxcEnable.GetSize(), nDisablePeaks = vxcEnable.GetSize(), nAllPeaks = vxc.GetSize();
	vector<int> vnColIndex(nAllPeaks), vnSatus(nAllPeaks);
	vector vw(nAllPeaks);
	int nPeakIndex = 1, ii;
	for ( ii = 0; ii < nAllPeaks; ii++ )
	{
		vnSatus[ii] =  ii < nEnablePeaks ? (nPeakIndex++) : PA_PEAK_EDIT_DISABLE;
		vnColIndex[ii] = ii;
	}	
	
	FUNC_HWND_LPCSTR_VN_VN_VS_VD_VD_VD_DW pfn = Project.FindFunction("OpenPeakEditDlg", "OriginLab\\PeakEditDlg.c");
	if ( !pfn )
		return false;
	

	int nAutoFind = trGetN.mode.nVal;
	DWORD	dwCtrl = FIND_MODE_AUTO == nAutoFind ? PA_PEAK_EDIT_OPTION_DISABLE : 0;

	if ( pfn(DynaCntrlContainer.GetSafeHwnd(), STR_PA_NLSF_CAT_PEAK, vnColIndex, vnSatus, NULL, vxc, NULL, vh, dwCtrl) )
	{
		for ( ii = 0; ii < vnSatus.GetSize(); ii++ )
		{
			if ( vnColIndex[ii] >= 0 && vnSatus[ii] >= 0 )
			{
				if ( vnColIndex[ii] < nEnablePeaks )
				{
					vxcEnable[vnColIndex[ii]] = vxc[ii];
					vhEnable[vnColIndex[ii]] = vh[ii];
				}
				else if ( vnColIndex[ii] < nAllPeaks )
				{
					int nIndex = vnColIndex[ii] - nEnablePeaks;
					vxcEnable[nIndex] = vxc[ii];
					vhEnable[nIndex] = vh[ii];
				}				
			}
		}
		// add peaks
		vector<uint> vnNewAdd, vnDelDisColInx;
		int nFound = vnSatus.Find(vnNewAdd, -1);
		for ( ii = 0; ii < nFound; ii++ )
		{
			vxcEnable.Add(vxc[vnNewAdd[ii]]);
			vhEnable.Add(vh[vnNewAdd[ii]]);
			if ( vnColIndex[vnNewAdd[ii]] >= 0 ) 
				vnDelDisColInx.Add(vnColIndex[vnNewAdd[ii]] - nEnablePeaks);
		}
		vnDelDisColInx.Sort(SORT_DESCENDING);
		for ( ii = 0; ii < vnDelDisColInx.GetSize(); ii++ )
		{
			vxcDisable.RemoveAt(vnDelDisColInx[ii]);
			vhDisable.RemoveAt(vnDelDisColInx[ii]);
		}
		vector<uint> vnDeleted, vnDelColIndex;
		nFound = vnSatus.Find(vnDeleted, -2);
		for ( ii = 0; ii < nFound; ii++ )
		{
			vxcDisable.Add(vxc[vnDeleted[ii]]);
			vhDisable.Add(vh[vnDeleted[ii]]);
			vnDelColIndex.Add(vnColIndex[vnDeleted[ii]]);			
		}
		vnDelColIndex.Sort(SORT_DESCENDING);
		for ( ii = 0; ii < nFound; ii++  )
		{
			vxcEnable.RemoveAt(vnDelColIndex[ii]);
			vhEnable.RemoveAt(vnDelColIndex[ii]);

		}
		
		peaks_center_to_tree(trGetN.otr, vxcEnable, vhEnable, true);
		peaks_center_to_tree(trGetN.distr, vxcDisable, vhDisable, true);

		if ( xyPeaksCenter.IsValid() )
			xyPeaksCenter.SetData(&vhEnable, &vxcEnable, 0, NULL, DRS_SET_COL_DESIGNATIONS);
	}


	return false;
}


static int _paw_find_peaks(TreeNode& trGetN)
{	
	PAWizCore* paCore = (PAWizCore*)get_xf_core_handler(trGetN);
	ASSERT(paCore);	
	
//----------Sandy 2008-11-18 APPLY_NEW_OCMATH_FUNCTION_PROTOTYPE_WITH_SG_DERIV
//	return _paw_find_peaks(paCore, trGetN.smooth.nVal, trGetN.dir.nVal, trGetN.method.nVal, trGetN.npts.nVal, trGetN.option.nVal, trGetN.height.dVal, trGetN.width.dVal, trGetN.filter.nVal, trGetN.value.dVal, trGetN.hwidth.dVal, trGetN.fheight.dVal, trGetN.otr, trGetN.distr);

	return _paw_find_peaks(paCore, trGetN.smooth.nVal, trGetN.dir.nVal, trGetN.method.nVal, trGetN.npts.nVal,
							trGetN.deriv_smooth, trGetN.option.nVal, trGetN.height.dVal, trGetN.width.dVal, 
							trGetN.filter.nVal, trGetN.value.dVal, trGetN.hwidth.dVal, trGetN.fheight.dVal, trGetN.otr, trGetN.distr);
}

//----------Sandy 2008-11-18 APPLY_NEW_OCMATH_FUNCTION_PROTOTYPE_WITH_SG_DERIV
//static int _paw_find_peaks(PAWizCore* paCore, const int& smooth, const int& dir, const int& method, const int& npts, const int& option, const double& height, const double& width, const int& filter, const double& value, const double& hwidth, const double& fheight, TreeNode& trPeaks, TreeNode& trDisablePeaks)
static int _paw_find_peaks(PAWizCore* paCore, const int& smooth, const int& dir, const int& method, const int& npts, TreeNode& deriv_smooth,  
			const int& option, const double& height, const double& width, const int& filter, const double& value, const double& hwidth,
			const double& fheight, TreeNode& trPeaks, TreeNode& trDisablePeaks)
{
	ASSERT(paCore);	
	XYRange yi, yo;
	if(!paCore->GetPeaksRange(yi) || !paCore->GetPeaksCenterRange(yo))
	{
		error_report("fail in get xyrange in PACore!");
		return XFERR_GET_DATA_FAILED;
	}	
	
	///Sandy 2008-12-12 always clean peaks after find button click
	vector  vEmpty;
	yo.SetData(&vEmpty, &vEmpty); //clean data
	peaks_center_to_tree(trPeaks, vEmpty, vEmpty);
	peaks_center_to_tree(trDisablePeaks, vEmpty, vEmpty);
	yo.SetData(&vEmpty, &vEmpty, 0, NULL, DRS_SET_COL_DESIGNATIONS);	
	//end
	
	vector vx, vy;		
	if(!yi.GetData(vy, vx) || vx.GetSize() < 3)
		return XFERR_GET_DATA_FAILED;
	
	// convert percentage to actual value
	double dValue = value;
	if ( filter_h == filter )
	{
		double dMin, dMax, dTotalHeight;	
		vy.GetMinMax(dMin, dMax);
		dTotalHeight = max(abs(dMax), abs(dMin));			
		dValue *= dTotalHeight / 100;
		
	}
	
	int nSize = vy.GetSize();
	double maxWidth = width, minHeight = height;
	vector<int> vPeaksInd(nSize);			
	vector vxPeaks(nSize), vyPeaks(nSize);	

	//----------Sandy 2008-11-18 APPLY_NEW_OCMATH_FUNCTION_PROTOTYPE_WITH_SG_DERIV
	//int nRet = find_peaks(vx, vy, vxPeaks, vyPeaks, vPeaksInd, method, maxWidth, minHeight, smooth, dir+1, npts, option, filter-1, &dValue);
	int nSmoothMethod;
	if( method == method_first || method == method_residue)
		nSmoothMethod = deriv_smooth.first.nVal;
	else if(method == method_second)
		nSmoothMethod =  deriv_smooth.second.nVal;
	
	vector v2ndDeriv;
	int nRet = find_peaks(vx, vy, vxPeaks, vyPeaks, vPeaksInd, method, maxWidth, minHeight, smooth, dir+1, npts, option, filter-1, &dValue,
				nSmoothMethod, v2ndDeriv, deriv_smooth.deriv_npts.nVal, deriv_smooth.fft_cutoff.dVal, deriv_smooth.deriv_poly.nVal);
	
	if(method == method_second)
	{
		paCore->SetSmoothed2ndDerivative(v2ndDeriv);
	}
	//------------end APPLY_NEW_OCMATH_FUNCTION_PROTOTYPE_WITH_SG_DERIV

	if ( nRet != OE_NOERROR && nRet !=  OE_POINT_OUTSIDE_RECT)	
		return get_find_peaks_xf_error_code(nRet);	
	
	//match peaks' position to preview graph no matter subtracted or not
	vector vxSource, vySource;
	bool bSubtracted = paCore->GetSubtractedMode();
	if(bSubtracted)
	{
		vxSource = vx;
		vySource = vy;
	}
	else
	{
		XYRange xyOriginal;
		if(!paCore->GetOriginalRange(xyOriginal))
		{
			error_report("fail in get xyrange in PACore!");
			return XFERR_GET_DATA_FAILED;
		}
		
		xyOriginal.GetData(vySource, vxSource);
	}
	match_peaks_centers_by_index(vxSource, vySource, vxPeaks.GetSize(), vPeaksInd, vxPeaks, vyPeaks );	
	
	vector<uint> vn;
	vxPeaks.Sort(SORT_ASCENDING, true, vn);
	vyPeaks.Reorder(vn);
	vPeaksInd.Reorder(vn);

	peaks_center_to_tree(trPeaks, vxPeaks, vyPeaks, true);
	//vector vEmpty;
	//vector<string> vstrEmpty;
	
	peaks_center_to_tree(trDisablePeaks, vEmpty, vEmpty, true);
	
	yo.SetData(&vyPeaks, &vxPeaks, 0, NULL, DRS_SET_COL_DESIGNATIONS);	
	return nRet;
}


static int _copy_data(XYRange& xyDst, XYRange& xySrc)
{
	if ( !xySrc.IsValid() )
		return XFERR_GET_DATA_FAILED;
	vector vx, vy;
	if ( !xySrc.GetData(vy, vx) || vy.GetSize() == 0 )
		return XFERR_NO_PEAK_FOUND;		
	xyDst.SetData(&vy, &vx, 0, NULL, DRS_SET_COL_DESIGNATIONS);
	return 0;
}

///Kyle 03/11/2010 PICK_PEAK_ROI_TOOL_SHARES_UTILS_FUNCTION_WITH_PA
/*
static bool _compute_peaks_number_by_filter_height(const vector& vx,const vector& vy, double dHeightThres, int& iPeakNum)
{

	iPeakNum = vx.GetSize();
	vector vxPeaks(iPeakNum), vyPeaks(iPeakNum);
	vector<int> vnIndices(iPeakNum);
	
	//if(OE_NOERROR != ocmath_find_peaks_1st_derivative(&iPeakNum, vx, vy, vxPeaks, vyPeaks, vnIndices, PKF_BOTH_DIRECTION, 0))
	if(OE_NOERROR != ocmath_find_peaks_1st_derivative(&iPeakNum, vx, vy, vxPeaks, vyPeaks, vnIndices, PKF_BOTH_DIRECTION, false, 0))
		return false;
	
	vxPeaks.SetSize(iPeakNum);
	vyPeaks.SetSize(iPeakNum);
	vnIndices.SetSize(iPeakNum);
	if(OE_NOERROR != ocmath_test_peaks_by_height(&iPeakNum, vxPeaks, vyPeaks, vnIndices, dHeightThres))
		return false;
	
	return true;
}
*/
///End PICK_PEAK_ROI_TOOL_SHARES_UTILS_FUNCTION_WITH_PA

//static 	bool _check_peaks_num_if_custom_mode(TreeNode trGetN, string& strErrMsg, bool bCleanErrmsg = true, bool bAfterFindClick = false)
static 	bool _check_peaks_num_if_custom_mode(TreeNode trGetN, string& strErrMsg, bool bCleanErrmsg = true, bool bAfterFindClick = false, bool bIsWarning = false)
{

	if(trGetN.mode.nVal == FIND_MODE_CUSTOM)
	{
		PAWizCore* paCore = (PAWizCore*)get_xf_core_handler(trGetN);
		ASSERT(paCore);
		
		if(bCleanErrmsg)
			strErrMsg = "";
		XYRange xyPeaksCenter;
		paCore->GetPeaksCenterRange( xyPeaksCenter);
		vector vxp, vyp;
		xyPeaksCenter.GetData(vyp, vxp);
		if(0 == vxp.GetSize())
		{
			strErrMsg = XFERR_NO_PEAK_FOUND;
			return false;		
		}	
	}
	else//		FIND_MODE_AUTO	
	{

		if(strErrMsg != "")
		{
			///Sandy 2008-12-1 Max said when click find button and no peak found, should disable next button.
			if(bAfterFindClick && !bIsWarning)
				return false;
		}

	}
	return true;
}

static bool _update_current_number_peaks(TreeNode& trGetN)
{
	vector dxc;
	dxc = trGetN.otr.xc.dVals;		
	int nOldVal = trGetN.numpeaks.nVal;
	trGetN.numpeaks.nVal = dxc.GetSize();
	return nOldVal != trGetN.numpeaks.nVal;
}

/// Iris 11/01/2008 V8.0963d MOVE_2ND_DERVITIVE_PLOT_CODES_TO_PAWIZCORE
void _init_derivative_preview(PAWizCore* paCore, const TreeNode& trGetN)
{
	paCore->SetAdditionalLayersName(_PREVIEW_2ND_DERVIA_LAYER);
}


bool _update_derivative_preview(PAWizCore* paCore, int* pnDerivativeShow)
{
	
	if( pnDerivativeShow )
	{
		int nDerivativeShow = *pnDerivativeShow;
		string strShow = nDerivativeShow;
		paCore->SetAdditionalLayersShow(strShow);
	}

	return paCore->Update2ndDervitivePreivew();
}
///end MOVE_2ND_DERVITIVE_PLOT_CODES_TO_PAWIZCORE


		//enum{
			//DERIV_SMOOTH_NONE,
			//DERIV_SMOOTH_FFT,
			//DERIV_SMOOTH_ADJ,
			//DERIV_SMOOTH_SG,
			//DERIV_SMOOTH_QSG,
		//}; defined in curve_utils.h	

// Sandy 2008-11-13 add smooth derivative

static void _get_deriv_status(TreeNode& trGetN, bool& bHasBasicDerivSmoothMethods, bool& bHas2ndDerivSmoothMethods, 
								bool& bUseDerivSmooth, bool& bUseSG, bool& bUseADJ, bool& bUseFFT)
{
	TreeNode trDerivSmooth 		= trGetN.deriv_smooth;
	bHasBasicDerivSmoothMethods = (trGetN.method.nVal == method_first
									|| trGetN.method.nVal ==method_residue);
	bHas2ndDerivSmoothMethods 	= (trGetN.method.nVal ==method_second);
	bUseDerivSmooth 			= (bHasBasicDerivSmoothMethods || bHas2ndDerivSmoothMethods) ;
	
	bUseSG						= (bHasBasicDerivSmoothMethods && (trDerivSmooth.first.nVal == DERIV_SMOOTH_SG))
									|| (bHas2ndDerivSmoothMethods && ((trDerivSmooth.second.nVal == DERIV_SMOOTH_SG) 
									|| (trDerivSmooth.second.nVal == DERIV_SMOOTH_QSG)));
	bUseADJ 					= (bHas2ndDerivSmoothMethods && (trDerivSmooth.second.nVal == DERIV_SMOOTH_ADJ));
	
	bUseFFT 					= (bHas2ndDerivSmoothMethods && (trDerivSmooth.second.nVal == DERIV_SMOOTH_FFT));

}
static bool _check_derivative_smooth_setting(TreeNode& trGetN, string& strErrMsg = NULL)
{
	bool bHasBasicDerivSmoothMethods,  bHas2ndDerivSmoothMethods, bUseDerivSmooth, bUseSG, bUseADJ, bUseFFT;
	_get_deriv_status(trGetN, bHasBasicDerivSmoothMethods, bHas2ndDerivSmoothMethods, bUseDerivSmooth,  bUseSG, bUseADJ, bUseFFT);
	TreeNode trDerivSmooth = trGetN.deriv_smooth;
	if(bUseDerivSmooth && bUseSG)
	{
		if(trDerivSmooth.deriv_npts.nVal <= 3 || trDerivSmooth.deriv_poly.nVal <= 0 
			|| trDerivSmooth.deriv_poly.nVal >=  trDerivSmooth.deriv_npts.nVal)
		{
			if(strErrMsg != NULL)
				strErrMsg = CER_TPS_INVALID_SMOOTH;// error
			return false;
		}

		////Sandy 2009-2-18 NO_EFFECT_END_REPORT_DO_NOT_SHOW_ERROR
		/*
		PAWizCore* paCore = (PAWizCore*)get_xf_core_handler(trGetN);
		if(!paCore)
		{
			error_report("Invalid PACore!");
			return false;		
		}		
		
		ASSERT(paCore);	
		XYRange yi;
		if(!paCore->GetPeaksRange(yi))
		{
			error_report("fail in get xyrange in PACore!");
			return false;
		}	
		
		vector vx, vy;		
		if(!yi.GetData(vy, vx) || vx.GetSize() < 3)
		{
			error_report("fail in get data from PACore!");	
			return false;
		}	
		
		double dInterval;
		int nRet =  ocmath_sampling_resolution(vx.GetSize(), vx, &dInterval);
		if(OE_NOERROR != nRet)
		{
			if(strErrMsg != NULL)
				strErrMsg = XFWAR_NOT_EVEN_SPACE_IN_SG_SMOOTH;// warning
		}
		*/
		return true;
	}	
	
	return true;
}
	
static void	_update_check_derivative_smooth_show_hide(TreeNode& trGetN)
{
	
	
	bool bHasBasicDerivSmoothMethods,  bHas2ndDerivSmoothMethods, bUseDerivSmooth, bUseSG, bUseADJ, bUseFFT;
	_get_deriv_status(trGetN, bHasBasicDerivSmoothMethods, bHas2ndDerivSmoothMethods, bUseDerivSmooth,  bUseSG, bUseADJ, bUseFFT);
	
	TreeNode trDerivSmooth = trGetN.deriv_smooth;
	trDerivSmooth.Show = bUseDerivSmooth;

	trDerivSmooth.first.Show = bHasBasicDerivSmoothMethods;
	trDerivSmooth.second.Show = bHas2ndDerivSmoothMethods;	
	
					
	trDerivSmooth.fft_cutoff.Show = bUseFFT;

	trDerivSmooth.deriv_npts.Show = (bUseADJ || bUseSG);
	
	trDerivSmooth.deriv_poly.Show = bUseSG;
	

}
//------end of Sandy 2008-11-13 add smooth derivative

///Jasmine 08/24/09 QA81-14165 DISPLAY_BUT_DISABLE_PRO_OPTION_IN_REG_VERSION
static bool s_bClean = false;	//this xf error checking is buggy, but I don't want to touch it
///End DISPLAY_BUT_DISABLE_PRO_OPTION_IN_REG_VERSION


void pa_peaks(const XYRange& iy, const int& numpeaks, const int& mode, const int& btn_find, const int& btns_manual, const int& btns_file, const int& derivative, const int& smooth, const int& dir, const int& method, const TreeNode& deriv_smooth, const int& option, const int& npts, const double& height, const double& width, const int& filter, const double& fheight, const double& hwidth, const double& value, const int& sl, const int& lc, const int& lr, const int& sc, TreeNode& distr, TreeNode& otr, const int& nXFCorePointer, ReportData& rd_oyb, ReportData& rd_peaks)
{
	
	///---Sim 01-07-2008 QA80-12833 FIX_APPLY_XF_WIZ_XF_TWICE
	//PAWizCore* paCore = (PAWizCore*)get_xf_core_handler(getnhandler);
	PAWizCore* paCore = (PAWizCore*)get_xf_core_handler(NODE_NAME_XF_WIZ_CORE_POINTER);
	///---END QA80-12833 FIX_APPLY_XF_WIZ_XF_TWICE
	if(!paCore)
		XF_THROW(XF_ERR_INVALID_PA_INSTANCE);
	
	XYRange xyPeaksCenter;
	if(!paCore->GetPeaksCenterRange(xyPeaksCenter))
	{
		XF_THROW(XF_ERR_INVALID_PA_INSTANCE);
	}
	
	if ( mode == FIND_MODE_AUTO)
	{
		//----------Sandy 2008-11-18 APPLY_NEW_OCMATH_FUNCTION_PROTOTYPE_WITH_SG_DERIV
		//int nRet = _paw_find_peaks(paCore, smooth, dir, method, npts, option, height, width, filter, value, hwidth, fheight,  otr, distr);
		int nRet = _paw_find_peaks(paCore, smooth, dir, method, npts, deriv_smooth,  option, height, width, filter, value, hwidth, fheight,  otr, distr);
		if(nRet != 0 && nRet !=  OE_POINT_OUTSIDE_RECT)
			XF_THROW(nRet);
		
		///Sandy 2008-10-21 fixed autofind will missing labels when go next directly.
		//if(!update_peaks_center_label(paCore, sc, sl, lc, lr))
		if(!paCore->UpdatePeaksCenterLabels(sc, sl, lc, lr))//Sandy 2008-12-12 turn to member function of pawizcore
		{
			error_report("fail in update peak labels.");
		}
		
		//------ Folger 11/01/08 QA80-12509 v8.0964 SUPPORT_PEAK_LABEL_SWITCHING_IN_PA_FIT_CONTROL_DIALOG
		paCore->AccessPeakLabelSettings(lc, false);
		//------
	}
	else if( mode == FIND_MODE_CUSTOM)
	{
	
		vector vx, vy;
		if ( !xyPeaksCenter.IsValid() || !xyPeaksCenter.GetData(vy, vx) || 0 == vy.GetSize() )
			XF_THROW(XFERR_NO_PEAK_FOUND);
	
	}
	
	paCore->UpdateInfoTree(otr, PA_TREE_PEAKS_CENTER_INFO, true);
	int nGoal = paCore->GetCurrGoal();	
	if(nGoal == PA_GOAL_FIND_PEAK)//if goal is create baseline, baseline should output to user assigned dataset
	{
		create_peak_center_table( paCore, rd_peaks);
	
		///Sandy 2008-9-1 add baseline output if there is baseline
		if(PA_BM_None != paCore->GetBaseMode())
		{
			create_baseline_table( paCore, rd_oyb);
		}
	}
	
}

//nEventID < 0 on event, like GETNE_ON_INIT, GETNE_ON_OK etc, >0 on change from control
//return 0 to do nothing, return PEVENT_GETN_RET_TO_CLOSE to close dialog
//dwEnables = bOKEnable, bBTN1Enable, bBTN2Enable, bBTN3Enable, , can set to false to disable OK/Apply buttons
//lpcszNodeName = the trGetN TreeNode tag name that generates the event, or is  if GETNE_ON_OK etc
//strAux = optional string for XF Wizard Bar, like DLG_NEED_CHANGE_GRID etc, it will be invalid if from internal node value change event
//strErrMsg = allowing messages to be shown
int pa_peaks_event1(TreeNode& trGetN, int nRow, int nEventID, DWORD& dwEnables, LPCSTR lpcszNodeName, WndContainer& DynaCntrlContainer, string& strAux, string& strErrMsg)
{
	if( xf_is_extended_event(nEventID) )
		return pa_peaks_event1_ex(trGetN, nRow, nEventID, dwEnables, lpcszNodeName, DynaCntrlContainer, strAux, strErrMsg);
	DECLARE_BUTTON_ENABLES
	
	///Jasmine 08/24/09 QA81-14165 DISPLAY_BUT_DISABLE_PRO_OPTION_IN_REG_VERSION
	if(s_bClean)
	{
		strErrMsg = "";
		s_bClean = false;
	}
	
	string strTempMethodErrMsg;
	if( !lstrcmpi(lpcszNodeName, "method") || GETNE_ON_INIT == nEventID || GETNE_ON_THEME == nEventID )
	{
		if( !is_find_peak_method_available(trGetN.method.nVal) )
		{
			if( !lstrcmpi(lpcszNodeName, "method") )
			{
				string strProOption = get_selected_string_from_combolist(trGetN.method);
				strTempMethodErrMsg = XFERR_PRO_OPTION_WARNNING_MSG;
				strTempMethodErrMsg += ":" + strProOption;
			}
			
			trGetN.method.nVal = method_max;
		}
	}
	///End DISPLAY_BUT_DISABLE_PRO_OPTION_IN_REG_VERSION
	
	PAWizCore* paCore = (PAWizCore*)get_xf_core_handler(trGetN);
	ASSERT(paCore);	
	
	//Sandy 2008-11-13 add reset smooth derivative
	bool b2ndSmoothedChanged = (!lstrcmpi(lpcszNodeName, "method") || !lstrcmpi(lpcszNodeName, "deriv_smooth") 
								||  !lstrcmpi(lpcszNodeName, "first") ||  !lstrcmpi(lpcszNodeName, "second")
								||  !lstrcmpi(lpcszNodeName, "fft_cutoff") ||  !lstrcmpi(lpcszNodeName, "deriv_poly") 
								||  !lstrcmpi(lpcszNodeName, "deriv_npts"));
	if(b2ndSmoothedChanged)
	{
		vector vEmpty;
		paCore->SetSmoothed2ndDerivative(vEmpty);
	}
	//end
	
	bOKEnable = _check_peaks_num_if_custom_mode(trGetN, strErrMsg);
	
	if ( GETNE_ON_INIT == nEventID )
	{
		_update_variables_status(trGetN);
		_update_current_number_peaks(trGetN); 
		
		trGetN.lc.Show = trGetN.lr.Show = trGetN.sl.nVal;
		//create_peaks_labels_plot(paCore, trGetN.lc.nVal, trGetN.sl.nVal,  trGetN.lr.nVal, trGetN.sc.nVal);
		xf_turnon_user_event_receiver(trGetN); 
		
		//------ Folger 11/01/08 QA80-12509 v8.0964 SUPPORT_PEAK_LABEL_SWITCHING_IN_PA_FIT_CONTROL_DIALOG
		//if(!update_peaks_center_label(paCore, trGetN.sc.nVal, trGetN.sl.nVal, trGetN.lc.nVal, trGetN.lr.nVal))
		if(!paCore->UpdatePeaksCenterLabels(trGetN.sc.nVal, trGetN.sl.nVal, trGetN.lc.nVal, trGetN.lr.nVal))
		{
			error_report("fail in update peak labels.");
		}
		//------ End SUPPORT_PEAK_LABEL_SWITCHING_IN_PA_FIT_CONTROL_DIALOG
	
		/// Iris 11/01/2008 V8.0963d MOVE_2ND_DERVITIVE_PLOT_CODES_TO_PAWIZCORE
		_init_derivative_preview(paCore, trGetN);
		int nDerivativeShow = trGetN.derivative.nVal;
		_update_derivative_preview(paCore, &nDerivativeShow);
		///end MOVE_2ND_DERVITIVE_PLOT_CODES_TO_PAWIZCORE	
	
		///Jasmine 08/24/09 QA81-14165 DISPLAY_BUT_DISABLE_PRO_OPTION_IN_REG_VERSION
		string strMethods = get_find_peak_methods();
		trGetN.method.SetAttribute(STR_COMBO_ATTRIB, strMethods);
		///End DISPLAY_BUT_DISABLE_PRO_OPTION_IN_REG_VERSION
		
		_update_check_derivative_smooth_show_hide(trGetN);////Sandy 2008-11-13 add smooth derivative
		bOKEnable = _check_derivative_smooth_setting(trGetN, strErrMsg);
		return true;
	
	}
	
	if ( GETNE_ON_UNDO == nEventID )
	{
		clear_peaks_labels_plot(paCore);
		//paCore->CleanUpContextRange(PA_DR_PEAKSRANGE);
		paCore->CleanUpContextRange(PA_DR_PEAK_CENTERS);
		
		/// Iris 11/01/2008 V8.0963d MOVE_2ND_DERVITIVE_PLOT_CODES_TO_PAWIZCORE
		int nDerivativeShow = 0;
		_update_derivative_preview(paCore, &nDerivativeShow);
		///end MOVE_2ND_DERVITIVE_PLOT_CODES_TO_PAWIZCORE		
		return true;
	}	
	
	if ( !lstrcmpi(lpcszNodeName, "mode") )
	{
		_update_find_params_status(trGetN);
		return true;
	}
	
	if ( !lstrcmpi(lpcszNodeName, "smooth") )
	{
		bOKEnable = _auto_smooth_point(trGetN,  &strErrMsg);
		
		return true;
	}
	
	if ( !lstrcmpi(lpcszNodeName, "method") )
	{
		_update_method_params_status(trGetN);
		_update_check_derivative_smooth_show_hide(trGetN);//Sandy 2008-11-13 add smooth derivative
		bOKEnable = _auto_smooth_point(trGetN, strErrMsg); 
	
		///Jasmine 08/24/09 QA81-14165 DISPLAY_BUT_DISABLE_PRO_OPTION_IN_REG_VERSION
		if( strErrMsg.IsEmpty() && !strTempMethodErrMsg.IsEmpty() )
		{
			strErrMsg = strTempMethodErrMsg;
			s_bClean = true;
		}
		///End DISPLAY_BUT_DISABLE_PRO_OPTION_IN_REG_VERSION
		return true;
	}
	
	//Sandy 2008-11-13 add smooth derivative
	if ( !lstrcmpi(lpcszNodeName, "deriv_smooth") ||  !lstrcmpi(lpcszNodeName, "first") ||  !lstrcmpi(lpcszNodeName, "second"))
	{
		_update_check_derivative_smooth_show_hide(trGetN);//Sandy 2008-11-13 add smooth derivative
		return true;
	}
	
	
	
	if ( !lstrcmpi(lpcszNodeName, "option") || !lstrcmpi(lpcszNodeName, "width") || !lstrcmpi(lpcszNodeName, "height") )
	{		
		_auto_method_parameters(trGetN);
		return true;
	}
	
	
	if ( !lstrcmpi(lpcszNodeName, "filter") || !lstrcmpi(lpcszNodeName, "value") )
	{
		_update_filter_params_status(trGetN);
		_auto_filter_parameter(trGetN);
		return true;
	}
	
	if ( !lstrcmpi(lpcszNodeName, "hwidth") || !lstrcmpi(lpcszNodeName, "fheight") )
	{
		vector vx, vy;
		_auto_marker_parameters(trGetN);
		return true;
	}	
	
	/// Iris 11/01/2008 V8.0963d MOVE_2ND_DERVITIVE_PLOT_CODES_TO_PAWIZCORE
	if ( !lstrcmpi(lpcszNodeName, "derivative") )
	{
		int nDerivativeShow = trGetN.derivative.nVal;
		return _update_derivative_preview(paCore, &nDerivativeShow);		
	}
	///end MOVE_2ND_DERVITIVE_PLOT_CODES_TO_PAWIZCORE	
	
	if ( !lstrcmpi(lpcszNodeName, "btn_find") )
	{
		bool bIsWarning = false;
		bool bCleanErrmsg = true;
		
	
		int nRet = _paw_find_peaks(trGetN);
		_update_current_number_peaks(trGetN);
		
		if ( nRet != 0 && nRet !=  OE_POINT_OUTSIDE_RECT)
		{			
			strErrMsg = nRet;
			bOKEnable = false;
		}
		else if(nRet ==  OE_POINT_OUTSIDE_RECT && trGetN.filter.nVal == filter_num)
		{
			int nMaxNumPeaks = trGetN.numpeaks.nVal;
			strErrMsg = XFERR_NO_MORE_PEAKS_CAN_BE_FOUND;
			strErrMsg += ":" + nMaxNumPeaks;
			
			bCleanErrmsg = false;		
			bOKEnable = true;
			bIsWarning = true;
		}
		else
		{
			bOKEnable = true;
			//strErrMsg = "";
			bCleanErrmsg = true;
		}
		
		//if(!update_peaks_center_label(paCore, trGetN.sc.nVal, trGetN.sl.nVal, trGetN.lc.nVal, trGetN.lr.nVal))
		if(!paCore->UpdatePeaksCenterLabels(trGetN.sc.nVal, trGetN.sl.nVal, trGetN.lc.nVal, trGetN.lr.nVal))
		{
			error_report("fail in update peak labels.");
		}
		
		///Sandy 2008-11-22 add check valid setting if there no warning and no error happen before here
		if(bOKEnable && !bIsWarning)
		{
			strErrMsg = "";
			bOKEnable = _check_derivative_smooth_setting(trGetN, strErrMsg);
			if(!bOKEnable)
				return true;
			else if(strErrMsg != "")
			{
				bIsWarning = true;
				bCleanErrmsg = false;
			}
		}
		//end		
		
		bOKEnable = _check_peaks_num_if_custom_mode(trGetN, strErrMsg, bCleanErrmsg, true, bIsWarning);
		
		int nDerivativeShow = trGetN.derivative.nVal;
		_update_derivative_preview(paCore, &nDerivativeShow);
		return true;			
	}
	
	if ( !lstrcmpi(lpcszNodeName, "btns_manual") )
	{		
	
		//GraphPage gp;
		//if(!paCore->GetTargetPage(gp) || !gp.IsValid())
			//return false;
		//
		//GraphLayer gl;
		//paCore->GetPreviewLayer(gl);
		//if(!gl)
			//return false;
	//
		//vector vxi, vyi;	
		//if(!_get_peaks_data_from_pacore(trGetN,  vxi, vyi))
			//return false;
		//
		//XYRange xyPeaksCenter;
		//paCore->GetPeaksCenterRange(xyPeaksCenter);	
		//vector vxp, vyp;
		//xyPeaksCenter.GetData(vyp, vxp);
		//
		//switch ( trGetN.btns_manual.nVal )
		//{				
		//case STR_BTN_ADD:
			//page_xf_dynadlg_shown_control(gp, 0, false); //close dlg during getting points from graph			
		//
			//vector vxNew, vyNew;
			//graph_get_points(vxNew, vyNew, STR_GRAPH_ADD_PTS_MSG1, STR_GRAPH_ADD_PTS_MSG2, NULL, NULL, -1, CURSOR_VERTICAL_GRID_LINES);
	//
			////snap_points_to_source_data(vxi,vyi, vxNew, vyNew);
			//
			//vxp.Append(vxNew);
			//vyp.Append(vyNew);
			//xyPeaksCenter.SetData(&vyp, &vxp,  0, NULL, DRS_SET_COL_DESIGNATIONS);
			//
			//TreeNode trPeaks = trGetN.otr;	
			//peaks_center_to_tree(trPeaks, vxp, vyp);
			//page_xf_dynadlg_shown_control(gp, 1, false); //open again after get points sucessfully
			//
			//
			//break;
			//
	//
		//case STR_BTN_MODIFY:
			//page_xf_dynadlg_shown_control(gp, 0, false);//close dlg during getting points from graph
			//vector<int> vnPlotIndices;
			//if ( 0 < check_has_plotted_in_graph(xyPeaksCenter, gl, vnPlotIndices) )
			//{					
				//int nplot = vnPlotIndices[0];
				//DataPlot dp = gl.DataPlots(nplot);
	//
				//attach_anchors_on_dataplot(dp, MDC_PEAKS);
			//}
			//graph_done_window(STR_PA_MODIFY_PEAKS, STR_PA_MOFIGY_PEAK_TITLE);
			//return true;
		//
			//break;
				//
				//
		//case STR_BTN_CLEARALL:
			//vector  vEmpty;
			//xyPeaksCenter.SetData(&vEmpty, &vEmpty); //clean data
			//peaks_center_to_tree(trGetN.otr, vEmpty, vEmpty);
			//peaks_center_to_tree(trGetN.distr, vEmpty, vEmpty);
			//break;
			//
		//default:
			//break;
		//}
		if(!modify_peaks_centers_buttons(paCore, trGetN.otr, trGetN.distr, trGetN.btns_manual.nVal))
		{
			error_report("fail in modify peaks.");
		}
		
		//if(!update_peaks_center_label(paCore, trGetN.sc.nVal, trGetN.sl.nVal, trGetN.lc.nVal, trGetN.lr.nVal))
		if(!paCore->UpdatePeaksCenterLabels( trGetN.sc.nVal, trGetN.sl.nVal, trGetN.lc.nVal, trGetN.lr.nVal))
		{
			error_report("fail in update peak labels.");
		}
		bOKEnable = _check_peaks_num_if_custom_mode(trGetN, strErrMsg);
		_update_current_number_peaks(trGetN);
	
		return true;
	}
	
	#define		STR_PEAK_INFO_TYPE		"[Peak Info File (*.DAT)] *.DAT"	///------ Folger 01/16/09 OPEN_AND_SAVE_AS_DIALOG_INSIDE_PA_SHOULD_BE_MODAL
	
	if ( !lstrcmpi(lpcszNodeName, "btns_file") )
	{	
		GraphPage gp;
		if(!paCore->GetTargetPage(gp) || !gp.IsValid())
			return false;
		switch ( trGetN.btns_file.nVal )
		{
			case STR_BTN_SAVE:
			{
				string strFileToSave;
				vector vxcEnable, vhEnable;
				peaks_center_to_tree(trGetN.otr, vxcEnable, vhEnable, false);
				///------ Folger 01/16/09 OPEN_AND_SAVE_AS_DIALOG_INSIDE_PA_SHOULD_BE_MODAL
				//strFileToSave = GetSaveAsBox( "[Peak Info File (*.DAT)] *.DAT", GetAppPath(FALSE) );
				StringArray		saTypes = {STR_PEAK_INFO_TYPE};
				if ( !okutil_FileDialog(&strFileToSave, true, &saTypes, GetAppPath(FALSE), 0, GetWindow(), _L("Save As")) )
					strFileToSave.Empty();
				///------ End OPEN_AND_SAVE_AS_DIALOG_INSIDE_PA_SHOULD_BE_MODAL
				if ( !strFileToSave.IsEmpty() )
				{
					store_peak_info(strFileToSave, true, vxcEnable, vhEnable);
				}
				break;
			}
			case STR_BTN_LOAD:
			{
				string strFile;
				vector vxcEnable, vhEnable;
				///------ Folger 01/16/09 OPEN_AND_SAVE_AS_DIALOG_INSIDE_PA_SHOULD_BE_MODAL
				//strFile = GetOpenBox( "[Peak Info File (*.DAT)] *.DAT", GetAppPath(FALSE) );
				StringArray		saTypes = {STR_PEAK_INFO_TYPE};
				if ( !okutil_FileDialog(&strFile, false, &saTypes, GetAppPath(FALSE), 0, GetWindow(), _L("Open")) )
					strFile.Empty();
				///------ End OPEN_AND_SAVE_AS_DIALOG_INSIDE_PA_SHOULD_BE_MODAL
				if ( !strFile.IsEmpty() )
				{
					store_peak_info(strFile, false, vxcEnable, vhEnable);
					XYRange xyPeaksCenter;
					paCore->GetPeaksCenterRange(xyPeaksCenter);	
					xyPeaksCenter.SetData(&vhEnable, &vxcEnable,  0, NULL, DRS_SET_COL_DESIGNATIONS);
					peaks_center_to_tree(trGetN.otr, vxcEnable, vhEnable, true);
					
				}
				break;
			}
			
			case STR_BTN_LIST:
			{
				_do_peak_list(trGetN, gp, DynaCntrlContainer);
				break;
			}
			/////---Sim 08-15-2008 REORDER_PEAK_BY_XC
			//case STR_BTN_REORDER:
			//{
				//vector vxcEnable, vhEnable;
				//peaks_center_to_tree(trGetN.otr, vxcEnable, vhEnable, false);
				//vector<uint> vnIndeces;
				//if ( vxcEnable.Sort(SORT_ASCENDING, TRUE, vnIndeces) )
				//{
					//vhEnable.Reorder(vnIndeces);
					//peaks_center_to_tree(trGetN.otr, vxcEnable, vhEnable, true);
				//}
				//break;
			//}
			/////---END REORDER_PEAK_BY_XC
		}
		
		//if(!update_peaks_center_label(paCore, trGetN.sc.nVal, trGetN.sl.nVal, trGetN.lc.nVal, trGetN.lr.nVal))
		if(!paCore->UpdatePeaksCenterLabels(trGetN.sc.nVal, trGetN.sl.nVal, trGetN.lc.nVal, trGetN.lr.nVal))
		{
			error_report("fail in update peak labels.");
		}
		bOKEnable = _check_peaks_num_if_custom_mode(trGetN, strErrMsg);
		_update_current_number_peaks(trGetN); 
	}
	
	
	if ( !lstrcmpi(lpcszNodeName, "lc") ||  !lstrcmpi(lpcszNodeName, "sl") || !lstrcmpi(lpcszNodeName, "lr") || !lstrcmpi(lpcszNodeName, "sc") )
	{
		trGetN.lc.Show = trGetN.lr.Show = trGetN.sl.nVal;
		//if(!update_peaks_center_label(paCore, trGetN.sc.nVal, trGetN.sl.nVal, trGetN.lc.nVal, trGetN.lr.nVal))
		if(!paCore->UpdatePeaksCenterLabels( trGetN.sc.nVal, trGetN.sl.nVal, trGetN.lc.nVal, trGetN.lr.nVal))
		{
			error_report("fail in update peak labels.");
		}
	}
	int	nUserEvent = -1;
	bool bPointsModified = xf_check_is_user_event(trGetN, nUserEvent);
	
	///Sandy 2008-10-21 For indicate all anchors are deleted.
	//if ( bPointsModified && nUserEvent == WPARAM_DONE_DLG_COSE)
	if ( bPointsModified && (nUserEvent == WPARAM_DONE_DLG_COSE || nUserEvent == WPARAM_NONE_ANCHOR))
	{		
		//vector vpx, vpy;	
		////XYRange xyPeaks;
		////if(!_get_peaks_data_from_pacore(trGetN,  vpx, vpy, xyPeaks))
			////return false;	
		//XYRange xyPeaksCenter;
		//paCore->GetPeaksCenterRange(xyPeaksCenter);	
		//xyPeaksCenter.GetData(vpy, vpx);
			//
		//GraphLayer gl;
		//paCore->GetPreviewLayer(gl);
		//if(!gl)
			//return false;
		//
		GraphPage gp;
		if(!paCore->GetTargetPage(gp) || !gp.IsValid())
			return false;	
			//
		//vector<int> vnPlotIndices;
		//if ( 0 < check_has_plotted_in_graph(xyPeaksCenter, gl, vnPlotIndices) )
		//{					
			//int nplot = vnPlotIndices[0];
			//DataPlot dp = gl.DataPlots(nplot);
			//dp.AttachXFunction("");
		//}
			//
		//
		//TreeNode trPeaks = trGetN.otr;
		//peaks_center_to_tree(trPeaks,  vpx, vpy, true);
		
		TreeNode trPeaks = trGetN.otr;
		if(!resume_peaks_centers_plot_after_modify_done(paCore,trPeaks, true, nUserEvent == WPARAM_DONE_DLG_COSE))
			error_report("fail in resume peaks centers plot!");
		
		if( _update_current_number_peaks(trGetN) )
		{
			// only XFunction itself can decide if to update dialog in this case
			// little modeless dialog with "Done" button is closed
			// in our case - we need to update if number of peaks changed. 
			// if user simply moved peak - we do not update
			
			xf_dynadlg_post_msg(gp, WM_USER_RECONSTRUCT, GRID_CHANGE_VALUE);
		}
		//if(!update_peaks_center_label(paCore, trGetN.sc.nVal, trGetN.sl.nVal, trGetN.lc.nVal, trGetN.lr.nVal))
		if(!paCore->UpdatePeaksCenterLabels(trGetN.sc.nVal, trGetN.sl.nVal, trGetN.lc.nVal, trGetN.lr.nVal))
		{
			error_report("fail in update peak labels.");
		}		
		bOKEnable = _check_peaks_num_if_custom_mode(trGetN, strErrMsg);
				
		
	}
	return false;
	

}

int pa_peaks_make_tree(TreeNode& tr, LPCSTR lpcszVarName)
{
	
	if ( !lstrcmpi(lpcszVarName, "distr") )
	{
		int nDataIDBase = GET_USER_DATAID(10);
		tree_check_get_node_by_dataid(tr, "xc", nDataIDBase++);
		tree_check_get_node_by_dataid(tr, "h",  nDataIDBase++);
	}
	
	if ( !lstrcmpi(lpcszVarName, STR_GETN_VAR_SHARED_PEAKS_INFO) )
	{
		//tree_check_get_node_by_dataid(tr, "xc",PA_PEAK_XC_DATAID_IN_GETN_TREE);
		//tree_check_get_node_by_dataid(tr, "h", PA_PEAK_H_DATAID_IN_GETN_TREE);
		
		TreeNode trXc = tree_check_get_node_by_dataid(tr, STR_GETN_VAR_SHARED_PEAKS_XC, PA_PEAK_XC_DATAID_IN_GETN_TREE);
		TreeNode trH = tree_check_get_node_by_dataid(tr, STR_GETN_VAR_SHARED_PEAKS_H, PA_PEAK_H_DATAID_IN_GETN_TREE);
	}
	
	if(!lstrcmpi(lpcszVarName, "deriv_smooth"))
	{
		int nDataIDBase = GET_USER_DATAID(20);
		GETN_USE(tr)  GETN_OPTION_BRANCH(GETNBRANCH_OPEN)
		/*
		GETN_LIST(first,_L("Method"), 0, "None|SG") 								GETN_ID(nDataIDBase++)
		GETN_LIST(second,_L("Method"), 0, "None|FFT|ADJ|SG|Quadratic SG")		    GETN_ID(nDataIDBase++)
		*/
		GETN_LIST(first,_L("Method"), 0, _L("None|Savitzky-Golay")) 								GETN_ID(nDataIDBase++)
		GETN_LIST(second,_L("Method"), 0, _L("None|FFT Filter|Adjacent-Averaging|Savitzky-Golay|Quadratic Savitzky-Golay"))		    GETN_ID(nDataIDBase++)
		GETN_NUM(fft_cutoff, _L("Cut Off Frequency"), 0.2) 									GETN_ID(nDataIDBase++)
		GETN_NUM(deriv_poly, _L("Polynomial Order"), 2) 									GETN_ID(nDataIDBase++)
		GETN_NUM(deriv_npts, _L("Points of Window"), 20) 									GETN_ID(nDataIDBase++)
		
		//-----Sandy 2008-11-13 add smooth derivative
		//enum{
			//DERIV_SMOOTH_NONE,
			//DERIV_SMOOTH_FFT,
			//DERIV_SMOOTH_ADJ,
			//DERIV_SMOOTH_SG,
			//DERIV_SMOOTH_QSG,
		//}; defined in curve_utils.h		
		vector<int> vnID1 = {DERIV_SMOOTH_NONE,	DERIV_SMOOTH_SG};
		remap_combo_indexes(tr.first, vnID1);
		vector<int> vnID2 = {DERIV_SMOOTH_NONE, DERIV_SMOOTH_FFT,	DERIV_SMOOTH_ADJ, DERIV_SMOOTH_SG, DERIV_SMOOTH_QSG};
		remap_combo_indexes(tr.second, vnID2);
		
	}
	return 0;
}
//nGetNDialog = 0,1,2, corresponding to the XF GetN dropdown, 0 = dialog is not used
//you can change nRet to be one of XFEVT_PROCEED (defualt), XFEVT_ABORT, XFEVT_PROCEED_NO_DLG or XFEVT_PROCEED_WITH_DLG(when nGetNDialog = 0)
//nGetNDialog = -1 when Ok on GetN dialog to allow handler to preocess <auto> etc variables
//dwCntrl is combination of bits
//LTXF_FROM_GUI_MENU, LTXF_FROM_GUI_PROMPT, LTXF_FROM_AUTO_UPDATE, LTXF_FROM_FUNCTION, LTXF_THEME_USED, LTXF_CHANGE_PARAM
void pa_peaks_before_execute(TreeNode& trGetN, int nGetNDialog, int& nRet, int dwCntrl)
{
	
	if ( nGetNDialog >= 0 )
	{
		trGetN.SetAttribute(STR_HELPID_ATTRIB, IDD_PA_RE_FINDP);
		PAWizCore* paCore = (PAWizCore*)get_xf_core_handler(trGetN);
		ASSERT(paCore);	
		
		if ( nGetNDialog >0 )
		{
			TreeNode trBtnAuto = trGetN.btn_find;
			trBtnAuto.SetAttribute(STR_ID_ATTRIB, ONODETYPE_PUSHBUTTON_GROUP);
			trBtnAuto.SetAttribute(STR_COMBO_ATTRIB, STR_BUTTON_FIND);			
			
			TreeNode trBtns = trGetN.btns_manual;//Sandy 2008-2-20 only for rename and separate
			trBtns.SetAttribute(STR_ID_ATTRIB, ONODETYPE_PUSHBUTTON_GROUP);
			trBtns.SetAttribute(STR_COMBO_ATTRIB, STR_BUTTON_LIST);			
			DWORD dwDisplyBits = DISPLAY_EDITOR_HORZ;
			trBtns.SetAttribute(STR_ATTRIB_DISPFMT, (string)dwDisplyBits);
		
			
			TreeNode trBtnsFile = trGetN.btns_file;
			trBtnsFile.SetAttribute(STR_ID_ATTRIB, ONODETYPE_PUSHBUTTON_GROUP);
			trBtnsFile.SetAttribute(STR_COMBO_ATTRIB, STR_BUTTON_FILE_LIST);
			trBtnsFile.SetAttribute(STR_ATTRIB_DISPFMT, (string)dwDisplyBits);
			
			///Jasmine 08/28/09 CENTRALIZE_FIND_PEAK_METHOD_COMBO
			///Jasmine 08/24/09 QA81-14165 DISPLAY_BUT_DISABLE_PRO_OPTION_IN_REG_VERSION
			//if(is_pro_version())
				//trGetN.method.SetAttribute(STR_COMBO_ATTRIB, _METHODS_LIST_IN_PRO_VERSION);
			//else
				//trGetN.method.SetAttribute(STR_COMBO_ATTRIB, _METHODS_LIST_IN_REG_VERSION);
			if( !is_find_peak_method_available(trGetN.method.nVal) )
				trGetN.method.nVal = method_max;
			///End DISPLAY_BUT_DISABLE_PRO_OPTION_IN_REG_VERSION
			///End CENTRALIZE_FIND_PEAK_METHOD_COMBO
			
			trGetN.numpeaks.Enable = ENABLE_READ_ONLY;
		
			_update_check_derivative_smooth_show_hide(trGetN);//Sandy 2008-11-13 add smooth derivative
			
			string strErrMsg;		
			
		}
	
		//if(nGetNDialog >=0)
		{
			
			///Sandy 2008-10-23 add for output "[<input>]<new>" ReportData to source wks page
			paCore->SetOriginalRangeToGetN(trGetN.iy);
			
			
			//if( FIND_MODE_AUTO == trGetN.mode.nVal )
			//{
				//vector vEmpty;
				//peaks_center_to_tree(trGetN.otr,vEmpty, vEmpty, true);
				//peaks_center_to_tree(trGetN.distr,vEmpty, vEmpty, true);
			//}
			//else
			{
				vector vxc, vh;
				peaks_center_to_tree(trGetN.otr,  vxc, vh, false);
				XYRange xyPeaksCenter;
				paCore->GetPeaksCenterRange(xyPeaksCenter);
				xyPeaksCenter.SetData(&vh, &vxc, 0, NULL, DRS_SET_COL_DESIGNATIONS);
			}
		    
		    _update_auto_value_by_input_change(trGetN);
		    
			string strRTvalue = _STR_DEFAULT_TEXT_FOR_REPORT_DATA_NODE;
			okutil_convert_localized_PDS(&strRTvalue);
			int nGoal = paCore->GetCurrGoal();
			if(nGoal == PA_GOAL_FIND_PEAK )
			{
				trGetN.rd_peaks.Show = true;
				if(!(dwCntrl & LTXF_CHANGE_PARAM) && !(dwCntrl & LTXF_EXEC_RECALCULATE) )
				{
					///------ Folger 09/27/09 QA80-14076-P1 PA_FIND_PEAKS_FAILS_TO_APPLY_THEME_TO_PEAK_CENTERS_OUTPUT
					string		strBook, strSheet, strCol;
					okutil_parse_complete_range_string(trGetN.rd_peaks.strVal, &strBook, &strSheet, &strCol);
					int			nType = okutil_cvt_str_to_predefined_type(strBook);
					if ( PDS_SAME == nType || PDS_OPTIONAL == nType )
					///------ End PA_FIND_PEAKS_FAILS_TO_APPLY_THEME_TO_PEAK_CENTERS_OUTPUT
						trGetN.rd_peaks.strVal = strRTvalue;
				}
			}
			else
			{
				trGetN.rd_peaks.strVal = STR_OPTIONAL;
				trGetN.rd_peaks.Show = false;
			}
			
			///Sandy 2008-9-1 add baseline output if there is baseline
			if(nGoal == PA_GOAL_FIND_PEAK && PA_BM_None != paCore->GetBaseMode())
			{
				//------ Folger 11/25/08 v8.0979 BETTER_SOLUTION_TO_SWITCH_BASELINE_OUTPUT
				/*
				trGetN.rd_oyb.Show = true;
				if(!(dwCntrl & LTXF_CHANGE_PARAM) && !(dwCntrl & LTXF_EXEC_RECALCULATE) )
					trGetN.rd_oyb.strVal = strRTvalue;
				
				//----Sandy 2008-11-22 reuse user range-string if change parameters
				else
				{
					trGetN.rd_oyb.strVal = trGetN.old_oyb.strVal;
				}
				//----
				*/
				bool		bPreShow = trGetN.rd_oyb.Show;
				trGetN.rd_oyb.Show = true;
				
				if ( !bPreShow )
					trGetN.rd_oyb.SetAttribute(STR_ATTRIB_DYNACONTROL_USE_CHECK, 1);
				//------ End BETTER_SOLUTION_TO_SWITCH_BASELINE_OUTPUT
			}
			else
			{
				//------ Folger 11/25/08 v8.0979 BETTER_SOLUTION_TO_SWITCH_BASELINE_OUTPUT
				/*
				//----sandy 2008-11-22 back up the user used range-string
				string str_oybUsed = trGetN.rd_oyb.strVal;
				if(PDS_USER == okutil_cvt_str_to_predefined_type(str_oybUsed))
					trGetN.old_oyb.strVal = str_oybUsed;
				trGetN.rd_oyb.strVal = STR_OPTIONAL;
				trGetN.rd_oyb.Show = false;
				//----
				*/
				trGetN.rd_oyb.SetAttribute(STR_ATTRIB_DYNACONTROL_USE_CHECK, 0);
				trGetN.rd_oyb.Show = false;
				//------ End BETTER_SOLUTION_TO_SWITCH_BASELINE_OUTPUT
			}		
		}
	}
}
//nEventID < 0 on event, like GETNE_ON_INIT, GETNE_ON_OK etc, >0 on change from control
//return 0 to do nothing, return PEVENT_GETN_RET_TO_CLOSE to close dialog
//dwEnables = bOKEnable, bBTN1Enable, bBTN2Enable, bBTN3Enable, , can set to false to disable OK/Apply buttons
//lpcszNodeName = the trGetN TreeNode tag name that generates the event, or is  if GETNE_ON_OK etc
//strAux = optional string for XF Wizard Bar, like DLG_NEED_CHANGE_GRID etc, it will be invalid if from internal node value change event
//strErrMsg = allowing messages to be shown
int pa_peaks_event1_ex(TreeNode& trGetN, int nRow, int nEventID, DWORD& dwEnables, LPCSTR lpcszNodeName, WndContainer& DynaCntrlContainer, string& strAux, string& strErrMsg)
{
	return false;
}
