#include <origin.h>
#include <GetNBox.h>
#include <xfutils.h>
//put additional include files here
#include	<..\Originlab\theme_utils.h>
#include	<..\Originlab\graph_utils.h>
#include	<..\Originlab\grobj_utils.h>
#include	<..\Originlab\GraphObjTools.h>
/*------------------------------------------------------------------------------*
 * Modification Log:															*
 *	Sophy 5/13/2010 ORG-23 OPTION_FOR_EXTRAPOLATE_TO_RECT_EDGES					*
 *	Sophy 5/13/2010 ORG-23 SUPPORT_SPECIFY_POSITION_OF_MAIN_RECT				*
 *	Sophy 5/13/2010 ORG-23 SUPPORT_CUSTOMIZE_INTERPOLATE_LINE_WIDTH				*
 *	Sophy 6/13/2010 ORG-23-S5 SHOW_APPLY_BUTTON_FOR_INTERP_PREFERENCE_DLG		*
 *	Sophy 6/13/2010 ORG-23-P5 PROPER_BORDER_CHECKING_ON_X_DESCENDING_ORDER		*
 *------------------------------------------------------------------------------*/
//put your own support static functions here
#include <o8dlg.h>

#define	XF_NAME		"addtool_curve_interp"
#define	TOOLNAME	_L("Gadget Interpolate")
#define	TOOL_PREFERENCES_TITLE	_L("Interpolate")

enum {
	ITT_OBJ_FIRST = GOT_OBJ_TOTAL,
	ITT_OBJ_INTERPOLATE,
};

//interpolate method
enum {
	INTERP_LINEAR 	= INTERP_TYPE_LINEAR,
	INTERP_SPLINE 	= INTERP_TYPE_SPLINE,
	INTERP_BSPLINE	= INTERP_TYPE_BSPLINE,
};

//interpolate/extrapolate method
enum {
	INTERP_LIMIT_RECT	= 0,
	INTERP_EXTRAP		= 1,
	INTERP_DATAPOINT	= 2,
};

///Sophy 6/28/2010 ORG-23-S8 XY_INTERP_FOR_GADGET_TOOL_DLG
enum {
	GOT_OPEN_INTERP_XY	= GOT_CMD_CUSTOM | 0x0010,
};

static	bool	_interpolate_check_y_at_x(TreeNode& tr, int nRow, int nType, Dialog& Dlg)
{
	TreeNode trGUI = tr.trGUI;
	if ( !trGUI )
		trGUI = tr;
	
	TreeNode trShowOnTop = trGUI.showtop;
	int nCheck = trShowOnTop.yAtX.nVal;
	trShowOnTop.xValue.Show = nCheck;
	return true;
}
///end XY_INTERP_FOR_GADGET_TOOL_DLG
static	bool	_interpolate_method_event(TreeNode& tr, int nRow, int nType, Dialog& Dlg)
{
	TreeNode trGUI = tr.trGUI;
	if ( !trGUI )
		trGUI  =tr;
	TreeNode trOptions = trGUI.interpOptions;
	int nMethod = trOptions.method.nVal;
	trOptions.sf.Show = (nMethod == INTERP_TYPE_BSPLINE);
	trOptions.boundary.Show = (nMethod == INTERP_SPLINE);
	return true;
}

///Sophy 6/13/2010 ORG-23-S5 SHOW_APPLY_BUTTON_FOR_INTERP_PREFERENCE_DLG
int	getn_handle_interp(TreeNode& tr, int nRow, int nEvent, DWORD& dwEnables, LPCSTR lpcszNodeName, WndContainer& getNContainer, string& strAux, string& strErrMsg)
{
	DECLARE_BUTTON_ENABLES

	if ( GETNE_ON_APPLY == nEvent )
	{
		bOKEnable = false;
		bApplyEnable = false;
	}
	return 0;
}
///end SHOW_APPLY_BUTTON_FOR_INTERP_PREFERENCE_DLG

static	int*	_get_xf_treenode_evt_handle_state()
{
	static int nUpdated = 0;
	return &nUpdated;
}

