#include <origin.h>
#include <GetNBox.h>
#include <xfutils.h>
//put additional include files here
///////////////////////////////////////////////////////////
#include <..\OriginLab\PAWizCore.h>
#include <o8dlg.h>



//put additional include files here
#include <..\OriginLab\XFWizard_utils.h>
#include <xfgraph_utils.h>
#include <..\OriginLab\curve_utils.h>
#include <..\OriginLab\graph_utils.h>

/**
* Iris 11/24/2008 v8.0978 FIX_CALL_PA_WITH_THEME_WITHOUT_DLG_FIT_STEP_RUNTIME_ERR
* Folger 12/03/08 v8.0982 CHECK_CREATE_BASELINE_SHOULD_BE_MEMBER_OF_PAWIZCORE
* Folger 04/07/09 CHANGE_ANY_MODE_TO_XPS_FAILS_TO_UPDATE_GETN
* Folger 09/15/09 PA_CREATE_BASELINE_FAILS_TO_SNAP_TO_SPECTRUM_WHEN_RUN_SCRIPT_MODE_IN_THEME
* Folger 09/17/09 PA_CREATE_BASELINE_FAILS_TO_RUN_IN_SCRIPT_MODE_WHEN_SAVED_THEME_IN_SELECT_GOAL_PAGE
* Kyle 03/11/2010 PICK_PEAK_ROI_TOOL_SHARES_UTILS_FUNCTION_WITH_PA
*/

//put your own support static functions here

#define _STR_BUTTON_LIST_IN_MODIFY ("Add|Modify/Del|Clear All")
//#define _STR_BM_OPTION_LIST_IN_FIND_PEAK _L("Constant|User Defined|Use Existing Dataset|None")
//#define _STR_BM_OPTION_LIST_ALL  _L("Constant|User Defined|Use Existing Dataset|Local Baseline|None")
//#define _STR_BM_OPTION_LIST 		   _L("Constant|User Defined|Use Existing Dataset|None")
//#define _STR_BM_OPTION_LIST_SUBTR_ONLY   _L("Constant|User Defined|Use Existing Dataset")
//#define _STR_BM_OPTION_LIST_INT_ONLY   _L("Constant|User Defined|Use Existing Dataset|Local Baseline|None")
//#define _LOCAL_BASELINE_INDEX_INTG_ONLY 3
//#define _NONE_BASELINE_INDEX_INTG_ONLY 4
//#define _NONE_BASELINE_INDEX 3

		
#define _STR_BUTTON_FIND ("Find")

#define _NUM_DEFAULT_NPTS 8
#define _AUTO_FIND_THRESHOLD 0.05
#define _MIN_BASE_PTS 2
#define _AUTO_FIND_DIFF_FROM_POLY_THRESHOLD 0.8

//static int _get_base_mode(int goal, int nIndexInList)
//{
	//vector<int> vnBaseModeInt = {PA_BM_CONSTANT, PA_BM_USERDEF,	PA_BM_USE_EX, PA_BM_LOCAL,	PA_BM_None};
	//vector<int> vnBaseMode =    {PA_BM_CONSTANT, PA_BM_USERDEF, PA_BM_USE_EX, PA_BM_None};	
	//
	//if(goal == PA_GOAL_INTEGRATE_PEAK)
	//{
		//ASSERT(nIndexInList<vnBaseModeInt.GetSize());
		//return vnBaseModeInt[nIndexInList];
	//}
	//else
	//{
		//ASSERT(nIndexInList<vnBaseMode.GetSize());
		//return vnBaseMode[nIndexInList];
	//}
//}


static void _hide_all_settings_except(TreeNode &trGetN, LPCSTR lpcszExcept)
{
	if(trGetN)
	{
		foreach(TreeNode tr in trGetN.Children)
		{
			if(tr.tagName != lpcszExcept)
			{
				tr.Show = false;
			}
		}
	}
}


static void _hide_all_settings_except_path_control(TreeNode &trGetN)
{
	_hide_all_settings_except(trGetN, "mode");
}


static BOOL	 _get_xy_minmax_value(XYRange& xyr, double *prMin, double *prMax)
{
	double dMin, dMax;
	
	vector vx, vy;	
	BOOL	bb = xyr.GetData(vy, vx);
	if(!bb)
	{
		dMin = NANUM;
		dMax = NANUM;
		
		return false;
	}
	else
	{
		vy.GetMinMax(dMin, dMax);
	}
	
	if ( prMin )
		*prMin = dMin;
	if ( prMax )
		*prMax = dMax;

	return bb;
}

//Sandy 2008-10-27 Easwar and Joe suggestion add option of constant=median 
//static double _get_xy_min_or_max_value(XYRange& xyr, bool bGetMax = false)
enum{
	_Y_MIN_VALUE_AS_BASELINE,
	_Y_MAX_VALUE_AS_BASELINE,
	_Y_MEAN_VALUE_AS_BASELINE,
	_Y_MEDIAN_VALUE_AS_BASELINE,
	_Y_CUSTOM_VALUE_AS_BASELINE,
};


