#include <origin.h>
#include <GetNBox.h>
#include <xfutils.h>
enum{
	type_upper,
	type_lower,
	type_both,
};
enum{
	method_spline,
};
//put additional include files here
#include <ReportTree.h>
#include <event_utils.h>

/***************************************************************************************
/// Modification Log :
/// Kyle 11/26/2008 QA80-12663 UPDATE_GRAPHLAYER_LEGEND_AFTER_PLOT
/// Kyle 09/04/2009 ADD_PREVIEW
/// Max 09/09/09 v8.1092-2 USE_PROPER_ERR_MSG
/// Kyle 09/11/2009 BETTER_COMMENTS_FOR_OUTPUT
/// Iris 10/13/09 QA70-14403 PREVIEW_GRAPH_SHOULD_NEVER_RESCALE_ON_CHANGE
/// Jasmine 08/13/2010 ORG-172-S2 CENTRALIZE_NOCLICK_BIT_FOR_PREVIEW_IN_OC_TOOL
***************************************************************************************/

//put your own support static functions here

enum
{
	GET_EXTREME_SUCCESS = 0,
	GET_EXTREME_FAILED = -1
};


enum _ENVELOPE
{
	_ENVELOPE_TABLE_UPPER = 100,
	_ENVELOPE_UPPERX,
	_ENVELOPE_UPPERY,
	_ENVELOPE_TABLE_LOWER,
	_ENVELOPE_LOWERX,
	_ENVELOPE_LOWERY,
};

///Kyle 09/11/2009 BETTER_COMMENTS_FOR_OUTPUT
//static bool _upper_envelope_update_report_data(ReportData& outData, const vector& vX, const vector& vY)
static bool _upper_envelope_update_report_data(ReportData& outData, const vector& vX, const vector& vY, LPCSTR lpcszIRange)
///End BETTER_COMMENTS_FOR_OUTPUT
{
	if (!outData)
		return false;
	int jj = 1; // hard code for upper envelope
	string strjj = ftoa(jj);
	///Kyle 09/11/2009 BETTER_COMMENTS_FOR_OUTPUT
	//ReportTable rtEnvelope = outData.CreateTable("Envelope1",  _L("Upper Envelope"), _ENVELOPE_TABLE_UPPER);
	string strComments;
	strComments.Format(_L("Upper Envelope of %s"), lpcszIRange);
	ReportTable rtEnvelope = outData.CreateTable("Envelope1",  strComments, _ENVELOPE_TABLE_UPPER);
	///End BETTER_COMMENTS_FOR_OUTPUT
	rtEnvelope.AddColumn(vX, "X"+strjj, _ENVELOPE_UPPERX, _L("Envelope X 1"), OKDATAOBJ_DESIGNATION_X);
	rtEnvelope.AddColumn(vY, "Y"+strjj, _ENVELOPE_UPPERY, _L("Envelope Y 1"), OKDATAOBJ_DESIGNATION_Y);
	
	return true;
}

