#include <origin.h>
#include <GetNBox.h>
#include <xfutils.h>
enum{
	filter_low,
	filter_high,
	filter_bandpass,
	filter_bandblock,
	filter_threshold,
	filter_lowpp,
};


static bool s_bInit = false;
static bool s_bChangeParam = false;
static string s_strErrMsg = "";

#include <xfbase.h> // for calling another XF, see add_axis_scroller
#include <event_utils.h> ///justin 10/30/2006 JUST_RECACULATE_WHEN_NECESSARY

//put additional include files here
#include <GetNBox.h>
#include <fft_utils.h>
#include <o8dlg.h>

///sandy 2007-3-8 add
#include <..\originlab\grobj_utils.h>

////////////////////////
// modification log
// CPY 11/14/06 ON_CHANGE_EVENT_SHOULD_NOT_REINIT_PREVIEW
// CPY 11/14/06 ON_MOVE_LINE_SHOULD_NOT_RESCALE_GRAPH
// CPY 6/13/08 FFT_FILTER_EXAMPLE_SAME_AS_75_NEED_SIMPLER_INTERFACE
// Folger 07/23/08 BETTER_OPREATION_OUTPUT_COLUMN_COMMENTS
// CPY 7/27/08 QA70-11868 CHANGE_BACK_TO_USE_CRLF_TO_SEP_LN_COMMENT
// CPY 10/18/08 QA70-12373 FFT_FILTER_PREVIEW_X_INC_MESS
/// Folger 04/10/09 QA80-12356 FFT_FILTERS_OUTPUT_FAILS_TO_KEEP_MISSING_VALUES_POSITION_AS_INPUT
/// Folger 04/14/09 QA80-13436 IMPROVE_MECHANISM_ABOUT_XF_ERR_MSG_SHOWN_IN_BODY
/// Folger 04/17/09 QA80-13429 RECREATE_X_DATA_FOR_NOT_EVEN_SPACE_INPUT_X
/// Kyle 07/28/2009 QA80-14026 FIX_WRONG_LEGEND_FOR_PREVIEW
/// CPY QA70-14088 FFT_FILTER_PREVIEW_RESCALE_TRIANGLE_ADDED_FOR_TOP_LEFT_GRAPH
/// CPY 8/20/09 QA70-14088-P3 INIFINITE_REFRESH_DUE_TO_TRIANGLE_MOVE_FOLLOWED_BY_LINE_MOVE
///	Jasmine 08/13/2010 ORG-172-S2 CENTRALIZE_NOCLICK_BIT_FOR_PREVIEW_IN_OC_TOOL

///------ Folger 04/14/09 QA80-13436 IMPROVE_MECHANISM_ABOUT_XF_ERR_MSG_SHOWN_IN_BODY
IMPLEMENT_SHOULD_WARNING_MSG_SHOW_IN_XF_BODY
///------ End IMPROVE_MECHANISM_ABOUT_XF_ERR_MSG_SHOWN_IN_BODY

#define STR_DATA_DISP_FORMAT		"*4*"
//---- CPY 10/25/06 
#define _DBM(_str)				//out_str(_str)
#define _DBM1(_fmt, _x1)		//printf(_fmt, _x1);
#define _DBM2(_fmt, _x1, _x2)	//printf(_fmt, _x1, _x2);
//----

//defined in FFTFilters.cpp, reuse
//enum
//{
	//filter_low		= 0,
	//filter_high,
	//filter_bandpass,
	//filter_bandblock,
	//filter_threshold,
//};

static void _update_tree_shown(TreeNode& tr)
{
	int nType = tr.filter.nVal;
	
	TreeNode trLow = tr.freq1;
	TreeNode trHigh = tr.freq2;
	TreeNode trCutOff = tr.cutoff;
	TreeNode trPass = tr.pass;
	TreeNode trStop = tr.stop;
	TreeNode trThresHold = tr.threshold;
	TreeNode trOffset = tr.offset;
	
	switch(nType)
	{
	case filter_low:			//	low-pass filtering;
		trLow.Show = false;
		trHigh.Show = false;
		trCutOff.Show = true;
		trPass.Show = false;
		trStop.Show = false;
		trThresHold.Show = false;
		trOffset.Enable = false;
		break;
	case filter_high:			//	high-pass filtering;
		trLow.Show = false;
		trHigh.Show = false;
		trCutOff.Show = true;
		trPass.Show = false;
		trStop.Show = false;
		trThresHold.Show = false;
		trOffset.Enable = true;
		break;
	case filter_bandpass:			//	band-pass filtering;
		trLow.Show = true;
		trHigh.Show = true;
		trCutOff.Show = false;
		trPass.Show = false;
		trStop.Show = false;
		trThresHold.Show = false;
		trOffset.Enable = true;
		break;
	case filter_bandblock:			//	band-block filtering;
		trLow.Show = true;
		trHigh.Show = true;
		trCutOff.Show = false;
		trPass.Show = false;
		trStop.Show = false;
		trThresHold.Show = false;
		trOffset.Enable = true;
		break;
	case filter_threshold:			//	threshold filtering
		trLow.Show = false;
		trHigh.Show = false;
		trCutOff.Show = false;
		trPass.Show = false;
		trStop.Show = false;
		trThresHold.Show = true;
		trOffset.Enable = false;
		break;
	case filter_lowpp:			//	low-pass parabolic filtering
		trLow.Show = false;
		trHigh.Show = false;
		trCutOff.Show = false;
		trPass.Show = true;
		trStop.Show = true;
		trThresHold.Show = false;
		trOffset.Enable = false;
		break;
	default:
		break;
	}
}

static void _update_graph_object_shown(TreeNode& tr, GraphLayer& gl)
{
	GraphObject goTop = gl.GraphObjects("top");
	GraphObject goLeft = gl.GraphObjects("left");
	GraphObject goRight = gl.GraphObjects("right");
	
	int nType = tr.filter.nVal;
	switch(nType)
	{
	case filter_low:			//	low-pass filtering;
	case filter_high:			//	high-pass filtering;
		goTop.Show = false;
		goLeft.Show = true;
		goRight.Show = false;
		break;
	case filter_bandpass:			//	band-pass filtering;
	case filter_bandblock:			//	band-block filtering;
	case filter_lowpp:			//	low-pass parabolic filtering
		goTop.Show = false;
		goLeft.Show = true;
		goRight.Show = true;
		break;
	case filter_threshold:			//	threshold filtering
		goTop.Show = true;
		goLeft.Show = false;
		goRight.Show = false;
		break;
	default:
		break;
	}
}

//----- CPY 11/14/06 ON_CHANGE_EVENT_SHOULD_NOT_REINIT_PREVIEW
// centralizd err checking code into this function, moved Sandy's code inside

