#include <origin.h>
#include <GetNBox.h>
#include <xfutils.h>
enum{
	bsopt_base,
	bsopt_y0,
};
enum{
	localbase_line,
	localbase_spline,
};
//put additional include files here
#include <o8dlg.h>
#include <..\Originlab\grobj_utils.h> 
#include <..\Originlab\PeakRectControlList.h> /// Hong 02/26/08 v8.0812 USING_CLASS_CENTRALIZE_CODE_OF_PEAK_CONTROL
#include <..\Originlab\curve_utils.h>
#include <..\originlab\graph_utils.h>
#include <ReportTree.h>
#include <..\OriginLab\PAWizCore.h>
#include <..\OriginLab\XFWizard_utils.h>
///---Sim 12-11-2008 PEAK_RECT_ADJUST_ON_PREVIEW_ALLOW_TO_APPLY_ALL_PEAKS
#include <Control.h>
#include <..\OriginLab\OriginEvents.h>
///---END PEAK_RECT_ADJUST_ON_PREVIEW_ALLOW_TO_APPLY_ALL_PEAKS

//#ifdef _DEBUG
//#include <Profiler.h>
//#endif

/*------------------------------------------------------------------------------*
 * Modification Log:															*
 *	Folger 04/20/09 QA80-13478-P1-P2 PA_INTEGRATE_NOT_WORKING_WHEN_Y_EQUAL_0_FOR_ALL_BASELINE_MODE
 *	Kenny 2/3/2010 QA81-14737 ADD_BUTTON_TO_PA_INTEGRATE_RECT_TO_PROVIDE_DIALOG_FOR_DIMENSION_SETTING*
 *	Folger 02/11/10 QA81-15085 PA_INTEG_FAILS_WHEN_SCALE_IN						*
 *------------------------------------------------------------------------------*/

#define _PAW_INTEGPEAKS_RECT_OBJECT_NAME  "goPAWIntPeaks"

/// Kenny 2/3/2010 QA81-14737 ADD_BUTTON_TO_PA_INTEGRATE_RECT_TO_PROVIDE_DIALOG_FOR_DIMENSION_SETTING
#define STR_INTEGPEAKS_BTN_NAME				(_PAW_INTEGPEAKS_RECT_OBJECT_NAME + "_DimBtn")
#define STR_PEAK_RECT_MENU_DIMENSION_TEXT	_L("Scale...")
/// End ADD_BUTTON_TO_PA_INTEGRATE_RECT_TO_PROVIDE_DIALOG_FOR_DIMENSION_SETTING

//#define _STR_BUTTON_RESIZE				 _L("Resize")
//#define _STR_BUTTON_FIXSIZE 			 _L("Fix")
#define _MAX_PEAKS_NUM  1000// 500 // too many window will use up system resource

#define _COL_INDEX_LEFT_MARKER_X 0
#define _COL_INDEX_RIGHT_MARKER_X 1

#define _ID_PEAKS_REPORT 1000
#define _ID_DATA_TABLE 2000

enum{
	INT_WINDOW_AUTO,
	INT_WINDOW_CUSTOM,
	INT_WINDOW_SAME_WIDTH,
};

///------ Folger 04/20/09 QA80-13478-P1-P2 PA_INTEGRATE_NOT_WORKING_WHEN_Y_EQUAL_0_FOR_ALL_BASELINE_MODE
static	bool	_get_peak_data_by_baseline_mode(vector& vy, vector& vx, PAWizCore* paCore, int nBaseMode)
{
	if(nBaseMode == bsopt_base || nBaseMode < 0
		|| paCore->GetSubtractedMode() )//base on baseline
	{
		XYRange xyPeaks;
		if(!paCore->GetPeaksRange(xyPeaks))
		{
			return false;
		}	
		xyPeaks.GetData(vy, vx);	
	}
	else
	{
		XYRange xyOriginal;
		if(!paCore->GetOriginalRange(xyOriginal))
		{
			return false;
		}	
		xyOriginal.GetData(vy, vx);	
	}
	
	return true;
}
///------ End PA_INTEGRATE_NOT_WORKING_WHEN_Y_EQUAL_0_FOR_ALL_BASELINE_MODE

static double _compute_whole_curve_area(PAWizCore* paCore, int nBaseMode  )
{
	ASSERT(paCore);
	vector vx, vy;

	///------ Folger 04/20/09 QA80-13478-P1-P2 PA_INTEGRATE_NOT_WORKING_WHEN_Y_EQUAL_0_FOR_ALL_BASELINE_MODE
	//if(nBaseMode == bsopt_base )//base on baseline
	//{
		//XYRange xyPeaks;
		//if(!paCore->GetPeaksRange(xyPeaks))
		//{
			//return false;
		//}	
		//xyPeaks.GetData(vy, vx);	
	//}
	//else
	//{
		//XYRange xyOriginal;
		//if(!paCore->GetOriginalRange(xyOriginal))
		//{
			//return false;
		//}	
		//xyOriginal.GetData(vy, vx);	
	//}
	_get_peak_data_by_baseline_mode(vy, vx, paCore, nBaseMode);
	///------ End PA_INTEGRATE_NOT_WORKING_WHEN_Y_EQUAL_0_FOR_ALL_BASELINE_MODE
	
	///Sandy 2009-2-11 if local baseline, compute the accumulative total of all area of peak base on local baseline later
	if(paCore->GetBaseMode() == PA_BM_LOCAL)
		return NANUM;
	//end
	
	IntegrationResult xTotalIntResult;
	if (OE_NOERROR != ocmath_integrate(vx, vy, 0, vx.GetSize()-1, &xTotalIntResult, NULL, ABSOLUTE_AREA))
	{
		error_report("integrate fail in pa_int:_compute_whole_curve_area()");
		return 0;
	}
	
	return xTotalIntResult.Area;
}

///------ Folger 04/20/09 QA80-13478-P1-P2 PA_INTEGRATE_NOT_WORKING_WHEN_Y_EQUAL_0_FOR_ALL_BASELINE_MODE
//static bool _get_ascending_peak_data(PAWizCore* paCore, /*int nBaseMode, */ vector& vx, vector& vy)
static bool _get_ascending_peak_data(PAWizCore* paCore, vector& vx, vector& vy, int nBaseMode = -1)
///------ End PA_INTEGRATE_NOT_WORKING_WHEN_Y_EQUAL_0_FOR_ALL_BASELINE_MODE
{
	ASSERT(paCore);
	//if(nBaseMode == 0)//base on baseline
	//{
		///------ Folger 04/20/09 QA80-13478-P1-P2 PA_INTEGRATE_NOT_WORKING_WHEN_Y_EQUAL_0_FOR_ALL_BASELINE_MODE
		//XYRange xyPeaks;
		//if(!paCore->GetPeaksRange(xyPeaks))
		//{
			//return false;
		//}	
		//xyPeaks.GetData(vy, vx);
		_get_peak_data_by_baseline_mode(vy, vx, paCore, nBaseMode);
		///------ End PA_INTEGRATE_NOT_WORKING_WHEN_Y_EQUAL_0_FOR_ALL_BASELINE_MODE
		
		//XYRange xyRaw;
		//if(!paCore->GetOriginalRange(xyRaw))
		//{
			//return false;
		//}	
		//if(strInputDesc != NULL)
			//strInputDesc = xyRaw.GetDescription();
		
	//}
	//else
	//{
		//XYRange xyOriginal;
		//if(!paCore->GetOriginalRange(xyOriginal))
		//{
			//return false;
		//}	
		//xyOriginal.GetData(vy, vx);	
		//
		//if(strInputDesc != NULL)
			//strInputDesc = xyOriginal.GetDescription(GETLC_NO_DESIGNATIONS|GETLC_NO_ROWS);
	//}
	
	vector<uint> vnIndex;		
	vx.Sort(SORT_ASCENDING, TRUE, vnIndex);
	vy.Reorder(vnIndex);
	return true;
}

static 	bool _update_npeaks(TreeNode& trGetN)
{
		
	PAWizCore* paCore = (PAWizCore*)get_xf_core_handler(trGetN);
	ASSERT(paCore);	
	
	XYRange xyPeaksCenter;
	if(!paCore->GetPeaksCenterRange(xyPeaksCenter))
	{
		error_report("fail in get xyrange in PACore!");
		return false;
	}
	vector vpx, vpy;
	xyPeaksCenter.GetData(vpy, vpx);
	
	///----Sandy 2008-12-2 remove duplicated peaks when intgral peaks
	int nSize = vpy.GetSize();
	///------ Folger 12/26/08 QA80-12856 v8.0991 IMRPOVE_ocmath_xy_remove_duplicates
	//if(OE_NOERROR != ocmath_xy_remove_duplicates(&nSize,vpx,vpy, Replace_With_Median, 1.0e-8, false))
	int nResize = ocmath_xy_remove_duplicates(vpx,vpy, nSize, Replace_With_Median, 1.0e-8, false);
	///------ End IMRPOVE_ocmath_xy_remove_duplicates
	
	if(nResize !=  vpy.GetSize() && nResize > 0)
	{
		vpy.SetSize(nResize);
		vpx.SetSize(nResize);
		xyPeaksCenter.SetData(&vpy, &vpx);
		error_report("There are duplicate peaks, have been removed and continue!");
	}
	//---end
	
	
	TreeNode trNpeaks = trGetN.npeaks;
	int npeaks = trNpeaks.nVal;
	if(1 == octree_get_auto_support(&trNpeaks))
	{
		npeaks = vpx.GetSize();
	}
	
	if(	npeaks <= 0)
		return false;
	
	//if(trGetN.intwindow.nVal != INT_WINDOW_CUSTOM )
	//{
		//if(npeaks > _MAX_PEAKS_NUM  || npeaks > vpx.GetSize())
			//return false;
	//}

	
	trGetN.npeaks.nVal = npeaks;
	return true;
}

///---Sim 12-11-2008 PEAK_RECT_ADJUST_ON_PREVIEW_ALLOW_TO_APPLY_ALL_PEAKS
enum{
	PEAKS_RECT_ADJUST,
	/// Kenny 2/8/2010 QA81-14737 ADD_BUTTON_TO_PA_INTEGRATE_RECT_TO_PROVIDE_DIALOG_FOR_DIMENSION_SETTING
	PEAKS_RECT_SET_DIMENSION,
	/// End ADD_BUTTON_TO_PA_INTEGRATE_RECT_TO_PROVIDE_DIALOG_FOR_DIMENSION_SETTING
	PEAKS_RECT_APPLY_TO_ALL,
	PEAKS_RECT_SET_ALL_SAME,
};

class PeaksRectMenu : public Menu
{
public:
	PeaksRectMenu(GraphObject& go)
	{
		m_grObject = go;
		
		Tree tr;
		tr = go.GetFormat(FPB_OTHER, FOB_ALL, true, true);
		DWORD dwStats = tr.Root.States.nVal;
		bool bEnable = !(dwStats & GOC_NO_RESIZE);
		
		DWORD dwEnable = bEnable ? MF_ENABLED : MF_GRAYED;
		
		/// Kenny 2/8/2010 QA81-14737 ADD_BUTTON_TO_PA_INTEGRATE_RECT_TO_PROVIDE_DIALOG_FOR_DIMENSION_SETTING
		Add(STR_PEAK_RECT_MENU_DIMENSION_TEXT, OnMenuItem, MF_STRING|dwEnable, PEAKS_RECT_SET_DIMENSION);
		Add("", OnMenuItem, MF_SEPARATOR|dwEnable, -1);
		/// End ADD_BUTTON_TO_PA_INTEGRATE_RECT_TO_PROVIDE_DIALOG_FOR_DIMENSION_SETTING
		
		Add(_L("Apply Width to all Peaks"), OnMenuItem, MF_STRING|dwEnable, PEAKS_RECT_APPLY_TO_ALL);		
		Add(_L("Set as Fixed Width to all Peaks"), OnMenuItem, MF_STRING|dwEnable, PEAKS_RECT_SET_ALL_SAME);
	}
	