///Kyle 09/11/2009 BETTER_COMMENTS_FOR_OUTPUT
//static bool _lower_envelope_update_report_data(ReportData& outData, const vector& vX, const vector& vY)
static bool _lower_envelope_update_report_data(ReportData& outData, const vector& vX, const vector& vY, LPCSTR lpcszIRange)
///End BETTER_COMMENTS_FOR_OUTPUT
{
	if (!outData)
		return false;
	int jj = 2; // hard code for lower envelope
	string strjj = ftoa(jj);
	///Kyle 09/11/2009 BETTER_COMMENTS_FOR_OUTPUT
	//ReportTable rtEnvelope = outData.CreateTable("Envelope2",  _L("Lower Envelope"), _ENVELOPE_TABLE_UPPER); // note that for sinlge envelope (upper or lower) output use the same ID, namely the _ENVELOPE_TABLE_UPPER
	string strComments;
	strComments.Format(_L("Lower Envelope of %s"), lpcszIRange);
	ReportTable rtEnvelope = outData.CreateTable("Envelope2",  strComments, _ENVELOPE_TABLE_LOWER);
	///End BETTER_COMMENTS_FOR_OUTPUT
	rtEnvelope.AddColumn(vX, "X"+strjj, _ENVELOPE_LOWERX, _L("Envelope X 2"), OKDATAOBJ_DESIGNATION_X);
	rtEnvelope.AddColumn(vY, "Y"+strjj, _ENVELOPE_LOWERY, _L("Envelope Y 2"), OKDATAOBJ_DESIGNATION_Y);
	
	return true;
}
///Kyle 09/11/2009 BETTER_COMMENTS_FOR_OUTPUT
//static bool _upper_lower_envelope_update_report_data(ReportData& outData, const vector& vX, const vector& vUpperEnvY, const vector& vLowerEnvY)
static bool _upper_lower_envelope_update_report_data(ReportData& outData, const vector& vX, const vector& vUpperEnvY, const vector& vLowerEnvY, LPCSTR lpcszIRange)
///End BETTER_COMMENTS_FOR_OUTPUT
{
	if (!outData)
		return false;
	int jj = 1; // hard code for upper envelope
	string strjj = ftoa(jj);
	///Kyle 09/11/2009 BETTER_COMMENTS_FOR_OUTPUT
	//ReportTable rtEnvelope = outData.CreateTable("Envelope1",  _L("Upper Envelope"), _ENVELOPE_TABLE_UPPER);
	string strComments;
	strComments.Format(_L("Upper Envelope of %s"), lpcszIRange);
	ReportTable rtEnvelope = outData.CreateTable("Envelope1",  strComments, _ENVELOPE_TABLE_UPPER);
	///End BETTER_COMMENTS_FOR_OUTPUT
	rtEnvelope.AddColumn(vX, "X"+strjj, _ENVELOPE_UPPERX, _L("Envelope X 1"), OKDATAOBJ_DESIGNATION_X);
	rtEnvelope.AddColumn(vUpperEnvY, "Y"+strjj, _ENVELOPE_UPPERY, _L("Envelope Y 1"), OKDATAOBJ_DESIGNATION_Y);
	
	jj = 2;
	strjj = ftoa(jj);
	///Kyle 09/11/2009 BETTER_COMMENTS_FOR_OUTPUT
	//rtEnvelope = outData.CreateTable("Envelope2",  _L("Lower Envelope"), _ENVELOPE_TABLE_LOWER);
	strComments.Format(_L("Lower Envelope of %s"), lpcszIRange);
	rtEnvelope = outData.CreateTable("Envelope2", strComments, _ENVELOPE_TABLE_LOWER);
	///End BETTER_COMMENTS_FOR_OUTPUT
	rtEnvelope.AddColumn(vX, "X"+strjj, _ENVELOPE_LOWERX, _L("Envelope X 2"), OKDATAOBJ_DESIGNATION_X);
	rtEnvelope.AddColumn(vLowerEnvY, "Y"+strjj, _ENVELOPE_LOWERY, _L("Envelope Y 2"), OKDATAOBJ_DESIGNATION_Y);
	return true;

}

/// Max 9/09/09 not used anymore
/*
static bool _envelopexy_set_data_range(XYRange& oy, const vector *pVMergeX, const vector *pVMergeY)
{
	ASSERT(oy.IsValid() && pVMergeX!=NULL || pVMergeY!=NULL);
	if(!oy.IsValid() || pVMergeX==NULL || pVMergeY==NULL)
		return false;
	oy.SetData(pVMergeY,pVMergeX);
	return true;
}
*/

///Kyle 09/04/2009 ADD_PREVIEW

static string s_strErrMsg = "";
static bool s_bIsFromUpdatePreview = false;
static bool s_bIsPreviewInitTime = true; /// Iris 10/13/09 QA70-14403 PREVIEW_GRAPH_SHOULD_NEVER_RESCALE_ON_CHANGE