static double _get_data_statistics_value(XYRange& xyr, int nConstantType)
{
	double dMin, dMax;
	

	if(nConstantType == _Y_MIN_VALUE_AS_BASELINE || nConstantType == _Y_MAX_VALUE_AS_BASELINE)
	{
		if(!_get_xy_minmax_value(xyr, &dMin, &dMax))
			return NANUM;
		
		if(nConstantType == _Y_MAX_VALUE_AS_BASELINE)
			return dMax;
		else
			return dMin;
	}
	
	if(nConstantType == _Y_MEDIAN_VALUE_AS_BASELINE )
	{
		vector vx, vy;	
		double dMedian;
		if(!xyr.GetData(vy, vx) || OE_NOERROR!=ocmath_get_median_in_vector(vx.GetSize(), vy, &dMedian))
			return NANUM;	
			
		return dMedian;
	}
	
	if(nConstantType == _Y_MEAN_VALUE_AS_BASELINE )
	{
		vector vx, vy;	
		double dSum;
		if(!xyr.GetData(vy, vx))
			return NANUM;
		
		if( 0 != vy.Sum(dSum))
			return NANUM;
		
		return (dSum/vy.GetSize());	
	}
	return NANUM;	
}

/*//-----Sandy 2008-10-30 SNOW_SUGGEST_MAKE_ALL_OPTIONS_RADIO
static 	void _update_constant_value(PAWizCore* paCore, TreeNode& trConstant)
{	
	ASSERT(paCore);
	XYRange xyOrigin;
	if(!paCore->GetOriginalRange(xyOrigin))
	{
		error_report("fail in get xyrange in PACore!");
	}		
	TreeNode trM = trConstant.con;
	if(1==octree_get_auto_support(&trM))
	{
		trConstant.minmax.Show = true;
		trM.dVal = _get_data_statistics_value(xyOrigin, trConstant.minmax.nVal);	
	}
	else
	{
		trConstant.minmax.Show = false;
	}
}
*/
static 	void _update_constant_value(PAWizCore* paCore, TreeNode& trConstant)
{	
	ASSERT(paCore);
	XYRange xyOrigin;
	if(!paCore->GetOriginalRange(xyOrigin))
	{
		error_report("fail in get xyrange in PACore!");
	}		

	if(trConstant.minmax.nVal != _Y_CUSTOM_VALUE_AS_BASELINE)
	{
		trConstant.con.Enable = ENABLE_READ_ONLY;
		trConstant.con.dVal = _get_data_statistics_value(xyOrigin, trConstant.minmax.nVal);	
	}
	else
	{
		trConstant.con.Enable = true;
	}
}


//static void _update_trGetN_for_mode_changed(TreeNode trGetN)	
static void _update_trGetN_for_mode_changed(TreeNode trGetN, int nBaseMode)	
{	
	_hide_all_settings_except_path_control(trGetN);
	
	TreeNode trInputYb = trGetN.yb;
	trGetN.yb.Show = false;
	XYRange xyb;
	if(!okxf_resolve_tree_construct_range(&trInputYb, &xyb)||!xyb.IsValid())
		trGetN.yb.SetAttribute(STR_DATA_ATTRIB, STR_OPTIONAL);//STR_UNASSIGNED		
	
	trGetN.snap.Show = (nBaseMode == PA_BM_USERDEF ? true : false);
	trGetN.hint_local.Show = (nBaseMode == PA_BM_LOCAL ? true : false);
	
#ifdef PA_WITH_XPS_BASELINE 
	trGetN.hint_xps.Show = (nBaseMode == PA_BM_XPS ? true : false);
#else
    trGetN.hint_xps.Show = false;
#endif
	//switch(trGetN.mode.nVal)
	switch(nBaseMode)
	{
	case PA_BM_USERDEF:
		trGetN.mode_UserDefine.Show = true;
		//trGetN.mode_UserDefine.Xs.Show = false;
		//trGetN.mode_UserDefine.Ys.Show = false;
	
		trGetN.mode_UserDefine.btns_modify.Show = true;
		trGetN.mode_UserDefine.btn_find.Show = true;
		
		break;
	case PA_BM_CONSTANT:
		trGetN.mode_Constant.Show = true;
		break;

	case PA_BM_USE_EX:
		trGetN.yb.Show = true;
		if(!okxf_resolve_tree_construct_range(&trInputYb, &xyb)||!xyb.IsValid())
		{
			trGetN.yb.SetAttribute(STR_DATA_ATTRIB, STR_UNASSIGNED);//	
			trGetN.offset.Show = false;
		}
		else
			trGetN.offset.Show = true;
		break;
	case PA_BM_None:
	case PA_BM_LOCAL:
		
		break;
		
	default:
		break;
	}
	

}

static bool _update_constant_baseline(PAWizCore* paCore, double dConstant)
{
	XYRange xyOrigin;
	if(!paCore->GetOriginalRange(xyOrigin))
	{
		error_report("fail in get xyrange in PACore!");
		return false;
	}
	
	vector vx, vy;
	if(!xyOrigin.GetData(vy, vx)||vx.GetSize()<=0  )
		return false;
	
	vector vbx(2), vby(2);
	double dxmin, dxmax;
	vx.GetMinMax(dxmin, dxmax);
	vbx[0] = dxmin;
	vbx[1] = dxmax;
	vby[0] = vby[1] =  dConstant;	
	
	XYRange xyBaseline;
	if( !paCore->GetBaselineRange(xyBaseline) )
		return false;
	
	return xyBaseline.SetData(&vby, &vbx);
}