	void	OnMenuItem(UINT nPos)
	{
	}
	
	bool	Show(int x, int y)
	{
		int nCmd = 0;
		TrackPopupMenu(0, x, y, GetWindow(), &nCmd);
		
		// hard code, can't get index of peaks, only assume name structure.
		// also better to use centralized name construct and destruct function
		string strName = m_grObject.GetName();
		strName = strName.Mid(strlen(_PAW_INTEGPEAKS_RECT_OBJECT_NAME+"_"));
		int nIndex = atoi(strName);

		post_getn_dialog_message(WM_USER_ON_GRAPH_OBJECT_CHANGE, nIndex, nCmd);
		
		return true;
	}
	
private:
	GraphObject		m_grObject;
};

class OC_REGISTERED PeaksRectEvents : public OriginEventsBase
{
public:
	virtual bool OnContextMenu(int x, int y, DWORD dwControl = 0)
	{
		PeaksRectMenu menu(m_grObject);
		return menu.Show(x, y);
	}
	
	virtual	bool SetObj(OriginObject& obj)
	{
		m_grObject = obj;
		
		if( m_grObject )
			return true;
		
		return false;
	}
	
protected:	
	GraphObject		m_grObject; 
};
///---END PEAK_RECT_ADJUST_ON_PREVIEW_ALLOW_TO_APPLY_ALL_PEAKS

/// Kenny 2/3/2010 QA81-14737 ADD_BUTTON_TO_PA_INTEGRATE_RECT_TO_PROVIDE_DIALOG_FOR_DIMENSION_SETTING
#define STR_PEAK_RECT_BTN_TEXT					_L("Scale")

static void _on_pa_rect_set_dimension(int nID)
{
	GraphLayer gl = Project.ActiveLayer();
	if (!gl)
	{
		error_report( _L("pa_rect_dimension_btn_event: Invalid active layer!") );
		return;
	}
	
	string strName = _PAW_INTEGPEAKS_RECT_OBJECT_NAME + "_" + (string)nID;
	ShapeControl sc(gl, strName);
	
	double dX1 = 0.0;
	double dX2 = 0.0;
	
	string strLTCmd;
	strLTCmd.Format("%s.x1", strName);
	LT_evaluate(strLTCmd, &dX1);
	
	strLTCmd.Format("%s.x2", strName);
	LT_evaluate(strLTCmd, &dX2);
	
	GETN_BOX(trDimension)
    GETN_NUM(x1, "X1", dX1)
	GETN_NUM(x2, "X2", dX2)
    if( GetNBox(trDimension, STR_PEAK_RECT_BTN_TEXT) )
    {
    	dX1 = trDimension.x1.dVal;
    	dX2 = trDimension.x2.dVal;
    	strLTCmd.Format("%s.x1 = %s;%s.x2 = %s;", strName, ftoa(dX1), strName, ftoa(dX2));
    	LT_execute(strLTCmd);
    	
    	// Must inform the change
    	post_getn_dialog_message(WM_USER_ON_GRAPH_OBJECT_CHANGE, nID, PEAKS_RECT_ADJUST);
    }
}

//#define PEAK_RECT_ADD_BTN
//#define PEAK_RECT_BTN_SHOW_CONTEXT_MENU	// for future use.

#ifdef PEAK_RECT_BTN_SHOW_CONTEXT_MENU
enum
{
	PEAK_RECT_BTN_MENU_SEPARATOR,
	PEAK_RECT_BTN_MENU_DIMENSION, 
};

#include <..\OriginLab\MenuBase.h>

class CPeakRectBtnMenu : public MenuBase
{
public:
	CPeakRectBtnMenu(int nRectID)
	{
		m_nPeakRectID = nRectID;
	}
public:
	int DoContextMenu()
	{
		if ( !Init() )
			return -1;
		
		GraphLayer gl = Project.ActiveLayer();
		ASSERT(gl);
		
		GraphObject goBtn = gl.GraphObjects(STR_INTEGPEAKS_BTN_NAME);
		ASSERT( goBtn.IsValid() );
		
		int nx = goBtn.Left + goBtn.Width;
		int ny = goBtn.Top;
		
		nx += goBtn.Height * 0.2;	// In case overlapping
		
		Page gp = gl.GetPage();
		gp.LPtoDP(nx, ny);

		Window wnd = gp.GetWindow();
		RECT rr;
		rr.left = rr.right = nx;
		rr.top = rr.bottom = ny;
		wnd.ClientToScreen(&rr);
		
		int nCmd = -1;
		
		TrackPopupMenu(0, rr.right, rr.top, GetWindow(), &nCmd);
		switch (nCmd)
		{
		case PEAK_RECT_BTN_MENU_DIMENSION:
			_on_pa_rect_set_dimension(m_nPeakRectID);
			break;
		default:
			break;
		}
		return nCmd;
	}
protected:
	BOOL Init()
	{
		vector<int> vnIDs;
		vector<string> vsTexts;
		
		vnIDs.Add(PEAK_RECT_BTN_MENU_DIMENSION);
		
		vsTexts.Add(STR_PEAK_RECT_MENU_DIMENSION_TEXT);
		
		return InitMenu(vnIDs, vsTexts);
	}
private:
	BOOL InitMenu(const vector<int>& vnIDs, const vector<string>& vsText, const vector<bool>& vbEnables = NULL)
	{
		const int nIDSize = vnIDs.GetSize();
		if ( nIDSize != vsText.GetSize() || (vbEnables && nIDSize != vbEnables.GetSize()) )
		{
			ASSERT(FALSE);
			return FALSE;
		}
		for(int ii = 0; ii < nIDSize; ++ii)
		{
			int nFlags;
			if(PEAK_RECT_BTN_MENU_SEPARATOR == vnIDs[ii])
				nFlags = MF_SEPARATOR;
			else
			{
				nFlags = MF_STRING;
				if( vbEnables && !vbEnables[ii] )
					nFlags |= MF_GRAYED | MF_DISABLED;
			}
			Add(vsText[ii], OnMenuItem, nFlags, vnIDs[ii]);
		}
		return TRUE;
	}
private:
	int	m_nPeakRectID;
};
#endif // PEAK_RECT_BTN_SHOW_CONTEXT_MENU

void pa_rect_dimension_btn_event(int nID)
{
#ifdef PEAK_RECT_BTN_SHOW_CONTEXT_MENU
	CPeakRectBtnMenu ctxMenu(nID);
	ctxMenu.DoContextMenu();
#else
	_on_pa_rect_set_dimension(nID);
#endif
}
/// End ADD_BUTTON_TO_PA_INTEGRATE_RECT_TO_PROVIDE_DIALOG_FOR_DIMENSION_SETTING
 
void events_from_paw_pks_rects(int nID, int nEvent)
{
	/// Kenny 2/3/2010 QA81-14737 ADD_BUTTON_TO_PA_INTEGRATE_RECT_TO_PROVIDE_DIALOG_FOR_DIMENSION_SETTING
	// Moved from the block underneath.
	GraphLayer gl = Project.ActiveLayer();
	if (!gl)
	{
		error_report("events_from_paw_pks_rects: Invalid active layer!");
		return;
	}
	
	string strName = _PAW_INTEGPEAKS_RECT_OBJECT_NAME+"_"+(string)nID;
	ShapeControl sc(gl, strName);
	/// End ADD_BUTTON_TO_PA_INTEGRATE_RECT_TO_PROVIDE_DIALOG_FOR_DIMENSION_SETTING
	
	if(nEvent == OE_MOVING || nEvent == OE_RESIZING || nEvent == OE_MOVE || nEvent == OE_RESIZE
		|| nEvent == OE_MOVE || nEvent == OE_RESIZE || nEvent == OE_DELETE)
	{
		/// Kenny 2/3/2010 QA81-14737 ADD_BUTTON_TO_PA_INTEGRATE_RECT_TO_PROVIDE_DIALOG_FOR_DIMENSION_SETTING
		//GraphLayer gl = Project.ActiveLayer();
		//if(!gl)
		//{
			//error_report("events_from_paw_pks_rects: Invalid active layer!");
			//return;
		//}
		//
		//string strName = _PAW_INTEGPEAKS_RECT_OBJECT_NAME+"_"+(string)nID;
		//ShapeControl sc(gl, strName);
		/// End ADD_BUTTON_TO_PA_INTEGRATE_RECT_TO_PROVIDE_DIALOG_FOR_DIMENSION_SETTING
		
		if(sc.IsValid())
		{
			string strData;
			if(nEvent == OE_MOVING || nEvent == OE_RESIZING || nEvent == OE_MOVE || nEvent == OE_RESIZE)
			{

				double dX, dY, dTop, dBottom, dLeft, dRight;
				sc.GetPosition(dX, dY,dLeft, dRight, dTop, dBottom);

				strData.Format("(X1:%s, X2:%s), Xc = %s", ftoa(dLeft), ftoa(dRight), ftoa(dX));
				SetDataDisplayText(strData);
				
			}
			
			if(nEvent == OE_MOVE || nEvent == OE_RESIZE)
			{
				///---Sim 12-11-2008 PEAK_RECT_ADJUST_ON_PREVIEW_ALLOW_TO_APPLY_ALL_PEAKS
				//post_getn_dialog_message(WM_USER_ON_GRAPH_OBJECT_CHANGE, nID);
				post_getn_dialog_message(WM_USER_ON_GRAPH_OBJECT_CHANGE, nID, PEAKS_RECT_ADJUST);
				///---Sim 12-11-2008 PEAK_RECT_ADJUST_ON_PREVIEW_ALLOW_TO_APPLY_ALL_PEAKS
			}
			
			
		}
		
		if(nEvent == OE_DELETE)
		{
			GraphObject goLine = gl.GraphObjects(strName+"_Line");
			goLine.Destroy();
			ShapeControlList scl(gl, _PAW_INTEGPEAKS_RECT_OBJECT_NAME, _MAX_PEAKS_NUM);
			scl.Sort();
			
			
			if(nEvent == OE_MOVE || nEvent == OE_RESIZE)
			{
				///---Sim 12-11-2008 PEAK_RECT_ADJUST_ON_PREVIEW_ALLOW_TO_APPLY_ALL_PEAKS
				//post_getn_dialog_message(WM_USER_ON_GRAPH_OBJECT_CHANGE, nID);
				post_getn_dialog_message(WM_USER_ON_GRAPH_OBJECT_CHANGE, nID, PEAKS_RECT_ADJUST);
				///---Sim 12-11-2008 PEAK_RECT_ADJUST_ON_PREVIEW_ALLOW_TO_APPLY_ALL_PEAKS
			}
			
		}

	}
	/// Kenny 2/3/2010 QA81-14737 ADD_BUTTON_TO_PA_INTEGRATE_RECT_TO_PROVIDE_DIALOG_FOR_DIMENSION_SETTING
#ifdef PEAK_RECT_ADD_BTN
	else if ( OE_SELECT == nEvent || OE_UNSELECT == nEvent )
	{
		if ( sc.IsValid() )
		{
			bool bIsSelecting	= OE_SELECT == nEvent;
			GraphObject goBtn	= gl.GraphObjects(STR_INTEGPEAKS_BTN_NAME);
			GraphObject goMain	= sc.GetMainObj();
			if ( !goBtn || !goMain )
				return;
			if ( bIsSelecting )
			{
				OGRGAP gp = {0.1, 0.1};
				bool bRet = connect_justify( goMain, goBtn, CTP_RIGHT_TOP, &gp );
				string strScript;
				strScript.Format("pa_rect_dimension_btn_event(%d);", nID);
				set_LT_script(goBtn, strScript, GRCT_MOUSEUP, 0);
			}
			//goBtn.Show = bIsSelecting;
			goBtn.Show = TRUE;
		}
	}
#endif // PEAK_RECT_ADD_BTN
	/// End ADD_BUTTON_TO_PA_INTEGRATE_RECT_TO_PROVIDE_DIALOG_FOR_DIMENSION_SETTING
}

