#include <origin.h>
#include <GetNBox.h>
#include <xfutils.h>
enum{
	method_aav,
	method_sg,
	method_pf,
	method_fft,
};
enum{
	boundary_none,
	boundary_reflect,
	boundary_repeat,
	boundary_periodic,
	boundary_extrap,
};
enum{
	filter_new,
	filter_old,
};
enum{
	baseline_two_ends,
	baseline_two_ends_1,
	baseline_none,
};

/********** Modification Log *************/
//Folger 07/23/08 BETTER_OPREATION_OUTPUT_COLUMN_COMMENTS
//CPY 07/26/08 QA70-11868 CHANGE_BACK_TO_USE_CRLF_TO_SEP_LN_COMMENT, Yuri had changed to use | to separate LN and comment, but I think CRLF is better
//YuI 10/02/08 QA70-12319 SMOOTH_WITH_MISSING_DATA_AT_BEGIN_HAD_RESULTS_SHIFTED
// Folger 11/27/08 QA80-12356 v8.0980 MORE_TOOLS_NEED_TO_HANDLE_INPUTS_WITH_MISSING_VALUE
// CPY 12/19/08 USE_SHARED_TEMPLATE_FOR_ALL_PREVIEW_XF
// Kyle 02/12/2009 SHOW_WARNING_MESSAGE_IF_INPUT_DATA_IS_NOT_EVEN_SPACED
/// Max 2/11/09 v8.0977b USE_ANOTHER_STRING_FOR_CENTRALIZATION
/// Kyle 03/13/2009 QA80-13260-S1 ADD_OPTION_TO_COPY_FORMAT_FROM_SOURCE_LAYER
/// Folger 04/13/09 QA80-13436 TRIGGER_WARNING_MSG_IN_BEFORE_EXECUTE_INSTEAD_OF_XF_BODY
/// Folger 07/07/09 IMPROVE_ERROR_CHECKING_OF_SMOOTH_ON_CHANGE
/// Kyle 07/28/2009 QA80-14026 FIX_WRONG_LEGEND_FOR_PREVIEW
///	Jasmine 08/13/2010 ORG-172-S2 CENTRALIZE_NOCLICK_BIT_FOR_PREVIEW_IN_OC_TOOL
/******************************************/

#include <event_utils.h> 
#include <o8dlg.h>

//put additional include files here
#include <..\OriginLab\fft.h>
//put your own support static functions here

///Leo 2006-02-06 TO_BE_CONSISTENT_WITH_INTERNAL_C
//enum {
//	SMOOTH_SG,
//	SMOOTH_ADJAVE,
//	SMOOTH_FFTFILTER,
//	SMOOTH_MEDIAN
//};
//enum {SMOOTH_ADJAVE, /*SMOOTH_FFTFILTER,*/ SMOOTH_SG, SMOOTH_MEDIAN_FILTER};
//enum {EDGEPAD_ZERO, EDGEPAD_REFLECT, EDGEPAD_REPEAT, EDGEPAD_PERIODIC, EDGEPAD_EXTRAPOLATE};

///Sandy 2008-8-14 add
static	double  _compute_max_freq(vector& vInputX)
{
	double dminX, dmaxX;
	int nSize = vInputX.GetSize();
	if(nSize <= 0)
		return -1;
	
	vInputX.GetMinMax(dminX, dmaxX);
	
	if(dmaxX-dminX == 0)
		return -1;
	
	double dFreqMax = ((nSize-1) / (dmaxX-dminX) / 2);
	return dFreqMax;
}

static bool s_bInit = false;
static string s_strErrMsg = "";
///------ Folger 04/13/09 QA80-13436 TRIGGER_WARNING_MSG_IN_BEFORE_EXECUTE_INSTEAD_OF_XF_BODY
//static bool s_bShowWarningMsg = true;		///Kyle 02/12/2009 SHOW_WARNING_MESSAGE_IF_INPUT_DATA_IS_NOT_EVEN_SPACED
static	bool	_is_input_data_even_space_in_sg_smooth(TreeNode& trGetN)
{
	if ( method_sg != trGetN.method.nVal )
	{
		ASSERT(false);
		return true;		/// anyway, if not sg method, properly return true ...
	}
	
	XYRange xyTemp;
	if ( xy_range_from_GetN_data_node(trGetN.iy, xyTemp) && xyTemp.IsValid() )
	{
		double dInterval;
		vector vx, vy;
		xyTemp.GetData(vy, vx,NULL, 0, 0);
		return OE_NOERROR == ocmath_sampling_resolution(vx.GetSize(), vx, &dInterval);
	}
	
	return false;
}

	IMPLEMENT_SHOULD_WARNING_MSG_SHOW_IN_XF_BODY
///------ End TRIGGER_WARNING_MSG_IN_BEFORE_EXECUTE_INSTEAD_OF_XF_BODY