static bool _update_anchors_to_GetN(TreeNode& trGetN, int nMode)
{   
	PAWizCore* paCore = (PAWizCore*)get_xf_core_handler(trGetN);
	ASSERT(paCore);
	
	XYRange xyOrigin, xyAnchors;
	if(!paCore->GetOriginalRange(xyOrigin) || !paCore->GetBaseAnchorsRange(xyAnchors))
	{
		error_report("fail in get xyrange in PACore!");
		return false;
	}
	
	vector vx, vy, vxAnchor, vyAnchor;
	if(!xyOrigin.GetData(vy, vx)||vx.GetSize()<=0 || !xyAnchors.GetData(vyAnchor, vxAnchor))
		return false;

	//if(trGetN.mode_UserDefine.snap.nVal)
	if(trGetN.snap.nVal)
	{
		snap_points_to_source_data(vx, vy, vxAnchor, vyAnchor);	
		//xyAnchors.SetData(&vyAnchor, &vxAnchor);
		xyAnchors.SetData(&vyAnchor, &vxAnchor, 0, NULL, DRS_SET_COL_DESIGNATIONS);
	}
	//if(!anchors_to_tree(vxAnchor, vyAnchor, trGetN.mode_UserDefine))
	if(!anchors_to_tree(vxAnchor, vyAnchor, trGetN.trAnchorXY))
		return false;
		
	if(nMode == PA_BM_USERDEF)
		trGetN.mode_UserDefine.snpts.nVal = vxAnchor.GetSize();

	return true;
}

///Kyle 03/11/2010 PICK_PEAK_ROI_TOOL_SHARES_UTILS_FUNCTION_WITH_PA, moved to curve_utils.h and renamed to auto_find_baseline_anchor_points
/*
static bool _auto_find_baseline_points(vector& vx, vector& vy, vector& vebx, vector& veby, int& npts)
{
	if(npts < _MIN_BASE_PTS)
		return false;
	
	vebx.SetSize(vx.GetSize());
	veby.SetSize(vx.GetSize());
	int nNumBaselinePts = ocmath_find_baseline_part_by_small_curvature(vx.GetSize(),vx,vy,vebx,veby,_AUTO_FIND_THRESHOLD, _AUTO_FIND_DIFF_FROM_POLY_THRESHOLD);
	if(nNumBaselinePts < _MIN_BASE_PTS) 
	{
		///Sandy 2008-4-29 add default points(beginning and ending points) as baseline points if no auto points
		nNumBaselinePts = _MIN_BASE_PTS;
		vebx.SetSize(_MIN_BASE_PTS);
		veby.SetSize(_MIN_BASE_PTS);
		double dMin, dMax;
		uint nMin, nMax;
		vx.GetMinMax(dMin, dMax, &nMin, &nMax);
		vebx[0] = dMin;
		vebx[1] = dMax;
		veby[0] = vy[nMin];
		veby[1] = vy[nMax];	
		//end 2008-4-29
	}
	//
	vebx.SetSize(nNumBaselinePts);
	veby.SetSize(nNumBaselinePts);
	
	if(npts>nNumBaselinePts)
	{
		npts = nNumBaselinePts;
	}
	

	//Get npts well-proportioned baseline points
	vector<uint> vn;
	vebx.Sort(SORT_ASCENDING, true, vn);
	veby.Reorder(vn);
	
	//int nStep = max(1, (int)((double)nNumBaselinePts /npts + 0.5));
	int nStep = max(1, ((nNumBaselinePts-1) /npts));
	int iMax = (nNumBaselinePts-1)/nStep;
	int nOffset = 0, ii = 0, nn = 0;
	vector vOutbx(npts-1), vOutby(npts-1);
	do
	{
		if( ii >= iMax )
		{
			nOffset++;
			ii = 0;	
		}
		
		ASSERT((ii*nStep + nOffset)<=(nNumBaselinePts-2));
		vOutbx[nn] = vebx[ii*nStep + nOffset];
		vOutby[nn] = veby[ii*nStep + nOffset];
		ii++;
		nn++;
	
	}
	while(nn < npts-1);

	vOutbx.Add(vebx[nNumBaselinePts - 1]);
	vOutby.Add(veby[nNumBaselinePts - 1]);
	
	vebx = vOutbx;
	veby = vOutby;
	
	return true;
}
*/
///End PICK_PEAK_ROI_TOOL_SHARES_UTILS_FUNCTION_WITH_PA
static bool _auto_find_baseline_points_button(TreeNode& trGetN)
{
	PAWizCore* paCore = (PAWizCore*)get_xf_core_handler(trGetN);
	ASSERT(paCore);
	
	vector vx, vy;
	XYRange xyOrigin, xyAnchors;
	if(!paCore->GetOriginalRange(xyOrigin) || !paCore->GetBaseAnchorsRange(xyAnchors))
	{
		error_report("fail in get xyrange in PACore!");
		return false;
	}
	if(!xyOrigin || !xyOrigin.GetData(vy, vx) || vx.GetSize()<=0)
		return false;
	
	int npts = trGetN.mode_UserDefine.npts.nVal;
	vector vxAnchors, vyAnchors;
	///Kyle 03/11/2010 PICK_PEAK_ROI_TOOL_SHARES_UTILS_FUNCTION_WITH_PA
	//if(!_auto_find_baseline_points(vx, vy, vxAnchors, vyAnchors, npts))
	if(!auto_find_baseline_anchor_points(vx, vy, vxAnchors, vyAnchors, npts))
	///End PICK_PEAK_ROI_TOOL_SHARES_UTILS_FUNCTION_WITH_PA
	{
		error_report("fail in auto find baseline points");
		return false;
	}

    //if(!xyAnchors.SetData(&vyAnchors, &vxAnchors))
    if(!xyAnchors.SetData(&vyAnchors, &vxAnchors, 0, NULL, DRS_SET_COL_DESIGNATIONS))
    {
    	error_report("fail in update anchors!");
    	return false;
    }

    return true;
}			