static void _add_plot_to_preview(const XYRange& iy, const ReportData& rdResult, GraphPage& gpPreview)
{
	if(!iy || !rdResult || !gpPreview)
		return;
	
	/// Iris 10/13/09 QA70-14403 PREVIEW_GRAPH_SHOULD_NEVER_RESCALE_ON_CHANGE
	//page_load(gpPreview, "CurvePreview", NOCLICK_DATA_PLOT | NOCLICK_TICKLABEL | NOCLICK_LAYER | NOCLICK_LAYERICON | NOCLICK_AXES);
	if( s_bIsPreviewInitTime )
		///Jasmine 08/13/2010 ORG-172-S2 CENTRALIZE_NOCLICK_BIT_FOR_PREVIEW_IN_OC_TOOL
		//page_load(gpPreview, "CurvePreview", NOCLICK_DATA_PLOT | NOCLICK_TICKLABEL | NOCLICK_LAYER | NOCLICK_LAYERICON | NOCLICK_AXES);
		page_load(gpPreview, "CurvePreview", OC_PREVIEW_NOCLICK_NOZOOMPAN);
		///End CENTRALIZE_NOCLICK_BIT_FOR_PREVIEW_IN_OC_TOOL
	///end PREVIEW_GRAPH_SHOULD_NEVER_RESCALE_ON_CHANGE
	
	GraphLayer gl = gpPreview.Layers(0);
	if(!gl)
		return;
	
	//remove all graph dataplot
	int nPlots = gl.DataPlots.Count();
	for(int ii = 0; ii < nPlots; ii++)
		gl.RemovePlot(0);

	DataPlot dpData;
	dpData = iy.MakePlot(gl, NULL, 0);
	int nDataPlotIndex = dpData.GetIndex();
	dpData.SetColor(0);

	rdResult.PlotIntoLayer(gl, _ENVELOPE_TABLE_UPPER, NULL);
	rdResult.PlotIntoLayer(gl, _ENVELOPE_TABLE_LOWER, NULL);
	
	int nColor = 1;
	for(ii=1; ii<gl.DataPlots.Count(); ii++)
	{
		DataPlot dp;
		dp = gl.DataPlots(ii);
		if(!dp)
			continue;
		dp.SetColor(nColor);
		nColor++;
	}

	legend_update(gl);
	/// Iris 10/13/09 QA70-14403 PREVIEW_GRAPH_SHOULD_NEVER_RESCALE_ON_CHANGE
	//gl.Rescale();
	if( s_bIsPreviewInitTime )
		gl.Rescale();
	///end PREVIEW_GRAPH_SHOULD_NEVER_RESCALE_ON_CHANGE
	gpPreview.Refresh();
}

static void _run_envelope_on_current_data(TreeNode& trGetN, PageBase& pgTemp, Worksheet& wksTemp)
{
	XYRange iy, xySim;
	xy_range_from_GetN_data_node(trGetN.iy, iy);

	int type = trGetN.type.nVal;
	int method = trGetN.method.nVal;
	int npts = trGetN.npts.nVal;
 
	Tree trReport;
	ReportData rdTemp(trReport);
	wksTemp.SetSize(-1, 0);
	rdTemp.SetWorksheet(wksTemp);
	s_bIsFromUpdatePreview = true;
	try {
		envelope(iy, type, method, npts, rdTemp);
	}
	catch(int nErr)
	{
	}
	s_bIsFromUpdatePreview = false;

	GraphPage gpPreview = pgTemp;
	_add_plot_to_preview(iy, rdTemp, gpPreview);
	
	/// Iris 10/13/09 QA70-14403 PREVIEW_GRAPH_SHOULD_NEVER_RESCALE_ON_CHANGE
	if( s_bIsPreviewInitTime )
		s_bIsPreviewInitTime = false;
	///end PREVIEW_GRAPH_SHOULD_NEVER_RESCALE_ON_CHANGE
}