#define MIN_BSPLINE_PTS 4
#define MIN_SPLINE_PTS 2
#define MIN_LINEAR_PTS 2
bool	_check_enough_points(int nMethod, int nPts)
{
	int nMinPts = 0;
	switch(nMethod)
	{
	case INTERP_LINEAR:
		nMinPts = MIN_LINEAR_PTS;
		break;
		
	case INTERP_SPLINE:
		nMinPts = MIN_SPLINE_PTS;
		break;
		
	case INTERP_BSPLINE:
		nMinPts = MIN_BSPLINE_PTS;
		break;
		
	default:
		ASSERT(false);
		return false;
	}
	return (nPts >= nMinPts);
}

class InterpolateTool : public GraphObjCurveTool
{
public:
	InterpolateTool(LPCSTR lpcszMainObjName = NULL) : GraphObjCurveTool(lpcszMainObjName)
	{
		m_vnObjIDs.Add(ITT_OBJ_INTERPOLATE);
		m_vsObjNames.Add("Interpolate");
	}
	//virtual
	string	GetSignature()
	{
		return "xf_" XF_NAME;
	}
	
	///Sophy 6/25/2010 ORG-23-S8 XY_INTERP_FOR_GADGET_TOOL_DLG
	void	DoOpenInterpXYDlg()
	{
		Tree trGUI;
		if ( GetData() && GetGUITree(trGUI) )
		{
			InterpParams stParams;
			stParams.nPlotIndex = m_dp.GetIndex();
			stParams.ni1 = m_i1;
			stParams.ni2 = m_i2;
			stParams.nMethod = trGUI.interpOptions.method.nVal;
			stParams.nBoundary = trGUI.interpOptions.boundary.nVal;
			stParams.dSmoothFactor = trGUI.interpOptions.sf.dVal;
			OpenInterpXYDlg(stParams);
		}
	}
	///end XY_INTERP_FOR_GADGET_TOOL_DLG

protected:
	//
	bool	DoOutput(bool bUpdateLastOutput)
	{
		return outputInterpolateResult(bUpdateLastOutput);
	}
	//virtual
	BOOL	OnMove()
	{
		if ( !OnPreMove() )
			return false;
		
		bool bShowPrev = false;
		if ( bShowPrev = updateInterpolateData() )
		{
			updateLabel();
		}
		updateInterpolateLine(bShowPrev);
		///Sophy 5/13/2010 ORG-23 SUPPORT_SPECIFY_POSITION_OF_MAIN_RECT
		if ( QUERY_ROI_TOOL_OPTION(ROI_OPTION_ON_MOVE_EVENT) )
		{
			Tree trGUI;
			if ( GetGUITree(trGUI) )
			{
				double dLeft, dRight;
				GetRectCoordinate(dLeft, dRight);
				trGUI.roi.XScale.leftx.strVal = get_value_by_format(m_dp, dLeft);
				trGUI.roi.XScale.rightx.strVal = get_value_by_format(m_dp, dRight);
				SetGUITree(trGUI);
			}
		}
		///end SUPPORT_SPECIFY_POSITION_OF_MAIN_RECT
		return GraphObjCurveTool::OnMove();
	}
	
	///Sophy 5/13/2010 ORG-23 SUPPORT_SPECIFY_POSITION_OF_MAIN_RECT
	//virtual
	bool CheckGetMainObjectPositionFromGUITree(const TreeNode& trGUI, double& x0, double& x1, bool& pbFixWidth, double& y0, double& y1)
	{
		TreeNode trXScale = trGUI.roi.XScale;
		if ( !trXScale )
			return false;
		
		x0 = get_value_by_format(m_dp, trXScale.leftx.strVal);
		x1 = get_value_by_format(m_dp, trXScale.rightx.strVal);
		pbFixWidth = false;
		return true;
	}
	///end SUPPORT_SPECIFY_POSITION_OF_MAIN_RECT