static bool _copy_exist_yb_data_to_pa( PAWizCore* paCore, XYRange xyExistBaseline)
{
	ASSERT(paCore);
	vector vbx, vby;
	if(!xyExistBaseline.GetData(vby, vbx) || vbx.GetSize() <=0)
		return false;
	
	XYRange xyBaseline;
	if( !paCore->GetBaselineRange(xyBaseline) )
		return false;
		
	return xyBaseline.SetData(&vby, &vbx);
}

static bool _copy_exist_yb_data_to_pa( PAWizCore* paCore, TreeNode &trGetN)
{
	XYRange xybUser;
	TreeNode trInputYb = trGetN.yb;
	if(!trInputYb)
		return false;	
			
	if(!okxf_resolve_tree_construct_range(&trInputYb, &xybUser)||!xybUser.IsValid())
		return false;
	
	return _copy_exist_yb_data_to_pa( paCore,  xybUser);
}

static bool _scale_baseline_range(PAWizCore* paCore, const double dOffset)
{
	ASSERT(paCore);
	XYRange xyBaseline;
	if( !paCore->GetBaselineRange(xyBaseline) )
		return false;
	
	if(!xyBaseline.IsValid())
		return false;

	vector vbx, vby;
	if(!xyBaseline.GetData(vby, vbx))
		return false;

	vby = vby + dOffset;
	xyBaseline.SetData(&vby, &vbx, 0, NULL, 0);
	
	return true;
}



bool _disable_yb_input(TreeNode trGetN)
{
	if(!trGetN.yb || !trGetN.offset)
		return false;
	
	TreeNode trInputYb = trGetN.yb;
	trGetN.yb.SetAttribute(STR_DATA_ATTRIB, STR_OPTIONAL);	
	trGetN.offset.dVal = 0.0;//for no support theme;
	
	return true;
}
			

void pa_basemode(const string& hint_local, const string& hint_xps, const int& mode, const int& snap, const TreeNode& mode_Constant, const TreeNode& mode_UserDefine, const XYRange& yb, const double& offset, const TreeNode& mode_Exist, const int& nXFCorePointer, const TreeNode& trAnchorXY)
{
	///---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 xyOrigin;
	vector vx, vy;
	if(!paCore->GetOriginalRange(xyOrigin) || !xyOrigin.GetData(vy, vx))
	{
		XF_THROW(XF_ERR_INVALID_PA_INSTANCE);
	}
	
	//vector<int> vnBaseModeList;
	//paCore->GetBaseModeList(vnBaseModeList);
	
	//paCore->ChangeBaseMode(mode); /// Iris 11/24/2008 v8.0978 FIX_CALL_PA_WITH_THEME_WITHOUT_DLG_FIT_STEP_RUNTIME_ERR, baseline mode always be const(=0).
	
	Tree treeParams;//for update baseline info tree
	switch(mode)
	{
	case PA_BM_USERDEF:
		XYRange xyAnchors;
		vector  vxAnchors, vyAnchors;
		if(!paCore->GetBaseAnchorsRange(xyAnchors))
		{
			XF_THROW(XF_ERR_INVALID_PA_INSTANCE);
		}
		//bool bInitFromGetN = true;
		int nAuto = mode_UserDefine.auto.nVal;
		if(nAuto == 1)
		{
			int npts = mode_UserDefine.npts.nVal;
			///Kyle 03/11/2010 PICK_PEAK_ROI_TOOL_SHARES_UTILS_FUNCTION_WITH_PA
			//if(!_auto_find_baseline_points(vx, vy, vxAnchors, vyAnchors, npts))
			if(!auto_find_baseline_anchor_points(vx, vy, vxAnchors, vyAnchors, npts))
			///End PICK_PEAK_ROI_TOOL_SHARES_UTILS_FUNCTION_WITH_PA
			{
				XF_THROW(XF_ERR_FAIL_IN_AUTO_BASELINE);
			}
			//xyAnchors.SetData(&vyAnchors, &vxAnchors);
			xyAnchors.SetData(&vyAnchors, &vxAnchors, 0, NULL, DRS_SET_COL_DESIGNATIONS);
		
		}
	
		anchors_to_tree(vxAnchors, vyAnchors, trAnchorXY);
		//create_anchor_plot(paCore,trAnchorXY, bInitFromGetN);	
		
		paCore->UpdateInfoTree(treeParams, PA_TREE_BASELINE_FIT_INFO, true); 
	
		break;
	case PA_BM_CONSTANT:
		_update_constant_baseline(paCore, mode_Constant.con.dVal);
		
		///Sandy 2008-10-13 need update baseline fit info tree to paCore
		
		string strFuncName = "Constant";
		vector vParams(1);
		vParams =  mode_Constant.con.dVal;
		if(!pa_make_baseline_param_tree(treeParams,strFuncName, vParams) )
			XF_THROW(XFERR_FAIL_CONVERT_BASELINE_PARAM_TREE);
		
		paCore->UpdateInfoTree(treeParams, PA_TREE_BASELINE_FIT_INFO, true); //update fit baseline info tree as empty
		//end of 2008-10-13
	
		break;
		
	case PA_BM_USE_EX:
	{	
		if( !_copy_exist_yb_data_to_pa( paCore, yb))
			XF_THROW(XFERR_NO_BASELINE);
			
		if( !_scale_baseline_range(paCore, offset))
			XF_THROW(XFERR_INVALID_ARG);
		
		paCore->SetBaseOffset(offset);///Sandy  2008-11-22 save existing baseline offset for report usage
		
		///Sophy 11/12/2008 SUPPORT_USE_EXISTING_DATARANGE_AS_BASELINE_IN_NEW_PA
		paCore->SetExistingBaselineRange(yb);
		///end SUPPORT_USE_EXISTING_DATARANGE_AS_BASELINE_IN_NEW_PA
		paCore->UpdateInfoTree(treeParams, PA_TREE_BASELINE_FIT_INFO, true); //update fit baseline info tree as empty
	}
		break;
	case PA_BM_None:
	case PA_BM_LOCAL:
		break;
		
	default:
		break;
	}
	
	
	
}