static 	void  _append_optional_settings_to_tree(TreeNode tr)
{
	TreeNode trOptionalSettings = tree_check_get_node(tr, "OptionalSettings");
	TreeNode trLTScript = tree_check_get_node(trOptionalSettings, "LTScript");
	TreeNode trEventID = tree_check_get_node(trOptionalSettings, "EventID");
	
	
	tr.OptionalSettings.LTScript.strVal = "events_from_paw_pks_rects";
	tr.OptionalSettings.EventID.nVal = GRCT_ANY_EVENT;//GRCT_SIZEMOVE;
	
	tr.OptionalSettings.Color.nVal = 6;// yellow
	tr.OptionalSettings.BorderColor.nVal = 3; //blue
	tr.OptionalSettings.PatternStyle.nVal = 1;
	tr.OptionalSettings.BorderWidth.dVal = 0.5;
	tr.OptionalSettings.PatternWidth.dVal = 0.2;
	tr.OptionalSettings.FillColor.nVal = INDEX_COLOR_TRANSPARENT;
	tr.OptionalSettings.BehindData.nVal = 0;
	
	tr.OptionalSettings.Deleteable.nVal = 0;///Sandy 2009-3-2 NO_SUPPOT_DEL_IN_PA_INTEGRATE
	
	///---Sim 12-11-2008 PEAK_RECT_ADJUST_ON_PREVIEW_ALLOW_TO_APPLY_ALL_PEAKS
	tr.OptionalSettings.Event.strVal = "PeaksRectEvents";
	///---END PEAK_RECT_ADJUST_ON_PREVIEW_ALLOW_TO_APPLY_ALL_PEAKS
}


//static bool _create_empty_integral_data_table(ReportData& rd)
//{
	//if(!rd.IsValid())
		//return false;	
		//
	//int nID = 200; 
	//int nTableFormat = GETNBRANCH_OPEN | GETNBRANCH_HIDE_COL_HEADINGS| GETNBRANCH_HIDE_ROW_HEADINGS | GETNBRANCH_FIT_COL_WIDTH | GETNBRANCH_FIT_ROW_HEIGHT;
	//
	//rd.ID = nID++; 
	//rd.SetAttribute(STR_LABEL_ATTRIB, "Integral Data"); //Table title
	//rd.SetAttribute(TREE_Table, nTableFormat);
	//
	//return true;
//}

///Kyle 12/24/2008 ADD_COMMENTS_FOR_OUTPUT_DATA
//static bool _append_integral_data_of_one_peak(ReportData& rd, int nPeakInd, vector& vX,  vector& vIntegrated)
static bool _append_integral_data_of_one_peak(ReportData& rd, int nPeakInd, vector& vX,  vector& vIntegrated, string strRange)
///End ADD_COMMENTS_FOR_OUTPUT_DATA
{
	
	if(!rd.IsValid())
		return false;	
		
	int nID = _ID_DATA_TABLE + nPeakInd * 4 + 1;
	int nIDx = _ID_DATA_TABLE + nPeakInd * 4 + 2;
	int nIDy = _ID_DATA_TABLE + nPeakInd * 4 + 3;
	
	ReportTable rtInteg;
	string strTableName;
	strTableName.Format("Peak%d", nPeakInd+1);
	///Kyle 12/24/2008 ADD_COMMENTS_FOR_OUTPUT_DATA
	//rtInteg = rd.CreateTable(strTableName, strTableName, nID);
	string strComments;
	strComments.Format("Peak%d of %s", nPeakInd+1, strRange);
	rtInteg = rd.CreateTable(strTableName, strComments, nID);
	///End ADD_COMMENTS_FOR_OUTPUT_DATA
	rtInteg.AddColumn(vX, "X", nIDx, "X", OKDATAOBJ_DESIGNATION_X);
	rtInteg.AddColumn(vIntegrated, "Y", nIDy, "Y", OKDATAOBJ_DESIGNATION_Y);	
	
	return true;
}
////static bool _create_empty_integrate_report_data_table(int nPeaks, ReportData& rd, vector<string>& vstrLabels, bool bArea, bool bAreaP, bool bid,  bool bx1, bool bx2, bool bfwhm, bool blwidth,bool brwidth, bool bPeakCenter, bool bHeight, bool bCentroid)
//static bool _create_integrate_report_long_name_list(vector<string>& vstrLabels, bool bArea, bool bAreaP, bool bid,  bool bx1, bool bx2, bool bfwhm, bool blwidth,bool brwidth, bool bPeakCenter, bool bHeight, bool bCentroid)
//{
	////if(!rd.IsValid())
		////return false;	
	//if(!bArea && !bAreaP && !bx1 && !bx2 && !bfwhm && !blwidth && !brwidth && !bPeakCenter && !bHeight && !bCentroid && !bid)	
 		//return false;
	//
	////Worksheet wks;
	////rd.GetWorksheet(wks);
	////
	////int nID = 100; 
	////int nTableFormat = GETNBRANCH_OPEN | GETNBRANCH_HIDE_COL_HEADINGS| GETNBRANCH_HIDE_ROW_HEADINGS | GETNBRANCH_FIT_COL_WIDTH | GETNBRANCH_FIT_ROW_HEIGHT;
	////
	////rd.ID = nID++; 
	////rd.SetAttribute(STR_LABEL_ATTRIB, "Integration Report"); //Table title
	////rd.SetAttribute(TREE_Table, nTableFormat);
	//
//
	//int nCol;
//
	//if(bArea)
	//{
		//vstrLabels.Add("Area");
	//}	
	//
	//if(bAreaP)
	//{
		//vstrLabels.Add("AreaIntgP(%)");
	//}
	//
	/////Sandy 2008-11-5 add row index to report as Easwar suggested
	//if(bid)
	//{
		//vstrLabels.Add("Row Index");
	//}
//
	//if(bx1)
	//{
		//vstrLabels.Add("Beginning X");
	//}
	//if(bx2)
	//{
		//vstrLabels.Add("Ending X");
	//}
	//
	//if(bfwhm)
	//{
		//vstrLabels.Add("FWHM");
	//}
//
	//if(blwidth)
	//{
		//vstrLabels.Add("Left Half Width");
	//}
	//
	//if(brwidth)
	//{
		//vstrLabels.Add("Right Half Width");
	//}
	//
	//if(bPeakCenter)
	//{
		//vstrLabels.Add("Center");
	//}
		//
	//if(bHeight)
	//{
		//vstrLabels.Add("Height");	
	//}
		//
	//if(bCentroid)
	//{
		//vstrLabels.Add("Centroid");	
	//}
	//
	////wks.SetSize(nPeaks, vstrLabels.GetSize() + 1);
	////Column colX(wks, 0);
	////colX.SetType(OKDATAOBJ_DESIGNATION_X);
	////for(int ii = 1; ii<=vstrLabels.GetSize(); ii++)
	////{
		////Column col(wks, ii);
		////col.SetLongName(vstrLabels[ii-1]);
	////}
	////
	////wks.HideLabelByType(RCLT_UNIT);
	////wks.HideLabelByType(RCLT_COMMENT);
//
	////
	//
	//return true;
//}

static bool _append_result_to_temp_mat(int nPeakInd, IntegrationResult& IntResult, matrix& matTemp)
{
	vector vValues;
	vValues.Add(IntResult.Area);	//Peak Area		
    vValues.Add(NANUM);   			//Percent of Area, will be set later
    vValues.Add(NANUM);   			//Area Curve, will be set later , sandy add 2008-11-27
	vValues.Add(IntResult.iPeak);	//Peak Index
	vValues.Add(IntResult.x1);		//beginning X
	vValues.Add(IntResult.x2);		//ending X

	double dLeftFromCenter, dRightFromCenter;
	if(IntResult.xLeft != NANUM)
	   dLeftFromCenter = IntResult.xPeak - IntResult.xLeft;
	else
		dLeftFromCenter = NANUM;
	
	if(IntResult.xRight != NANUM)
		dRightFromCenter = IntResult.xRight - IntResult.xPeak;
	else
		dRightFromCenter = NANUM;
	
	vValues.Add(IntResult.dxPeak);   //Peak's width
	vValues.Add(dLeftFromCenter);    //Peak's Left width
	vValues.Add(dRightFromCenter);	 //Peak's Right width
	vValues.Add(IntResult.xPeak);    //Peak's Center X
	vValues.Add(IntResult.yPeak);    //Peak's Y Value 

	double dc = (IntResult.xCentroid<IntResult.x1 || IntResult.xCentroid > IntResult.x2)?NANUM:IntResult.xCentroid;
	vValues.Add(dc);				 //Peak's x Centriod
	
	if(!matTemp.SetSize( nPeakInd+1 , vValues.GetSize(), true))// keep data
		return false;
	if(0 != matTemp.SetRow(vValues, nPeakInd))//as the index starts 0
		return false;
	
	return true;
		
}