///Sandy 2007-8-28 Rename
//static bool _check_GUI_params(TreeNode& trGetN, string& strErrMsg)
static bool _check_input(TreeNode& trGetN, string& strErrMsg, double& dXMin=NULL, double& dXMax=NULL, double& dYMin=NULL, double& dYMax=NULL)
{
	XYRange xyIn;
	//add by sandy 2006-11-9
	int nSize;
	TreeNode trInput= trGetN.iy;
	bool bRet;
	
	bRet = get_error_for_input_xyrange(trInput, strErrMsg, nSize, xyIn);
	if(bRet == false)
	{
		return false;
	}
	//end
	
	vector vecX, vecY;
	
	/////Sandy 2008-8-11 get all data including missing
	//xyIn.GetData(vecY, vecX);
	int nIndex = 0;
    vector vErr;
	xyIn.GetData(vecY, vecX, &vErr, nIndex,  DRR_GET_MISSING);
	if(vecY.GetSize() == 0)
	{
		//XF_THROW(XFERR_GET_DATA_FAILED);
		strErrMsg = XFERR_GET_DATA_FAILED;
		return false;
	}
	
	///Sandy 2008-8-11 prevent missing in y data
	int nMissing = ocmath_count(NANUM, nSize, vecY);
	if(nMissing != 0 )
	{
		//strErrMsg = XFWAR_MISSING_IN_INPUT;
		strErrMsg = CER_HAS_MISSING_VALUE;
		return false;
	}
	
	if(dXMin!=NULL && dXMax!=NULL && dYMin!=NULL && dYMax!=NULL)
	{
		//if(!_get_fft_range_amp_of_input(vecX, vecY))
		if(!_get_fft_range_amp_of_input(vecX, vecY, strErrMsg))//Sandy 2008-6-13 add error message
			return false;
		
		vecX.GetMinMax(dXMin, dXMax);
		vecY.GetMinMax(dYMin, dYMax);
	}
	
	return true;
}
//-----


//static void _init_filter_graph(TreeNode& trGetN, PageBase& pgTemp, Datasheet& wksTemp)
//static bool _init_filter_graph(TreeNode& trGetN, PageBase& pgTemp, Datasheet& wksTemp, string& strErrMsg)
static bool _init_filter_graph(TreeNode& trGetN, PageBase& pgTemp, Datasheet& wksTemp)
{
	Worksheet wks = wksTemp;
	XYRange xyIn, xyPrew;
	// 1 = 2nd layer, which will automatically check to see if there is a 3rd layer and move data plots from 2nd to 3rd as well
	// it will also run gr script upon rescale to also update 3rd layer scale.
	init_preview_graph(trGetN.iy, pgTemp, wks, "FFTFilterCntrl", &xyIn, &xyPrew, 1, SYSCOLOR_GRAY, SYSCOLOR_LTMAGENTA);

	GraphPage gp = pgTemp;
	if(!gp)
		return false;
	
	GraphLayer gl = gp.Layers(0);
	XFBase xf("axis_scroller");
	if( xf )
	{
		xf.SetArg(0, gl);
		//--- CPY QA70-14088 FFT_FILTER_PREVIEW_RESCALE_TRIANGLE_ADDED_FOR_TOP_LEFT_GRAPH
		double ss=1.5;
		xf.SetArg("ysize", ss);
		//---
		xf.Evaluate();
		
		//--- CPY QA70-14088 FFT_FILTER_PREVIEW_RESCALE_TRIANGLE_ADDED_FOR_TOP_LEFT_GRAPH
		GraphLayer gl2 = gp.Layers(1);
		xf.SetArg(0, gl2);
		int nTop = 1;
		xf.SetArg(1, nTop);
		ss = 2;
		xf.SetArg(2, ss);
		xf.Evaluate();
		//----
	}
	else
		XF_WARN(XFERR_AXIS_SCROLLER_NOT_FOUND);

	//out_str("_init_filter_graph");

	///Sandy 2007-8-28 Move the checking to _check_input()
	vector vecX, vecY;
	xyIn.GetData(vecY, vecX);
	
	_update_graph_object_shown(trGetN, gl);
	

	///Sandy 2008-6-13 add error checking
	//_control_graph(trGetN, vecX, vecY, gl, wks, true);
	if(!_control_graph(trGetN, vecX, vecY, gl, wks, true))
		return false;
	
	return true;
}
			