//return false if OK button should be disabled
static bool _update_grid_hide_show(TreeNode& trGetN)
{
	XYRange xy;
	bool bRet = xy_range_from_GetN_data_node(trGetN.iy, xy);

	vector vInputX, vInputY;
	bRet = xy.GetData(vInputY, vInputX);
	
	int nSliderBegin = 2; //0 < nLeftRights < nSize
	int nSliderEnd;
	bool bShowSG = false;
	bool bShowMF = false;
	switch(trGetN.method.nVal)
	{
	case SMOOTH_SG:
		///Sandy 2007-8-30 Change the begin points to 3
		//nSliderBegin = 4;  //1 < nLeftpts <= nSize
		nSliderBegin = 3;  //1 < nLeftpts <= nSize
		trGetN.npts.Show = true;
		bShowSG = true;
		trGetN.boundary.Show = true;
		trGetN.weight.Show  = false;
		/// Cloud 2007-11-8
		trGetN.cutoff.Show = false;
		//trGetN.freq.Show = false;
		//trGetN.fpass.Show = false;
		//trGetN.fstop.Show = false;
		//trGetN.pad.Show = false;
		//trGetN.filter.Show = false;
		//trGetN.baseline.Show = false;
		
		break;
	case SMOOTH_ADJAVE:
		trGetN.npts.Show = true;
		trGetN.boundary.Show = true;
		trGetN.weight.Show  = true;
		/// Cloud 2007-11-8
		trGetN.cutoff.Show = false;
		//trGetN.freq.Show = false;
		//trGetN.fpass.Show = false;
		//trGetN.fstop.Show = false;
		//trGetN.pad.Show = false;
		//trGetN.filter.Show = false;
		//trGetN.baseline.Show = false;
		break;
	/// Cloud 5/29/2007 add fft filter method back
	///Sandy 2006-8-3 REMOVE_FFT_FILTER
	//case SMOOTH_FFTFILTER:
	case method_fft:
		//bShowFFT = true;
		nSliderBegin = 1;
		trGetN.npts.Show = true;
		trGetN.boundary.Show = false;
		//bShowMF = false;
		/// Cloud 2007-11-8
		
		
		trGetN.cutoff.Show = true;
		//trGetN.freq.Show = true;
		//trGetN.fpass.Show = true;
		//trGetN.fstop.Show = true;
		trGetN.weight.Show = false;
		
		//trGetN.pad.Show = true;
		//trGetN.filter.Show = true;
		//trGetN.baseline.Show = true;
		
		break;
	case SMOOTH_MEDIAN_FILTER:
		bShowMF = true;
		trGetN.boundary.Show = true;
		trGetN.weight.Show  = false;
		/// Cloud 2007-11-8
		trGetN.cutoff.Show = false;
		//trGetN.freq.Show = false;
		//trGetN.fpass.Show = false;
		//trGetN.fstop.Show = false;
		
		//trGetN.pad.Show = false;
		//trGetN.filter.Show = false;
		//trGetN.baseline.Show = false;
		
		break;
	}
	
	///Sandy 2007-8-30 Change the begin points to 3
	//nSliderEnd = bRet ? ((vInputY.GetSize()-1)*2 + 1) / 3 : nSliderBegin + 200;
	//nSliderEnd =  ((vInputY.GetSize()-1)*2 + 1) / 3;
	nSliderEnd =  vInputY.GetSize(); //-1;   ///Sandy 2007-11-12 expand the window size = signel size -1
	nSliderEnd = (nSliderEnd>=nSliderBegin? nSliderEnd:nSliderBegin);
	//end
	
	///Sandy 2008-3-5 add to modify the limit for two special methods to replace Cloud's modify
	if (SMOOTH_MEDIAN_FILTER==trGetN.method.nVal || SMOOTH_SG==trGetN.method.nVal)
		if (0 == nSliderEnd%2)
			nSliderEnd--;
	///end
	
	string strSliderBegin, strSliderEnd, strSliderStep;
	strSliderBegin.Format("%d", nSliderBegin);
	strSliderEnd.Format("%d", nSliderEnd);
	strSliderStep.Format("%d", nSliderEnd - nSliderBegin);
	string strComboAttrib = strSliderBegin+ "|" + strSliderEnd + "|" + strSliderStep;
	
	///Sandy 2007-8-30 add checking 
	if(bRet)
	{
		trGetN.npts.Enable = true;
		trGetN.npts.SetAttribute(STR_COMBO_ATTRIB, strComboAttrib);
		if(trGetN.npts.nVal < nSliderBegin)
			trGetN.npts.nVal = nSliderBegin;
		else if(trGetN.npts.nVal > nSliderEnd)
			trGetN.npts.nVal = nSliderEnd;
		//trGetN.npts.nVal = (trGetN.npts.nVal < nSliderBegin) ? nSliderBegin : trGetN.npts.nVal;

		/// Cloud 11/8/07
		//int nSize = vInputX.GetSize();
		//if (nSize<=0)
			//return false;
		
		double freqmax = _compute_max_freq(vInputX);
		if(freqmax<0)
			error_report("Invalid input data!");
		//double dminX, dmaxX;
		//vInputX.GetMinMax(dminX, dmaxX);
		//double freqmax = (nSize-1) / (dmaxX-dminX) / 2;
		/*
		///Sandy 2008-6-13 should use X-Min/Max value when compute maximum of freq
		//double freqmax = (nSize-1) / (vInputX[nSize-1]-vInputX[0]) / 2;
		double dminX, dmaxX;
		vInputX.GetMinMax(dminX, dmaxX);
		double freqmax = (nSize-1) / (dmaxX-dminX) / 2;
		//end 2008-6-13
		
		//string strFreqMax, strFreqStep;
		//strFreqMax.Format("%lf", freqmax);
		//strFreqStep.Format("%d", (nSize-1)/2);
		//string strFreqSlider = "0|" + strFreqMax + "|" + strFreqStep;
		//if (bRet)
		//{
			//trGetN.cutoff.Enable = true;
			//trGetN.cutoff.SetAttribute(STR_ID_ATTRIB, TRGP_SLIDER);
			//trGetN.cutoff.SetAttribute(STR_COMBO_ATTRIB, strFreqSlider);
			//if (trGetN.cutoff.dVal<0)
				//trGetN.cutoff.dVal = 0;
			//if (trGetN.cutoff.dVal>freqmax)
				//trGetN.cutoff.dVal = freqmax;
		//}
		//else
			//trGetN.cutoff.Enable = false;
		*/
		
		
		trGetN.cutoff.dVal = freqmax / trGetN.npts.nVal;
		trGetN.cutoff.Enable = ENABLE_READ_ONLY;
	}
	else
		trGetN.npts.Enable = false;
	
	trGetN.polyorder.Show = bShowSG;
	trGetN.percent.Show = bShowMF;
	return bRet;
}