static bool _check_input(TreeNode& trGetN, string& strErrMsg)
{
	int nErr = CER_NO_ERROR;
	int nSize =  get_input_xyrange_data_size(trGetN.iy);
	if(get_input_xyrange_num(trGetN.iy) < 1)
		nErr = XFERR_AT_LEAST_ONE_XYRANGE;
	else if(0 >= nSize)
		nErr = CER_NO_DATA;
	if(nErr != CER_NO_ERROR)
	{
		strErrMsg = nErr;
		return false;
	}

	if(trGetN.npts.nVal<1)
	{
		/// Max 09/09/09 v8.1092-2 USE_PROPER_ERR_MSG
		//strErrMsg = "Too small smooth points";
		strErrMsg = CER_INVALID_POSITIVE_INTEGER;
		strErrMsg += ":" + _L("Number of smooth points");
		return false;
		///---
	}
	return true;
}

///End ADD_PREVIEW



void envelope(const XYRange& iy, const int& type, const int& method, const int& npts, ReportData& rd)
{
	DWORD dwRules = DRR_NO_WEIGHTS | DRR_GET_DEPENDENT | DRR_NO_FACTORS;
	int nNumRanges = iy.GetNumData(dwRules);
	if (nNumRanges < 1)
		XF_THROW(XFERR_AT_LEAST_ONE_XYRANGE);
	
	
	
	vector vX, vY, vEnvelopeY, vXPeak, vYPeak;
	
	iy.GetData(vY, vX, NULL,  0);  //// note that all the missing value will be trimmed in getting this data
	if(0 == vY.GetSize() || 0 == vX.GetSize())
	{
		XF_THROW(CER_NO_DATA);
	}
	
	
	
	vector<int>  vInd;
	int nSrcDataSize = vY.GetSize();
	vInd.SetSize(nSrcDataSize);
	vXPeak.SetSize(nSrcDataSize);
	vYPeak.SetSize(nSrcDataSize);
	vector vEnvelopeX; 
	vEnvelopeX = vX;
	vEnvelopeY.SetSize(nSrcDataSize);
	uint nPeakSize = nSrcDataSize;
	//	int npts = 5; // default use a lower local points
	ASSERT(npts>=1);
	
	
	switch(method)
	{
		case method_spline:
			if(type==type_upper)
			{
				int dwCtrl=POSITIVE_DIRECTION;
				int nRet = ocmath_find_local_extremes(&nPeakSize, vX, vY, vXPeak, vYPeak, vInd, dwCtrl, npts);
	    		if(nRet!=OE_NOERROR)
	    		{
	    			error_report("Failed to get extreme points."); // todo: through XF error
	    			XF_THROW(XF_ENVELOPE_FAILED_TO_GET_EXTREME_PTS);
	    		}
	    			
	    		vXPeak.SetSize(nPeakSize);
	    		vYPeak.SetSize(nPeakSize);
	    		
	    		if(nPeakSize<2)
	    		{
	    			error_report("Failed to get enough extreme points.");// too small extreme points
	    			XF_THROW(XF_ENVELOPE_EXTREME_PTS_TOO_SMALL);
	    		}
	    			
	    		int nMode = INTERP_TYPE_SPLINE;
	    		nRet = ocmath_interpolate(vX, vEnvelopeY, nSrcDataSize, vXPeak, vYPeak, nPeakSize, nMode);
	    		if(nRet!=OE_NOERROR)
	    		{
	    			error_report("Failed to interpolate."); // todo: through XF error
	    			XF_THROW(XF_ENVELOPE_FAILED_TO_INTERPOLATE);
	    		}
	
	
	    		///Kyle 09/11/2009 BETTER_COMMENTS_FOR_OUTPUT
	    		//_upper_envelope_update_report_data(rd, vEnvelopeX, vEnvelopeY);
	    		_upper_envelope_update_report_data(rd, vEnvelopeX, vEnvelopeY, get_input_data_range_string(iy));
	    		///End BETTER_COMMENTS_FOR_OUTPUT
	    		if(s_bIsFromUpdatePreview == false)				///Kyle 09/04/2009 ADD_PREVIEW
	    		{
		    		DataPlot dpData;
		    		if(iy.GetPlot(dpData)) // check If data is from a graph
		    		{
			    		DataRange		drPlot;
						int YID = _ENVELOPE_UPPERY;
						if(1!=rd.GetDataRange(drPlot, _ENVELOPE_TABLE_UPPER, _ENVELOPE_UPPERX, &YID))
							error_report("envelope failed to get range");  // todo: error report fail to get range
						else
						{
							xf_check_plot_output_rng_in_source_rng_graph(iy, drPlot);
						}
		    		}
	    		}
			}
	    	else if(type==type_lower)
	    	{
	    		int dwCtrl=NEGATIVE_DIRECTION;
				int nRet = ocmath_find_local_extremes(&nPeakSize, vX, vY, vXPeak, vYPeak, vInd, dwCtrl, npts);
	    		if(nRet!=OE_NOERROR)
	    		{
	    			error_report("Failed to get extreme points."); // todo: through XF error
	    			XF_THROW(XF_ENVELOPE_FAILED_TO_GET_EXTREME_PTS);
	    		}
	    			
	    		vXPeak.SetSize(nPeakSize);
	    		vYPeak.SetSize(nPeakSize);
	    		
	    		if(nPeakSize<2)
	    		{
	    			error_report("Failed to get enough extreme points.");// too small extreme points
	    			XF_THROW(XF_ENVELOPE_EXTREME_PTS_TOO_SMALL);
	    		}
	    		
	    		int nMode = INTERP_TYPE_SPLINE;
	    		nRet = ocmath_interpolate(vX, vEnvelopeY, nSrcDataSize, vXPeak, vYPeak, nPeakSize, nMode);
	    		if(nRet!=OE_NOERROR)
	    		{
	    			error_report("Failed to interpolate."); // todo: through XF error
	    			XF_THROW(XF_ENVELOPE_FAILED_TO_INTERPOLATE);
	    		}
	    		
	
	    		///Kyle 09/11/2009 BETTER_COMMENTS_FOR_OUTPUT
	    		//_lower_envelope_update_report_data(rd, vEnvelopeX, vEnvelopeY);
	    		_lower_envelope_update_report_data(rd, vEnvelopeX, vEnvelopeY, get_input_data_range_string(iy));
	    		///End BETTER_COMMENTS_FOR_OUTPUT
	    		
	    		if(s_bIsFromUpdatePreview == false)				///Kyle 09/04/2009 ADD_PREVIEW
	    		{
		    		DataPlot dpData;
		    		if(iy.GetPlot(dpData)) // check If data is from a graph
		    		{
		    			DataRange		drPlot;
						int YID = _ENVELOPE_LOWERY;
		    			if(1!=rd.GetDataRange(drPlot, _ENVELOPE_TABLE_LOWER, _ENVELOPE_LOWERX, &YID))
							error_report("envelope failed to get range");  // todo: error report fail to get range
						else
						{
							xf_check_plot_output_rng_in_source_rng_graph(iy, drPlot);
						}
		    		}
	    		}
	    	}
	    	else // output both envelope
	    	{
	    		int dwCtrl=POSITIVE_DIRECTION;
				int nRet = ocmath_find_local_extremes(&nPeakSize, vX, vY, vXPeak, vYPeak, vInd, dwCtrl, npts);
	    		if(nRet!=OE_NOERROR)
	    		{
	    			error_report("Failed to get extreme points."); // todo: through XF error
	    			XF_THROW(XF_ENVELOPE_FAILED_TO_GET_EXTREME_PTS);
	    		}
	    			
	    		
	    		vXPeak.SetSize(nPeakSize);
	    		vYPeak.SetSize(nPeakSize);
	    		
	    		if(nPeakSize<2)
	    		{
	    			error_report("Failed to get enough extreme points.");// too small extreme points
	    			XF_THROW(XF_ENVELOPE_EXTREME_PTS_TOO_SMALL);
	    		}
	    		
	    		int nMode = INTERP_TYPE_SPLINE;
	    		nRet = ocmath_interpolate(vX, vEnvelopeY, nSrcDataSize, vXPeak, vYPeak, nPeakSize, nMode);
	    		if(nRet!=OE_NOERROR)
	    		{
	    			error_report("Failed to interpolate."); // todo: through XF error
	    			XF_THROW(XF_ENVELOPE_FAILED_TO_INTERPOLATE);
	    		}
	    		
	
	    		
	//	    		_upper_envelope_update_report_data(rd, vEnvelopeX, vEnvelopeY);
	    		
	    		
	    		vInd.SetSize(nSrcDataSize); // reinitilize
				vXPeak.SetSize(nSrcDataSize);
				vYPeak.SetSize(nSrcDataSize);
				nPeakSize = nSrcDataSize;
				
	    		dwCtrl=NEGATIVE_DIRECTION;
				nRet = ocmath_find_local_extremes(&nPeakSize, vX, vY, vXPeak, vYPeak, vInd, dwCtrl, npts);
	    		if(nRet!=OE_NOERROR)
	    		{
	    			error_report("Failed to get extreme points."); 
	    			XF_THROW(XF_ENVELOPE_FAILED_TO_GET_EXTREME_PTS);
	    		}
	    		vXPeak.SetSize(nPeakSize);
	    		vYPeak.SetSize(nPeakSize);
	
	    		
	    		vector vLowerEnvelope;  // for lower envelope storage
	    		vLowerEnvelope.SetSize(nSrcDataSize);
	    		
	    		if(nPeakSize<2)
	    		{
	    			XF_THROW(XF_ENVELOPE_EXTREME_PTS_TOO_SMALL);
	    			error_report("Failed to get enough extreme points.");// too small extreme points
	    		}
	    		
	    		nMode = INTERP_TYPE_SPLINE;
	    		nRet = ocmath_interpolate(vX, vLowerEnvelope, nSrcDataSize, vXPeak, vYPeak, nPeakSize, nMode);
	    		if(nRet!=OE_NOERROR)
	    		{
	    			error_report("Failed to interpolate."); // todo: through XF error
	    			XF_THROW(XF_ENVELOPE_FAILED_TO_INTERPOLATE);
	    		}
	    		
	
	    		
	//	    		_lower_envelope_update_report_data(rd, vEnvelopeX, vEnvelopeY);
				///Kyle 09/11/2009 BETTER_COMMENTS_FOR_OUTPUT
				//_upper_lower_envelope_update_report_data(rd, vEnvelopeX, vEnvelopeY, vLowerEnvelope);
				_upper_lower_envelope_update_report_data(rd, vEnvelopeX, vEnvelopeY, vLowerEnvelope, get_input_data_range_string(iy));
				///End BETTER_COMMENTS_FOR_OUTPUT
	    		if(s_bIsFromUpdatePreview == false)				///Kyle 09/04/2009 ADD_PREVIEW
	    		{
		    		DataPlot dpData;
		    		if(iy.GetPlot(dpData)) // check If data is from a graph
		    		{
		    			DataRange		drPlot;
						int YID = _ENVELOPE_UPPERY;
						if(1!=rd.GetDataRange(drPlot, _ENVELOPE_TABLE_UPPER, _ENVELOPE_UPPERX, &YID))
							error_report("envelope failed to get range");  // todo: error report fail to get range
						else
						{
							xf_check_plot_output_rng_in_source_rng_graph(iy, drPlot);
						}
		    		
						DataRange drPlotLower;
						int YIDLower = _ENVELOPE_LOWERY;
		    			if(1!=rd.GetDataRange(drPlotLower, _ENVELOPE_TABLE_LOWER, _ENVELOPE_LOWERX, &YIDLower))
							error_report("envelope failed to get range");  // todo: error report fail to get range
						else
						{
							xf_check_plot_output_rng_in_source_rng_graph(iy, drPlotLower);
						}
		    		}	
	    		}
	    	}
			break;	
	}
	///Kyle 11/26/2008 QA80-12663 UPDATE_GRAPHLAYER_LEGEND_AFTER_PLOT
	if(s_bIsFromUpdatePreview == false)			///Kyle 09/04/2009 ADD_PREVIEW
	{
		DataPlot dpData;
		if(iy.GetPlot(dpData)) // check If data is from a graph
		{
			GraphLayer gl;
			dpData.GetParent(gl);
			legend_update(gl);
		}
	}
	///End UPDATE_GRAPHLAYER_LEGEND_AFTER_PLOT
	
	/*		
	if(!rd)  // if not specified an output range, create one for it
	{
		Worksheet wks;
		wks.Create();
		wks.SetSize(-1, 2);
		rd.Create();
		xy_range_from_wks_cols(rd,wks,0,1);
	}
	
	_envelopexy_set_data_range(rd,&vEnvelopeX, &vEnvelopeY);
		//_reducexy_update_report_data(rd, vMergedX, vMergedY);
	*/	
}