/*
static bool _get_data_from_range(XYRange& dr, Dataset& dsDataX, Dataset& dsDataY)
{
	if(!dr.IsValid())
		return -1;
	
	Worksheet wks;
	int r1, r2, cx, c2, cy;
	string strRange = "X";
	dr.GetRange(strRange, r1, cx, r2, c2, wks);
	strRange = "Y";
	dr.GetRange(strRange, r1, cy, r2, c2, wks);
	
	dsDataX.Attach(wks, cx);
	dsDataY.Attach(wks, cy);
	
	return true;
}*/
static void _set_frequency(TreeNode& tr, double dLow, double dHigh, double dThreshold)
{
	TreeNode trLow = tr.freq1;
	TreeNode trHigh = tr.freq2;
	TreeNode trCutOff = tr.cutoff;
	TreeNode trThresHold = tr.threshold;
	/// Cloud 11/9/07 add lowpass parabolic filter
	TreeNode trPass = tr.pass;
	TreeNode trStop = tr.stop;
	
	//trLow.strVal = ftoa(dLow, STR_DATA_DISP_FORMAT);
	//trHigh.strVal = ftoa(dHigh, STR_DATA_DISP_FORMAT);
	//trCutOff.strVal = ftoa(dLow, STR_DATA_DISP_FORMAT);
	//trThresHold.strVal = ftoa(dThreshold, STR_DATA_DISP_FORMAT);
	//trPass.strVal = ftoa(dLow, STR_DATA_DISP_FORMAT);
	//trStop.strVal = ftoa(dHigh, STR_DATA_DISP_FORMAT);
	
	trLow.dVal = dLow;//ftoa(dLow, STR_DATA_DISP_FORMAT);
	trHigh.dVal =dHigh;// ftoa(dHigh, STR_DATA_DISP_FORMAT);
	trCutOff.dVal = dLow;//ftoa(dLow, STR_DATA_DISP_FORMAT);
	trThresHold.dVal = dThreshold;//ftoa(dThreshold, STR_DATA_DISP_FORMAT);
	trPass.dVal = dLow;//ftoa(dLow, STR_DATA_DISP_FORMAT);
	trStop.dVal = dHigh;//ftoa(dHigh, STR_DATA_DISP_FORMAT);
}
//----- CPY 11/14/06 ON_MOVE_LINE_SHOULD_NOT_RESCALE_GRAPH
// we should try not to change obj xy if not needed
static bool _check_range(double v, double v1, double v2)
//static bool _check_range(double v, double v1, double v2, double& vNew)
{
	//if(v < v1) {vNew = v1; return true;}
	//if(v > v2) {vNew = v2; return true;}
	//return false;
	
	if(v < v1) return false;
	if(v > v2) return false;
	
	return true;
}
//-----
//bSetTree = true to update grid tree, false = update graph lines
//----- CPY 11/14/06 ON_MOVE_LINE_SHOULD_NOT_RESCALE_GRAPH, added bCheckRange, should call this only when init first time
static bool _graph_lines_and_tree_update(GraphLayer& gl, TreeNode& trGetN, bool bSetTree, bool bCheckRange = false)
{
	GraphObject goTop = gl.GraphObjects("top");
	GraphObject goLeft = gl.GraphObjects("left");
	GraphObject goRight = gl.GraphObjects("right");
	
	//----- CPY 8/20/09 QA70-14088-P3 INIFINITE_REFRESH_DUE_TO_TRIANGLE_MOVE_FOLLOWED_BY_LINE_MOVE
	LTVarTempChange __junk("@GOS", 1);// disable event trigger when setting obj position, which will lead to reentrance due to PostMessage
	//-----
	
	int nType = trGetN.filter.nVal;
	if(nType != filter_low && nType != filter_high)//add by sandy 2008-2-20 only two line-controls need compare and interchange
	{
		///Sandy 2006-11-22 move from upward, since always need to exchange the low and high freq value
		if(goLeft.X > goRight.X)
		{
			double temp = goLeft.X;
			goLeft.X = goRight.X;
			goRight.X = temp;
		}
	}
	
	///Sandy 2006-11-22 add for check the frequency always should be larger than zero
	if(goLeft.X < 0) goLeft.X = 0;
	if(goRight.X < 0) goRight.X = 0;
	//if(goTop.Y < 0) goTop.Y = 0;

	///Sandy 2007-8-8 
	//if(bSetTree)
	if(bSetTree)// check range = init
	{
		double dTop = goTop.Y, dMin=goLeft.X, dMax=goRight.X;
		
		if(bCheckRange)
		{
			if(!_check_range(goLeft.X, gl.X.From, gl.X.To))
			{
				double dLow;
				dLow =  (gl.X.To - gl.X.From)/4.0 + gl.X.From;
				goLeft.X = dLow;
				move_span_vline(goLeft, dLow);	
			}
			if(!_check_range(goRight.X, gl.X.From, gl.X.To))
			{
				double dHight;
				dHight =  (gl.X.To - gl.X.From)/4.0*3 + gl.X.From;
				goRight.X = dHight;
				move_span_vline(goRight, dHight);
			}
			if(!_check_range(goTop.Y, gl.Y.From, gl.Y.To))
			{
				double dThres;
				dThres = (gl.Y.To - gl.Y.From)/10.0 + gl.Y.From;
				goTop.Y = dThres;
			}
		}	
		
		//_set_frequency(trGetN, dMin, dMax, dTop);
		_set_frequency(trGetN, dMin, dMax, dTop);
		_DBM2("setting tree, low = %g, hight = %g\n", dMin, dMax)
		

	}
	else 
	{
		//goTop.Y = trGetN.threshold.dVal;
		/// Cloud 11/9/07 add lowpass palabolic filter
		//double dLow = trGetN.cutoff.Show ? trGetN.cutoff.dVal : trGetN.freq1.dVal;
		//double dHigh = trGetN.freq2.dVal;
		double dLow, dHigh;
		switch (trGetN.filter.nVal)
		{
		case filter_low:
		case filter_high:
			dLow = trGetN.cutoff.dVal;
			break;
		case filter_bandpass:
		case filter_bandblock:
			dLow = trGetN.freq1.dVal;
			dHigh = trGetN.freq2.dVal;
			break;
		case filter_lowpp:
			dLow = trGetN.pass.dVal;
			dHigh = trGetN.stop.dVal;
			break;
		default:
			break;
		}
		double dThres = trGetN.threshold.dVal;
		

		if(bCheckRange)
		{
			if(!_check_range(dLow, gl.X.From, gl.X.To))
			{
				dLow =  (gl.X.To - gl.X.From)/4.0 + gl.X.From;
				trGetN.cutoff.dVal = trGetN.freq1.dVal = dLow;
			}
			if(!_check_range(dHigh, gl.X.From, gl.X.To))
			{
				dHigh =  (gl.X.To - gl.X.From)/4.0*3 + gl.X.From;
				trGetN.freq2.dVal = dHigh;
			}
			if(!_check_range(dThres, gl.Y.From, gl.Y.To))
			{
				
				dThres = (gl.Y.To - gl.Y.From)/10.0 + gl.Y.From;
				trGetN.threshold.dVal = dThres;
			}
		}
			
		//Sandy move line by utility function
		//goLeft.X= dLow;
		//goRight.X= dHigh;
		move_span_vline(goLeft, dLow);
		move_span_vline(goRight, dHigh);
		goTop.Y = dThres;
		
		///Sandy 2006-11-22 for test the GraphObject postion problem
		//double dd = goLeft.X;	
		//end 
		_DBM2("setting line in graph, low = %g, hight = %g\n", dLow, dHigh)
	}
	//----- CPY 11/14/06 ON_MOVE_LINE_SHOULD_NOT_RESCALE_GRAPH
	//gl.Rescale();
	//-----			
	return true;
}

///Sandy 2008-6-13 add error message return 
//static bool _get_fft_range_amp_of_input(vector& vecX, vector& vecY)
static bool _get_fft_range_amp_of_input(vector& vecX, vector& vecY, string& strErrMsg =NULL)
{	
	int nSize = vecY.GetSize();
	if(nSize < 2) return error_report("vecX size < 2");
	double dXStep;
	int nRet = fft_sampling_resolution(&vecX, dXStep);
	
	///Sandy 2008-6-13  add error checking for uneven spaced signal
	//if( nRet > 0 )	
		//return false;
		
	//Sandy 2009-4-9 QA80-13429 JUST_WARNNING_WHEN_UNEVEN_INTERVAL
	//if( dXStep <= 0 || dXStep == NANUM || nRet == OE_NOT_SPACED_EQUALLY)
	//{
		//if(strErrMsg)
			//strErrMsg = XF_ERR_INVALID_FFT_INTERVAL;
		//
		//return false;
	//}
	if(nRet == OE_NOT_SPACED_EQUALLY && strErrMsg)
		strErrMsg = XFWAR_TIME_SEQ_INVALID;	
		
	if(dXStep < 0)
		dXStep *= -1;
		
    if(dXStep == NANUM || dXStep == 0)
    {
		if(strErrMsg)
			strErrMsg = XF_ERR_INVALID_FFT_INTERVAL;
		return false;
    }
	//end  JUST_WARNNING_WHEN_UNEVEN_INTERVAL

	///end  make error checking perfect
	
	double dFreMax = 1/(2*dXStep);
	double dStep = dFreMax/(nSize/2);

	
	vecX.Data(0, dFreMax, dStep);

	fft_real(nSize, vecY);

	vector<complex> vResult(nSize);
	fft_hermitian_to_complex(nSize, vecY, vResult);
	vector vecAmp(nSize);
	vResult.GetAmplitude(vecAmp);
	vecY = vecAmp;
	
	return true;
}