static void	_run_smooth_on_current_data(TreeNode& trGetN, PageBase& pgTemp, Worksheet& wksTemp)
{
	XYRange xy, xySim;	
	if(!init_preview_graph(trGetN.iy, pgTemp, wksTemp, NULL, &xy, &xySim))
		return;
	int method = trGetN.method.nVal;
	int weight = trGetN.weight.nVal;
	int npts = trGetN.npts.nVal;
	
	///Sandy 2008-3-5 should not modify npts here, we should limit the value on dlg directly
	/*
	/// Cloud 04/03/2007 QA80-9408 ADD_NO_PADDING_CASE_FOR_SMOOTH
	if (SMOOTH_MEDIAN_FILTER==method || SMOOTH_SG==method)
		if (0 == npts%2)
			npts--;
	/// End ADD_NO_PADDING_CASE_FOR_SMOOTH
	*/
	///end of 2008-3-5
	int boundary = trGetN.boundary.nVal;
	int polyorder = trGetN.polyorder.nVal;
	//double alpha = trGetN.alpha.dVal;
	double percent = trGetN.percent.dVal;
	/// Cloud 2007-11-8
	double cutoff = trGetN.cutoff.dVal;
	int pad = trGetN.pad.nVal;
	int filter = trGetN.filter.nVal;
	int baseline = trGetN.baseline.nVal;

	//double fpass = trGetN.fpass.dVal;
	//double fstop = trGetN.fstop.dVal;
	///------ Folger 04/13/09 QA80-13436 TRIGGER_WARNING_MSG_IN_BEFORE_EXECUTE_INSTEAD_OF_XF_BODY
	//s_bShowWarningMsg = false;	///Kyle 02/12/2009 SHOW_WARNING_MESSAGE_IF_INPUT_DATA_IS_NOT_EVEN_SPACED
	///------ End TRIGGER_WARNING_MSG_IN_BEFORE_EXECUTE_INSTEAD_OF_XF_BODY
	try {
		smooth(xy, method, weight, npts, boundary, polyorder, percent, cutoff, pad, filter, baseline, xySim);
		//smooth(xy, method, weight, npts, boundary, polyorder, percent, fpass, fstop, xySim);
	}
	catch(int nErr)
	{
	}
	GraphPage gp = pgTemp;
	
	///------ Folger 04/13/09 QA80-13436 TRIGGER_WARNING_MSG_IN_BEFORE_EXECUTE_INSTEAD_OF_XF_BODY
	//s_bShowWarningMsg = true;	///Kyle 02/12/2009 SHOW_WARNING_MESSAGE_IF_INPUT_DATA_IS_NOT_EVEN_SPACED
	///------ End TRIGGER_WARNING_MSG_IN_BEFORE_EXECUTE_INSTEAD_OF_XF_BODY
}

//---- CPY 07/26/08 QA70-11868 CHANGE_BACK_TO_USE_CRLF_TO_SEP_LN_COMMENT
/*
//------ Folger 07/23/08 BETTER_OPREATION_OUTPUT_COLUMN_COMMENTS
static	void	_set_output_range_comments(XYRange& oy, const XYRange& iy, int nMethod, int npts)
{
	vector<string>	vsMethods = {"Adjacent-Averaging", "Savitzky-Golay", "Percentile Filter", "FFT Filter"};
	string strComment;
	strComment.Format("%d %s %s", npts, _L("points"), _LC(vsMethods[nMethod], "smooth"));
	//oy.SetOutputComment(strComment + "\r\n" + get_input_data_range_string(iy));
	string strCurrentComment = oy.GetOutputComment();
	strCurrentComment += "|" + strComment;
	oy.SetOutputComment(strCurrentComment);
}
//------ End BETTER_OPREATION_OUTPUT_COLUMN_COMMENTS
*/
static	void	_set_output_range_comments(XYRange& oy, const XYRange& iy, int nMethod, int npts)
{
	vector<string>	vsMethods = {"AAv", "SG", "PF", "FFT"};//CPY we should use shorter method name, same as the LT one
	string strComment;
	//I remove _L for methods as the short names for them are
	strComment.Format("%d %s %s smooth of %s", npts, _L("pts"), vsMethods[nMethod], get_input_data_range_string(iy));
	oy.SetOutputComment(strComment);
}
//---- end CHANGE_BACK_TO_USE_CRLF_TO_SEP_LN_COMMENT