enum{
	_INTG_RESULT_COL_ID_AREA = 0,
	_INTG_RESULT_COL_ID_AREA_P = 1,
	_INTG_RESULT_COL_ID_AREA_C = 2, //Sandy 2008-11-27 add curve area as Snow suggested
	_INTG_RESULT_COL_ID_INDEX =3,
	_INTG_RESULT_COL_ID_X1 = 4,
	_INTG_RESULT_COL_ID_X2 = 5,
	_INTG_RESULT_COL_ID_FWHM  = 6,
	_INTG_RESULT_COL_ID_LEFT_WIDTH = 7,
	_INTG_RESULT_COL_ID_RIGHT_WIDTH = 8,
	_INTG_RESULT_COL_ID_PEAK_CENTER = 9,
	_INTG_RESULT_COL_ID_PEAK_HEIGHT =10 ,
	_INTG_RESULT_COL_ID_CENTROID =11,
};
static bool _construct_result_data(matrix& matTemp,  vector<string>& vstrLabels, double dTotalArea,
									 bool bArea, bool bAreaP, bool bAreaC, bool bid,  bool bx1, bool bx2, 
									 bool bfwhm, bool blwidth,bool brwidth, bool bPeakCenter, 
									 bool bHeight, bool bCentroid)
{
 	if(!bArea && !bAreaP && !bAreaC && !bid && !bx1 && !bx2 && !bfwhm && !blwidth && !brwidth && !bPeakCenter && !bHeight && !bCentroid)	
 	{
 		return false;
 	}
 	
#ifdef _DEBUG
    vector vout;
    matTemp.GetAsVector(vout);
#endif 	
 	
 	matrix mat;
 	mat = matTemp;
 	vstrLabels.SetSize(0);
 	//if one variable need output, add label string, otherwise set all col value missing
 	vector vMissing(matTemp.GetNumRows());
 	vMissing = NANUM;
	if(bArea)
	{
		//vector vArea;
		//if(matTemp.GetColumn( vArea, _INTG_RESULT_COL_ID_AREA ))
		//{
			//matTemp.SetColumn(vArea, _INTG_RESULT_COL_ID_AREA);	
		//}
	
		vstrLabels.Add("Area");		
	}
	else
	{
		mat.SetColumn(vMissing, _INTG_RESULT_COL_ID_AREA);		
	} 	 
	
	if(bAreaP && dTotalArea!=0)
	{
		vector vArea, vAreaP;
		if(matTemp.GetColumn( vArea, _INTG_RESULT_COL_ID_AREA ))
		{
			vAreaP = vArea/dTotalArea*100.0;
			mat.SetColumn(vAreaP, _INTG_RESULT_COL_ID_AREA_P);	
		}
		vstrLabels.Add("AreaIntgP(%)");
	}
	else
	{
		mat.SetColumn(vMissing, _INTG_RESULT_COL_ID_AREA_P);	
	}
	
	if(bAreaC)
	{
		vector vAreaC(vMissing.GetSize());
		vAreaC = dTotalArea;
		mat.SetColumn(vAreaC, _INTG_RESULT_COL_ID_AREA_C);	
		vstrLabels.Add("Curve Area");
	}
	else
	{
		mat.SetColumn(vMissing, _INTG_RESULT_COL_ID_AREA_C);	
	}
	
	///Sandy 2008-11-5 add row index to report as Easwar suggested
	if(bid)
	{
		vstrLabels.Add("Row Index");
		//matTemp.SetColumn(vMissing, _INTG_RESULT_COL_ID_INDEX);	
	}
	else
	{
		mat.SetColumn(vMissing, _INTG_RESULT_COL_ID_INDEX);	
	}

	if(bx1)
	{
		vstrLabels.Add("Beginning X");
	}
	else
	{
		mat.SetColumn(vMissing, _INTG_RESULT_COL_ID_X1);	
	}
	
	if(bx2)
	{
		vstrLabels.Add("Ending X");
	}
	else
	{
		mat.SetColumn(vMissing, _INTG_RESULT_COL_ID_X2);	
	}
	
	if(bfwhm)
	{
		vstrLabels.Add("FWHM");
	}
	else
	{
		mat.SetColumn(vMissing, _INTG_RESULT_COL_ID_FWHM);	
	}

	if(blwidth)
	{
		vstrLabels.Add("Left Half Width");
	}
	else
	{
		mat.SetColumn(vMissing, _INTG_RESULT_COL_ID_LEFT_WIDTH);	
	}
	
	if(brwidth)
	{
		vstrLabels.Add("Right Half Width");
	}
	else
	{
		mat.SetColumn(vMissing, _INTG_RESULT_COL_ID_RIGHT_WIDTH);	
	}

	if(bPeakCenter)
	{
		vstrLabels.Add("Center");
	}
	else
	{
		mat.SetColumn(vMissing, _INTG_RESULT_COL_ID_PEAK_CENTER);	
	}
		
	if(bHeight)
	{
		vstrLabels.Add("Height");
	}
	else
	{
		mat.SetColumn(vMissing, _INTG_RESULT_COL_ID_PEAK_HEIGHT);	
	}
		
	if(bCentroid)
	{
		vstrLabels.Add("Centroid");	
	}
	else
	{
		mat.SetColumn(vMissing, _INTG_RESULT_COL_ID_CENTROID);	
	}
#ifdef _DEBUG
    mat.GetAsVector(vout);
#endif	
	///remove all missing column 
	mat.Transpose(); 
	mat.RemoveEmptyRows();
	mat.Transpose(); 

#ifdef _DEBUG
    mat.GetAsVector(vout);
#endif

	matTemp = mat;
	return true;
}
///Kyle 12/24/2008 ADD_COMMENTS_FOR_OUTPUT_DATA
//static bool _convert_value_to_tables(ReportData& rd, vector<string>& vstrlabels, matrix& mResult, int nPeaks, int nParams, int base)
static bool _convert_value_to_tables(ReportData& rd, vector<string>& vstrlabels, matrix& mResult, int nPeaks, int nParams, int base, string strRange)
///End ADD_COMMENTS_FOR_OUTPUT_DATA
{
	if(!rd || mResult.GetNumCols() < nParams || mResult.GetNumRows() < nPeaks || vstrlabels.GetSize() <  nParams)
		return false;
	
	int nID = _ID_PEAKS_REPORT;
	int nIDy = _ID_PEAKS_REPORT + 1000;
	///Kyle 12/24/2008 ADD_COMMENTS_FOR_OUTPUT_DATA
	//ReportTable rtInt = rd.CreateTable("Integ", _L("Integral Result"), _ID_PEAKS_REPORT);
	string strComments;
	strComments.Format(_L("Integral Result of %s"), strRange);
	ReportTable rtInt = rd.CreateTable("Integ", strComments, _ID_PEAKS_REPORT);
	///End ADD_COMMENTS_FOR_OUTPUT_DATA
	//if(rtInt)
	//{
		//int nBits;
		//rtInt.GetAttribute(TREE_Table, nBits);
		//rtInt.SetAttribute(TREE_Table, nBits|GETNBRANCH_FIT_COL_WIDTH);
	//}
	vector vIndex;
	vIndex.Data(1, nPeaks, 1);
	rtInt.AddColumn(vIndex, "Index", nIDy++, _L("Index"), OKDATAOBJ_DESIGNATION_X);
	
	for(int ii = 0; ii<nParams; ii++)
	{	
		vector vb;
		if(!mResult.GetColumn( vb, ii ))
			return false;
		string strName = "P"+(string)ii;
		rtInt.AddColumn(vb, strName, nIDy++, vstrlabels[ii]);
	}
	
	return true;
}


static void _delete_peak_control_list_obj(TreeNode trPtr)
{
	PeakRectControlList* ptrPRCL = _get_peak_control_list_obj(trPtr.dVal);
	if ( ptrPRCL )	
		delete ptrPRCL;		

	trPtr.dVal = 0;
}

static PeakRectControlList* _get_peak_control_list_obj(DWORD dwPtrAddr)
{	
	return (PeakRectControlList*)dwPtrAddr;
}

static void _create_peak_control_list_obj(TreeNode trPtr)
{
	if ( 0 != trPtr.dVal )
		_delete_peak_control_list_obj(trPtr);
	
	PeakRectControlList* ptrPRCL = new PeakRectControlList;	
	trPtr.dVal = (DWORD)ptrPRCL; 
}

bool _convert_roi_data_to_settings(TreeNode trROIData, TreeNode trSettings, bool bDataToSettings = true)
{
	if(!trSettings || !trROIData || !trROIData.Index || !trROIData.Xs || !trROIData.Ys || !trROIData.Left || !trROIData.Right || !trROIData.LineX)
		return false;
	
	vector<int> vIndex; 
	vector vXs, vYs, vLeft, vRight, vLineX;
	
	if(bDataToSettings)
	{
	
		vIndex = trROIData.Index.nVals;
		vXs = trROIData.Xs.dVals;
		vYs = trROIData.Ys.dVals;
		vLeft = trROIData.Left.dVals;
		vRight = trROIData.Right.dVals;
		vLineX = trROIData.LineX.dVals;///Sandy 2009-3-19 on beginning, LineX = dx
		//vLineX = trROIData.Xs.dVals;
		int nNum = vIndex.GetSize();
		for(int ii= 0 ; ii<nNum; ii++)
		{
			TreeNode trNode = tree_check_get_node(trSettings, "s"+(ii+1));
			TreeNode trLineX = tree_check_get_node(trNode, "LineX");
			TreeNode trLeft = tree_check_get_node(trNode, "Left");
			TreeNode trRight = tree_check_get_node(trNode, "Right");
			TreeNode trX = tree_check_get_node(trNode, "X");
			TreeNode trY = tree_check_get_node(trNode, "Y");
			TreeNode trIndex = tree_check_get_node(trNode, "Index");
			
			if(!trNode || !trLineX || !trLeft || !trRight || !trX || !trIndex)
				return false;
			trLineX.dVal = vLineX[ii];
			trLeft.dVal = vLeft[ii];
			trRight.dVal = vRight[ii];
			trX.dVal = vXs[ii];
			trY.dVal = 0;
			trIndex.nVal = vIndex[ii];
		}
	}
	else// settings tree to data
	{
		TreeNode trNum = trSettings.GetNode("Number");	
		if(!trNum)
			return false;
		
		int nNum = trNum.nVal;
		vIndex.SetSize(nNum); 
		vXs.SetSize(nNum); 
		vYs.SetSize(nNum); 
		vLeft.SetSize(nNum); 
		vRight.SetSize(nNum); 
		vLineX.SetSize(nNum); 

		for(int ii= 0 ; ii<nNum; ii++)
		{
			TreeNode trNode = tree_check_get_node(trSettings, "s"+(ii+1));
			TreeNode trLineX = tree_check_get_node(trNode, "LineX");
			TreeNode trLeft = tree_check_get_node(trNode, "Left");
			TreeNode trRight = tree_check_get_node(trNode, "Right");
			TreeNode trX = tree_check_get_node(trNode, "X");
			TreeNode trY = tree_check_get_node(trNode, "Y");
			TreeNode trIndex = tree_check_get_node(trNode, "Index");
			
			if(!trNode || !trLineX || !trLeft || !trRight || !trX || !trIndex)
				return false;
			vLineX[ii] = trLineX.dVal;
			vLeft[ii] = trLeft.dVal;
			vRight[ii] = trRight.dVal;
			vXs[ii] = trX.dVal;
			trY.dVal = 0;
			vIndex[ii] = trIndex.nVal;
		}
		trROIData.Index.nVals = vIndex;
		trROIData.Xs.dVals = vXs;
		trROIData.Ys.dVals = vYs;
		trROIData.Left.dVals = vLeft;
		trROIData.Right.dVals = vRight;
		trROIData.LineX.dVals = vLineX;		
	}
	

	return true;
	
}

static bool _check_all_peaks_inside_rects(int nRects, vector& vxp, vector<int>& vIndex, vector& vXs, vector& vYs,vector& vLeft,vector& vRight, vector& vLineX)
{			
			
	if( vxp.GetSize() != nRects || vIndex.GetSize()!= nRects || vXs.GetSize()!= nRects || vYs.GetSize()!= nRects 
	||vLeft.GetSize()!= nRects ||vRight.GetSize()!= nRects ||vLineX.GetSize()!= nRects )
	{
		return false;
	}
	else
	{

		double dMin, dMax;
		vxp.GetMinMax(dMin, dMax);
		
		double dTolerance = (dMax - dMin)/(nRects*2);
		for(int ii = 0; ii< nRects; ii++)
		{
			///Sandy 2008-10-20 should search peak between left and right bands.
			//int nFound = vxp.Find(vnIndex, vLineX[ii]-dTolerance, _ONAN, 2);
			vector<uint> vnIndex;
			int nFound = vxp.Find(vnIndex, vLeft[ii], vRight[ii], 4);
			
			if(nFound<=0)
			{
				return false;
			}
			else//Sandy 2009-3-19 should update the new xc even no need to re-init rect
			{
				vXs[ii] = vxp[vnIndex[0]];
			}
		}
	}
	return true;

}

static void _convert_tree_to_vectors(TreeNode& trROI_data,  vector<int>& vIndex, vector& vXs,vector& vYs,vector& vLeft,vector& vRight,vector& vLineX, bool bIsTreeToVec)
{
	if(bIsTreeToVec)
	{
		vIndex = trROI_data.Index.nVals;
		vXs = trROI_data.Xs.dVals;
		vYs = trROI_data.Ys.dVals;
		vLeft = trROI_data.Left.dVals;
		vRight = trROI_data.Right.dVals;	
		vLineX = trROI_data.LineX.dVals;
	}
	else
	{
		trROI_data.Index.nVals = vIndex;
		trROI_data.Xs.dVals = vXs;
		trROI_data.Ys.dVals = vYs;
		trROI_data.Left.dVals = vLeft;
		trROI_data.Right.dVals = vRight;
		trROI_data.LineX.dVals = vLineX;		
	}
}