static bool _control_graph(TreeNode& tr, vector& vecX, vector& vecY, GraphLayer& gl, Worksheet& wksdata, bool bInit = false)
{
	int nColX = 2;
	int nColY = 3;
	if(bInit)
	{
		
		///Sandy 2007-6-22 for clear data and reuse when changing iy
		//if(wksdata.GetNumCols() < nColY+1)
		//	wksdata.SetSize(-1, nColY+1); // we will use col 1,2 for preview data and col 3,4 for control spectrum
		wksdata.SetSize(-1, nColY+1, true);
		
		wksdata.Columns(nColX).SetType(OKDATAOBJ_DESIGNATION_X);
		wksdata.Columns(nColY).SetType(OKDATAOBJ_DESIGNATION_Y);
	}
	
	Dataset dsX(wksdata, nColX), dsY(wksdata, nColY);
	
	///Sandy 2007-8-30 centeralize code
	if(!_get_fft_range_amp_of_input(vecX, vecY))
		return false;
	///end of centeralize code
	dsX = vecX;
	dsY = vecY;
	
	//Curve cur(dsY.GetName());
	if(bInit)
	{
		Curve cur(wksdata, nColX, nColY);
		int nn = gl.AddPlot(cur, IDM_PLOT_LINE);
	}
	//init tree by data
	double dYMin, dYMax, dXMin, dXMax;
	
	//Sandy 2006-7-25 DEBUG
	//vecFre.GetMinMax(dYMin, dYMax);
	vecY.GetMinMax(dYMin, dYMax);
	vecX.GetMinMax(dXMin, dXMax);
	//--- CPY 8/8/06 INIT_LINE_POSITION_NOT_EFFECTIVE_FIX
	if(!bInit)
		return true;
	
	Scale xaxis(gl.X);
	xaxis.From = dXMin;
	xaxis.To = dXMax;
	//---- CPY 10/18/08 QA70-12373 FFT_FILTER_PREVIEW_X_INC_MESS
	//xaxis.Inc = (dXMax-dXMin)/10;  ///Sandy 2008-2-20 displace sticks
	xaxis.Inc = 0;// to force internal recalculate nice inc
	//----
	Scale yaxis(gl.Y);
	//since Y is log scale, we have to limit to 10 decades
	if(dYMin < dYMax * 1E-10)
		dYMin = dYMax * 1E-10;
	yaxis.From = dYMin;
	yaxis.To = dYMax;
	//--------	

	///sandy 2009-4-14 Fix when change parameters the line controls in back to default position
	bool bNeedCheckGLRange = !s_bChangeParam && bInit;
	///Sandy 2007-8-8 should update lines after scale changing
	//_graph_lines_and_tree_update(gl, tr, false, bInit);
	_graph_lines_and_tree_update(gl, tr, false, bNeedCheckGLRange);
	return true;
}
// apply filter to input XYRange
static void _update_preview(TreeNode& trGetN, Worksheet& wksdata, GraphLayer& gl)
{
	XYRange xyIn;
	
	TreeNode& trGetNinputData = trGetN.iy;
	xy_range_from_GetN_data_node(trGetNinputData, xyIn);

	/// ML 10/11/2006 GETTING_SAMPLE_RATE_EVEN_IF_NO_DATAPLOT 
	/////add by Sandy 2006-10-09 temp solution for XYRange
	//DataPlot dpData = xyIn.MakePlot(gl);
	////end
	/// end GETTING_SAMPLE_RATE_EVEN_IF_NO_DATAPLOT
	vector vecX, vecY;
	xyIn.GetData(vecY, vecX);	//Empty XYRange will cause run time error
	_update_preview_data(trGetN, vecX, vecY, wksdata);
}
// apply filter to vecX, vecY and put into wksdata col 1,2
///Sandy 2007-7-12 get error message with standard way
//static void _update_preview_data(TreeNode& tr, vector& vecX, vector& vecY, Worksheet& wksdata)
static bool _update_preview_data(TreeNode& tr, vector& vecX, vector& vecY, Worksheet& wksdata)
{
	Dataset dsX(wksdata, 0), dsY(wksdata, 1);
	
	TreeNode trLow = tr.freq1;
	TreeNode trHigh = tr.freq2;
	TreeNode trCutOff = tr.cutoff;
	TreeNode trPass = tr.pass;
	TreeNode trStop = tr.stop;
	TreeNode trThresHold = tr.threshold;
	TreeNode trOffset = tr.offset;
	
	bool bAddOffset = trOffset.nVal;
	int nType = tr.filter.nVal;
	double dFre1, dFre2;
	switch(nType)
	{
	case filter_low:
	case filter_high:
		dFre1 = trCutOff.dVal;
		break;
	case filter_bandpass:
	case filter_bandblock:
		dFre1 = trLow.dVal;
		dFre2 = trHigh.dVal;
		break;
	case filter_threshold:
		dFre1 = trThresHold.dVal;
		break;
	case filter_lowpp:
		dFre1 = trPass.dVal;
		dFre2 = trStop.dVal;
		break;
	default:
		//out_int("FFT_filter: nType not valid ", nType);
		//strErrMsg = XFERR_FFT_FILTER_TYPE_INVALID;
		return false;
		break;
	}

	///Sandy 2007-7-12 get error message with standard way
	//if(_apply_filters(nType, dFre1, dFre2, bAddOffset, vecY, &vecX) <= 0)
	//{
		//_DBM2("filter applied, f1=%g, f2=%g\n", dFre1, dFre2)
		//dsX = vecX;
		//dsY = vecY;
	//}
	//else
		//out_str("failed to apply filter");
		
	int nRet = _apply_filters(nType, dFre1, dFre2, bAddOffset, vecY, &vecX);
	if(nRet > 0)
	{
		//strErrMsg = XFERR_FAIL_APPLY_FILTER;
		return false;
	}
	///Justin 2007-07-16 
	//else if(nRet < 0)
	//{
		////strErrMsg = XFWAR_TIME_SEQ_INVALID;
		//return true;		
	//}
	else 
	{
		dsX = vecX;
		dsY = vecY;
		return true;		
	}
	///End
	//end
	
	
	
	return true;
		
}