void smooth(const XYRange& iy, const int& method, const int& weight, const int& npts, const int& boundary, const int& polyorder, const double& percent, const double& cutoff, const int& pad, const int& filter, const int& baseline, XYRange& oy)
{
	
	waitCursor junk;
	//2006-4-28 add by sandy to keep the layer active(if there is a graph layer)
	DataPlot dpData;
	if(iy.GetPlot(dpData))
	{
		GraphLayer gl;
		dpData.GetParent(gl);
		GraphPage gp = gl.GetPage();
		gp.SetShow();
	}
	//end
	
	vector vInputX;
	vector vInputY;
	// Copy X, Y data from XYRange into vectors
	
	//------ Folger 11/27/08 QA80-12356 v8.0980 MORE_TOOLS_NEED_TO_HANDLE_INPUTS_WITH_MISSING_VALUE
	//if( !iy.GetData(vInputY, vInputX) )
	vector<int>		vnMissingValsIndices;
	if( !iy.GetData(vInputY, vInputX, NULL, 0, DRR_BAD_WEIGHT_TREATMENT, &vnMissingValsIndices) )
	//------ End MORE_TOOLS_NEED_TO_HANDLE_INPUTS_WITH_MISSING_VALUE
		XF_THROW(XFERR_GET_DATA_FAILED);
	
	/// YuI 10/02/08 QA70-12319 SMOOTH_WITH_MISSING_DATA_AT_BEGIN_HAD_RESULTS_SHIFTED
	// in case output X is <input>, we may need to adjust the vector to include some number of missing
	// values at the beginning in order to synchromize X and Y
	int nOutputStartRow = 0;
	if( oy.IsIntersect(iy, "X") )
	{
		vector vInputYWithMissingValues;
		vector vInputXWithMissingValues;
		if( !iy.GetData(vInputYWithMissingValues, vInputXWithMissingValues, NULL, 0, DRR_GET_MISSING | DRR_BAD_WEIGHT_TREATMENT) )
			XF_THROW(XFERR_GET_DATA_FAILED);
		
		Curve cv(vInputXWithMissingValues, vInputYWithMissingValues);
		nOutputStartRow = cv.TrimLeft(TRUE);
	}
	/// end YuI SMOOTH_WITH_MISSING_DATA_AT_BEGIN_HAD_RESULTS_SHIFTED
	
	if(method == SMOOTH_SG)
		if(npts <= polyorder)
			XF_THROW(XFERR_INVALID_NUM_WINPTS);
	///Kyle 02/12/2009 SHOW_WARNING_MESSAGE_IF_INPUT_DATA_IS_NOT_EVEN_SPACED
	// for warning, should check this at last
	double dInterval;
	bool bIsEvenSpaced = true;
	if(method == SMOOTH_SG)
		bIsEvenSpaced = (OE_NOERROR == ocmath_sampling_resolution(vInputX.GetSize(), vInputX, &dInterval));
	///End SHOW_WARNING_MESSAGE_IF_INPUT_DATA_IS_NOT_EVEN_SPACED
	
	
	vector vSmooth;
	vSmooth = vInputY;
	int nSize = vInputY.GetSize();
	/// Cloud 5/29/2007 ADD_FFT_FILTER_METHOD_BACK
	int nRet;
	if (method_fft==method)
	{
		/* Fisher 2008-07-10 QA80-11828 NEW_OPTIONS_FOR_FFT_SMOOTH  
		//double dFreq;
		//double dFc;
		vector vWindow(nSize);
		//dFreq = nSize / (vInputX[nSize-1] - vInputX[0]);
		//dFc = dFreq * percent / 100;
		//dFreq /= nSize;
		/// Cloud 2007-11-8
		//nRet = fft_filter_window(nSize, LOW_PASS_PARABOLIC_FILTERING, vWindow,
			//0, cutoff/200, 1.0/(nSize-1), true);
		//double dFreq = 1.0 / abs(vInputX[nSize-1] - vInputX[0]);
		nRet = fft_filter_window(nSize, LOW_PASS_PARABOLIC_FILTERING, vWindow,
			0, cutoff, 1.0 / abs(vInputX[nSize-1]-vInputX[0]), true);
		if (nRet==OE_NOERROR)
			nRet = fft_fft_filter(nSize, vSmooth, vWindow);
		*/
		int filter_s, baseline_s;
		
		switch(filter)
		{
		case filter_new:
			filter_s = LOW_PASS_PARABOLIC_FILTERING;
			break;
		case filter_old:
			filter_s = LOW_PASS_PARABOLIC_FILTERING_75;
			break;
		default:
			filter_s = LOW_PASS_PARABOLIC_FILTERING;
			break;
		}
		
		switch(baseline)
		{
		case baseline_two_ends:
			baseline_s = BASELINE_TWO_ENDS;
			break;
		case baseline_none:
			baseline_s = BASELINE_NONE;
			break;
		case baseline_two_ends_1:
		default:
			baseline_s = BASELINE_TWO_ENDS_1_PERCENT;
			break;
		}		
		
		fft_smooth(nSize, npts, cutoff, vInputX, vInputY, vSmooth, pad, filter_s, baseline_s);
	}
	/// End ADD_FFT_FILTER_METHOD_BACK
	else
	{
		nRet = ocmath_smooth(nSize, vInputY, vSmooth, npts/2, method, boundary, npts/2, polyorder, 0, percent, weight);	
	}
	
	if(nRet != OE_NOERROR)
		XF_THROW_EX(CER_UNKNOWN_ERROR_EX, nRet);
	// Place results in the newly created output data range
	//--------- CPY 3/2/06 ALLOW_INTERNAL_XY_RANGE_CREATION_FOR_XF
	if(!oy) // user had specified <unassigned> so we will just creat a new wks for it here
	{
		Worksheet wks;
		wks.Create();
		wks.SetSize(-1, 2);
		oy.Create();
		xy_range_from_wks_cols(oy, wks, 0, 1);
	}
	//--------- 
	///Justin 2007-04-24 CHECK_IF_OUTPUT_AND_INPUT_SHARE_x
	//if (!oy.SetData(&vSmooth, &vInputX))
		//XF_THROW(XFERR_FAIL_IN_SET_XYRANGE_DATA);
	
	//Column col;
	//bool bRet = oy.GetXColumn(col);
	//bRet = col.SetLongName("Smoothed X");
	//bRet = oy.GetYColumn(col);
	//bRet = col.SetLongName("Smoothed Y");
	/// YuI 06/12/07 QA70-9913 XYRNAGE_EVEN_SAMPLING_PROPER_SUPPORT
	/*
	bool bXShare = oy.IsIntersect(iy,"X");
	bool bYShare = oy.IsIntersect(iy,"Y");
	vector *pX = &vInputX;
	if(bXShare)
		pX = NULL;
	if (!oy.SetData(&vSmooth, pX))
		XF_THROW(XFERR_FAIL_IN_SET_XYRANGE_DATA);
	*/
	//------ Folger 11/27/08 QA80-12356 v8.0980 MORE_TOOLS_NEED_TO_HANDLE_INPUTS_WITH_MISSING_VALUE
	///// YuI 10/02/08 QA70-12319 SMOOTH_WITH_MISSING_DATA_AT_BEGIN_HAD_RESULTS_SHIFTED
	////	if( !set_xyrange_data_ex(oy, &vSmooth, &vInputX, 0, iy) ) 
	////		XF_THROW(XFERR_FAIL_IN_SET_XYRANGE_DATA);
	//vector* pInputX = &vInputX;
	//vector* pSmooth = &vSmooth;
	//vector vAdjustedX;
	//vector vAdjustedSmooth;
	//if( nOutputStartRow > 0 )
	//{
		//vAdjustedX.SetSize(nOutputStartRow + vInputX.GetSize());
		//vAdjustedX = NANUM;
		//vAdjustedX.SetSubVector(vInputX, nOutputStartRow);
		//
		//vAdjustedSmooth.SetSize(nOutputStartRow + vSmooth.GetSize());
		//vAdjustedSmooth = NANUM;
		//vAdjustedSmooth.SetSubVector(vSmooth, nOutputStartRow);
		//
		//pInputX = &vAdjustedX;
		//pSmooth = &vAdjustedSmooth;
	//}
	
	//if( !set_xyrange_data_ex(oy, pSmooth, pInputX, 0, iy) ) 
		//XF_THROW(XFERR_FAIL_IN_SET_XYRANGE_DATA);
	///// end YuI SMOOTH_WITH_MISSING_DATA_AT_BEGIN_HAD_RESULTS_SHIFTED
	if( !set_xyrange_data_ex(oy, &vSmooth, &vInputX, 0, iy, &vnMissingValsIndices) ) 
		XF_THROW(XFERR_FAIL_IN_SET_XYRANGE_DATA);
	//------ End MORE_TOOLS_NEED_TO_HANDLE_INPUTS_WITH_MISSING_VALUE
	
	/// end XYRNAGE_EVEN_SAMPLING_PROPER_SUPPORT	
	/// YuI 05/02/07 QA80-9715 DEFAULT_NAMES_FOR_XFUNCTION_OUTPUTS
	// naming is moved to the framework
	/*
	Column col;
	if(!bXShare)
	{
		bool bRet = oy.GetXColumn(col);
		bRet = col.SetLongName("Smoothed X");
	}
	if(!bYShare)
	{
		bool bRet = oy.GetYColumn(col);
		bRet = col.SetLongName("Smoothed Y");
	}
	*/
	/// end DEFAULT_NAMES_FOR_XFUNCTION_OUTPUTS
	///END CHECK_IF_OUTPUT_AND_INPUT_SHARE_x
	
	
	
	// If user started from a graph, plot it.
	///Arvin 08/16/07 QA70-10073 KEEP_OUTPUT_CURVE_CUSTOMIZATION_AFTER_RECALCULATE_FOR_XF
	//DataPlot dp = oy.MakePlot(iy);
	//if(dp)
	//{
		//dp.SetColor(1, true);
		//GraphLayer gl;
		//dp.GetParent(gl);
		//legend_update(gl);
	//}
	xf_check_plot_output_rng_in_source_rng_graph(iy, oy);
	///end KEEP_OUTPUT_CURVE_CUSTOMIZATION_AFTER_RECALCULATE_FOR_XF
	
	_set_output_range_comments(oy, iy, method, npts);	//------ Folger 07/23/08 BETTER_OPREATION_OUTPUT_COLUMN_COMMENTS
	
	///------ Folger 04/13/09 QA80-13436 TRIGGER_WARNING_MSG_IN_BEFORE_EXECUTE_INSTEAD_OF_XF_BODY
	/////Kyle 02/12/2009 SHOW_WARNING_MESSAGE_IF_INPUT_DATA_IS_NOT_EVEN_SPACED
	//if(method == SMOOTH_SG && s_bShowWarningMsg && !bIsEvenSpaced)
		//warning_msg_box(XFWAR_NOT_EVEN_SPACE_IN_SG_SMOOTH, false, 'I');
	/////End SHOW_WARNING_MESSAGE_IF_INPUT_DATA_IS_NOT_EVEN_SPACED
	if ( SHOULD_WARNING_MSG_SHOW_IN_XF_BODY && SMOOTH_SG == method && !bIsEvenSpaced )
		warning_msg_box(XFWAR_NOT_EVEN_SPACE_IN_SG_SMOOTH, false, 'I');
	///------ End TRIGGER_WARNING_MSG_IN_BEFORE_EXECUTE_INSTEAD_OF_XF_BODY
	
	
}