static void _append_more_rects(int nPeaks, int nMoreRects, vector&  vxi, vector<int>& vIndex, vector& vXs, vector& vYs,vector&  vLeft,vector&  vRight, vector&  vLineX)
{
	double dMin, dMax;
	vxi.GetMinMax(dMin, dMax);
	double dw = (dMax - dMin)/20;//ensure 10 rects can be add to the current span.
	for(int ii = 0; ii< nMoreRects; ii++)
	{
		vIndex.Add(ii+nPeaks);
		vLeft.Add(dMin + dw*2*ii);
		vLineX.Add(dMin + dw*2*ii+dw);
		vRight.Add(dMin + dw*2*(ii+1));
		vXs.Add(vLineX[ii]);
		vYs.Add(0);	
	} 
}
static bool _update_auto_compute_roi(int& nRects, TreeNode& trROI_data, vector& vxi, vector& vyi, vector& vxp,vector& vyp, bool bForceInit = false, bool bEnsurePeakInside = false)
{
	if(!trROI_data || !trROI_data.Index || !trROI_data.Xs || !trROI_data.Ys || !trROI_data.Left || !trROI_data.Right || !trROI_data.LineX)
		return false;
	
	int nPeaks =  min(vyp.GetSize(), nRects);
	int nMoreRects = nRects - nPeaks;

	vector<int> vIndex; 
	vector vXs, vYs, vLeft, vRight, vLineX;
	
	_convert_tree_to_vectors(trROI_data, vIndex, vXs, vYs, vLeft, vRight, vLineX, true);
	int iSize = vxi.GetSize();

	vector<uint> vnIndex;		
	vxp.Sort(SORT_ASCENDING, TRUE, vnIndex);
	vyp.Reorder(vnIndex);
	
	vLineX.Sort(SORT_ASCENDING, TRUE, vnIndex);
	vXs.Reorder(vnIndex);
	vYs.Reorder(vnIndex);
	vLeft.Reorder(vnIndex);
	vRight.Reorder(vnIndex);
	vIndex.Reorder(vnIndex);
	
	//if(bEnsurePeakInside)///Sandy 2009-3-19 if auto mode, don't check inside rect, always init
	if(bEnsurePeakInside && !bForceInit)
	{
		bForceInit = !_check_all_peaks_inside_rects(nPeaks, vxp, vIndex, vXs, vYs, vLeft, vRight, vLineX);			
	}

	if(bForceInit)//need to recreate trROI tree
	{
		
		//Sandy 2008-8-18 sort vxi and vyi for ensure left is smaller than right
		vector<uint> vn;
		vxi.Sort(SORT_ASCENDING, true, vn);
		vyi.Reorder(vn);
		//end
		
		vIndex.SetSize(nPeaks);
		vXs.SetSize(nPeaks);
		vYs.SetSize(nPeaks); 
	    vLeft.SetSize(nPeaks);
	    vRight.SetSize(nPeaks);
	    vLineX.SetSize(nPeaks);
	    
		double dMinHeight, dMaxWidth, dMinWidth;
		dMinHeight = ocmath_get_noise_level(iSize, vyi) * 0.8;
		double dXMax,dXMin;
		vxi.GetMinMax(dXMin, dXMax);
		dMaxWidth = abs(dXMax - dXMin);
		vector<int> vnMarkers(nRects*2);
	    if(OE_NOERROR != ocmath_find_markers_of_peak_centers_by_height_and_width(vxi.GetSize(), vxi, vyi, nPeaks,  vxp, nPeaks*2, vnMarkers, dMinHeight, dMaxWidth, dMinWidth))
				return false;
				
		for(int ii = 0; ii< nPeaks; ii++)
		{
			vLineX[ii] = vxp[ii];
			vXs[ii] = (vxi[vnMarkers[ii*2 + 1]] + vxi[vnMarkers[ii*2]])/2;
			vYs[ii] = 0;
			vLeft[ii] = vxi[vnMarkers[ii*2]];
			vRight[ii]  = vxi[vnMarkers[ii*2 + 1]];
			vIndex[ii] = ii+1;
		}  
	}
		
	if(nMoreRects>0)
	{
		_append_more_rects(nPeaks,nMoreRects, vxi, vIndex, vXs, vYs, vLeft, vRight, vLineX);
	}
	
	_convert_tree_to_vectors(trROI_data, vIndex, vXs, vYs, vLeft, vRight, vLineX, false);
	
	return true;	
}

///---Sim 12-11-2008 PEAK_RECT_ADJUST_ON_PREVIEW_ALLOW_TO_APPLY_ALL_PEAKS
//static bool _update_roi_data(TreeNode& trGetN, bool bSwitchMode = false)
static bool _update_roi_data(TreeNode& trGetN, bool bSwitchMode = false, double dLeftWidth = -1, double dRightWidth = -1)
///---END PEAK_RECT_ADJUST_ON_PREVIEW_ALLOW_TO_APPLY_ALL_PEAKS
{
	PAWizCore* paCore = (PAWizCore*)get_xf_core_handler(trGetN);
	ASSERT(paCore);
	
	TreeNode trNpeaks = trGetN.npeaks;
	TreeNode trROI_Data = trGetN.trROI_data;
	
	if(!trNpeaks || !trROI_Data)
		return false;
	
	vector vxi, vyi;
	if(!_get_ascending_peak_data(paCore, vxi, vyi))
		return false;

	XYRange xyPeaksCenter;
	if(!paCore->GetPeaksCenterRange(xyPeaksCenter))
		return false;
	
	vector vxp, vyp;
	if(!xyPeaksCenter.GetData(vyp, vxp))
		return false;

	int nRects = trNpeaks.nVal;
	
	bool bEnsurePeaksIndside = true;
	if(nRects > vyp.GetSize() || bSwitchMode)
	{
		bEnsurePeaksIndside = false;
	}
	
	bool bRet;
	
	///---Sim 12-11-2008 PEAK_RECT_ADJUST_ON_PREVIEW_ALLOW_TO_APPLY_ALL_PEAKS
	if ( dLeftWidth >= 0 && dRightWidth >= 0 )
		bRet = _update_same_roi_width(dLeftWidth, dRightWidth, nRects, trROI_Data, vxi, vxp, false, bEnsurePeaksIndside);
	else
	///---END PEAK_RECT_ADJUST_ON_PREVIEW_ALLOW_TO_APPLY_ALL_PEAKS	
	if(trGetN.intwindow.nVal == INT_WINDOW_AUTO)
	{
		bRet = _update_auto_compute_roi(nRects, trROI_Data,  vxi, vyi, vxp, vyp,true, bEnsurePeaksIndside);
	}
	else if(trGetN.intwindow.nVal == INT_WINDOW_SAME_WIDTH)
		///---Sim 12-10-2008 IMPLEMENT_ASYMMETRIC_WINDOW_WIDTH
		//bRet = _update_same_roi_width(trGetN.width.dVal, nRects, trROI_Data, vxi, vxp, true, bEnsurePeaksIndside);
		///---Sim 12-11-2008 PEAK_RECT_ADJUST_ON_PREVIEW_ALLOW_TO_APPLY_ALL_PEAKS
		//bRet = _update_same_roi_width(trGetN.lwidth.dVal, trGetN.rwidth.dVal, nRects, trROI_Data, vxi, vxp, true, bEnsurePeaksIndside);
		
		// on the custom adjust, user move windwos and that may change peaks center, and then they set to the window to trGetN
		// so, trGetN is keep recent setting that user expected
		// it should not always force init peaks center
		bRet = _update_same_roi_width(trGetN.lwidth.dVal, trGetN.rwidth.dVal, nRects, trROI_Data, vxi, vxp, false, bEnsurePeaksIndside);
		///---END PEAK_RECT_ADJUST_ON_PREVIEW_ALLOW_TO_APPLY_ALL_PEAKS
		///---END IMPLEMENT_ASYMMETRIC_WINDOW_WIDTH
	else//// or INT_WINDOW_CUSTOM
		bRet = _update_auto_compute_roi(nRects, trROI_Data, vxi, vyi, vxp, vyp, false, bEnsurePeaksIndside);
		
	return bRet;
}
///---Sim 12-10-2008 IMPLEMENT_ASYMMETRIC_WINDOW_WIDTH
//static bool _update_same_roi_width(double dWidth, int& nRects, TreeNode& trROI_data, vector& vxi, vector& vxp, bool bForceInit = false, bool bEnsurePeakInside = false)
static bool _update_same_roi_width(double dLeftWidth, double dRightWidth, int& nRects, TreeNode& trROI_data, vector& vxi, vector& vxp, bool bForceInit = false, bool bEnsurePeakInside = false)
///---END IMPLEMENT_ASYMMETRIC_WINDOW_WIDTH
{
	if(!trROI_data || !trROI_data.Index || !trROI_data.Xs || !trROI_data.Ys || !trROI_data.Left || !trROI_data.Right || !trROI_data.LineX)
		return false;
	
	int nPeaks =  min(vxp.GetSize(), nRects);
	int nMoreRects = nRects - nPeaks;

	vector<int> vIndex; 
	vector vXs(nPeaks), vLineX(nPeaks), vYs(nPeaks), vLeft(nPeaks), vRight(nPeaks);
	_convert_tree_to_vectors(trROI_data, vIndex, vXs, vYs, vLeft, vRight, vLineX, true);
	
	//vector<int> vIndex; 
	//vIndex = trROI_data.Index.nVals;

	if(bEnsurePeakInside)
	{
		bForceInit = !_check_all_peaks_inside_rects(nRects, vxp, vIndex, vXs, vYs, vLeft, vRight, vLineX);			
	}

	if(bForceInit)
	{
		vIndex.Data(1, nPeaks, 1);
		vector<uint> vnIndex;		
		vLineX = vxp;
		vLineX.Sort(SORT_ASCENDING, TRUE, vnIndex);
		vIndex.Reorder(vnIndex);
		vXs = vLineX;
		vYs = 0;
		
	}

	if(nMoreRects>0)
	{
		_append_more_rects(nPeaks,nMoreRects, vxi, vIndex, vXs, vYs, vLeft, vRight, vLineX);
	}
	
	///---Sim 12-10-2008 IMPLEMENT_ASYMMETRIC_WINDOW_WIDTH
	//vLeft = vLineX - dWidth/2;
	//vRight = vLineX + dWidth/2;
	vLeft = vLineX - dLeftWidth;
	vRight = vLineX + dRightWidth;
	///---END IMPLEMENT_ASYMMETRIC_WINDOW_WIDTH
	
	_convert_tree_to_vectors(trROI_data, vIndex, vXs, vYs, vLeft, vRight, vLineX, false);
	
	return true;	
}

//static void _subtract_local_baseline(vector& vxTemp, vector& vyTemp, PAWizCore* paCore, int ii)
//static void _subtract_local_baseline(vector& vxTemp, vector& vyTemp, PAWizCore* paCore, int ii,  double dLeft, double dRight, int nLocalbaseType)
static void _subtract_local_baseline(vector& vxTemp, vector& vyTemp, PAWizCore* paCore, int ii,  double dLeft, double dRight, int nLocalbaseType, int& nFrom, int& nTo)///Sandy 2009-2-11 need return the row index of begin and end
{
	vector vxlocalbase, vylocalbase;
	XYRange xyLocalBaseline;
	if(!paCore->GetLocalBaselineRange(xyLocalBaseline, ii+1))//local index offset is 1
		error_report("fail to get local baseline range");
	if(!xyLocalBaseline.GetData(vylocalbase, vxlocalbase))
		error_report("fail to get the %s local baseline data", ii+1);

	///--Sandy 2008-12-19 FIX_NO_LOCAL_BASELINE_IN_SCRIPT_MODE	
	if(vylocalbase.GetSize()<=0)
	{	
		//vector  vxlocalbase, vylocalbase;
		int nLeft, nRight;
		if(!get_local_baseline_by_interp(vxTemp, vyTemp, vxlocalbase, vylocalbase, dLeft, dRight, nLocalbaseType, nLeft, nRight) || abs(nRight - nLeft)<2)
			error_report("Fail to create local baseline in body of pa_int!");
		xyLocalBaseline.SetData(&vylocalbase, &vxlocalbase,  0, NULL, DRS_SET_COL_DESIGNATIONS);
				
	}
	//--end FIX_NO_LOCAL_BASELINE_IN_SCRIPT_MODE
	
	int nBeginX, nEndX;
	//double dLeft, dRight;
	vxlocalbase.GetMinMax(dLeft, dRight);
	int nRet = get_sub_range_from_xy(vxTemp, vyTemp, dLeft, dRight, nBeginX, nEndX);
	if(nRet != CER_NO_ERROR)
	{

		error_report("Fail to get local peaks range!");
		return;
	}
	
	subtract_baseline(vxTemp, vyTemp, vxlocalbase, vylocalbase);
	nFrom = nBeginX;
	nTo = nEndX;
}