static int _apply_filters(int nType, double dFre1, double dFre2, bool bAddOffset, vector& vecY, vector* pvecX=NULL)
{
	int nStatus = 0;
	switch(nType)
	{
	case filter_low:
		if(0 > dFre1)
			dFre1 = 0;
		nStatus = fft_lowpass(vecY, dFre1, pvecX);
		break;
	case filter_high:
		if(0 > dFre1)
			dFre1 = 0;
		nStatus = fft_highpass(vecY, dFre1, pvecX, bAddOffset);
		break;
	case filter_bandpass:
		if(0 > dFre1)
			dFre1 = 0;
		if(0 > dFre2)
			dFre2 = 0;
		if(dFre1 > dFre2)
		{
			//exchange frequency
			double dTemp = dFre1;
			dFre1 = dFre2;
			dFre2 = dTemp;
		}
		nStatus = fft_bandpass(vecY, dFre1, dFre2, pvecX, bAddOffset);
		break;
	case filter_bandblock:
		if(0 > dFre1)
			dFre1 = 0;
		if(0 > dFre2)
			dFre2 = 0;
		if(dFre1 > dFre2)
		{
			//exchange frequency
			double dTemp = dFre1;
			dFre1 = dFre2;
			dFre2 = dTemp;
		}
		nStatus = fft_bandblock(vecY, dFre1, dFre2, pvecX, bAddOffset);
		break;
	case filter_threshold:
		if(0 > dFre1)
			dFre1=0;
		nStatus = fft_threshold(vecY, dFre1, pvecX);
		break;
	/// Cloud 11/9/07 add lowpass parabolic filter
	case filter_lowpp:
		int nSize = vecY.GetSize();
		vector vWindow(nSize);
		double dFreqStep;
		//fft_sampling_resolution(pvecX, dFreqStep);
		int nRet = fft_sampling_resolution(pvecX, dFreqStep);//Sandy 2009-4-9 add error checking, maybe need centralized after SR5
		if(nRet != 0 || dFreqStep == 0 || dFreqStep == NANUM)////Sandy 2009-4-9 QA80-13429 JUST_WARNNING_WHEN_UNEVEN_INTERVAL
		{
			//if(nRet != OE_NOT_SPACED_EQUALLY || dFreqStep <= 0)
			if(nRet != OE_NOT_SPACED_EQUALLY || dFreqStep == 0 || dFreqStep == NANUM)  //Sandy 2009-4-10 allow descending x data or unsorted xy data
				return nRet;
			///------ Folger 04/17/09 QA80-13429 RECREATE_X_DATA_FOR_NOT_EVEN_SPACE_INPUT_X
			if ( pvecX )
				recreate_even_space_time_vector(*pvecX, dFreqStep);
			///------ End RECREATE_X_DATA_FOR_NOT_EVEN_SPACE_INPUT_X
		}
		//dFreqStep = 1 / nSize / dFreqStep;
		dFreqStep = abs(1 / nSize / dFreqStep); //Sandy 2009-4-10 allow descending x data or unsorted xy data
		
		nStatus = fft_filter_window(nSize, LOW_PASS_PARABOLIC_FILTERING, vWindow,
			dFre1, dFre2, dFreqStep, true);
		if (nStatus==OE_NOERROR)
			nStatus = fft_fft_filter(nSize, vecY, vWindow);
		break;
	default:
		nStatus = 1;//error happen
		break;
	}
	
	///Sandy 2007-7-12 should move outside and let caller to handle
	//if(nStatus < 0)
		/////Cheney 2006-10-30 USE_WARNING_BOX
		////XF_TRACE();
		////warning_msg_box("Warning: Not appropriate time increament! Will use default setting.", false);
		//XF_WARN(XFWAR_TIME_SEQ_INVALID);
		/////end USE_WARNING_BOX
	
	return nStatus;
}
//---- CPY 7/27/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 nFilter, double freq1, double freq2, double cutoff, double pass, double stop, double threshold)
{
	vector<string>	vsFilterTypes = {"Low Pass", "High Pass", "Band Pass", "Band Block", "Threshold", "Low Pass Parabolic"};
	string strComment;
	switch ( nFilter )
	{
	case filter_low:
	case filter_high:
		strComment.Format("%g Hz ", cutoff);
		break;
	case filter_bandpass:
	case filter_bandblock:
		strComment.Format("%g Hz %s %g Hz ", freq1, _L("to"), freq2);
		break;
	
	case filter_threshold:
		strComment.Format("%g ", threshold);
		break;
		
	case filter_lowpp:
		strComment.Format("%g Hz %s %g Hz ", pass, _L("to"), stop);
		break;
		
	default:
		break;
	}
	
	oy.SetOutputComment(strComment + _LC(vsFilterTypes[nFilter], "fft_filters") + " Filter\r\n" + get_input_data_range_string(iy));
}
//------ End BETTER_OPREATION_OUTPUT_COLUMN_COMMENTS
*/
static	void	_set_output_range_comments(XYRange& oy, const XYRange& iy, int nFilter, double freq1, double freq2, double cutoff, double pass, double stop, double threshold)
{
	vector<string>	vsFilterTypes = {"Low Pass", "High Pass", "Band Pass", "Band Block", "Threshold", "Parabolic"};
	string strComment;
	switch ( nFilter )
	{
	case filter_low:
	case filter_high:
		strComment.Format("%g Hz ", cutoff);
		break;
	case filter_bandpass:
	case filter_bandblock:
		strComment.Format("%g - %g Hz ", freq1, freq2);
		break;
	
	case filter_threshold:
		strComment.Format("%g ", threshold);
		break;
		
	case filter_lowpp:
		strComment.Format("%g, %g Hz ", pass, stop);
		break;
		
	default:
		break;
	}
	
	oy.SetOutputComment(strComment + _LC(vsFilterTypes[nFilter], "fft_filters") + " fft filter of " + get_input_data_range_string(iy));
}
//----- end CHANGE_BACK_TO_USE_CRLF_TO_SEP_LN_COMMENT