//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_basemode_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_basemode_event1_ex(trGetN, nRow, nEventID, dwEnables, lpcszNodeName, DynaCntrlContainer, strAux, strErrMsg);
	DECLARE_BUTTON_ENABLES
	
	if (nEventID == GETNE_ON_INIT )
	{	
		xf_turnon_user_event_receiver(trGetN);
	}
	
	PAWizCore* paCore = (PAWizCore*)get_xf_core_handler(trGetN);
	ASSERT(paCore);
	
	/// YuI 03/17/09 QA70-13292 TWEAKING_INTERACTIVE_CONTROL_FOR_PA_BASELINE
	if( nEventID == GETNE_ON_INIT && NULL != paCore )
	{
		DataRange drSource;
		paCore->GetSourceRange(drSource);
		if( drSource )
		{
			string strSourceRangeString;
			if( drSource.GetRangeString(strSourceRangeString) )
			{
				trGetN.yb.SetAttribute(STR_ATTRIB_PA_SOURCE_DATARANGE, strSourceRangeString);
			}
		}
	}
	/// end TWEAKING_INTERACTIVE_CONTROL_FOR_PA_BASELINE
	
	vector<int> vnBaseModeList;
	paCore->GetBaseModeList(vnBaseModeList);
	int nMode = trGetN.mode.nVal;		
	
	if( nEventID ==GETNE_ON_INIT ||0 == lstrcmp(lpcszNodeName,  "mode"))
	{
		strErrMsg = "";
		
		///Sandy 2008-10-16
		//paCore->ChangeBaseMode(trGetN.mode.nVal);
		//_update_trGetN_for_mode_changed(trGetN);
		//int nBaseMode = _get_base_mode(paCore->GetCurrGoal(), trGetN.mode.nVal);
		
		paCore->ChangeBaseMode(nMode); 
		_update_trGetN_for_mode_changed(trGetN, nMode);
		
		//------ Folger 12/03/08 v8.0982 CHECK_CREATE_BASELINE_SHOULD_BE_MEMBER_OF_PAWIZCORE
		//create_baseline_plot( paCore);
		paCore->CheckCreateBaselinePlot();
		//------
		
		//clean_up_baseline_anchors_data(paCore);
		//clean_up_baseline_data(paCore);
		paCore->CleanUpContextRange(PA_DR_BASEANCHORS);
		paCore->CleanUpContextRange(PA_DR_BASELINE);	
		bOKEnable = true;
		
		///Sandy 2009-2-20 CLEAN_ANCHOR_TREE_WHEN_INIT_IN_AUTO_MODE
		if(nEventID ==GETNE_ON_INIT && trGetN.mode_UserDefine.auto.nVal == 1)
		{
			vector vempty;
			anchors_to_tree(vempty, vempty, trGetN.trAnchorXY);
		}
		
		///Sandy 2009-2-23 UNDO_RESET_BASELINE_FIT_INFO
		Tree treeParams;
		paCore->UpdateInfoTree(treeParams, PA_TREE_BASELINE_FIT_INFO, true); 
		//end UNDO_RESET_BASELINE_FIT_INFO
	
	}
	
	
	//*************events for select baseline points********************//
	if(nMode == PA_BM_USERDEF)
	{ 
		int nUserEventID;
		bool bPointModified =  xf_check_is_user_event(trGetN, nUserEventID);
		if(	   0 == lstrcmp(lpcszNodeName,  "npts")		|| 0 == lstrcmp(lpcszNodeName,  "btn_find")		
			|| 0 == lstrcmp(lpcszNodeName,  "auto")		|| 0 == lstrcmp(lpcszNodeName,  "snap")			
			|| 0 == lstrcmp(lpcszNodeName,  "mode")		|| 0 == lstrcmp(lpcszNodeName,  "btns_modify")	
			|| bPointModified || nEventID == GETNE_ON_INIT)
	
		{
			/// Folger, 12/12/08, diable peak modify when change parameter
			//trGetN.mode_UserDefine.btns_modify.Enable = ((trGetN.mode_UserDefine.auto.nVal == 1)? false:true);
			trGetN.mode_UserDefine.btns_modify.Enable = (paCore->IsAutoUpdated() || (trGetN.mode_UserDefine.auto.nVal == 1)? false:true);
			
			///Sandy 2008-10-14 snap should keep enable when auto find
			//trGetN.snap.Enable = ((trGetN.mode_UserDefine.auto.nVal == 1)? false:true);	
			
			bool bInitFromGetN = !bPointModified;
			//bool bInitFromGetN = (nEventID == GETNE_ON_INIT);
			create_anchor_plot(paCore,trGetN.trAnchorXY, bInitFromGetN);
			
			XYRange xyOrigin, xyAnchors;
			if(!paCore->GetOriginalRange(xyOrigin) || !paCore->GetBaseAnchorsRange(xyAnchors))
			{
				error_report("fail in get xyrange in PACore!");
				return false;
			}
		
			///Sandy 2008-10-21 For indicate all anchors are deleted.
			//if(bPointModified && nUserEventID == WPARAM_DONE_DLG_COSE)
			//{
				//resume_anchor_plot_after_modify_done(paCore);
				//GETN_CHANGE_GRID	
			//}
			if ( bPointModified && (nUserEventID == WPARAM_DONE_DLG_COSE || nUserEventID == WPARAM_NONE_ANCHOR))
			{
				resume_anchor_plot_after_modify_done(paCore, nUserEventID == WPARAM_DONE_DLG_COSE);
				GETN_CHANGE_GRID
			}
			
		
			if(0 == lstrcmp(lpcszNodeName,  "btns_modify"))
			{
				modify_baseline_points_buttons(paCore, trGetN.mode_UserDefine.btns_modify.nVal);
			}
			
			if(0 == lstrcmp(lpcszNodeName,  "btn_find"))
			{
				_auto_find_baseline_points_button(trGetN);
			}
			
		    if(!_update_anchors_to_GetN(trGetN,nMode))
		    {
		     	error_report("fail in update GetN after anchor changed!");
		    	return false;   	
		    }	
		    
			
			strErrMsg = "";
			if((trGetN.mode_UserDefine.auto.nVal == 0 && trGetN.mode_UserDefine.snpts.nVal < _MIN_BASE_PTS )
				|| (trGetN.mode_UserDefine.auto.nVal == 1 && trGetN.mode_UserDefine.npts.nVal < _MIN_BASE_PTS) )
			{	 
				bOKEnable = false;
				strErrMsg = CER_DATA_TOO_FEW;
				strErrMsg += ":" + _MIN_BASE_PTS;
				//return true;
			}		    
		    
			return true;
		}
	}		
	
	//************ event for constant baseline ****************//
	if(nMode == PA_BM_CONSTANT)
	{
		if( 0 == lstrcmp(lpcszNodeName,  "minmax")  ||	0 == lstrcmp(lpcszNodeName,  "con")
		    || 0 == lstrcmp(lpcszNodeName,  "mode")	|| nEventID == GETNE_ON_INIT || nEventID == GETNE_ON_RESTORE )
		{
			_update_constant_value(paCore,  trGetN.mode_Constant);	
			_update_constant_baseline(paCore, trGetN.mode_Constant.con.dVal);
			return true;
		}
	}
	
	//************ event for exist dataset baseline ****************//
	if(nMode == PA_BM_USE_EX)
	{
		if(	  (0 == lstrcmp(lpcszNodeName,  "offset"))  ||	(0 == lstrcmp(lpcszNodeName,  "yb"))
			||(0 == lstrcmp(lpcszNodeName,  "mode"))	||	nEventID == GETNE_ON_INIT || nEventID == GETNE_ON_RESTORE )
	 	{	
	 			strErrMsg = "";
				if(!_copy_exist_yb_data_to_pa( paCore, trGetN))	
				{
					trGetN.offset.Show = false;
					strErrMsg = XFERR_NO_BASELINE;
					bOKEnable = false;
					return true;
				}
				else	
					trGetN.offset.Show = true;
				
				double dOffset = trGetN.offset.dVal;
				if(dOffset != 0)
				{	
					if(!_scale_baseline_range(paCore, dOffset))
					{
						strErrMsg = XFERR_INVALID_ARG;
						bOKEnable = false;
						return true;						
					}
				}
				return true;
	 	}
	}
	///------ Folger 04/07/09 CHANGE_ANY_MODE_TO_XPS_FAILS_TO_UPDATE_GETN
	if ( 0 == lstrcmp(lpcszNodeName,  "mode") && PA_BM_XPS == nMode )
		return true;
	///------ End CHANGE_ANY_MODE_TO_XPS_FAILS_TO_UPDATE_GETN
	if(nEventID == GETNE_ON_UNDO)
	{
		//clean_up_baseline_anchors_data(paCore);
		//clean_up_baseline_data(paCore);
		paCore->CleanUpContextRange(PA_DR_BASEANCHORS);
		paCore->CleanUpContextRange(PA_DR_BASELINE);
		return true;
	}	

}