static bool _update_peaks_markers_data(PAWizCore*paCore, TreeNode& trROI_data,vector& vLefts, vector& vRights)
{

	if(!trROI_data.Left || !trROI_data.Right)
		return false;
	
	vLefts = trROI_data.Left.dVals;
	vRights = trROI_data.Right.dVals;
	
	///get markers' position in source data
	vector vxmarkers,vymarkers;
	vxmarkers.Append(vLefts);
	vxmarkers.Append(vRights);
	vxmarkers.Sort(SORT_ASCENDING);
	vymarkers.SetSize(vxmarkers.GetSize());
	
	XYRange xyOriginal, xyPeaksMarker;
	if(!paCore->GetOriginalRange(xyOriginal) || !paCore->GetPeaksMarkerRange(xyPeaksMarker))
	{
		return false;
	}		
	
	vector vxi, vyi;
	xyOriginal.GetData(vyi, vxi);
	
	if(OE_NOERROR !=ocmath_interpolate(vxmarkers, vymarkers, vxmarkers.GetSize(), vxi, vyi, vxi.GetSize(), INTERP_TYPE_LINEAR))
	   return false;
	
	xyPeaksMarker.SetData(&vymarkers, &vxmarkers);
	
	return true;
}

///Sandy 2009-1-7 add error checking
//static 	void _create_local_baseline_plots(PAWizCore* paCore, GraphLayer&  gl, int npeaks, int LocalBaseType, PeakRectControlList* ptrPRCL)
static 	bool _create_local_baseline_plots(PAWizCore* paCore, GraphLayer&  gl, int npeaks, int LocalBaseType, PeakRectControlList* ptrPRCL, string& strErrMsg)
{
	strErrMsg = "";
	if(ptrPRCL == NULL || paCore == NULL || !gl.IsValid())
	{
		//error_report("invalid object when create local baseline plots!");
		strErrMsg = XF_ERR_INVALID_PA_INSTANCE;
		return false;
	}
	
	int  nCount = 0;///Sandy 2009-1-7 add error checking
	for(int ii=1; ii<=npeaks; ii++)
	{
		vector vxlocal, vylocal;
		if(0>ptrPRCL->UpdatePeak(ii, LocalBaseType, vxlocal, vylocal))
		{
			///Sandy 2009-1-7 add error checking
			vxlocal.SetSize(0);
			vylocal.SetSize(0);		
		}
			
		XYRange xyLocalBaseline;
		if(!paCore->GetLocalBaselineRange(xyLocalBaseline, ii))
		{
			//error_report("fail to get local baseline range");
			strErrMsg = XF_ERR_INVALID_PA_INSTANCE;///Sandy 2009-1-7 add error checking
			break;
		}
		xyLocalBaseline.SetData(&vylocal, &vxlocal, 0, NULL, DRS_SET_COL_DESIGNATIONS);
		
		if(vxlocal.GetSize()>0)///Sandy 2009-1-7 add error checking
		{
			DataPlot dp = xyLocalBaseline.MakePlot(gl);
			dp.SetColor(SYSCOLOR_RED);	
			nCount++;///Sandy 2009-1-7 add error checking
		}
	}
	
	///Sandy 2009-1-7 add error checking
	if(nCount == npeaks)
		return true;
	else
	{
		strErrMsg = XFERR_FAIL_CREATE_LOCAL_BASELINE;
		return false;
	}
}

void pa_int(const string& hint_custom, const XYRange& iy, const int& npeaks, const int& intwindow, const double& lwidth, const double& rwidth, const int& bsopt, const int& localbase, const int& out_area, const int& out_area_p, const int& out_area_c, const int& out_id, const int& out_x1, const int& out_x2, const int& out_p, const int& out_h, const int& out_fwhm, const int& out_lw, const int& out_rw, const int& out_c, TreeNode& trROI, const double& ptr, const TreeNode& trROI_data, const int& nXFCorePointer, ReportData& rd_report, ReportData& rd_int, ReportData& rd_plot)
{
	
	//#ifdef _DEBUG
	//Profiler junk;
	//#endif
	
	///---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);	
	
	vector vx, vy;
	string strInputDesc;
	
	///------ Folger 04/20/09 QA80-13478-P1-P2 PA_INTEGRATE_NOT_WORKING_WHEN_Y_EQUAL_0_FOR_ALL_BASELINE_MODE
	//if(!_get_ascending_peak_data(paCore,vx, vy))
	if(!_get_ascending_peak_data(paCore,vx, vy, bsopt))
	///------ End PA_INTEGRATE_NOT_WORKING_WHEN_Y_EQUAL_0_FOR_ALL_BASELINE_MODEv
		XF_THROW(XFERR_GET_DATA_FAILED);
	
	vector vLefts, vRights;
	if(!_update_peaks_markers_data(paCore, trROI_data, vLefts, vRights))
		error_report("error happen when update peaks' markers from ROI tree!");
	
	///Sandy 2008-11-26 total area should be the whole data curve
	double dTotalArea = _compute_whole_curve_area(paCore, bsopt);	
	//end
	
	string strRange = get_input_data_range_string(iy);		///Kyle 12/24/2008 ADD_COMMENTS_FOR_OUTPUT_DATA
	
	///Sandy 2008-9-5 update peaks' centers to paWizCore
	vector vxCenters, vyCenters;
	vector vResultValues;
	//double dTotalArea = 0; ///Sandy 2008-11-26 total area should be the whole data curve
	matrix matTemp;
	
	//--Sandy 2009-1-8 ADD_PROGRESSBOX_AND_GIVE_USER_FEEDBACK_AND_CANCEL_WHEN_THE_PROGRESS_SLOW
	string strTitle = _L("Integrating Peaks......");
	string strTips;
	/// YuI 01/29/09 QA70-13036 INTEGRATION_CANCEL_IMPROVEMENTS
	//	progressBox pb("", PBOX_TOPMOST, npeaks < PAINT_NUM_PEAKS_THRESHOLD_TO_SHOW_PROGRESSBOX? true:false);
	progressBox pb("", 0, npeaks < PAINT_NUM_PEAKS_THRESHOLD_TO_SHOW_PROGRESSBOX? true:false);
	/// end INTEGRATION_CANCEL_IMPROVEMENTS
	pb.SetText(strTitle, PBOXT_TITLE);
	pb.SetRange(0,npeaks);
	//--end ADD_PROGRESSBOX_AND_GIVE_USER_FEEDBACK_AND_CANCEL_WHEN_THE_PROGRESS_SLOW	
	
	
	///Sandy 2009-2-11 if local baseline, compute the accumulative total of all area of peak base on local baseline
	if(paCore->GetBaseMode() == PA_BM_LOCAL)
		dTotalArea = 0;
	//end
	
	for(int ii = 0; ii< npeaks; ii++)
	{
		//--Sandy  2009-1-8 ADD_PROGRESSBOX_AND_GIVE_USER_FEEDBACK_AND_CANCEL_WHEN_THE_PROGRESS_SLOW
	        //strTips.Format(_L("Integrating Peaks, current is %d......"), ii);
	        strTips.Format(_L("Integrating peak %d of %d"), ii, npeaks);///Sandy 2009-2-1 SNOW_SUGGEST_IMPROVE_TEXT_OF_PROGRESS_BOX
	        if(pb.Set(ii))
	        {
	            pb.SetText(strTips, PBOXT_MIDCENTER);
	        }
	        else
	        {
	        	/// YuI 01/29/09 QA70-13036 INTEGRATION_CANCEL_IMPROVEMENTS
	        	// if we just break out of cycle XF is still considered to be succesfully executed
	        	// so dialog is closed. We need to throw to stay on the page
	        	// out_str("User Abort");
	        	// break;
	            XF_THROW("User Abort");
	            /// end INTEGRATION_CANCEL_IMPROVEMENTS
	        }
	        //--endADD_PROGRESSBOX_AND_GIVE_USER_FEEDBACK_AND_CANCEL_WHEN_THE_PROGRESS_SLOW 		
		
	
		double dLeft, dRight;
	
		dLeft = vLefts[ii];
		dRight = vRights[ii];
	
		IntegrationResult IntResult;
		vector vIntegrated;
		int nTo, nFrom;
		
		vector vxTemp , vyTemp;
		vxTemp = vx;
		vyTemp = vy;
		
		int nLocalStart = 0, nLocalEnd;
		if(paCore->GetBaseMode() == PA_BM_LOCAL)
		{
			//_subtract_local_baseline(vxTemp, vyTemp, paCore, ii);
			_subtract_local_baseline(vxTemp, vyTemp, paCore, ii,  dLeft, dRight, localbase, nLocalStart, nLocalEnd);
		}
		
		if(integrate_individual_peak(vxTemp, vyTemp, dLeft, dRight,  IntResult,nFrom, nTo, vIntegrated))
		{
			//dTotalArea += abs(IntResult.Area);///Sandy 2008-11-26 total area should be the whole data curve
			vector vSubVx;
			vx.GetSubVector(vSubVx, nFrom,nTo);
			
			
			///Sandy 2009-2-11 if local baseline, compute the accumulative total of all area of peak base on local baseline
			if(paCore->GetBaseMode() == PA_BM_LOCAL)
			{
				dTotalArea += abs(IntResult.Area);
				IntResult.iPeak += nLocalStart;
				vx.GetSubVector(vSubVx, nLocalStart, nLocalEnd);
			}
			//end
			
	
			if(rd_int.IsValid())
				///Kyle 12/24/2008 ADD_COMMENTS_FOR_OUTPUT_DATA
				//_append_integral_data_of_one_peak(rd_int, ii, vSubVx, vIntegrated);
				_append_integral_data_of_one_peak(rd_int, ii, vSubVx, vIntegrated, strRange);
				///End ADD_COMMENTS_FOR_OUTPUT_DATA
			
			vxCenters.Add(IntResult.xPeak);///Sandy 2008-9-5 update peaks' centers to paWizCore
			vyCenters.Add(IntResult.yPeak);///Sandy 2008-9-5 update peaks' centers to paWizCore
			_append_result_to_temp_mat(ii, IntResult,matTemp);
			
	
		}
		else
			XF_THROW(XFERR_FAIL_TO_INTEGRATE_PEAK);
	}
	
	///Sandy 2008-9-5 update peaks' centers to paWizCore
	XYRange xyPeaksCenter;
	if(!paCore->GetPeaksCenterRange(xyPeaksCenter))
	{
		XF_THROW(XF_ERR_INVALID_PA_INSTANCE);	
	}
	xyPeaksCenter.SetData(&vyCenters, &vxCenters, 0, NULL, DRS_SET_COL_DESIGNATIONS);	
	
	
	//output result
	if(rd_report.IsValid())
	{
		vector<string> vstrLabels;
		if(!_construct_result_data(matTemp, vstrLabels, dTotalArea,
									out_area, out_area_p, out_area_c, out_id, out_x1, out_x2, out_fwhm, out_lw, out_rw, out_p, out_h, out_c))
			error_report("Error happen when construct integral result matrix!");
		///Kyle 12/24/2008 ADD_COMMENTS_FOR_OUTPUT_DATA
		//if(!_convert_value_to_tables(rd_report, vstrLabels, matTemp, npeaks, vstrLabels.GetSize(), bsopt))
		if(!_convert_value_to_tables(rd_report, vstrLabels, matTemp, npeaks, vstrLabels.GetSize(), bsopt, strRange))
			///End ADD_COMMENTS_FOR_OUTPUT_DATA
			error_report("Error happen when convert value to report table");
	}
	
	if(rd_plot.IsValid())
	{
		///Sandy 2008-9-1 add baseline output if there is baseline
		create_baseline_table( paCore, rd_plot);	
		create_peak_center_table( paCore, rd_plot);	
		create_peak_marker_table( paCore, rd_plot);
	}
}