	//virtual
	int		CreateAttachments()
	{
		int nRet = GraphObjCurveTool::CreateAttachments();
		if ( 0 != nRet )
			return nRet;
		
		nRet = CreateAttachment(m_goInterpCurve, ITT_OBJ_INTERPOLATE, CTP_FREE_1, GROBJ_TN_POLYLINE);
		if ( 0 != nRet )
			return nRet;
		set_go_color(m_goInterpCurve, SYSCOLOR_BLUE);
		set_go_selectable(m_goInterpCurve, false);
		updateInterpolateSettings();
		return nRet;
	}
	//virtual
	int		GetAttachments()
	{
		int nRet = GraphObjCurveTool::GetAttachments();
		if ( 0 != nRet )
			return nRet;
		nRet = GetAttachment(m_goInterpCurve, ITT_OBJ_INTERPOLATE);
		if ( 0 != nRet )
			return nRet;
		
		return nRet;
	}
protected:
	//virtual
	string	GetXFName(){ return XF_NAME; }
	//virtual
	string	GetToolName() { return TOOLNAME; }
	//virtual
	string	GetPreferenceTitle(){ return TOOL_PREFERENCES_TITLE; }
	//virtual
	int*	GetXFEventHandlersState() { return _get_xf_treenode_evt_handle_state(); }

	//virtual
	TreeNode	GetFillColorNode(const TreeNode& trGUI)
	{
		TreeNode trColor;
		if ( trGUI )
			trColor = trGUI.roi.rectcolor;
		return trColor;
	}
	//virtual
	TreeNode	GetToolNameNode(const TreeNode& trGUI)
	{
		TreeNode trToolName;
		if ( trGUI )
			trToolName = trGUI.roi.toolname;
		return trToolName;
	}

	//virtual
	BOOL		GetReportWorksheet(Worksheet& wksReport)
	{
		Tree trGUI;
		if ( !GetGUITree(trGUI) )
			return FALSE;
		string strWorksheet = trGUI.output.wksName.strVal;
		wksReport.Attach(strWorksheet);
		return wksReport.IsValid();
	}
	//virtual
	bool	UpdateROIGUI()
	{
		updateMainObjPosition();
		updateInterpolateSettings();
		return GraphObjCurveTool::UpdateROIGUI();
	}
	
	///Sophy 6/28/2010 ORG-23-S8 XY_INTERP_FOR_GADGET_TOOL_DLG
	//virtual
	bool	UpdateContextMenu(Menu& pm, uint& nPosition)
	{
#define	MF_STRING		0x00000000L		//since XF should not include control relative headers, I have to define it here.
#define MF_SEPARATOR	0x00000800L
		InsertMenuItem(pm, nPosition, NULL, 0, MF_SEPARATOR);	nPosition++;
		InsertMenuItem(pm, nPosition, _L("Interpolate X/Y..."), GOT_OPEN_INTERP_XY, MF_STRING); nPosition++;
		return true;
	}
	
	//virtual
	bool	OnCmdCustom(int nCmdID)
	{
		switch( nCmdID )
		{
		case GOT_OPEN_INTERP_XY:
			DoOpenInterpXYDlg();
			break;
		default:
			ASSERT(false);
			break;
		}
		return true;
	}
	///end XY_INTERP_FOR_GADGET_TOOL_DLG

	
private:
	
	void	updateMainObjPosition()
	{
		Tree trGUI;
		if ( GetGUITree(trGUI) )
		{
			TreeNode trXScale = trGUI.roi.XScale;
			string strXLeft = trXScale.leftx.strVal;
			string strXRight = trXScale.rightx.strVal;
			double x0 = get_value_by_format(m_dp, strXLeft);
			double x1 = get_value_by_format(m_dp, strXRight);
			CheckSetMainObjectXPosition(x0, x1);	
		}
	}
	void	updateInterpolateSettings()
	{
		Tree trGUI;
		if ( GetGUITree(trGUI) )
		{
			int nColor = trGUI.roi.interpLineColor.nVal;
			///Sophy 5/13/2010 ORG-23 SUPPORT_CUSTOMIZE_INTERPOLATE_LINE_WIDTH
			//set_go_color(m_goInterpCurve, nColor);
			double dWidth = trGUI.roi.interpLineWidth.dVal;
			Tree trFormat;
			trFormat = m_goInterpCurve.GetFormat(FPB_ALL, FOB_ALL, true, true);
			trFormat.Root.Color.nVal = nColor;
			trFormat.Root.Width.dVal = dWidth;
			m_goInterpCurve.ApplyFormat(trFormat, true, true);
			///end SUPPORT_CUSTOMIZE_INTERPOLATE_LINE_WIDTH
		}
	}
	