int pa_basemode_make_tree(TreeNode& tr, LPCSTR lpcszVarName)
{
	
	if(tr.IsValid())
	{
		
		string strVarName = lpcszVarName;
		int nBranchID;
	
	
		if (strVarName == "mode_Constant")
		{
			nBranchID = GET_USER_DATAID(10);
			GETN_USE(tr)  GETN_OPTION_BRANCH(GETNBRANCH_OPEN)
			GETN_NUM(con, _L("Y="), 0) GETN_ID(nBranchID  + 1)
			
			
			/*//-----Sandy 2008-10-30 SNOW_SUGGEST_MAKE_ALL_OPTIONS_RADIO\
			TreeNode trCon = tr.con;
			if(trCon)
			{
				octree_set_auto_support(&trCon);
				//string strLabel = _LC("Use Min/Max", "pa_basemode");//Sandy 2008-10-27 Easwar and Joe suggestion add option of constant=median 
				string strLabel = _LC("Use Data Statistics", "pa_basemode");
				trCon.SetAttribute(STR_ATTRIB_AUTO, "1|" + strLabel + "|1");
	
			}
			//GETN_RADIO_INDEX(minmax, 0, _L("Minimum|Maximum"))	GETN_ID(nBranchID  + 2)
			GETN_RADIO_INDEX(minmax, 0, _L("Minimum|Mean|Maximum|Median"))	GETN_ID(nBranchID  + 2)
			tr.minmax.SetAttribute(STR_ATTRIB_DISPFMT, DISPLAY_EDITOR_HORZ);
			*/
			GETN_RADIO_INDEX(minmax, 0, _L("Minimum|Maximum|Mean|Median|Custom"))	GETN_ID(nBranchID  + 2)
			
		}
		
		if (strVarName == "mode_UserDefine")
		{
			nBranchID = GET_USER_DATAID(0);
			
			///gui settings
			GETN_USE(tr)  GETN_OPTION_BRANCH(GETNBRANCH_OPEN)
			GETN_NUM(snpts, _L("Current Number of Points"), 0)  GETN_ID(nBranchID  + 2)
			GETN_CHECK(auto, _L("Enable Auto Find"), 1)	GETN_ID(nBranchID + 1)
			
			
			GETN_NUM(npts, _L("Number of Points to Find"), _NUM_DEFAULT_NPTS) GETN_ID(nBranchID + 5) // only use in auto find and un-save to theme
			tr.snpts.Enable = ENABLE_READ_ONLY;
			
			TreeNode trFind = tr.AddNode("btn_find");
			if(trFind)
			{
				trFind.SetAttribute(STR_ID_ATTRIB, ONODETYPE_PUSHBUTTON_GROUP);
				trFind.SetAttribute(STR_COMBO_ATTRIB, _STR_BUTTON_FIND);			
			}
			
			TreeNode trModify = tr.AddNode("btns_modify");
			if(trModify)
			{
				trModify.SetAttribute(STR_LABEL_ATTRIB, _L(" "));	
				trModify.SetAttribute(STR_ID_ATTRIB, ONODETYPE_PUSHBUTTON_GROUP);
				trModify.SetAttribute(STR_COMBO_ATTRIB, _STR_BUTTON_LIST_IN_MODIFY);			
				DWORD dwDisplyBits = DISPLAY_EDITOR_HORZ;
				trModify.SetAttribute(STR_ATTRIB_DISPFMT, (string)dwDisplyBits);
			}	
			
			
			//GETN_CHECK(snap, _L("Snap to Spectrum"), 0)	GETN_ID(nBranchID + 4)
			
			/*
			//string strXs = "Xs";
			TreeNode trXs = tree_check_get_node_by_dataid(tr, STR_GETN_VAR_SHARED_BASE_ANCHORS_XS, PA_BASE_ANCHOR_X_DATAID_IN_GETN_TREE);
			//string strYs = "Ys";
			TreeNode trYs = tree_check_get_node_by_dataid(tr, STR_GETN_VAR_SHARED_BASE_ANCHORS_YS, PA_BASE_ANCHOR_Y_DATAID_IN_GETN_TREE);
			trYs.Show = trXs.Show = false;
			*/
	
		}
		
		if (strVarName == "mode_Exist")
		{
			nBranchID = GET_USER_DATAID(40);
		}
		
		if(strVarName == "trAnchorXY")
		{
			TreeNode trXs = tree_check_get_node_by_dataid(tr, STR_GETN_VAR_SHARED_BASE_ANCHORS_XS, PA_BASE_ANCHOR_X_DATAID_IN_GETN_TREE);
			TreeNode trYs = tree_check_get_node_by_dataid(tr, STR_GETN_VAR_SHARED_BASE_ANCHORS_YS, PA_BASE_ANCHOR_Y_DATAID_IN_GETN_TREE);
		}
		
		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_basemode_before_execute(TreeNode& trGetN, int nGetNDialog, int& nRet, int dwCntrl)
{
	if(nGetNDialog >= 0)
	{
		trGetN.SetAttribute(STR_HELPID_ATTRIB, IDD_PA_BASELINE_MODE);
		PAWizCore* paCore = (PAWizCore*)get_xf_core_handler(trGetN);
		ASSERT(paCore);	
		
		vector<int> vnBaseModeList;
		string strComboList;
		int nModeMaxNum = paCore->GetBaseModeList(vnBaseModeList,  strComboList);	
		
		int nMode = trGetN.mode.nVal;
		vector<uint> vecIndex;
		int nFound = vnBaseModeList.Find(vecIndex, nMode);
	    	if( 0 >= nFound|| vecIndex == NULL)
	    		//trGetN.mode.nVal = vnBaseModeList[0];
	    		nMode = trGetN.mode.nVal = vnBaseModeList[0];
	
		//paCore->ChangeBaseMode(nMode);
	
		TreeNode tr = trGetN.mode;
		tr.SetAttribute(STR_COMBO_ATTRIB, strComboList);
		
		
		///Sandy 2008-11-11 keep combo list index mapping consist with SR4, make theme converting easier
		remap_combo_indexes(tr, vnBaseModeList);
		//end
		
		///---Sandy 2008-12-30 Greg suggested add xps baseline when create baseline
		//tr.Enable = ( paCore->GetCurrGoal() == PA_GOAL_CREATE_BASELINE? false:true);
	
		//Sandy 2008-11-26 only need to reset this node in script mode 
		//if(nMode!= PA_BM_USE_EX)
		//{
			//if(!_disable_yb_input(trGetN))
			//{
				//error_report("there is no yb treenode inside trGetN!");
				//nRet = XFEVT_ABORT;		
			//}
		//}
	//
		if(nMode == PA_BM_CONSTANT)
		{
			_update_constant_value(paCore,  trGetN.mode_Constant);
		}
		
		paCore->CleanUpContextRange(PA_DR_PEAKSRANGE);   ///Sandy 2008-10-24 add for always clean up peakrange when beginning
		
		if(nGetNDialog == 0) //Script mode
		{
			/// Iris 11/24/2008 v8.0978 FIX_CALL_PA_WITH_THEME_WITHOUT_DLG_FIT_STEP_RUNTIME_ERR, moved to main funciton
			paCore->ChangeBaseMode(nMode); 
			///end FIX_CALL_PA_WITH_THEME_WITHOUT_DLG_FIT_STEP_RUNTIME_ERR
			
			// check existing dataset
			if(nMode == PA_BM_USE_EX)
			{
				TreeNode trBaseline= trGetN.yb;
				XYRange dr;
				if(!okxf_resolve_tree_construct_range(&trBaseline, &dr)||!dr.IsValid())
				{
					warning_msg_box(XFERR_NO_BASELINE, false, 'E');
					nRet = XFEVT_ABORT;	
				}
			}
			
			///------ Folger 09/17/09 PA_CREATE_BASELINE_FAILS_TO_RUN_IN_SCRIPT_MODE_WHEN_SAVED_THEME_IN_SELECT_GOAL_PAGE
			/////Sandy 2009-1-7 fix script mode fail
			/////------ Folger 09/15/09 PA_CREATE_BASELINE_FAILS_TO_SNAP_TO_SPECTRUM_WHEN_RUN_SCRIPT_MODE_IN_THEME
			////else if(nMode == PA_BM_USERDEF && trGetN.mode_UserDefine.auto.nVal == 0)
			////{
				////create_anchor_plot(paCore,trGetN.trAnchorXY, true);
			////}
			//else if ( nMode == PA_BM_USERDEF )
			//{
				//if ( trGetN.mode_UserDefine.auto.nVal == 0 )
					//create_anchor_plot(paCore,trGetN.trAnchorXY, true);
				//if ( trGetN.snap.nVal )
				//{
					//if ( !_update_anchors_to_GetN(trGetN,nMode) )
				    //{
				     	//error_report("fail in update GetN after anchor changed!");
				    	//nRet = XFEVT_ABORT;
				    //}
				//}				   
			//}
			/////------ End PA_CREATE_BASELINE_FAILS_TO_SNAP_TO_SPECTRUM_WHEN_RUN_SCRIPT_MODE_IN_THEME
			////end 
			//
			////Sandy 2008-11-26 only need to reset this node in script mode 
			//else
			//{
				//if(!_disable_yb_input(trGetN))
				//{
					//error_report("there is no yb treenode inside trGetN!");
					//nRet = XFEVT_ABORT;		
				//}
			//}
			else
			{
				if ( nMode == PA_BM_USERDEF )
				{
					if ( trGetN.mode_UserDefine.auto.nVal == 0 )
						create_anchor_plot(paCore,trGetN.trAnchorXY, true);
					if ( trGetN.snap.nVal )
					{
						if ( !_update_anchors_to_GetN(trGetN,nMode) )
					    {
					     	error_report("fail in update GetN after anchor changed!");
					    	nRet = XFEVT_ABORT;
					    }
					}
				}
				
				if(!_disable_yb_input(trGetN))
				{
					error_report("there is no yb treenode inside trGetN!");
					nRet = XFEVT_ABORT;		
				}
			}
			///------ End PA_CREATE_BASELINE_FAILS_TO_RUN_IN_SCRIPT_MODE_WHEN_SAVED_THEME_IN_SELECT_GOAL_PAGE
		}
	}
}
//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_basemode_event1_ex(TreeNode& trGetN, int nRow, int nEventID, DWORD& dwEnables, LPCSTR lpcszNodeName, WndContainer& DynaCntrlContainer, string& strAux, string& strErrMsg)
{
	return false;
}