void fft_filters(const XYRange& iy, const int& filter, const double& freq1, const double& freq2, const double& cutoff, const double& pass, const double& stop, const double& threshold, const int& offset, XYRange& oy)
{
	waitCursor junk;																
	vector vecX, vecY;
	///------ Folger 04/10/09 QA80-12356 FFT_FILTERS_OUTPUT_FAILS_TO_KEEP_MISSING_VALUES_POSITION_AS_INPUT
	//iy.GetData(vecY, vecX);
	vector<int>		vnMissingValsIndices;
	if( !iy.GetData(vecY, vecX, NULL, 0, DRR_BAD_WEIGHT_TREATMENT, &vnMissingValsIndices) )
		XF_THROW(XFERR_GET_DATA_FAILED);
	///------ End FFT_FILTERS_OUTPUT_FAILS_TO_KEEP_MISSING_VALUES_POSITION_AS_INPUT
	
	double dFre1, dFre2;
	switch(filter)
	{
	case filter_low:
	case filter_high:
		//-----CPY 6/13/08 FFT_FILTER_EXAMPLE_SAME_AS_75_NEED_SIMPLER_INTERFACE
		if(cutoff < 0)
			dFre1 = freq1;
		else
		//-----
		dFre1 = cutoff;
		break;
	case filter_bandpass:
	case filter_bandblock:
		dFre1 = freq1;
		dFre2 = freq2;
		break;
	case filter_threshold:
		//-----CPY 6/13/08 FFT_FILTER_EXAMPLE_SAME_AS_75_NEED_SIMPLER_INTERFACE
		if(threshold < 0)
			dFre1 = freq1;
		else
		//-----
		dFre1 = threshold;
		break;
	/// Cloud 11/9/07 add lowpass parabolic filter
	case filter_lowpp:
		//-----CPY 6/13/08 FFT_FILTER_EXAMPLE_SAME_AS_75_NEED_SIMPLER_INTERFACE
		if(pass < 0 && stop < 0)
		{
			dFre1 = freq1;
			dFre2 = freq2;
		}
		else
		//-----
		{
			dFre1 = pass;
			dFre2 = stop;
		}
		break;
	default:
		break;
	}
	
	///Sandy 2007-7-12 get error message with standard way
	//if(_apply_filters(filter, dFre1, dFre2, offset, vecY, &vecX) > 0)
		//XF_THROW(XFERR_FAIL_APPLY_FILTER);
	int nRet = _apply_filters(filter, dFre1, dFre2, offset, vecY, &vecX);
	if(nRet > 0)
	{
		XF_THROW(XFERR_FAIL_APPLY_FILTER);
	}
	else if(nRet < 0)
	{
		///------ Folger 04/14/09 QA80-13436 IMPROVE_MECHANISM_ABOUT_XF_ERR_MSG_SHOWN_IN_BODY
		if ( SHOULD_WARNING_MSG_SHOW_IN_XF_BODY )
		///------ End IMPROVE_MECHANISM_ABOUT_XF_ERR_MSG_SHOWN_IN_BODY
			XF_WARN(XFWAR_TIME_SEQ_INVALID);		
	}	
	//end
	
	
	/// Cloud 6/13/2007 XYRANGE_EVEN_SAMPLING
	//oy.SetData(&vecY, &vecX);
	///------ Folger 04/10/09 QA80-12356 FFT_FILTERS_OUTPUT_FAILS_TO_KEEP_MISSING_VALUES_POSITION_AS_INPUT
	//if (!set_xyrange_data_ex(oy, &vecY, &vecX, 0, iy))
	if( !set_xyrange_data_ex(oy, &vecY, &vecX, 0, iy, &vnMissingValsIndices) )
	///------ End FFT_FILTERS_OUTPUT_FAILS_TO_KEEP_MISSING_VALUES_POSITION_AS_INPUT
		XF_THROW(XFERR_FAIL_IN_SET_XYRANGE_DATA);
	/// End XYRANGE_EVEN_SAMPLING
	//Column col;
	//bool bRet = oy.GetXColumn(col);
	//bRet = col.SetLongName("Filtered X");
	//bRet = oy.GetYColumn(col);
	//bRet = col.SetLongName("Filtered Y");
	///Arvin 08/16/07 QA70-10073 KEEP_OUTPUT_CURVE_CUSTOMIZATION_AFTER_RECALCULATE_FOR_XF
	//DataPlot dp = oy.MakePlot(iy);
	//if( !dp )
	//{
		////ASSERT(FALSE);	///DG 7/6/05 : do filter to wks, no need plot
		//return;
	//}
	//dp.SetColor(1, true);
		
	//GraphLayer gl;
	//dp.GetParent(gl);
	
	//Set legend
	//string strSourceColName = curData.GetName();
	
	///Sandy 2007-8-20
	//DataPlot dpSrc;
	//iy.GetPlot(dpSrc);
	//if(!dpSrc)
	//{
		////ASSERT(0);
	//}
	//string strSourceColName = dpSrc.GetDatasetName();
	/// Max 07-11-06 SHOULD_NOT_SET_NAME_IN_XF_BODY // use option string N instead
	/*
	Column colSrcY;
	iy.GetYColumn(colSrcY);
	string strSourceColName = colSrcY.GetName();
	
	vector<string> vsFilterTypeLabel={" Hz Low Pass", " Hz High Pass", " Hz Band Pass", " Hz Band Block", " Amp ThresHold"};
	Column colY;
	oy.GetYColumn(colY);
	string strLabel;
	strLabel = ftoa(dFre1, STR_DATA_DISP_FORMAT);
	if(filter_bandpass==filter || filter_bandblock==filter)
		strLabel = ftoa(dFre1, STR_DATA_DISP_FORMAT) + " to "+ ftoa(dFre2, STR_DATA_DISP_FORMAT);
	
	strLabel += vsFilterTypeLabel[filter] + " Filter on Col" + strSourceColName;
	colY.SetLabel(strLabel);
	*/
	/// END SHOULD_NOT_SET_NAME_IN_XF_BODY
	///Arvin 08/16/07 QA70-10073 KEEP_OUTPUT_CURVE_CUSTOMIZATION_AFTER_RECALCULATE_FOR_XF
	//gl.LT_execute("legend -s");
	//gl.Rescale();
	DataPlot dp;
	xf_check_plot_output_rng_in_source_rng_graph(iy, oy, &dp);
	if(dp.IsValid())
	{
		GraphLayer gl;
		dp.GetParent(gl);
		//gl.Rescale();//Sandy 2009-3-6  DON'T_RESCALE_AND_KEEP_USER_SCALES
	}
	///end KEEP_OUTPUT_CURVE_CUSTOMIZATION_AFTER_RECALCULATE_FOR_XF
	
	//------ Folger 07/23/08 BETTER_OPREATION_OUTPUT_COLUMN_COMMENTS
	_set_output_range_comments(oy, iy, filter, freq1, freq2, cutoff, pass, stop, threshold);
	//------
	
}