//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_int_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_int_event1_ex(trGetN, nRow, nEventID, dwEnables, lpcszNodeName, DynaCntrlContainer, strAux, strErrMsg);
	DECLARE_BUTTON_ENABLES
	//#ifdef _DEBUG
	//Profiler junk;
	//#endif
	
	PAWizCore* paCore = (PAWizCore*)get_xf_core_handler(trGetN);
	ASSERT(paCore);	
	
	///Sandy 2009-1-8 if there is more than 100 peaks, do not prepare windows since they will use up system resource
	vector vx, vy;
	if(!_get_ascending_peak_data(paCore,vx, vy))
	{
		strErrMsg = XFERR_GET_DATA_FAILED;
		return false;
	}
	bool bIsWarnning = true;
	int nDataSize = vy.GetSize();
	bool bShowWindows = ((trGetN.npeaks.nVal * nDataSize) < (PAINT_NUM_PEAKS_THRESHOLD_TO_SHOW_PROGRESSBOX * 100000));
	//end  2009-1-8
	
	if (nEventID == GETNE_ON_INIT  && bShowWindows)
	{	
		xf_turnon_user_event_receiver(trGetN);		
		_create_peak_control_list_obj(trGetN.ptr);						
	}
	
	PeakRectControlList* ptrPRCL = _get_peak_control_list_obj(trGetN.ptr.dVal);
	if ( NULL == ptrPRCL && bShowWindows) // object not create yet
	{
		_create_peak_control_list_obj(trGetN.ptr);
	}
		
	
	
	//move begin, Sim 12-11-2008 PEAK_RECT_ADJUST_ON_PREVIEW_ALLOW_TO_APPLY_ALL_PEAKS
	///---Sim 12-11-2008 PEAK_RECT_ADJUST_ON_PREVIEW_ALLOW_TO_APPLY_ALL_PEAKS
	bool bApplyWidthToAllPeaks = false;
	double dLeftWidth = -1, dRightWidth = -1;
	///---END PEAK_RECT_ADJUST_ON_PREVIEW_ALLOW_TO_APPLY_ALL_PEAKS
	
	int	nObjID = -1;
	///---Sim 12-11-2008 PEAK_RECT_ADJUST_ON_PREVIEW_ALLOW_TO_APPLY_ALL_PEAKS
	//if(xf_check_is_user_event(trGetN, nObjID))// && (nObjID > 0 && nObjID <= MAX_PEAKS_NUM))
	int nCmd;
	if(xf_check_is_user_event(trGetN, nObjID, &nCmd) && bShowWindows)// && (nObjID > 0 && nObjID <= MAX_PEAKS_NUM))
	///---END PEAK_RECT_ADJUST_ON_PREVIEW_ALLOW_TO_APPLY_ALL_PEAKS
	{
		///---Sim 12-11-2008 PEAK_RECT_ADJUST_ON_PREVIEW_ALLOW_TO_APPLY_ALL_PEAKS
		switch (nCmd)
		{
		case PEAKS_RECT_ADJUST:
			{
			///---END PEAK_RECT_ADJUST_ON_PREVIEW_ALLOW_TO_APPLY_ALL_PEAKS
				//depend on baseline
				vector vxBaseline, vyBaseline;
				XYRange xyBaseline;
				
				
				///Sandy 2008-11-14  when has subtracted, integral should base on baseline.
				//if(trGetN.bsopt.nVal == bsopt_base && paCore->GetBaselineRange(xyBaseline) && xyBaseline.GetData(vyBaseline, vxBaseline))
				bool bSubtracted = paCore->GetSubtractedMode();
				bool bFromBase = (trGetN.bsopt.nVal == bsopt_base || bSubtracted);
				//end
				
				if(bFromBase && paCore->GetBaselineRange(xyBaseline) && xyBaseline.GetData(vyBaseline, vxBaseline))
				{
					ptrPRCL->UpdatePeak(nObjID, vxBaseline, vyBaseline);
				}
				else if(paCore->GetBaseMode() == PA_BM_LOCAL)
				{
					vector vxlocal, vylocal;
					
					strErrMsg = "";
					
					///Sandy 2009-1-7 add error checking
					//ptrPRCL->UpdatePeak(nObjID, trGetN.localbase.nVal, vxlocal, vylocal);
					if(0>ptrPRCL->UpdatePeak(nObjID, trGetN.localbase.nVal, vxlocal, vylocal))
					{
						strErrMsg = XFERR_FAIL_CREATE_LOCAL_BASELINE;
						bIsWarnning = false;
						bOKEnable = false;
						vxlocal.SetSize(0);
						vylocal.SetSize(0);
					}
					XYRange xyLocalBaseline;
					if(!paCore->GetLocalBaselineRange(xyLocalBaseline, nObjID))
						error_report("fail to get local baseline range");
					xyLocalBaseline.SetData(&vylocal, &vxlocal, 0, NULL, DRS_SET_COL_DESIGNATIONS);
				}
				else
				{
					ptrPRCL->UpdatePeak(nObjID);
				}
			
				
				ptrPRCL->SaveToTree(trGetN.trROI);
				
				_convert_roi_data_to_settings(trGetN.trROI_data, trGetN.trROI, false);
				return true;
			}
		///---Sim 12-11-2008 PEAK_RECT_ADJUST_ON_PREVIEW_ALLOW_TO_APPLY_ALL_PEAKS
		case PEAKS_RECT_APPLY_TO_ALL:
		case PEAKS_RECT_SET_ALL_SAME:
			{
				GraphLayer gl = Project.ActiveLayer();
				if(!gl)
				{
					return error_report("events_from_apply_width_to_all_peaks: Invalid active layer!");
				}
				
				string strName = _PAW_INTEGPEAKS_RECT_OBJECT_NAME+"_"+(string)nObjID;
				ShapeControl sc(gl, strName);
				if( !sc.IsValid())
					return error_report("events_from_apply_width_to_all_peaks: Invalid ShapeControl!");
				
				double dX, dY, dLeft, dRight, dTop, dBottom;
				sc.GetPosition(dX, dY, dLeft, dRight, dTop, dBottom);
				double dLineX;
				sc.GetLinePos(dLineX);
				
				dLeftWidth = dLineX - dLeft;
				dRightWidth = dRight - dLineX;
				
				if ( PEAKS_RECT_SET_ALL_SAME == nCmd )
				{
					trGetN.intwindow.nVal = INT_WINDOW_SAME_WIDTH;
					trGetN.lwidth.dVal = dLeftWidth;
					trGetN.rwidth.dVal = dRightWidth;
					TreeNode trRightWidth = trGetN.rwidth;
					octree_set_auto_support(&trRightWidth, -1); // uncheck auto
					GETN_CHANGE_GRID
				}
				
				bApplyWidthToAllPeaks = true;
				// later will go to refresh all peaks rectangle
			}
		/// Kenny 2/8/2010 QA81-14737 ADD_BUTTON_TO_PA_INTEGRATE_RECT_TO_PROVIDE_DIALOG_FOR_DIMENSION_SETTING
			break;
		case PEAKS_RECT_SET_DIMENSION:
			_on_pa_rect_set_dimension(nObjID);
			break;
		/// End ADD_BUTTON_TO_PA_INTEGRATE_RECT_TO_PROVIDE_DIALOG_FOR_DIMENSION_SETTING
		}
		///---END PEAK_RECT_ADJUST_ON_PREVIEW_ALLOW_TO_APPLY_ALL_PEAKS
	}
	//move end, Sim 12-11-2008 PEAK_RECT_ADJUST_ON_PREVIEW_ALLOW_TO_APPLY_ALL_PEAKS
	
	if(nEventID == GETNE_ON_INIT || !lstrcmpi(lpcszNodeName, "npeaks") 
		///---Sim 12-10-2008 IMPLEMENT_ASYMMETRIC_WINDOW_WIDTH
		 //||  !lstrcmpi(lpcszNodeName, "intwindow") ||  !lstrcmpi(lpcszNodeName, "width") )
		 ///---Sim 12-11-2008 PEAK_RECT_ADJUST_ON_PREVIEW_ALLOW_TO_APPLY_ALL_PEAKS
		 //||  !lstrcmpi(lpcszNodeName, "intwindow") ||  !lstrcmpi(lpcszNodeName, "lwidth") || !lstrcmpi(lpcszNodeName, "rwidth"))
		 ||  !lstrcmpi(lpcszNodeName, "intwindow") ||  !lstrcmpi(lpcszNodeName, "lwidth") || !lstrcmpi(lpcszNodeName, "rwidth")
		 || bApplyWidthToAllPeaks )
		 ///---END PEAK_RECT_ADJUST_ON_PREVIEW_ALLOW_TO_APPLY_ALL_PEAKS
		///---END IMPLEMENT_ASYMMETRIC_WINDOW_WIDTH
	{
		
		///---Sim 12-10-2008 IMPLEMENT_ASYMMETRIC_WINDOW_WIDTH
		//trGetN.width.Show = (trGetN.intwindow.nVal == INT_WINDOW_SAME_WIDTH ? true:false);
		trGetN.lwidth.Show = trGetN.rwidth.Show = (trGetN.intwindow.nVal == INT_WINDOW_SAME_WIDTH ? true:false);
		if ( !lstrcmpi(lpcszNodeName, "lwidth") || !lstrcmpi(lpcszNodeName, "rwidth") )
		{
			TreeNode trRightWidth = trGetN.rwidth;
			if(1 == octree_get_auto_support(&trRightWidth) )
			{
				trGetN.rwidth.dVal = trGetN.lwidth.dVal
			}
		}
		///---END IMPLEMENT_ASYMMETRIC_WINDOW_WIDTH
		trGetN.hint_custom.Show = (trGetN.intwindow.nVal == INT_WINDOW_CUSTOM ? true:false);
	
		
		///---Sim 12-10-2008 IMPLEMENT_ASYMMETRIC_WINDOW_WIDTH
		//if(!lstrcmpi(lpcszNodeName, "npeaks") ||  !lstrcmpi(lpcszNodeName, "intwindow")||  !lstrcmpi(lpcszNodeName, "width")  )
		//---Sim 12-11-2008 PEAK_RECT_ADJUST_ON_PREVIEW_ALLOW_TO_APPLY_ALL_PEAKS
		//if(!lstrcmpi(lpcszNodeName, "npeaks") ||  !lstrcmpi(lpcszNodeName, "intwindow")||  !lstrcmpi(lpcszNodeName, "lwidth") || !lstrcmpi(lpcszNodeName, "rwidth") )
		if(!lstrcmpi(lpcszNodeName, "npeaks") ||  !lstrcmpi(lpcszNodeName, "intwindow")||  !lstrcmpi(lpcszNodeName, "lwidth") || !lstrcmpi(lpcszNodeName, "rwidth") 
			|| bApplyWidthToAllPeaks )
		//---END PEAK_RECT_ADJUST_ON_PREVIEW_ALLOW_TO_APPLY_ALL_PEAKS
		///---END IMPLEMENT_ASYMMETRIC_WINDOW_WIDTH
		{
			strErrMsg = "";
			//---Sim 12-11-2008 PEAK_RECT_ADJUST_ON_PREVIEW_ALLOW_TO_APPLY_ALL_PEAKS
			//if(!lstrcmpi(lpcszNodeName, "npeaks") ||  !lstrcmpi(lpcszNodeName, "intwindow"))
			if(!lstrcmpi(lpcszNodeName, "npeaks") ||  !lstrcmpi(lpcszNodeName, "intwindow")
				|| bApplyWidthToAllPeaks )
			//---END PEAK_RECT_ADJUST_ON_PREVIEW_ALLOW_TO_APPLY_ALL_PEAKS
			{
				if(!_update_npeaks(trGetN))
				{
					bOKEnable = false;
					strErrMsg =	XFERR_WRONG_PARAM_NUMBER;
					return true;
				}
			}
	
			//---Sim 12-11-2008 PEAK_RECT_ADJUST_ON_PREVIEW_ALLOW_TO_APPLY_ALL_PEAKS
			//bool bSwitchMode =  !lstrcmpi(lpcszNodeName, "intwindow");
			bool bSwitchMode = ( !lstrcmpi(lpcszNodeName, "intwindow") || bApplyWidthToAllPeaks );
			//---END PEAK_RECT_ADJUST_ON_PREVIEW_ALLOW_TO_APPLY_ALL_PEAKS
			//---Sim 12-11-2008 PEAK_RECT_ADJUST_ON_PREVIEW_ALLOW_TO_APPLY_ALL_PEAKS
		   	//if(!_update_roi_data(trGetN, bSwitchMode))
		   	bool bRet;
		   	if ( bApplyWidthToAllPeaks )
		   		bRet = _update_roi_data(trGetN, bSwitchMode, dLeftWidth, dRightWidth);
		   	else
		   		bRet = _update_roi_data(trGetN, bSwitchMode);
		   	if ( !bRet )
			//---END PEAK_RECT_ADJUST_ON_PREVIEW_ALLOW_TO_APPLY_ALL_PEAKS
			{
				strErrMsg = XFERR_INVALID_ARG;
				bOKEnable = false;
				return true;					
			}
		}
		
		if(bShowWindows)
		{
			if(!_convert_roi_data_to_settings(trGetN.trROI_data, trGetN.trROI))
			{
				strErrMsg = XFERR_INVALID_ARG;
				bOKEnable = false;
				return true;				
			}
		}
	}
	
	
	if(  bShowWindows && (!ptrPRCL->IsValid() || nEventID == GETNE_ON_INIT || !lstrcmpi(lpcszNodeName, "npeaks") || !lstrcmpi(lpcszNodeName, "localbase") 
		///---Sim 12-10-2008 IMPLEMENT_ASYMMETRIC_WINDOW_WIDTH
		//||  !lstrcmpi(lpcszNodeName, "intwindow") ||  !lstrcmpi(lpcszNodeName, "width")) 
		//---Sim 12-11-2008 PEAK_RECT_ADJUST_ON_PREVIEW_ALLOW_TO_APPLY_ALL_PEAKS
		//||  !lstrcmpi(lpcszNodeName, "intwindow") ||  !lstrcmpi(lpcszNodeName, "lwidth") || !lstrcmpi(lpcszNodeName, "rwidth"))
		||  !lstrcmpi(lpcszNodeName, "intwindow") ||  !lstrcmpi(lpcszNodeName, "lwidth") || !lstrcmpi(lpcszNodeName, "rwidth")
		|| bApplyWidthToAllPeaks ))
		//---END PEAK_RECT_ADJUST_ON_PREVIEW_ALLOW_TO_APPLY_ALL_PEAKS
		///---END IMPLEMENT_ASYMMETRIC_WINDOW_WIDTH
	{
		strErrMsg = "";
	
		vector vXPos, vxLeft, vxRight;
		vector vx, vy;
		XYRange xyOriginal;
		if(!paCore->GetOriginalRange(xyOriginal))
		{
			strErrMsg = XF_ERR_INVALID_PA_INSTANCE;
			bOKEnable = false;
			return false;
		}	
		xyOriginal.GetData(vy, vx);			
		
		GraphLayer gl;
		if(!paCore->GetPreviewLayer(gl)||!gl.IsValid())
		{
			strErrMsg = XFERR_INVALID_GRAPH_LAYER;
			bOKEnable = false;
			return true;					
		}
		
		ptrPRCL->CreateList(gl, _PAW_INTEGPEAKS_RECT_OBJECT_NAME, _MAX_PEAKS_NUM, trGetN.npeaks.nVal, trGetN.trROI, vx, vy, false, true, GROT_RECT, true, false, true);	
		
		///Sandy 2008-10-20 add
		if ( ptrPRCL && ptrPRCL->IsValid() )
		{
			bool bFix = (trGetN.intwindow.nVal == INT_WINDOW_CUSTOM)? false:true;
			ptrPRCL->FixPositions(bFix);
			
			/// Kenny 2/4/2010 QA81-14737 ADD_BUTTON_TO_PA_INTEGRATE_RECT_TO_PROVIDE_DIALOG_FOR_DIMENSION_SETTING
	#ifdef PEAK_RECT_ADD_BTN
			if ( !bFix )
			{
				GraphObject goBtn	= gl.CreateGraphObject( GROT_TEXT, STR_INTEGPEAKS_BTN_NAME );
				ASSERT(goBtn);
				goBtn.Text	= STR_PEAK_RECT_BTN_TEXT;
				Tree tr;
				tr.Root.Font.Size.nVal = 16;
			 	tr.Root.States.nVal = GOC_NO_RESIZE | GOC_NO_ROTATE | GOC_NO_SKEW 
			 						| GOC_NO_EDIT | GOC_NO_BORDERSIZE | GOC_NO_IN_PLACE_EDIT;
				goBtn.UpdateThemeIDs(tr.Root);
				goBtn.ApplyFormat(tr, true, true);
				if ( goBtn )
				{
					goBtn.Show = FALSE;	// Only visible when selected.
				}
			}
	#endif // PEAK_RECT_ADD_BTN
			/// End QA81-14737 ADD_BUTTON_TO_PA_INTEGRATE_RECT_TO_PROVIDE_DIALOG_FOR_DIMENSION_SETTING
		}
		
		///Sandy 2008-9-11 add local baseline 
		if(paCore->GetBaseMode() == PA_BM_LOCAL)
		{
	
			///Sandy 2009-1-7 add error checking
			bOKEnable = _create_local_baseline_plots(paCore, gl, trGetN.npeaks.nVal,trGetN.localbase.nVal, ptrPRCL, strErrMsg);//true for update rectangles
			if(!bOKEnable)
				return true;
		}
		//end
	
		if(trGetN.npeaks.nVal <= 0)
		{
			strErrMsg = XFERR_INVALID_ARG;
			bOKEnable = false;
			return true;			
		}
		
		ptrPRCL->SaveToTree(trGetN.trROI);
	}
	
	///---Sim 12-11-2008 PEAK_RECT_ADJUST_ON_PREVIEW_ALLOW_TO_APPLY_ALL_PEAKS
	/*
	int	nObjID = -1;
	if(xf_check_is_user_event(trGetN, nObjID))// && (nObjID > 0 && nObjID <= MAX_PEAKS_NUM))
	{
	
		//depend on baseline
		vector vxBaseline, vyBaseline;
		XYRange xyBaseline;
		
		
		///Sandy 2008-11-14  when has subtracted, integral should base on baseline.
		//if(trGetN.bsopt.nVal == bsopt_base && paCore->GetBaselineRange(xyBaseline) && xyBaseline.GetData(vyBaseline, vxBaseline))
		bool bSubtracted = paCore->GetSubtractedMode();
		bool bFromBase = (trGetN.bsopt.nVal == bsopt_base || bSubtracted);
		//end
		
		if(bFromBase && paCore->GetBaselineRange(xyBaseline) && xyBaseline.GetData(vyBaseline, vxBaseline))
		{
			ptrPRCL->UpdatePeak(nObjID, vxBaseline, vyBaseline);
		}
		else if(paCore->GetBaseMode() == PA_BM_LOCAL)
		{
			vector vxlocal, vylocal;
			ptrPRCL->UpdatePeak(nObjID, trGetN.localbase.nVal, vxlocal, vylocal);
			XYRange xyLocalBaseline;
			if(!paCore->GetLocalBaselineRange(xyLocalBaseline, nObjID))
				error_report("fail to get local baseline range");
			xyLocalBaseline.SetData(&vylocal, &vxlocal, 0, NULL, DRS_SET_COL_DESIGNATIONS);
		}
		else
		{
			ptrPRCL->UpdatePeak(nObjID);
		}
	
		
		ptrPRCL->SaveToTree(trGetN.trROI);
		
		_convert_roi_data_to_settings(trGetN.trROI_data, trGetN.trROI, false);
		return true;
	}
	*/
	///---END PEAK_RECT_ADJUST_ON_PREVIEW_ALLOW_TO_APPLY_ALL_PEAKS
	
	if(!bShowWindows && bIsWarnning)
			strErrMsg = XFWAR_TURN_OFF_WINDOWS;
	
	if(nEventID == GETNE_ON_UNDO)
	{
	
		PeakRectControlList* ptrPRCL = _get_peak_control_list_obj(trGetN.ptr.dVal);
		if ( ptrPRCL && ptrPRCL->IsValid() )
		{
			ptrPRCL->SaveToTree(trGetN.trROI);
			ptrPRCL->RemoveAll();
		}			
		SetDataDisplayText(NULL);
		_delete_peak_control_list_obj(trGetN.ptr);
		
		paCore->CleanUpContextRange(PA_DRS_LOCAL_BASELINE);
	
		return true;
	}

}