	///Sophy 5/13/2010 ORG-23 OPTION_FOR_EXTRAPOLATE_TO_RECT_EDGES
	bool	updateMinMax(const TreeNode& trGUI, double& dMinX, double& dMaxX)
	{
		double dLeft, dRight;
		GetRectCoordinate(dLeft, dRight);
		bool bExchange = dLeft > dRight;
		int	nExtrap = trGUI.interpOptions.extrap.nVal;
		if ( nExtrap != INTERP_DATAPOINT )
		{

			bool bLeft = false, bRight = false;
			XYRange xyData;
			vector vPlotY, vPlotX;
			if ( m_dp.GetDataRange(xyData, 0, -1) && xyData && xyData.GetData(vPlotY, vPlotX) )
			{
				///Sophy 6/13/2010 ORG-23-P5 PROPER_BORDER_CHECKING_ON_X_DESCENDING_ORDER
				//if ( dLeft < vPlotX[0] )
					//bLeft = true;
				//if ( dRight > vPlotX[vPlotX.GetSize() - 1] )
					//bRight = true;
				if ( dLeft > dRight )
				{
					double dTemp = dLeft ;
					dLeft = dRight;
					dRight = dTemp;
				}
				double dMin, dMax;
				vPlotX.GetMinMax(dMin, dMax);
				if ( dLeft < dMin )
					bLeft = true;
				if ( dRight > dMax )
					bRight = true;
				///end PROPER_BORDER_CHECKING_ON_X_DESCENDING_ORDER
			}

			if ( dLeft < dMinX && (nExtrap == INTERP_EXTRAP || !bLeft) )
			{
				dMinX = dLeft;
			}
			if ( dRight > dMaxX && (nExtrap == INTERP_EXTRAP || !bRight) )
			{
				dMaxX = dRight;
			}
		}
		return bExchange;
	}
	///end OPTION_FOR_EXTRAPOLATE_TO_RECT_EDGES
	