//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 fft_filters_event1(TreeNode& trGetN, int nRow, int nEventID, DWORD& dwEnables, LPCSTR lpcszNodeName, WndContainer& DynaCntrlContainer, string& strAux, string& strErrMsg)
{
	if( xf_is_extended_event(nEventID) )
		return fft_filters_event1_ex(trGetN, nRow, nEventID, dwEnables, lpcszNodeName, DynaCntrlContainer, strAux, strErrMsg);
	DECLARE_BUTTON_ENABLES
	
		_update_tree_shown(trGetN);
		return true;	
	

}

int fft_filters_make_tree(TreeNode& tr, LPCSTR lpcszVarName)
{
	
	// from old code
	/*
		bool bInit = (dwCntrl & GETNEVENT_ON_INIT) ? true : false;
		bool bUpdateGraph = (dwCntrl & GETNEVENT_UPDATE_GRAPH) ? true : false;
		bool bUpdatePrew = (dwCntrl & GETNEVENT_UPDATE_PREVIEW) ? true : false;
	
		bool bUpdateTreeByGraph = (dwCntrl & GETNEVENT_UPDATE_GUI_TREE) ? true : false;
	
		///DG 7/27/05 : handle input data change
		if(!bInit && trNode && trNode.Parent())
		{
			TreeNode trData = trNode.Parent();
			if("xy"==trData.tagName)
				bInit=true;
		}
		///end
	
		GraphPage gp(theGraph);
		GraphLayer gl = gp.Layers(0);
		GraphObject goTop = gl.GraphObjects("top");
		GraphObject goLeft = gl.GraphObjects("left");
		GraphObject goRight = gl.GraphObjects("right");
	
		//update tree, should put to another event, but now we don't have, so temp put here
		if((bInit || (trNode && "type"==trNode.tagName)) && bUpdateGraph)
		{
			//update_tree_shown(myTree);
			update_graph_object_shown(trGetN, gl);
		}
		else if(bUpdateGraph && trNode && ("low"==trNode.tagName || "high"==trNode.tagName || "cutoff"==trNode.tagName || "threshold"==trNode.tagName))
		{
			TreeNode trLow = trGetN.low;
			TreeNode trHigh = trGetN.high;
			TreeNode trCutOff = trGetN.cutoff;
			TreeNode trThresHold = trGetN.threshold;
	
			goTop.Y=trThresHold.dVal;
			double dLow = trCutOff.Show ? trCutOff.dVal : trLow.dVal;
			goLeft.X=dLow;
			goRight.X=trHigh.dVal;
		}
		else if(bUpdatePrew && trNode && "Color" == trNode.tagName)	//update curve color only
		{
			DataPlot dpCurve = gl.DataPlots(1);
			if(dpCurve)
				dpCurve.SetColor(trGetN.output.curve.color.nVal);
	
			goto quit;
		}
		else if(bUpdateTreeByGraph)
		{
			double dTop = goTop.Y, dMin=goLeft.X, dMax=goRight.X;
			set_frequency(trGetN, dMin, dMax, dTop);
		}
	
		//update graph	
		vector vecX, vecY;
		XYRange xy;
		TreeNode trJunk;
		xy.SetTree(trGetN.src, trJunk);
		xy.InitFromTree();
	
		bool bData;
		try
		{
			bData = xy.GetData(vecY, vecX);	//Empty XYRange will cause run time error
		}
		catch(int nError)
		{
			bData = false;
		}
		if(!bData)
		{
			ASSERT(0);
			XF_THROW(ERR_GET_INPUT_FAIL);
		}
	
		if(bUpdateGraph)	//update view graph
		{
			if(bInit)
				init_viewgraph(trGetN, vecX, vecY, gl, datawks);
		}
		else if(bUpdatePrew)
		{
			if(bInit)
				init_previewgraph(trGetN, xy, gl, datawks);
	
			update_previewgraph(trGetN, vecX, vecY, gl, datawks);
		}
	quit:	
		gl.Rescale();
		gp.Refresh();
		return true;	
	*/
	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 fft_filters_before_execute(TreeNode& trGetN, int nGetNDialog, int& nRet, int dwCntrl)
{
	
	string strErrMsg;
	
	//------ fisher 11/16/07 ADD_MAP_ID_TO_CHM
	if(is_use_origin_chm())
		trGetN.SetAttribute(STR_HELPID_ATTRIB, IDD_XF_fft_filters);
	
	if ( (dwCntrl&LTXF_THEME_USED) && nGetNDialog <= 0 )
	{ 
		int nSize;
		TreeNode trInput= trGetN.iy;
		XYRange xyi;
		
		if(!get_error_for_input_xyrange(trInput, strErrMsg, nSize, xyi))
			nRet = XFEVT_PROCEED_WITH_DLG; 
	}
	
	///Sandy 2007-9-3 FIX_CHANGE_PARAM
	s_bChangeParam = false;
	if(dwCntrl&LTXF_CHANGE_PARAM) 	
	{
		s_bChangeParam = true;
	}
	
	
	if(nGetNDialog>-1)
	{
		s_bInit = false;
	}
	
	///------ Folger 04/14/09 QA80-13436 IMPROVE_MECHANISM_ABOUT_XF_ERR_MSG_SHOWN_IN_BODY
	if ( is_xf_startup(nGetNDialog, dwCntrl) )
		SET_WARNING_MSG_SHOW_IN_XF_BODY(IS_ERR_MSG_OK_TO_SHOW_IN_BODY);
	///------ End IMPROVE_MECHANISM_ABOUT_XF_ERR_MSG_SHOWN_IN_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 fft_filters_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

	/////Sandy 2007-8-30 add code to initial cutoff
	double dXMin, dXMax, dYMin, dYMax;
	if(bOKEnable = _check_input(trGetN, strErrMsg, dXMin, dXMax, dYMin, dYMax))
	{
	
		if(!s_bChangeParam && (trGetN.freq1.dVal < 0 && trGetN.freq2.dVal < 0 && trGetN.threshold.dVal < 0))
		{
			_set_frequency(trGetN, (dXMax+dXMin)/4., (dXMax+dXMin)*3/4., dYMax/10);
		}
	}
	
	_update_tree_shown(trGetN);	

	//bUpdateGraph = _check_input(trGetN, strErrMsg);
	bUpdateGraph = bOKEnable;
	
	///Kyle 07/28/2009 QA80-14026 FIX_WRONG_LEGEND_FOR_PREVIEW, always init the temp worksheet
	{
		Worksheet wks = wksTemp;
		wks.SetSize(-1, 4, WSS_CLEAR_DATA);
		wks.SetColDesignations("XYXY");
		wks.Columns(1).SetLongName("Filtered");
		wks.Columns(3).SetLongName("FFT Amplitude");
	}
	///End FIX_WRONG_LEGEND_FOR_PREVIEW
	
	s_strErrMsg = strErrMsg;//Sandy 2008-5-22 keep the err message for OnInitGraph;
	
	s_bInit = false;
		
}

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

// 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

	/*Worksheet wks = wksTemp;
	XYRange xyIn, xyPrew;
	init_preview_graph(trGetN.iy, pgTemp, wks, "FFTFilterCntrl", &xyIn, &xyPrew,1, SYSCOLOR_GRAY, SYSCOLOR_LTMAGENTA);// preview in Layer 1, control in layer 0

	GraphPage gp = pgTemp;	
	//----------- CPY 8/15/06 ADD_X_AXIS_SCALE_SCROLLER
	if(!gp)
		return;
	GraphLayer gl = gp.Layers(0);
	// 1st layer is bottom freq range
	XFBase xf("add_axis_scroller");
	if( xf )
	{
		if( xf.SetArg(0, gl) )
			xf.Evaluate();
	}
	//-----------

	//GraphPage gp(CntrlGraph);
	vector vecX, vecY;
	xyIn.GetData(vecY, vecX);	//Empty XYRange will cause run time error
	if(vecY.GetSize() == 0)
	{
		//ASSERT(0);
		XF_THROW(XFERR_GET_DATA_FAILED);
	}
	
	//Sandy 2006-7-25 DEBUG
//	_update_preview_data(trGetN, vecX, vecY, wksTemp);
	//_init_viewgraph(trGetN, vecX, vecY, gl, CntrlGraphData);
	_control_graph(trGetN, vecX, vecY, gl, wks, true);
	_update_graph_object_shown(trGetN, gl);*/
	
	//bOKEnable = _init_filter_graph(trGetN, pgTemp, wksTemp, strErrMsg);

	
	//if(bOKEnable)
	//{
		//GraphPage gp = pgTemp;
		//GraphLayer gl = gp.Layers(0);
		//Worksheet wks = wksTemp;
		//_update_preview(trGetN, wks, gl);
	//}
	strErrMsg = s_strErrMsg; //Sandy 2008-5-22 use the err message which save in OnInitGrid;
	///Sandy 2007-8-28 Clean initial code to speed up open dlg
	///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)
{

	
	//GraphPage gp(previewGraph);
	GraphPage gp = pgTemp;
	GraphLayer gl = gp.Layers(0);
	
	if(!s_bInit)
		s_bInit = _init_filter_graph(trGetN, pgTemp, wksTemp);
	//XYRange xyIn;
	//
	//TreeNode& trGetNinputData = trGetN.iy;
	//xy_range_from_GetN_data_node(trGetNinputData, xyIn);
	//
	/////add by Sandy 2006-10-09 temp solution for XYRange
	//DataPlot dpData = xyIn.MakePlot(gl);
	////end
//
	//vector vecX, vecY;
	//xyIn.GetData(vecY, vecX);	//Empty XYRange will cause run time error
	Worksheet wks = wksTemp;
	//_update_preview_data(trGetN, vecX, vecY, wks);
	_update_preview(trGetN, wks, gl);
	
	
}

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

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


	bUpdateGrid = true;
	
	//----- CPY 11/14/06 ON_CHANGE_EVENT_SHOULD_NOT_REINIT_PREVIEW
	//	bOKEnable = _init_filter_graph(trGetN, pgTemp, wksTemp, strErrMsg);	
	//bOKEnable = _check_input(trGetN, strErrMsg);
	//-----
	double dXMin, dXMax, dYMin, dYMax;
	strErrMsg = "";
	if(bOKEnable = _check_input(trGetN, strErrMsg, dXMin, dXMax, dYMin, dYMax))
	{
		if((trNode.IsValid() && (trNode.tagName == "iy" || trNode.tagName == "filter"))
		 || (trGetN.freq1.dVal < 0 && trGetN.freq2.dVal < 0 && trGetN.threshold.dVal < 0 && trGetN.pass.dVal < 0 && trGetN.stop.dVal < 0))//factory default
		{
			_update_tree_shown(trGetN);
			_set_frequency(trGetN, (dXMax+dXMin)/4., (dXMax+dXMin)*3/4., dYMax/10);
		}
	}
	
	GraphPage gp = pgTemp;
	GraphLayer gl = gp.Layers(0);	
	if(bOKEnable)
	{
		if(bChangedByGraph)
		{
			if(s_bInit)
			   bUpdateGraph = bUpdateGrid = _graph_lines_and_tree_update(gl, trGetN, true);
		}
		else if(trNode)
		{
			bUpdateGrid = true;
			
			if("filter" == trNode.tagName)
			{
				_update_tree_shown(trGetN);
				if(s_bInit)
				{
					_update_graph_object_shown(trGetN, gl);
					_graph_lines_and_tree_update(gl, trGetN, false);
					bUpdateGraph = true;
				}
				
			}
			/// Cloud 11/9/07 add lowpass parabolic filter
			//else if("freq1"==trNode.tagName || "freq2"==trNode.tagName || "cutoff"==trNode.tagName || "threshold"==trNode.tagName || "offset"==trNode.tagName)
			else if("freq1"==trNode.tagName || "freq2"==trNode.tagName || "cutoff"==trNode.tagName || "threshold"==trNode.tagName || "offset"==trNode.tagName || "pass"==trNode.tagName || "stop"==trNode.tagName)
			{
				if(trNode.tagName != "offset")
					trNode.dVal = (trNode.dVal < 0) ? 0. : trNode.dVal;
				
				if(trGetN.freq1.dVal>trGetN.freq2.dVal)
				{
					double temp = trGetN.freq2.dVal;
					trGetN.freq2.dVal = trGetN.freq1.dVal;
					trGetN.freq1.dVal = temp;
				}
				
				if(s_bInit)
					bUpdateGraph = _graph_lines_and_tree_update(gl, trGetN, false);
			}
			else if("iy" == trNode.tagName)
			{
				
				//bool bRet = _init_filter_graph(trGetN, pgTemp, wksTemp, strErrMsg);	
				//bool bRet = _init_filter_graph(trGetN, pgTemp, wksTemp);	
				//if(bRet)
				//{
					s_bInit = false;
					bUpdateGraph = true;
				//}		
			}
		}
		else
		{
			_update_tree_shown(trGetN);
			
			if(s_bInit)
			{
				_update_graph_object_shown(trGetN, gl);
				
				///Sandy 2007-8-8 need check range when change theme or else
				//_graph_lines_and_tree_update(gl, trGetN, false);
				_graph_lines_and_tree_update(gl, trGetN, false, true);
				
				bUpdateGraph = true;	
			}
		}		
	}
	
	if(!bOKEnable)
		dwUpdateGraph = UPDATE_GRAPH_INVALID; //nUpdateGraph = UPDATE_GRAPH_ERROR;	
	
}

// 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_fft_filters(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

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