//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 smooth_event1(TreeNode& trGetN, int nRow, int nEventID, DWORD& dwEnables, LPCSTR lpcszNodeName, WndContainer& DynaCntrlContainer, string& strAux, string& strErrMsg)
{
	if( xf_is_extended_event(nEventID) )
		return smooth_event1_ex(trGetN, nRow, nEventID, dwEnables, lpcszNodeName, DynaCntrlContainer, strAux, strErrMsg);
	DECLARE_BUTTON_ENABLES
	
	//printf("%s:nRow = %d, nEventID = %d\n", lpcszNodeName, nRow, nEventID);
	///Cheney 2006-10-30 USE_STRERRMESSAGE_TO_REPLACE_BOKENABLE
	//bOKEnable = _update_grid_hide_show(trGetN);
	//if (lstrcmpi(lpcszNodeName, "oy")!=0)	/// Cloud 5/21/2007 need not update preview when change output
		//if(!(bOKEnable = _update_grid_hide_show(trGetN)))
			//strErrMsg = XFERR_GET_DATA_FAILED;
	///end USE_STRERRMESSAGE_TO_REPLACE_BOKENABLE
	//if(TRGP_ENUM_LIST == nEventID)
	//if(nRow == 0)
	//{
		//return true;
	//}
	//
	return false;
	

}