	bool	updateInterpolateData()
	{
		Tree trGUI;
		if ( GetData() && GetGUITree(trGUI) )
		{
			int nMethod = trGUI.interpOptions.method.nVal;
			int nPts = trGUI.interpOptions.npts.nVal;
			double dSmoothFactor = trGUI.interpOptions.sf.dVal;
			int nBoundary = trGUI.interpOptions.boundary.nVal;
			
			vector<int> vnIndices(m_vX.GetSize());
			int nSize = ocmath_1d_remove_missingvalue(m_vX, m_vY, m_vX.GetSize(), NANUM, vnIndices);
			if ( !_check_enough_points(nMethod, nSize ) )
			{
				UpdateTopLabel(_L("There are no enough data points to perform cubic spline/b-spline interpolation"), true);
				return false;
			}
			///Sophy 9/14/2010 ORG-1051-P1 INTERPOLATE_GET_WRONG_RESULT_WHEN_EXIST_DUPLUCATED_POINTS
			int nBeforeRemoveDup = nSize;
			nSize = ocmath_xy_remove_duplicates(m_vX, m_vY, nBeforeRemoveDup);
			if ( nBeforeRemoveDup > nSize && !_check_enough_points(nMethod, nSize ) )
			{
				UpdateTopLabel(_L("Too many duplicate data points"), true);
				return false;
			}
			///end INTERPOLATE_GET_WRONG_RESULT_WHEN_EXIST_DUPLUCATED_POINTS
			m_vX.SetSize(nSize);
			m_vY.SetSize(nSize);
			
			double dMinX, dMaxX;
			m_vX.GetMinMax(dMinX, dMaxX);
			///Sophy 5/13/2010 ORG-23 OPTION_FOR_EXTRAPOLATE_TO_RECT_EDGES
			bool bExchange = updateMinMax(trGUI, dMinX, dMaxX);
			///end OPTION_FOR_EXTRAPOLATE_TO_RECT_EDGES
			m_vInterpX.Data(dMinX, dMaxX, (dMaxX - dMinX) / (nPts - 1));
			m_vInterpY.SetSize(m_vInterpX.GetSize());
			
			//Apparent Interpolation, always do as to Max's suggestion since Gadget all play on GraphLayer
			int nXScale = LINEAR_SPACE, nYScale = LINEAR_SPACE;
			axis_get_scale_type(m_gl, &nXScale, &nYScale);
			ASSERT(!is_missing_value(dMinX) && !is_missing_value(dMaxX));
			m_vInterpX = real_space(m_vInterpX, nXScale);
			m_vX = real_space(m_vX, nXScale);
			m_vY = real_space(m_vY, nYScale);
			
			///Sophy 6/13/2010 ORG-23-P5 PROPER_BORDER_CHECKING_ON_X_DESCENDING_ORDER
			//DWORD dwCtrl = OCMATH_SRCDATA_X_MONOTONIC;
			DWORD dwCtrl = 0;
			///end PROPER_BORDER_CHECKING_ON_X_DESCENDING_ORDER
			int nRet = ocmath_interpolate(m_vInterpX, m_vInterpY, nPts, m_vX, m_vY, m_vX.GetSize(), nMethod, dSmoothFactor, NULL, NULL, dwCtrl, nBoundary);
			///Sophy 6/28/2010 ORG-23-S8 XY_INTERP_FOR_GADGET_TOOL_DLG
			m_dX = trGUI.showTop.xValue.dVal;
			m_dX = real_space(m_dX, nXScale);
			nRet = ocmath_interpolate(&m_dX, &m_dY, 1, m_vX, m_vY, m_vX.GetSize(), nMethod, dSmoothFactor, NULL, NULL, dwCtrl, nBoundary);
			m_dX = real_inv_space(m_dX, nXScale);
			m_dY = real_inv_space(m_dY, nYScale);
			///end XY_INTERP_FOR_GADGET_TOOL_DLG
			//Apparent Interpolation
			m_vInterpX = real_inv_space(m_vInterpX, nXScale);
			m_vInterpY = real_inv_space(m_vInterpY, nYScale);
			
			m_dYLeft = real_inv_space(m_vInterpY[0], nYScale);
			m_dYRight = real_inv_space(m_vInterpY[m_vInterpY.GetSize() - 1], nYScale);
			///Sophy 6/13/2010 ORG-23-P5 PROPER_BORDER_CHECKING_ON_X_DESCENDING_ORDER
			if ( bExchange )
			{
				double dTemp = m_dYLeft;
				m_dYLeft = m_dYRight;
				m_dYRight = dTemp;
			}
			///end PROPER_BORDER_CHECKING_ON_X_DESCENDING_ORDER
			return true;
		}
		return false;
	}
	
	bool	updateLabel()
	{
		string strLabel = "";
		Tree trGUI;
		if ( GetGUITree(trGUI) )
		{
			if ( trGUI.showtop.yLeft.nVal )
			{
				strLabel.Format("Y at Left = %.5lf", m_dYLeft);
			}
			if ( trGUI.showtop.yRight.nVal )
			{
				strLabel.Format("%sY at Right = %.5lf", (strLabel.IsEmpty() ? "" : strLabel + "\n"), m_dYRight);
			}
			///Sophy 6/28/2010 ORG-23-S8 XY_INTERP_FOR_GADGET_TOOL_DLG
			if ( trGUI.showtop.yAtX.nVal )
			{
				strLabel.Format("%sY at %s = %.5lf", (strLabel.IsEmpty() ? "" : strLabel + "\n" ), get_value_by_format(m_dp, m_dX), m_dY);
			}
			///end XY_INTERP_FOR_GADGET_TOOL_DLG
		}
		return UpdateTopLabel(strLabel);
	}
	
	bool	updateInterpolateLine(bool bShow = true)
	{
		if ( m_goInterpCurve )
		{
			m_goInterpCurve.SetPoints(m_vInterpX, m_vInterpY);
			m_goInterpCurve.Show = bShow;
			m_gp.Refresh();
		}
		return true;
	}
	