//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 envelope_event1(TreeNode& trGetN, int nRow, int nEventID, DWORD& dwEnables, LPCSTR lpcszNodeName, WndContainer& DynaCntrlContainer, string& strAux, string& strErrMsg)
{
	if( xf_is_extended_event(nEventID) )
		return envelope_event1_ex(trGetN, nRow, nEventID, dwEnables, lpcszNodeName, DynaCntrlContainer, strAux, strErrMsg);
	DECLARE_BUTTON_ENABLES
	//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 nErr = CER_NO_ERROR;
	int nSize =  get_input_xyrange_data_size(trGetN.iy);
	if(get_input_xyrange_num(trGetN.iy) < 1)
		nErr = XFERR_AT_LEAST_ONE_XYRANGE;
	else if(0 >= nSize)
		nErr = CER_NO_DATA;
	
	if(trGetN.npts.nVal<1)
	{
		bOKEnable = false;
		/// Max 09/09/09 v8.1092-2 USE_PROPER_ERR_MSG
		//strErrMsg = "Too small smooth points";
		strErrMsg = CER_INVALID_POSITIVE_INTEGER;
		strErrMsg += ":" + _L("Number of smooth points");
		return false;
		///---
	
	}
		
	if(nErr != CER_NO_ERROR)
	{
		bOKEnable = false;
		strErrMsg = nErr;
	}
	return true;	
	

}