int pa_int_make_tree(TreeNode& tr, LPCSTR lpcszVarName)
{
	string strVarName = lpcszVarName;
	
	if ( strVarName == "trROI" && tr.IsValid())
	{
		 _append_optional_settings_to_tree(tr);	
	}
	
	if(strVarName == "trROI_data" && tr.IsValid())
	{
		int nBranchID = GET_USER_DATAID(0);
		TreeNode trIndex = tree_check_get_node_by_dataid(tr, "Index", (nBranchID + 0));
		TreeNode trXs = tree_check_get_node_by_dataid(tr, "Xs", (nBranchID + 1));
		TreeNode trYs = tree_check_get_node_by_dataid(tr, "Ys", (nBranchID + 2));
		TreeNode trLeft = tree_check_get_node_by_dataid(tr, "Left", (nBranchID + 3));
		TreeNode trRight = tree_check_get_node_by_dataid(tr, "Right", (nBranchID + 4));
		TreeNode trLineX = tree_check_get_node_by_dataid(tr, "LineX", (nBranchID + 5));
	}
	
	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_int_before_execute(TreeNode& trGetN, int nGetNDialog, int& nRet, int dwCntrl)
{
	
	//#ifdef _DEBUG
	//Profiler junk;
	//#endif
	
	if( nGetNDialog >= 0 )
	{
		trGetN.SetAttribute(STR_HELPID_ATTRIB, IDD_PA_RE_IP);//folger 2008-12-19
	
		if(!_update_npeaks(trGetN))
			nRet = XFEVT_ABORT;
		
		///Sandy 2009-3-19 if come from recalculate, the rectangles should not be check if peak inside.
		bool bReUseRects = ((dwCntrl&LTXF_CHANGE_PARAM) || (dwCntrl&LTXF_FROM_AUTO_UPDATE));
		
		//if(!_update_roi_data(trGetN))
		if(!_update_roi_data(trGetN, bReUseRects))
			nRet = XFEVT_ABORT;
		
		PAWizCore* paCore = (PAWizCore*)get_xf_core_handler(trGetN);
		ASSERT(paCore);	
		
		///Sandy 2008-10-23 add for output "[<input>]<new>" ReportData to source wks page
		paCore->SetOriginalRangeToGetN(trGetN.iy);		
		
	
		/* --- Sandy 2008-9-9 add local baseline option
		//if there is baseline or not subtracted, bsopt should be show, otherwise use Y =0 as the base of integral
		if(paCore->GetBaseMode() != PA_BM_None && paCore->GetSubtractedMode() == false)
			trGetN.bsopt.Show = true;
		else
		{
			trGetN.bsopt.Show = false;
			trGetN.bsopt.nVal = 1; //Y = 0;
		}
		*/
	
		trGetN.localbase.Show = ((paCore->GetBaseMode() == PA_BM_LOCAL)? true: false);
		if( (paCore->GetBaseMode() == PA_BM_CONSTANT || paCore->GetBaseMode() == PA_BM_USERDEF || paCore->GetBaseMode() == PA_BM_USE_EX )
			&& paCore->GetSubtractedMode() == false)
			trGetN.bsopt.Show = true;
		else
		{
			trGetN.bsopt.Show = false;
			trGetN.bsopt.nVal = bsopt_y0; //Y = 0;
		}
	}
	///------ Folger 02/11/10 QA81-15085 PA_INTEG_FAILS_WHEN_SCALE_IN
	else if ( -2 == nGetNDialog )	/// click Finish
	{
		_delete_peak_control_list_obj(trGetN.ptr);
	}
	///------ End PA_INTEG_FAILS_WHEN_SCALE_IN
}
//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_int_event1_ex(TreeNode& trGetN, int nRow, int nEventID, DWORD& dwEnables, LPCSTR lpcszNodeName, WndContainer& DynaCntrlContainer, string& strAux, string& strErrMsg)
{
	return false;
}