	bool	outputInterpolateResult(bool bUpdateLastOutput = false)
	{
		Tree trGUI;
		string	strLTCmd;
		if ( GetData() && GetGUITree(trGUI) )
		{
			string strInputRange;
			strInputRange.Format("[%s]%d!%d", m_gp.GetName(), m_gl.GetIndex() + 1, m_dp.GetIndex() + 1);
			int i1, i2;
			m_dp.GetRange(i1, i2);
			if ( i1 != m_i1 || i2 != m_i2 ) //not full range
			{
				strInputRange.Format("%s[%d:%d]", strInputRange, m_i1 + 1, m_i2 + 1);
			}
			
			int nMethod = trGUI.interpOptions.method.nVal;
			int nPts = trGUI.interpOptions.npts.nVal;
			double dSmoothFactor = trGUI.interpOptions.sf.dVal;
			int nBoundary = trGUI.interpOptions.boundary.nVal;
			
			double dMinX, dMaxX;
			vector<int> vnIndices(m_vX.GetSize());
			int nSize = ocmath_1d_remove_missingvalue(m_vX, m_vY, m_vX.GetSize(), NANUM, vnIndices);
			m_vX.SetSize(nSize);
			m_vY.SetSize(nSize);
	
			m_vX.GetMinMax(dMinX, dMaxX);
			///Sophy 5/13/2010 ORG-23 OPTION_FOR_EXTRAPOLATE_TO_RECT_EDGES
			updateMinMax(trGUI, dMinX, dMaxX);
			///end OPTION_FOR_EXTRAPOLATE_TO_RECT_EDGES
			strLTCmd = "interp1xy iy:=" + strInputRange;
			strLTCmd += " method :=" + nMethod;
			strLTCmd += " npts:=" + nPts;
			strLTCmd += " xmin:=" + dMinX;
			strLTCmd += " xmax:=" + dMaxX;
			strLTCmd += " boundary:=" + nBoundary;
			strLTCmd += " sf:=" + dSmoothFactor;
			strLTCmd += " apparent:=1";
			
			string strOutputRange;
			strOutputRange.Format(" oy:=%s!%s", trGUI.output.wksName.strVal, "<new>");
			strLTCmd += strOutputRange;
			BOOL bCheck = LT_execute(strLTCmd);
			///Sophy 5/13/2010 ORG-23 SUPPORT_CUSTOMIZE_INTERPOLATE_LINE_WIDTH
			if ( bCheck ) //apply preview settings to result plot.
			{
				DataPlot dpOut = m_gl.DataPlots(m_gl.DataPlots.Count() - 1);
				if ( dpOut )
				{
					Tree trFormat;
					trFormat = dpOut.GetFormat(FPB_ALL, FOB_ALL, true, true);
					trFormat.Root.Line.Color.nVal = trGUI.roi.interpLineColor.nVal;
					trFormat.Root.Line.Width.dVal = trGUI.roi.interpLineWidth.dVal;
					dpOut.ApplyFormat(trFormat, true, true);
				}
				m_gl.CheckShowActivate();	///Sophy 6/11/2010 ORG-23-P4 ACTIVATE_SRC_GRAPH_AFTER_GENERATE_RESULT_SHEET
			}
			///end SUPPORT_CUSTOMIZE_INTERPOLATE_LINE_WIDTH
			return true;
		}
		return false;
	}
private:
	PolylineGraphObject	m_goInterpCurve;
	vector				m_vInterpX;
	vector				m_vInterpY;
	double				m_dYLeft, m_dYRight;
	double				m_dX, m_dY;	///Sophy 6/28/2010 ORG-23-S8 XY_INTERP_FOR_GADGET_TOOL_DLG
	
};

void	addtool_curve_interp_events(string strGrName, int nEvent, int nMsg = 0)
{
	InterpolateTool itool;
	graphobjtool_events(itool, strGrName, nEvent, nMsg);
}

void addtool_curve_interp(const TreeNode& trGUI)
{
	InterpolateTool itool;
	int nErr = itool.Create(XF_NAME, 0, trGUI);
	if ( nErr < 0 )
	{
		XF_THROW(XFERR_INVALID_GRAPH_LAYER);
		return;
	}
	if ( nErr )
		error_report("addtool_interpolate failed Init");
	
}