int smooth_make_tree(TreeNode& tr, LPCSTR lpcszVarName)
{
	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 smooth_before_execute(TreeNode& trGetN, int nGetNDialog, int& nRet, int dwCntrl)
{
	
	///Sandy add for auto comput cutoff when script mode.
	if(nGetNDialog == 0)
	{
		XYRange xy;
		bool bRet = xy_range_from_GetN_data_node(trGetN.iy, xy);
	
		vector vInputX, vInputY;
		bRet = xy.GetData(vInputY, vInputX);
			
		double freqmax = _compute_max_freq(vInputX);
		if(freqmax<0)
			error_report("Invalid input data!");
		
		trGetN.cutoff.dVal = freqmax / trGetN.npts.nVal;
	}
	
	//------ fisher 11/16/07 ADD_MAP_ID_TO_CHM
	if(is_use_origin_chm())
		trGetN.SetAttribute(STR_HELPID_ATTRIB, IDD_XF_smooth);
	
	if ( (dwCntrl&LTXF_THEME_USED) && nGetNDialog <= 0 )
	{ 
		int nSize;
		TreeNode trInput= trGetN.iy;
		XYRange xyi;
		string strErrMsg;
		if(!get_error_for_input_xyrange(trInput, strErrMsg, nSize, xyi))
			nRet = XFEVT_PROCEED_WITH_DLG;
			
		if(trGetN.method.nVal == SMOOTH_SG && (trGetN.npts.nVal <= trGetN.polyorder.nVal || 0 >= trGetN.polyorder.nVal))
			nRet = XFEVT_PROCEED_WITH_DLG;
	
		/// Cloud 11/9/07
		//vector vInputX, vInputY;
		//xyi.GetData(vInputX, vInputY);
		//double freqmax = (nSize-1) / (vInputX[nSize-1]-vInputX[0]) / 2;
		//if (trGetN.cutoff.dVal<0)
			//trGetN.cutoff.dVal = 0;
		//if (trGetN.cutoff.dVal>freqmax)
			//trGetN.cutoff.dVal = freqmax;
	}
	/// Cloud 11/7/07 set absolute frequency
	/*
	else
	{
		XYRange xyi;
		bool bRet = xy_range_from_GetN_data_node(trGetN.iy, xyi);
	
		vector vInputX, vInputY;
		bRet = xyi.GetData(vInputY, vInputX);
		if (!bRet)
			nRet = XFEVT_ABORT;
	
		int nSize = vInputX.GetSize();
		double freq = (nSize-1) / (vInputX[nSize-1]-vInputX[0]);
		if (trGetN.freq.dVal==NANUM)
			trGetN.freq.dVal = trGetN.cutoff.dVal * freq * 0.5412 / 100;
		else
		{
			trGetN.cutoff.dVal = trGetN.freq.dVal / freq / 0.5412 * 100;
			if (trGetN.cutoff.dVal < 0)
			{
				trGetN.cutoff.dVal = 0;
				trGetN.freq.dVal = 0;
			}
			if (trGetN.cutoff.dVal > 100)
			{
				trGetN.cutoff.dVal = 100;
				trGetN.freq.dVal = 100 * 0.5412;
			}
		}
	}
	*/
	//XYRange xyi;
	//bool bRet = xy_range_from_GetN_data_node(trGetN.iy, xyi);
	//
	//vector vInputX, vInputY;
	//bRet = xyi.GetData(vInputY, vInputX);
	//if (!bRet)
		//nRet = XFEVT_ABORT;
	//
	//int nSize = vInputX.GetSize();
	//trGetN.fstop.dVal = (nSize-1) / (vInputX[nSize-1]-vInputX[0]) / 2;
	//
	//if(nGetNDialog>-1)
	//{
		//s_bInit = false;
	//}
	///------ Folger 04/13/09 QA80-13436 TRIGGER_WARNING_MSG_IN_BEFORE_EXECUTE_INSTEAD_OF_XF_BODY
	if ( is_xf_startup(nGetNDialog, dwCntrl) )
		SET_WARNING_MSG_SHOW_IN_XF_BODY(IS_ERR_MSG_OK_TO_SHOW_IN_BODY);
	//s_bShowWarningMsg = true;	///Kyle 02/12/2009 SHOW_WARNING_MESSAGE_IF_INPUT_DATA_IS_NOT_EVEN_SPACED
	///------ End TRIGGER_WARNING_MSG_IN_BEFORE_EXECUTE_INSTEAD_OF_XF_BODY
}
//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 smooth_event1_ex(TreeNode& trGetN, int nRow, int nEventID, DWORD& dwEnables, LPCSTR lpcszNodeName, WndContainer& DynaCntrlContainer, string& strAux, string& strErrMsg)
{
	return false;
}


// put your grid initialization here
// you may also initialize wksTemp here
static void GetNGraphPreview_OnInitGrid(TreeNode& trGetN, PageBase& pgTemp, Datasheet& wksTemp,
PictureControl& pict, // optional tab for showing an image or EMF, as requested in OnDialogSetup 
DWORD& dwUpdateGraph,  // default to 0, UPDATE_GRAPH_CHANGED to cause graphs to be updated, UPDATE_GRAPH_INVALID to disable preview button
DWORD& dwUpdateGrid, // default to 0, set to UPDATE_GRID_SIMPLE to update the DynaControl grid, UPDATE_GRID_RESET to reset DynaControl grid
DWORD& dwEnables,// bOKEnable, bBTN1Enable, bBTN2Enable and bBTN3Enable :default to true, can set to false to disable buttons
string& strErrMsg) // optional err msg to be shown on dialog
{
	DECLARE_BUTTON_ENABLES
	DECLARE_UPDATE_GRAPH
	DECLARE_UPDATE_GRID

	
	bUpdateGraph = true;
	int nSize;
	TreeNode trInput= trGetN.iy;
	XYRange xyi;
	
	///Cheney 2006-10-30 USE_STRERRMESSAGE_TO_REPLACE_BOKENABLE
	//bool bOK =_update_grid_hide_show(trGetN);
	/// Cloud 06/27/07 UPDATE_CONTROL_EVEN_IF_OK_IS_DISABLED
	if(!_update_grid_hide_show(trGetN))
	{	
		strErrMsg = XFERR_GET_DATA_FAILED;
		bOKEnable = false;
		//return;
	}
	
 	bOKEnable = get_error_for_input_xyrange(trInput, strErrMsg, nSize, xyi);
	
	///Sandy 2007-8-30 Add checking
	if(bOKEnable)
	{
		if(nSize<3 && trGetN.method.nVal ==	method_sg)
		{
			strErrMsg = XFERR_INPUT_SIZE_TOO_SMALL;
			bOKEnable = false;
			bUpdateGraph = false;
			//return;
		}
	}
	
	///------ Folger 04/13/09 QA80-13436 TRIGGER_WARNING_MSG_IN_BEFORE_EXECUTE_INSTEAD_OF_XF_BODY
	/////Kyle 02/12/2009 SHOW_WARNING_MESSAGE_IF_INPUT_DATA_IS_NOT_EVEN_SPACED
	//// for warning, should check this at last
	//if(bOKEnable && trGetN.method.nVal == method_sg)
	//{
		//XYRange xyTemp;
		//if(xy_range_from_GetN_data_node(trGetN.iy, xyTemp) && xyTemp.IsValid())
		//{
			//double dInterval;
			//vector vx, vy;
			//xyTemp.GetData(vy, vx,NULL, 0, 0);
			//if(OE_NOERROR != ocmath_sampling_resolution(vx.GetSize(), vx, &dInterval))
				///// Max 2/11/09 v8.0977b USE_ANOTHER_STRING_FOR_CENTRALIZATION
				////strErrMsg = CER_DATA_NOT_SUITABLE_FOR_SMOOTH;
				//strErrMsg = XFWAR_NOT_EVEN_SPACE_IN_SG_SMOOTH;
				///// ---
		//}
	//}
	/////End SHOW_WARNING_MESSAGE_IF_INPUT_DATA_IS_NOT_EVEN_SPACED
	if ( bOKEnable && method_sg == trGetN.method.nVal && !_is_input_data_even_space_in_sg_smooth(trGetN) )
		strErrMsg = XFWAR_NOT_EVEN_SPACE_IN_SG_SMOOTH;
	///------ End TRIGGER_WARNING_MSG_IN_BEFORE_EXECUTE_INSTEAD_OF_XF_BODY

	///Kyle 07/28/2009 QA80-14026 FIX_WRONG_LEGEND_FOR_PREVIEW, always init the temp worksheet
	//if(bOKEnable)
	bUpdateGraph = bOKEnable;
	///End FIX_WRONG_LEGEND_FOR_PREVIEW
	{
	/// End UPDATE_CONTROL_EVEN_IF_OK_IS_DISABLED
		///end USE_STRERRMESSAGE_TO_REPLACE_BOKENABLE
		Worksheet wks = wksTemp;
		wks.SetSize(-1, 2);
		wks.SetColDesignations("XY");
		//--- CPY 9/28/06 SMOOTH_XF_COLOR_AND_LABEL_PROBLEM
		wks.Columns(1).SetLongName("Smoothed");
		//---
		//bOKEnable = bOK;  ///Cheney 2006-10-30 USE_STRERRMESSAGE_TO_REPLACE_BOKENABLE

	}

	s_bInit = false;
	s_strErrMsg = strErrMsg;//Sandy 2008-5-22 keep the err message for OnInitGraph;
	
}

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

// pgTemp is the graph for preview or control
// wksTemp is the the temp wks created to hold data to plot into pgTemp
static void GetNGraphPreview_OnInitGraph(TreeNode& trGetN, PageBase& pgTemp, Datasheet& wksTemp,
PictureControl& pict, // optional tab for showing an image or EMF, as requested in OnDialogSetup  
DWORD& dwUpdateGrid, // default to 0, set to UPDATE_GRID_SIMPLE to update the DynaControl grid, UPDATE_GRID_RESET to reset DynaControl grid
DWORD& dwEnables,// bOKEnable, bBTN1Enable, bBTN2Enable and bBTN3Enable :default to true, can set to false to disable buttons
string& strErrMsg) // optional err msg to be shown on dialog
{
	DECLARE_BUTTON_ENABLES
	DECLARE_UPDATE_GRID

	strErrMsg = s_strErrMsg; 
	///Jasmine 08/13/2010 ORG-172-S2 CENTRALIZE_NOCLICK_BIT_FOR_PREVIEW_IN_OC_TOOL
	//GraphPage gp = pgTemp;
	//page_load(gp, "NonePreview"); 	
	//
	//load_text_for_nonepreview_graphpage(gp, TEMPLATE_NONE_PREVIEW_CONTENT, TEMPLATE_NONE_PREVIEW_HINTS);
	xf_load_nopreview(pgTemp);
	///End CENTRALIZE_NOCLICK_BIT_FOR_PREVIEW_IN_OC_TOOL
	
}

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

static void GetNGraphPreview_OnUpdateGraph(TreeNode& trGetN, PageBase& pgTemp, Datasheet& wksTemp, PictureControl& pict)
{
	Worksheet wks = wksTemp;
	if(!s_bInit)
	{
		Worksheet wks = wksTemp;
		wks.SetSize(0,-1, true);
		//--- CPY 12/19/08 USE_SHARED_TEMPLATE_FOR_ALL_PREVIEW_XF
		//init_preview_graph(trGetN.iy, pgTemp, wks, "SmoothLine");
		///Kyle 03/13/2009 QA80-13260-S1 ADD_OPTION_TO_COPY_FORMAT_FROM_SOURCE_LAYER
		//init_preview_graph(trGetN.iy, pgTemp, wks, "CurvePreview");
		init_preview_graph(trGetN.iy, pgTemp, wks, "CurvePreview", NULL, NULL, 0, 0, 1, PREVIEW_LAYER_FORMAT_SCALE_TYPE);
		///End ADD_OPTION_TO_COPY_FORMAT_FROM_SOURCE_LAYER
		//---
		GraphPage gp = pgTemp;
		gp.Refresh(true);
		s_bInit = true;
	}

	_run_smooth_on_current_data(trGetN, pgTemp, wks);

}

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

static void GetNGraphPreview_OnChange(TreeNode& trGetN, TreeNode& trNode, PageBase& pgTemp, Datasheet& wksTemp,
PictureControl& pict, // optional tab for showing an image or EMF that might be present, as requested in OnDialogSetup  
bool bChangedByGraph, // called when graph has been modified by user, like dragging a vertical line
DWORD& dwUpdateGraph,  // default to 0, UPDATE_GRAPH_CHANGED to cause graphs to be updated, UPDATE_GRAPH_INVALID to disable preview button
DWORD& dwUpdateGrid,  // default to 0, set to UPDATE_GRID_SIMPLE to update the DynaControl grid, UPDATE_GRID_RESET to reset DynaControl grid
DWORD& dwEnables,	// bOKEnable, bBTN1Enable, bBTN2Enable and bBTN3Enable :default to true, can set to false to disable buttons
string& strErrMsg) // optional err msg to be shown on dialog
{
	DECLARE_BUTTON_ENABLES
	DECLARE_UPDATE_GRAPH
	DECLARE_UPDATE_GRID
	int nSize;
	TreeNode trInput= trGetN.iy;
	XYRange xyi;

	/// Cloud 5/21/2007 need not update preview when change output
	/// Cloud 7/18/2007 FIX_BUG_OF_CHANGE_THEME
	//if (trNode.tagName!="oy")

	///Sandy 2007-8-7 should not update preview when trNode == NULL
	//if (trNode  trNode.tagName!="oy")
	/// End FIX_BUG_OF_CHANGE_THEME


	bOKEnable = get_error_for_input_xyrange(trInput, strErrMsg, nSize, xyi);
	
	///Sandy 2007-8-30 Add checking
	if(nSize<3 && trGetN.method.nVal ==	method_sg)
	{
		strErrMsg = XFERR_INPUT_SIZE_TOO_SMALL;
		bOKEnable = false;
		bUpdateGraph = false;
	}	
	
	if (trNode && (trNode.tagName =="iy"))
	{
		s_bInit = false;
	}
	
	/// Cloud 11/07/07 set absolute frequency
	/*
	if (trNode && ((trNode.tagName=="cutoff") || (trNode.tagName=="freq")))
	{
		vector vInputX, vInputY;
		xyi.GetData(vInputY, vInputX);
		int nSize = vInputX.GetSize();
		double freq = (nSize-1) / (vInputX[nSize-1]-vInputX[0]);
		if (trNode.tagName=="cutoff")
			trGetN.freq.dVal = trGetN.cutoff.dVal * freq * 0.5412 / 100;
		else
		{
			trGetN.cutoff.dVal = trGetN.freq.dVal / freq / 0.5412 * 100;
			if (trGetN.cutoff.dVal<0)
			{
				trGetN.cutoff.dVal = 0;
				trGetN.freq.dVal = 0;
			}
			if (trGetN.cutoff.dVal>100)
			{
				trGetN.cutoff.dVal = 100;
				trGetN.freq.dVal = freq * 0.5412;
			}
		}
	}
	*/
	///------ Folger 07/07/09 IMPROVE_ERROR_CHECKING_OF_SMOOTH_ON_CHANGE
	//if (!trNode || (trNode && (trNode.tagName!="oy") && (trNode.tagName !="AutoUpdate")))
	///------ End IMPROVE_ERROR_CHECKING_OF_SMOOTH_ON_CHANGE
	{
		/// Cloud 06/27/07 UPDATE_CONTROL_EVEN_IF_OK_IS_DISABLED
		//if (!trNode)
		//{
			//vector vInputX, vInputY;
			//xyi.GetData(vInputY, vInputX);
			//int nSize = vInputX.GetSize();
			//double freq = (nSize-1) / (vInputX[nSize-1]-vInputX[0]);
			//trGetN.freq.dVal = trGetN.cutoff.dVal * freq * 0.5412 / 100;
		//}

		if(!_update_grid_hide_show(trGetN))
		{	
			strErrMsg = XFERR_GET_DATA_FAILED;
			bOKEnable = false;
		}
		if(bOKEnable)
		{
			///Cheney 2006-10-30 USE_STRERRMESSAGE_TO_REPLACE_BOKENABLE
			//bOKEnable = _update_grid_hide_show(trGetN);
			//if(!(bOKEnable = _update_grid_hide_show(trGetN)))
				//strErrMsg = XFERR_GET_DATA_FAILED;
			///end USE_STRERRMESSAGE_TO_REPLACE_BOKENABLE
		/// End UPDATE_CONTROL_EVEN_IF_OK_IS_DISABLED
			bUpdateGraph = true;
			bUpdateGrid = true;		
		}
		
		if(	(trGetN.method.nVal == SMOOTH_SG) && (trGetN.npts.nVal <= trGetN.polyorder.nVal || 0 >= trGetN.polyorder.nVal))
		{
			strErrMsg = XFERR_INVALID_NUM_WINPTS;
			bUpdateGraph = false;
			bUpdateGrid = true;	
			bOKEnable = false;
		}
		
	}
	
	///------ Folger 04/13/09 QA80-13436 TRIGGER_WARNING_MSG_IN_BEFORE_EXECUTE_INSTEAD_OF_XF_BODY
	/////Kyle 02/12/2009 SHOW_WARNING_MESSAGE_IF_INPUT_DATA_IS_NOT_EVEN_SPACED
	//// for warning, should check this at last
	//if(bOKEnable && trGetN.method.nVal == method_sg)
	//{
		//XYRange xyTemp;
		//if(xy_range_from_GetN_data_node(trGetN.iy, xyTemp) && xyTemp.IsValid())
		//{
			//double dInterval;
			//vector vx, vy;
			//xyTemp.GetData(vy, vx,NULL, 0, 0);
			//if(OE_NOERROR != ocmath_sampling_resolution(vx.GetSize(), vx, &dInterval))
				///// Max 2/11/09 v8.0977b USE_ANOTHER_STRING_FOR_CENTRALIZATION
				////strErrMsg = CER_DATA_NOT_SUITABLE_FOR_SMOOTH;
				//strErrMsg = XFWAR_NOT_EVEN_SPACE_IN_SG_SMOOTH;
				///// ---
		//}
	//}
	/////End SHOW_WARNING_MESSAGE_IF_INPUT_DATA_IS_NOT_EVEN_SPACED
	if ( bOKEnable && method_sg == trGetN.method.nVal && !_is_input_data_even_space_in_sg_smooth(trGetN) )
		strErrMsg = XFWAR_NOT_EVEN_SPACE_IN_SG_SMOOTH;
	///------ End TRIGGER_WARNING_MSG_IN_BEFORE_EXECUTE_INSTEAD_OF_XF_BODY
	

	if(!bOKEnable)
		dwUpdateGraph = UPDATE_GRAPH_INVALID; //nUpdateGraph = UPDATE_GRAPH_ERROR;
	else
		bUpdateGraph = bOKEnable;

}

// called from OnInitDialog to allow options on setting up of dialog
// dwOptions = 0 (default) will create a line graph with data in a temp worksheet
// dwOptions = XFGSETUP_IMAGEGRAPH_CNTRL to create an image graph with data in a temp matrix book
// dwOptions = XFGSETUP_MATRIX_CNTRL to have a MatrixControl with data in a temp matrix book
// dwOptions = XFGSETUP_2_TABS | XFGSETUP_EMF_1ST to have a PictureControl on 1st tab and a GraphControl on 2nd tab
// vsTabTitles is empty on entering the event, but you can put tab title strings in this array.
static void GetNGraphPreview_OnDialogSetup(TreeNode& trGetN, WndContainer& theDlg, DWORD& dwOptions, vector<string>& vsTabTitles)
{

}

// called when dialog is being destroyed, either as OK button or as Cancel button being pressed
static void GetNGraphPreview_OnDestroy(TreeNode& trGetN, PageBase& pgTemp, Datasheet& wksTemp, PictureControl& pict)
{

}
//------------
//
static void GetNGraphPreview_OnCustomButton(TreeNode& trGetN, int nButton, PageBase& pgTemp, Datasheet& wksTemp,
PictureControl& pict, // optional tab for showing an image or EMF that might be present, as requested in OnDialogSetup  
bool bChangedByGraph, // called when graph has been modified by user, like dragging a vertical line
DWORD& dwUpdateGraph,  // default to 0, UPDATE_GRAPH_CHANGED to cause graphs to be updated, UPDATE_GRAPH_INVALID to disable preview button
DWORD& dwUpdateGrid,  // default to 0, set to UPDATE_GRID_SIMPLE to update the DynaControl grid, UPDATE_GRID_RESET to reset DynaControl grid
DWORD& dwEnables,	// bOKEnable, bBTN1Enable, bBTN2Enable and bBTN3Enable :default to true, can set to false to disable buttons
string& strErrMsg) // optional err msg to be shown on dialog
{
	DECLARE_BUTTON_ENABLES
	DECLARE_UPDATE_GRAPH
	DECLARE_UPDATE_GRID

}
//


///////////////////////////////////////////////////////
	
int GetNGraphBox_smooth(TreeNode& trGetN, int nRow, int nCol, TreeNode& trNode, DWORD dwCntrl, int nType, WndContainer& theDlg, PageBase& pgTemp, Datasheet& wksTemp, PictureControl& pict)
{
	return xf_GetNPreviewDlg_event_handler(trGetN, nRow, nCol, trNode, dwCntrl, nType, theDlg, pgTemp, wksTemp, pict,
	GetNGraphPreview_OnInitGrid, GetNGraphPreview_OnInitGraph,
	GetNGraphPreview_OnChange, GetNGraphPreview_OnUpdateGraph, GetNGraphPreview_OnDialogSetup, GetNGraphPreview_OnDestroy,
	GetNGraphPreview_OnCustomButton);	
}


//This file is the template for GetNEvent4

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