int envelope_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 envelope_before_execute(TreeNode& trGetN, int nGetNDialog, int& nRet, int dwCntrl)
{
	if(is_xf_startup(nGetNDialog, dwCntrl))
		s_bIsFromUpdatePreview = false;
}
//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 envelope_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

	bOKEnable = _check_input(trGetN, strErrMsg);

	bUpdateGraph = bOKEnable;
	s_bIsPreviewInitTime = true; /// Iris 10/13/09 QA70-14403 PREVIEW_GRAPH_SHOULD_NEVER_RESCALE_ON_CHANGE
	s_strErrMsg = strErrMsg; //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)
{
	
	/// Iris 10/13/09 QA70-14403 PREVIEW_GRAPH_SHOULD_NEVER_RESCALE_ON_CHANGE
	
	Worksheet wks = wksTemp;
	_run_envelope_on_current_data(trGetN, pgTemp, wks);
	/*
	Worksheet wks = wksTemp;
	if(!s_bInit)
	{
		Worksheet wks = wksTemp;
		wks.SetSize(0,-1, true);
		init_preview_graph(trGetN.iy, pgTemp, wks, "CurvePreview", NULL, NULL, 0, 0, 1, PREVIEW_LAYER_FORMAT_SCALE_TYPE);		
		GraphPage gp = pgTemp;
		gp.Refresh(true);
		s_bInit = true;
	}
	_run_envelope_on_current_data(trGetN, pgTemp, wks);
	*/
	///end PREVIEW_GRAPH_SHOULD_NEVER_RESCALE_ON_CHANGE
	
}

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

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

	bOKEnable = _check_input(trGetN, strErrMsg);

	/// Iris 10/13/09 QA70-14403 PREVIEW_GRAPH_SHOULD_NEVER_RESCALE_ON_CHANGE
	if (trNode && trNode.tagName =="iy")
		s_bIsPreviewInitTime = true;
	///end PREVIEW_GRAPH_SHOULD_NEVER_RESCALE_ON_CHANGE
	
	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_envelope(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

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