//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 addtool_curve_interp_event1(TreeNode& trGetN, int nRow, int nEventID, DWORD& dwEnables, LPCSTR lpcszNodeName, WndContainer& DynaCntrlContainer, string& strAux, string& strErrMsg)
{
	if( xf_is_extended_event(nEventID) )
		return addtool_curve_interp_event1_ex(trGetN, nRow, nEventID, dwEnables, lpcszNodeName, DynaCntrlContainer, strAux, strErrMsg);
	DECLARE_BUTTON_ENABLES
	int nThemeSettings = xf_is_theme_applied(trGetN);
	if ( nEventID == GETNE_ON_INIT || nThemeSettings == THEME_NONE )
	{
		GraphLayer gl = Project.ActiveLayer();
		if ( gl )
		{
			///Sophy 10/29/2010 ORG-1370 PROPER_INIT_SMOOTH_FACTOR_VALUE
			//DataPlot dp = gl.DataPlots();
			//vector vX, vY;
			//dp.GetDataPoints(0, -1, vX, vY);
			//double dVal = ocmath_get_noise_level(vX.GetSize(), vY, vX);
			//trGetN.trGUI.interpOptions.sf.dVal = dVal * dVal;
			if ( nEventID == GETNE_ON_INIT )
			{
				DataPlot dp = gl.DataPlots();
				vector vX, vY;
				dp.GetDataPoints(0, -1, vX, vY);
				double dVal = ocmath_get_noise_level(vX.GetSize(), vY, vX);
				trGetN.trGUI.interpOptions.sf.dVal = dVal * dVal;
			}
			///end PROPER_INIT_SMOOTH_FACTOR_VALUE
			///Sophy 5/13/2010 SUPPORT_SPECIFY_POSITION_OF_MAIN_RECT
			string strLeft, strRight;
			GraphLayer gl = Project.ActiveLayer();
			TreeNode trXScale = trGetN.trGUI.roi.XScale;
			if ( check_get_roi_x_position(gl, strLeft, strRight, "") && trXScale )
			{
				trXScale.leftx.strVal = strLeft;
				trXScale.rightx.strVal = strRight;
				trGetN.trGUI.showTop.xValue.dVal = (gl.X.From + gl.X.To) / 2;	///Sophy 6/28/2010 ORG-23-S8 XY_INTERP_FOR_GADGET_TOOL_DLG 
	
			}
			///end SUPPORT_SPECIFY_POSITION_OF_MAIN_RECT
		}
	}
	return false;

}

int addtool_curve_interp_make_tree(TreeNode& tr, LPCSTR lpcszVarName)
{
	if ( tr.IsValid() )
	{
		int nBranchID = 1;
		int nUserID = GET_USER_DATAID(0);
		if ( strcmp(lpcszVarName, "trGUI") == 0 )
		{
			GETN_USE(tr)
			GETN_OPTION_BRANCH(GETNBRANCH_OPEN)
			GETN_BEGIN_BRANCH(roi, STR_ROI_LABEL)	GETN_ID(nBranchID++)
				GETN_BEGIN_BRANCH(XScale, _L("X Scale")) GETN_ID(nBranchID++)
					GETN_STR(leftx, _L("From"), "")	GETN_ID(nUserID++)
					GETN_STR(rightx, _L("To"), "")	GETN_ID(nUserID++)
				GETN_END_BRANCH(XScale)
				GETN_STR(toolname, STR_TOOLNAME, TOOLNAME)	GETN_ID(nUserID++)	GETN_CONTROL_OPTION_BOX(0)
				GETN_COLOR(rectcolor, STR_FILL_COLOR, SYSCOLOR_LTYELLOW)	GETN_COLOR_CHOICE_OPTIONS(COLORLIST_CUSTOM | COLORLIST_SINGLE)	GETN_ID(nUserID++)
				GETN_COLOR(interpLineColor, _L("Interpolation Line Color"), SYSCOLOR_ORANGE)	GETN_COLOR_CHOICE_OPTIONS(COLORLIST_CUSTOM | COLORLIST_SINGLE)	GETN_ID(nUserID++)
				GETN_COMBO(interpLineWidth, _L("Interpolation Line Width"), 0.5, "|0.2|0.5|1|1.5|2|3|4|5")	GETN_ID(nUserID++)
			GETN_END_BRANCH(roi)
			GETN_BEGIN_BRANCH(showtop, _L("Show on Center-Top of ROI Box"))	GETN_ID(nBranchID++)
				GETN_CHECK(yLeft, _L("Y at Left"), true)	GETN_ID(nUserID++)
				GETN_CHECK(yRight, _L("Y at Right"), true)	GETN_ID(nUserID++)
				///Sophy 6/28/2010 ORG-23-S8 XY_INTERP_FOR_GADGET_TOOL_DLG
				GETN_CHECK(yAtX, _L("Y at Specified X"), false)	GETN_ID(nUserID++)	GETN_OPTION_EVENT(_interpolate_check_y_at_x)
				GETN_NUM(xValue, _L("X"), 1)					GETN_ID(nUserID++)
				///end XY_INTERP_FOR_GADGET_TOOL_DLG
			GETN_END_BRANCH(showtop)
			GETN_BEGIN_BRANCH(interpOptions, _L("Interpolate/Extrapolate Options"))		GETN_ID(nBranchID++)
				GETN_LIST(method, _L("Method"), 0, _L("Linear|Cubic Spline|Cubic B-Spline"))	GETN_ID(nUserID++)	GETN_OPTION_EVENT(_interpolate_method_event)
				GETN_NUM(npts, _L("Number of Points"), 100)	GETN_OPTION_NUM_FORMAT("%d")	GETN_ID(nUserID++)
				GETN_LIST(boundary, _L("Boundary"), 0, _L("Natural|Not-A-Knot"))	GETN_ID(nUserID++)
				GETN_NUM(sf, _L("Smoothing Factor"), 5) GETN_OPTION_NUM_FORMAT("*5*")		GETN_ID(nUserID++)
				GETN_LIST(extrap, _L("Fit Limits To"), 0, _L("Interpolate to Rectangle Edge|Interpolate/Extrapolate to Rectangle Edge|Data Points"))			GETN_ID(nUserID++)
			GETN_END_BRANCH(interpOptions)
			GETN_BEGIN_BRANCH(output, _L("Output To"))	GETN_ID(nBranchID++)
				GETN_STR(wksName, _L("Result Worksheet Name"), "[Interpolate]Result")	GETN_ID(nUserID++)
			GETN_END_BRANCH(output)
			///Sophy 6/13/2010 ORG-23-S5 SHOW_APPLY_BUTTON_FOR_INTERP_PREFERENCE_DLG
			GETN_STR(GETNEVT, "EventHandle", "") GETN_GLOBAL_EVT(getn_handle_interp)	GETN_ID(nUserID++) GETN_CURRENT_SUBNODE.Show = false;
			GETN_STR(APPLYEVT, "ApplyHandle", "")	GETN_APPLY_EVT(ROI_apply_handle)	GETN_ID(nUserID++) GETN_CURRENT_SUBNODE.Show = false;
			///end SHOW_APPLY_BUTTON_FOR_INTERP_PREFERENCE_DLG
		}
	}
	return false;
}
//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 addtool_curve_interp_before_execute(TreeNode& trGetN, int nGetNDialog, int& nRet, int dwCntrl)
{
	///Sophy 7/19/2010 ORG-23-P7 QUICK_INTEPOLATE_SHOULD_IGNORE_POSITION_SETTINGS_IN_THEME
	if ( is_xf_startup(nGetNDialog, dwCntrl) )
	{
		if(is_use_origin_chm())
			trGetN.SetAttribute(STR_HELPID_ATTRIB, IDD_XF_addtool_curve_interp);
		
		string strLeft, strRight;
		TreeNode trROI = trGetN.trGUI.roi;
		GraphLayer gl = Project.ActiveLayer();
		if( check_get_roi_x_position(gl, strLeft, strRight, "") )
		{
			trROI.XScale.leftx.strVal = strLeft;
			trROI.XScale.rightx.strVal = strRight;
		}
	}
	///end QUICK_INTEPOLATE_SHOULD_IGNORE_POSITION_SETTINGS_IN_THEME
}
//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 addtool_curve_interp_event1_ex(TreeNode& trGetN, int nRow, int nEventID, DWORD& dwEnables, LPCSTR lpcszNodeName, WndContainer& DynaCntrlContainer, string& strAux, string& strErrMsg)
{
	return false;
}
