#include <origin.h>
#include <GetNBox.h>
#include <xfutils.h>
enum{
	method_ave,
	method_concatenate,
};
enum{
	avex_same,
	avex_common,
	avex_full,
	avex_custom,
	avex_trace,
};
enum{
	interp_linear,
	interp_spline,
	interp_bspline,
};
enum{
	sortx_none,
	sortx_ascend,
	sortx_descend,
};
#include <stats_utils.h>
#include <event_utils.h>		///------ Folger 03/13/09 QA80-13262 CONVERT_OBJECT_VARIABLE_OPTIOANL_TO_NEW_IN_XF_DIALOG


///////////////////////////////////////////////////////////////////////
//////// modification log
/*
/*	Hong 03/09/09 QA80-13243 IMPROVE_AVE_XY_AVOID_MEMORY_LEAKING	*/
/*	Hong 03/10/09 QA80-13243 RECONSTRUCT_GUI_SUGGESTED_BY_EASWAR	*/
/*	Hong 03/13/09 FIX_RUN_FROM_LT_WITHOUT_DLG_FAIL_GET_AUTO_VALUE	*/
/*	Hong 03/13/09 QA80-13243 CONCATENATE_NEED_SORT_X_OPTION			*/
/*	Hong 03/13/09 FIX_CHANGE_THEME_AND_CHECK_AUTO_OF_NPTS_FAIL_AUTU_VALUE*/
/*	Folger 03/13/09 QA80-13262 CONVERT_OBJECT_VARIABLE_OPTIOANL_TO_NEW_IN_XF_DIALOG*/
/*	Hong 03/13/09 MIN_MAX_SHOULD_BE_AUTO_WHEN_DISABLE				*/
/*	Hong 03/16/09 MIN_MAX_SHOULD_BE_AUTO_WHEN_DISABLE				*/
/*	Hong 04/02/09 FIX_FAIL_AUTO_XMAN_IF_OPEN_DLG_WITH_THEME_WHICH_IS_FULL_RANGE_AUTO_UNCEHCK	*/
/*	Max 4/09/09 QA70-13262 v8.0976b _check_init_auto_SHOULD_RUN_EVEN_NO_OUTPUT	*/
/*	Max 4/09/09 QA70-13262 v8.0976b_new THROW_ERR_MSG_WHEN_NOTHING_IS_OUTPUT	*/
/// Folger 04/10/09 QA80-13262-P2 OPTIONAL_SHOWN_INSTEAD_OF_NEW_AFTER_RESET_THEME
/*	Kyle 06/22/2009 QA80-13736 SKIP_THE_RANGE_THAT_WITHOUT_DATA		*/
/*	Kyle 10/10/2009 AT_LEAST_ONE_POINT								*/
/*	Hong 10/22/09 NO_NEED_CHECK_NPTS_IF_NOT_USED					*/
/*	Kyle 10/30/2009 QA80-14550 HANDLE_MISSING_IN_OCMATH_AVE_MULTIPLE_CURVES_IF_NOT_INTERP	*/
/*	Kyle 12/09/2009 DISABLE_SD_SE_N_OUTPUT_ON_METHOD_CONCATENATE_SELECTED		*/
///////////////////////////////////////////////////////////////////////

//put your own support static functions here
/*
enum{
	AVE_REPULICA,
	AVE_BY_INTERP_OR_TOLER,
	CONCATENATE
};
*/
static void _update_tree_shown(TreeNode& trGetN)
{
	/// Hong 03/10/09 QA80-13243 RECONSTRUCT_GUI_SUGGESTED_BY_EASWAR
	/*
	trGetN.sd.Show 		 = true;
	trGetN.se.Show 		 = true;
	trGetN.n.Show 		 = true;
	trGetN.interp.Show 	 = true;
	trGetN.toler.Show 	 = true;
	trGetN.segments.Show = true;
	
	if(trGetN.method.nVal == method_concatenate)
	{
		trGetN.sd.Show 		 = false;
		trGetN.se.Show 		 = false;
		trGetN.n.Show 		 = false;
		trGetN.interp.Show 	 = false;
		trGetN.toler.Show 	 = false;
		trGetN.segments.Show = false;
	}
	else if(trGetN.method.nVal == method_ave)
	{
		trGetN.interp.Show 	 = false;
		trGetN.toler.Show 	 = false;
		trGetN.segments.Show = false;
	}
	else
	{
		trGetN.toler.Show = trGetN.interp.nVal == interp_none? true : false;
	}
	*/
	bool		bShowOpts = (method_ave == trGetN.method.nVal) ? true : false;
	/// Hong 03/13/09 QA80-13243 CONCATENATE_NEED_SORT_X_OPTION
	trGetN.sortx.Show	= !bShowOpts;
	/// end CONCATENATE_NEED_SORT_X_OPTION

	trGetN.avex.Show	= bShowOpts;
	trGetN.sd.Show 		= bShowOpts;
	trGetN.se.Show 		= bShowOpts;
	trGetN.n.Show 		= bShowOpts;
	
	bool	bShowOpt = (avex_same == trGetN.avex.nVal) ? true : false;
	bShowOpt &= bShowOpts;
	trGetN.toler.Show	= bShowOpt;
	
	bShowOpt = (avex_same != trGetN.avex.nVal && avex_trace != trGetN.avex.nVal) ? true : false;
	bShowOpt &= bShowOpts;
	trGetN.xmin.Show	= bShowOpt;
	trGetN.xmax.Show	= bShowOpt;
	
	bShowOpt = (avex_same != trGetN.avex.nVal) ? true : false;
	bShowOpt &= bShowOpts;
	trGetN.npts.Show	= bShowOpt;
	trGetN.interp.Show	= bShowOpt;
	
	bool	bEnable = (avex_custom == trGetN.avex.nVal) ? true : false;
	trGetN.xmin.Enable	= bEnable;
	trGetN.xmax.Enable	= bEnable;
	/// Hong 03/16/09 MIN_MAX_SHOULD_BE_AUTO_WHEN_DISABLE
	/* Hong, the following fix have refreshing problem, as in VC level, only set the auto status when create control.
	/// Hong 03/13/09 MIN_MAX_SHOULD_BE_AUTO_WHEN_DISABLE
	if ( !bEnable )
	{
		TreeNode	trXMin = trGetN.xmin;
		TreeNode	trXMax = trGetN.xmax;
		octree_set_auto_support(&trXMin);
		octree_set_auto_support(&trXMax);
	}
	/// end MIN_MAX_SHOULD_BE_AUTO_WHEN_DISABLE
	*/
	/// end MIN_MAX_SHOULD_BE_AUTO_WHEN_DISABLE
	/// end RECONSTRUCT_GUI_SUGGESTED_BY_EASWAR
}

/// Hong 03/09/09 QA80-13243 IMPROVE_AVE_XY_AVOID_MEMORY_LEAKING
/*
static bool _get_multi_curves_data(const XYRange& rg, int nNumData, OneCurveData *multiCruveData, int& iActualCount, int& nTotalSize, int& nSeg)
{
	for(int ii = 0; ii < nNumData; ii++)
	{
		vector	vxData, vyData, verrData;
		DWORD dwRules = DRR_GET_MISSING | DRR_BAD_WEIGHT_TREATMENT | DRR_GET_DEPENDENT | DRR_NO_FACTORS;
		if ( !rg.GetData(vyData, vxData, &verrData, ii, dwRules) )
			return false;
		
		int	nDataSize = vyData.GetSize();
		if (vxData.GetSize() < nDataSize)
			nDataSize = vxData.GetSize();
		
		int	nErrSize = verrData.GetSize();
		
		if (nDataSize <= 0)
			continue;
		
		if (nErrSize < nDataSize)
			nErrSize = 0;
		
		//adjust segments, ensure each segments has at least 2 points.
		if(nSeg != 0)
			nSeg = (nDataSize/nSeg < 2) ? nDataSize/2 : nSeg;
		
		double *px = (double*)malloc(sizeof(double) * nDataSize);
		double *py = (double*)malloc(sizeof(double) * nDataSize);
		if (NULL == px || NULL == py)
			return false;
		
		memcpy(px, vxData, sizeof(double)*nDataSize);
		memcpy(py, vyData, sizeof(double)*nDataSize);
		
		double *pErr = NULL;
		if (0 < nErrSize)
			memcpy(pErr, verrData, sizeof(double)*nDataSize);
		
		multiCruveData[iActualCount].nSize = nDataSize;
		multiCruveData[iActualCount].pX = px;
		multiCruveData[iActualCount].pY = py;
		multiCruveData[iActualCount].pErr = pErr;
		
		nTotalSize += nDataSize; 
	
		++iActualCount;
	}
	
	if (nTotalSize <= 0)
		return false;
	
	return true;
}
*/
static bool _get_data_tirm_both_end(vector& vx, vector& vy, const XYRange& rg, int indexData, DWORD dwDataRules)
{
	DataRange	drSub;
	if ( !rg.GetSubRange(drSub, dwDataRules, indexData) )
	{
		ASSERT(FALSE);
		return false;
	}
	XYRange		xySub(drSub);
	if ( !xySub )
		return false;
	// Hong QA80-13243, trim missing value at both end as easwar said
	Curve		crv(0, xySub);
	crv.TrimLeft(TRUE);
	crv.TrimRight(TRUE);

	if ( !crv.CopyData(vx, vy) )
		return false;
	
	return true;
}

static bool _get_multi_curves_data(const XYRange& rg, int nNumData, OneCurveDataMngr& mngr, int& iActualCount, int& nTotalSize, int& nSeg)
{
	if ( !mngr.IsValid() )
		return false;
	
	DWORD 		dwRules = DRR_GET_MISSING | DRR_BAD_WEIGHT_TREATMENT | DRR_GET_DEPENDENT | DRR_NO_FACTORS;
	///Kyle 06/22/2009 QA80-13736 SKIP_THE_RANGE_THAT_WITHOUT_DATA
	iActualCount = 0;
	nTotalSize = 0;
	///End SKIP_THE_RANGE_THAT_WITHOUT_DATA
	for(int ii = 0; ii < nNumData; ii++)
	{
		vector		vxData, vyData;
		if ( !_get_data_tirm_both_end(vxData, vyData, rg, ii, dwRules) )
			continue;
		
		int			nDataSize = min(vxData.GetSize(), vyData.GetSize());
		if ( nDataSize <= 0 )
			continue;
		
		//adjust segments, ensure each segments has at least 2 points.
		if ( nSeg != 0 )
			nSeg = (nDataSize/nSeg < 2) ? nDataSize/2 : nSeg;
		
		///Kyle 06/22/2009 QA80-13736 SKIP_THE_RANGE_THAT_WITHOUT_DATA
		//if ( !mngr.Create(ii, FALSE, nDataSize) )
		//	return false;
		//OneCurveData*	pOCD = mngr.GetAt(ii);
		if ( !mngr.Create(iActualCount, FALSE, nDataSize) )
			return false;
		OneCurveData*	pOCD = mngr.GetAt(iActualCount);
		///End SKIP_THE_RANGE_THAT_WITHOUT_DATA
		ASSERT(NULL != pOCD);
		memcpy(pOCD->pX, vxData, sizeof(double)*nDataSize);
		memcpy(pOCD->pY, vyData, sizeof(double)*nDataSize);
		
		nTotalSize += nDataSize;
		++iActualCount;
	}
	
	return (nTotalSize > 0) ? true : false;
}
/// end IMPROVE_AVE_XY_AVOID_MEMORY_LEAKING

static int _check_input_error(TreeNode& trGetN)
{
	int nErr = CER_NO_ERROR;
	
	int nxUse = -1, nyUse = -1, nsdUse = -1, nseUse = -1, nnUse = -1;
	trGetN.x.GetAttribute(STR_ATTRIB_DYNACONTROL_USE_CHECK, nxUse);
	trGetN.y.GetAttribute(STR_ATTRIB_DYNACONTROL_USE_CHECK, nyUse);
	trGetN.sd.GetAttribute(STR_ATTRIB_DYNACONTROL_USE_CHECK, nsdUse);
	trGetN.se.GetAttribute(STR_ATTRIB_DYNACONTROL_USE_CHECK, nseUse);
	trGetN.n.GetAttribute(STR_ATTRIB_DYNACONTROL_USE_CHECK, nnUse);
	
	/// Max 8/3/07 QA70-6073 AVE_MULTI_CURVES_SUPPORT_ONE_CURVE
	///Cheney 2007-7-18 AVE_MULTI_CURVES_NEED_TWO_CURVES_INPUT
	//if(get_input_xyrange_num(trGetN.iy) < 1)
	//	nErr = XFERR_AT_LEAST_ONE_XYRANGE;
	//if(get_input_xyrange_num(trGetN.iy) < 2)
		//nErr = XFERR_AT_LEAST_TWO_XYRANGES;
	///end AVE_MULTI_CURVES_NEED_TWO_CURVES_INPUT
	if(1 > get_input_xyrange_num(trGetN.iy))
		nErr = XFERR_AT_LEAST_ONE_XYRANGE;
	/// END AVE_MULTI_CURVES_SUPPORT_ONE_CURVE
	else if(0>= get_input_xyrange_data_size(trGetN.iy))
		nErr = CER_NO_DATA;
	///Kyle 12/09/2009 DISABLE_SD_SE_N_OUTPUT_ON_METHOD_CONCATENATE_SELECTED
	//else if(nxUse+nyUse+nsdUse+nseUse+nnUse ==0)
	//	nErr= CER_SUPPRESS_ALL_OUTPUT;
	else
	{
		bool bHasOutput = nxUse || nyUse || ( trGetN.method.nVal == method_ave && (nsdUse || nsdUse || nnUse) );
		if( !bHasOutput )
			nErr= CER_SUPPRESS_ALL_OUTPUT;
	}
	///End DISABLE_SD_SE_N_OUTPUT_ON_METHOD_CONCATENATE_SELECTED
	
	return nErr;
}

/// Hong 03/18/09 ADD_ERROR_CHECKING_OF_NPTS
static int _get_min_npts()
{
	return 2;
}
/// end ADD_ERROR_CHECKING_OF_NPTS

/// Hong 03/10/09 QA80-13243 RECONSTRUCT_GUI_SUGGESTED_BY_EASWAR
static int _check_init_auto(TreeNode& trGetN)
{
	/// Hong 03/16/09 MIN_MAX_SHOULD_BE_AUTO_WHEN_DISABLE
	/*
	TreeNode		trXMin = trGetN.xmin;
	bool			bAutoXMin = (1 == octree_get_auto_support(&trXMin)) ? true : false;
	TreeNode		trXMax = trGetN.xmax;
	bool			bAutoXMax = (1 == octree_get_auto_support(&trXMax)) ? true : false;
	TreeNode		trNPts = trGetN.npts;
	bool			bAutoNPts = (1 == octree_get_auto_support(&trNPts)) ? true : false;
	if ( (!tree_is_visible(trXMin) && !tree_is_visible(trXMax) && !tree_is_visible(trNPts)) || ( !bAutoXMin && !bAutoXMax && !bAutoNPts) )
		return CER_NO_ERROR;
	*/
	TreeNode		trXMin = trGetN.xmin, trXMax = trGetN.xmax, trNPts = trGetN.npts;
	bool			bAutoXMin = ( (1 == octree_get_auto_support(&trXMin) || !tree_is_editable(trXMin)) && tree_is_visible(trXMin) ) ? true : false;
	bool			bAutoXMax = ( (1 == octree_get_auto_support(&trXMax) || !tree_is_editable(trXMax)) && tree_is_visible(trXMax) ) ? true : false;
	bool			bAutoNPts = (1 == octree_get_auto_support(&trNPts) && tree_is_visible(trNPts) ) ? true : false;
	if ( !(bAutoXMin || bAutoXMax || bAutoNPts) )
		return CER_NO_ERROR;
	/// end MIN_MAX_SHOULD_BE_AUTO_WHEN_DISABLE
	
	XYRange 		iy;
	TreeNode		trInput = trGetN.iy;
	if ( !okxf_resolve_tree_construct_range(&trInput, &iy) )
		return CER_INVALID_RANGE;
	
	DWORD			dwDataRules = DRR_GET_MISSING | DRR_BAD_WEIGHT_TREATMENT | DRR_GET_DEPENDENT | DRR_NO_FACTORS;
	int				nNumData = iy.GetNumData(dwDataRules);
	if ( 0 == nNumData )
		return CER_INVALID_RANGE;
	
	bool			bIntersect = (avex_same == trGetN.avex.nVal || avex_common == trGetN.avex.nVal) ? true : false;
	bool			bNoValidData = true;
	double			dXMin, dXMax;
	int				nNumTotalPts(0);
	vector			vx, vy;
	for ( int ii = 0; ii < nNumData; ii++ )
	{
		if ( !_get_data_tirm_both_end(vx, vy, iy, ii, dwDataRules) )
			continue;
		
		if ( 0 == vy.GetSize() )
			continue;
		
		nNumTotalPts += vy.GetSize();
		
		double		dMin, dMax;
		int			nMinIdx;
		vx.GetMinMax(dMin, dMax, &nMinIdx);
		if ( -1 == nMinIdx )
			continue;
		
		if ( !bNoValidData )
			dXMin = bIntersect ? max(dXMin, dMin) : min(dXMin, dMin);
		else
			dXMin = dMin;
			
		if ( !bNoValidData )
			dXMax = bIntersect ? min(dXMax, dMax) : max(dXMax, dMax);
		else
			dXMax = dMax;
		bNoValidData = false;
	}
	if ( bAutoXMin )
		trXMin.dVal = dXMin;
	if ( bAutoXMax )
		trXMax.dVal = dXMax;
	if ( bAutoNPts )
	{
		/// Hong 03/18/09 ADD_ERROR_CHECKING_OF_NPTS
		//trNPts.nVal = min(1000, nNumTotalPts / nNumData * 5);
		trNPts.nVal = max(min(1000, nNumTotalPts / nNumData * 5), _get_min_npts());
		/// end ADD_ERROR_CHECKING_OF_NPTS
	}
	
	if ( bNoValidData )
		return CER_NO_DATA;
	
	if ( trXMin.dVal > trXMax.dVal )
		return (avex_same == trGetN.avex.nVal) ? XFERR_NO_COMMON_X_RANGE: CER_MIN_MAX;
	
	return CER_NO_ERROR;
}
/// end RECONSTRUCT_GUI_SUGGESTED_BY_EASWAR


void averagexy(const XYRange& iy, const int& method, const int& avex, const double& toler, const int& npts, const double& xmin, const double& xmax, const int& interp, const int& sortx, vector& x, vector& y, vector& sd, vector& se, vector& n)
{
	///Max 4/09/09 QA70-13262 v8.0976b_new THROW_ERR_MSG_WHEN_NOTHING_IS_OUTPUT
	///Kyle 12/09/2009 DISABLE_SD_SE_N_OUTPUT_ON_METHOD_CONCATENATE_SELECTED
	//if(!x && !y && !se && !sd && !n)
	bool bHasOutput = x || y || ( method == method_ave && (se || sd || n) );
	if( !bHasOutput)
	///End DISABLE_SD_SE_N_OUTPUT_ON_METHOD_CONCATENATE_SELECTED
		XF_THROW(CER_SUPPRESS_ALL_OUTPUT);
	/// THROW_ERR_MSG_WHEN_NOTHING_IS_OUTPUT
	
	int	nNumData = iy.GetNumData(DRR_GET_MISSING | DRR_BAD_WEIGHT_TREATMENT | DRR_GET_DEPENDENT | DRR_NO_FACTORS);
	if (nNumData <= 0)
		XF_THROW(XFERR_GET_DATA_FAILED);
	
	/// Hong 03/18/09 ADD_ERROR_CHECKING_OF_NPTS
	/// Hong 10/22/09 NO_NEED_CHECK_NPTS_IF_NOT_USED
	//if ( method_concatenate != method && npts < _get_min_npts() )
	if ( method_concatenate != method && avex_same != avex && npts < _get_min_npts() )
	/// end NO_NEED_CHECK_NPTS_IF_NOT_USED
		XF_THROW_EX2(CER_INPUT_ARGUMENT_LESS_THAN_SPECIFIED_VALUE, _L("Number of Points"), _get_min_npts());
	/// end ADD_ERROR_CHECKING_OF_NPTS
	
	int nAveSize = 0;
	
	vector vx, vy, vsdTemp;
	vector<int> vnTemp;
	
	if(method == method_concatenate) 
	{
		DWORD dwPlotID;
		if(iy.GetData(DRR_COMBINED_SIMPLE | DRR_GET_DEPENDENT, 0, &dwPlotID, NULL, &vy, &vx) < 0)
			XF_THROW(XFERR_GET_DATA_FAILED);
		/// Hong 03/13/09 QA80-13243 CONCATENATE_NEED_SORT_X_OPTION
		if ( sortx_none != sortx )
		{
			bool			bAscending = (sortx_ascend == sortx) ? true : false;
			vector<UINT>	nvIndices;
			vx.Sort(bAscending ? SORT_ASCENDING : SORT_DESCENDING, TRUE, nvIndices);
			vy.Reorder(nvIndices);
		}
		/// end CONCATENATE_NEED_SORT_X_OPTION
	}
	else  //average replicate data or average by interp or toler
	{
		/// Hong 03/09/09 QA80-13243 IMPROVE_AVE_XY_AVOID_MEMORY_LEAKING
		/*
		OneCurveData *multiCruveData = (OneCurveData*)malloc(sizeof(OneCurveData)*nNumData);
		if (NULL == multiCruveData)
			XF_THROW(XFERR_NULL_POINTER);
		
		int	iActualCount;
		if(!_get_multi_curves_data(iy, nNumData, multiCruveData, iActualCount, nAveSize, segments))
			XF_THROW(XFERR_GET_DATA_FAILED);
		*/
		OneCurveDataMngr 		mngr(nNumData);
		if ( !mngr.IsValid() )
			XF_THROW(XFERR_NULL_POINTER);
		
		/// Hong 03/10/09 QA80-13243 RECONSTRUCT_GUI_SUGGESTED_BY_EASWAR
		int			segments(3); // Hong, temp for compile, need fisher to continue
		/// end RECONSTRUCT_GUI_SUGGESTED_BY_EASWAR
		int			iActualCount;
		if ( !_get_multi_curves_data(iy, nNumData, mngr, iActualCount, nAveSize, segments) )
			XF_THROW(XFERR_GET_DATA_FAILED);
		
		OneCurveData*			multiCruveData = mngr.GetAt(0);
		ASSERT(NULL != multiCruveData);
		/// end IMPROVE_AVE_XY_AVOID_MEMORY_LEAKING
		
		/// Fisher 3/10/09 QA80-13243 REWRITE_OCMATH_AVERAGE_MULTIPLE_CURVES
		//vx.SetSize(nAveSize);
		//vy.SetSize(nAveSize);
		if(method_ave == method && avex_trace == avex)
		{
			nAveSize = npts;
			vx.SetSize(nAveSize);
			vy.SetSize(nAveSize);		
		}
		else if( method_ave == method && avex_same != avex && avex_trace != avex)
		{
			vx.Data(xmin, xmax, (xmax-xmin)/(npts-1));
			///Kyle 10/10/2009 AT_LEAST_ONE_POINT
			if(vx.GetSize() < 1)
				vx.Add(xmin);
			///End AT_LEAST_ONE_POINT
			nAveSize = vx.GetSize();
			vy.SetSize(nAveSize);
		}
		else
		{
			vx.SetSize(nAveSize);
			vy.SetSize(nAveSize);
		}
		/// End REWRITE_OCMATH_AVERAGE_MULTIPLE_CURVES		
		
		double *pErrOutput = NULL;
		if (sd || se)
		{
			vsdTemp.SetSize(nAveSize);
			pErrOutput = vsdTemp;
		}
		
		int	*pn = NULL;
		if(sd || se || n)
		{
			vnTemp.SetSize(nAveSize);
			pn = vnTemp;
		}
		
		/// Fisher 1/7/09 QA80-12727 AVECURVES_RESULTS_NOT_GOOD_WHEN_CURVES_HAVE_MISSING_VALUES
		if(avex_same != avex)			///Kyle 10/30/2009 QA80-14550 HANDLE_MISSING_IN_OCMATH_AVE_MULTIPLE_CURVES_IF_NOT_INTERP
		ocmath_ave_multiple_curves_remove_missing_value( iActualCount, multiCruveData);
		/// End AVECURVES_RESULTS_NOT_GOOD_WHEN_CURVES_HAVE_MISSING_VALUES
		
		
		int	nAveRet;
		///Cheney 2007-7-17 USE_WROGN_CONDITION
		//if(method == method_ave)  //average by interp or toler
		if(method == method_ave)  //average by interp or toler
		/// end RECONSTRUCT_GUI_SUGGESTED_BY_EASWAR
		///end USE_WROGN_CONDITION
		{
			//if segments == 0, that means only 1 point, average it directly.
			
			/// Fisher 3/10/09 QA80-13243 REWRITE_OCMATH_AVERAGE_MULTIPLE_CURVES
			/*
			int nCheckOrder = (segments == 0) ? MCO_MONO_CONSISTENT : ocmath_check_order_multiple_curves(iActualCount, multiCruveData, segments);
	
			if(nCheckOrder == MCO_MONO_CONSISTENT) // consistent monotonic
			{
				nAveRet = ocmath_ave_multiple_curves(iActualCount, multiCruveData, &nAveSize, vx, vy, pErrOutput,
							AVMC_SD, bInterp, interp - 1, toler, pn);				
			}
			else if(nCheckOrder == MCO_MONO_NOT_CONSISTENT) // not monotonic but consistent
			{
				nAveRet = ocmath_ave_multiple_curves_by_length_parameter(iActualCount, multiCruveData, 
								&nAveSize, vx, vy, pErrOutput, AVMC_SD, pn);
			}
			else
				XF_THROW(XFERR_NOT_CONSISTENT);
			*/
			if(avex_trace == avex)
			{
				nAveRet = ocmath_ave_multiple_curves_by_length_parameter(iActualCount, multiCruveData, 
								&nAveSize, vx, vy, pErrOutput, AVMC_SD, pn, interp);				
			}
			else
			{
				bool bInterp = avex_same != avex;
				nAveRet = ocmath_ave_multiple_curves(iActualCount, multiCruveData, &nAveSize, vx, vy, pErrOutput,
					AVMC_SD, bInterp, interp, toler, pn);				
			}
			/// End REWRITE_OCMATH_AVERAGE_MULTIPLE_CURVES
			
		}
		else //average replicate data
		{
			nAveRet = ocmath_ave_replica_data_for_multiple_curves(iActualCount, multiCruveData, 
								&nAveSize, vx, vy, pErrOutput, AVMC_SD, pn);
		}
						
		/// Hong 03/09/09 QA80-13243 IMPROVE_AVE_XY_AVOID_MEMORY_LEAKING
		/*
		for (int ii = 0; ii < iActualCount; ii++)
		{
			free(multiCruveData[ii].pX);
			free(multiCruveData[ii].pY);
			if ( multiCruveData[ii].pErr )
				free(multiCruveData[ii].pErr);
		}
		free(multiCruveData);
		*/
		/// end IMPROVE_AVE_XY_AVOID_MEMORY_LEAKING
		
		if ( nAveRet != OE_NOERROR )
			XF_THROW_EX(CER_UNKNOWN_ERROR_EX, nAveRet);
		
		vx.SetSize(nAveSize);
		vy.SetSize(nAveSize);
	}
	
	//get result, check vector size for forbidding user input wrong thing by script window
	if(x && vx.GetSize() > 0)
		x = vx;
	
	if(y && vy.GetSize() > 0)
		y = vy;
	
	if(sd && vsdTemp.GetSize() > 0)
	{
		vsdTemp.SetSize(nAveSize);
		sd = vsdTemp;
	}
	
	if(se && vsdTemp.GetSize() > 0)
	{
		vsdTemp.SetSize(nAveSize);
		vnTemp.SetSize(nAveSize);
		se = vsdTemp / sqrt(vnTemp * 1.0);
	}
	
	if(n && vnTemp.GetSize() > 0)
	{
		vnTemp.SetSize(nAveSize);
		n = vnTemp;
	}
	
}

//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 averagexy_event1(TreeNode& trGetN, int nRow, int nEventID, DWORD& dwEnables, LPCSTR lpcszNodeName, WndContainer& DynaCntrlContainer, string& strAux, string& strErrMsg)
{
	if( xf_is_extended_event(nEventID) )
		return averagexy_event1_ex(trGetN, nRow, nEventID, dwEnables, lpcszNodeName, DynaCntrlContainer, strAux, strErrMsg);
	DECLARE_BUTTON_ENABLES
	
	///------ Folger 04/10/09 QA80-13262-P2 OPTIONAL_SHOWN_INSTEAD_OF_NEW_AFTER_RESET_THEME
	if ( GETNE_ON_THEME == nEventID )
		check_convert_optional_outputs_to_new(trGetN);
	///------ End OPTIONAL_SHOWN_INSTEAD_OF_NEW_AFTER_RESET_THEME
	
	_update_tree_shown(trGetN);
	
	int nErr = CER_NO_ERROR;
	
	nErr = _check_input_error(trGetN);
	
	if(nErr != CER_NO_ERROR)
	{
		bOKEnable = false;
		strErrMsg = nErr;
	}
	
	/// Hong 03/10/09 QA80-13243 RECONSTRUCT_GUI_SUGGESTED_BY_EASWAR
	/// Hong 03/13/09 FIX_RUN_FROM_LT_WITHOUT_DLG_FAIL_GET_AUTO_VALUE
	//if ( CER_NO_ERROR == nErr && (nEventID == GETNE_ON_INIT || !lstrcmpi(lpcszNodeName, "iy") || !lstrcmpi(lpcszNodeName, "method")
	//	 || !lstrcmpi(lpcszNodeName, "avex") || !lstrcmpi(lpcszNodeName, "xmin") || !lstrcmpi(lpcszNodeName, "xmax")) )
	/// Hong 03/13/09 FIX_CHANGE_THEME_AND_CHECK_AUTO_OF_NPTS_FAIL_AUTU_VALUE
	//if ( CER_NO_ERROR == nErr && (!lstrcmpi(lpcszNodeName, "iy") || !lstrcmpi(lpcszNodeName, "method")
	//	 || !lstrcmpi(lpcszNodeName, "avex") || !lstrcmpi(lpcszNodeName, "xmin") || !lstrcmpi(lpcszNodeName, "xmax")) )
	if ( CER_NO_ERROR == nErr && (GETNE_ON_THEME == nEventID || !lstrcmpi(lpcszNodeName, "iy") || !lstrcmpi(lpcszNodeName, "method") || !lstrcmpi(lpcszNodeName, "npts")
		 || !lstrcmpi(lpcszNodeName, "avex") || !lstrcmpi(lpcszNodeName, "xmin") || !lstrcmpi(lpcszNodeName, "xmax")) )
	/// end FIX_CHANGE_THEME_AND_CHECK_AUTO_OF_NPTS_FAIL_AUTU_VALUE
	/// end FIX_RUN_FROM_LT_WITHOUT_DLG_FAIL_GET_AUTO_VALUE
	{
		nErr = _check_init_auto(trGetN);
		if ( CER_NO_ERROR != nErr )
		{
			strErrMsg = nErr;
			bOKEnable = false;
		}
		/// Hong 03/18/09 ADD_ERROR_CHECKING_OF_NPTS
		/// Hong 10/22/09 NO_NEED_CHECK_NPTS_IF_NOT_USED
		//if ( GETNE_ON_THEME == nEventID || !lstrcmpi(lpcszNodeName, "npts") )
		if ( tree_is_visible(trGetN.npts) )
		/// end NO_NEED_CHECK_NPTS_IF_NOT_USED
		{
			int			nMinPts = _get_min_npts();
			if ( trGetN.npts.nVal < nMinPts )
			{
				strErrMsg = CER_INPUT_ARGUMENT_LESS_THAN_SPECIFIED_VALUE;
				strErrMsg += ":" + _L("Number of Points")+ "|" + nMinPts;
				bOKEnable = false;
			}
		}
		/// end ADD_ERROR_CHECKING_OF_NPTS
	}
	/// end RECONSTRUCT_GUI_SUGGESTED_BY_EASWAR
	
	return true;

}

int averagexy_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 averagexy_before_execute(TreeNode& trGetN, int nGetNDialog, int& nRet, int dwCntrl)
{
	//_update_tree_shown(trGetN);
	/// Hong 03/13/09 FIX_RUN_FROM_LT_WITHOUT_DLG_FAIL_GET_AUTO_VALUE
	if ( is_xf_startup(nGetNDialog, dwCntrl) )
	{
		int			nErr = _check_input_error(trGetN);
		/// Max 4/09/09 QA70-13262 v8.0976b _check_init_auto_SHOULD_RUN_EVEN_NO_OUTPUT
		//if ( CER_NO_ERROR == nErr )
		if ( CER_NO_ERROR == nErr || CER_SUPPRESS_ALL_OUTPUT == nErr)
		/// ---
		{
			/// Hong 04/02/09 FIX_FAIL_AUTO_XMAN_IF_OPEN_DLG_WITH_THEME_WHICH_IS_FULL_RANGE_AUTO_UNCEHCK
			// Hong, function _check_init_auto depend on trNode Enable/Shown status, so need update before calling
			_update_tree_shown(trGetN);			
			/// end FIX_FAIL_AUTO_XMAN_IF_OPEN_DLG_WITH_THEME_WHICH_IS_FULL_RANGE_AUTO_UNCEHCK
			nErr = _check_init_auto(trGetN);
		}
		
		if ( CER_NO_ERROR != nErr && 0 == nGetNDialog && (dwCntrl&LTXF_THEME_USED) && (dwCntrl&LTXF_FROM_GUI_MENU) )
			nRet = XFEVT_PROCEED_WITH_DLG;
	}
	/// end FIX_RUN_FROM_LT_WITHOUT_DLG_FAIL_GET_AUTO_VALUE
	
	///Kyle 12/09/2009 DISABLE_SD_SE_N_OUTPUT_ON_METHOD_CONCATENATE_SELECTED
	if(nGetNDialog == 0 && (dwCntrl & LTXF_EXECUTE) && trGetN.method.nVal == method_concatenate)
	{
		int		nUseCheck = 0;
		trGetN.sd.SetAttribute(STR_ATTRIB_DYNACONTROL_USE_CHECK, nUseCheck);
		trGetN.se.SetAttribute(STR_ATTRIB_DYNACONTROL_USE_CHECK, nUseCheck);
		trGetN.n.SetAttribute(STR_ATTRIB_DYNACONTROL_USE_CHECK, nUseCheck);
	}
	///End DISABLE_SD_SE_N_OUTPUT_ON_METHOD_CONCATENATE_SELECTED
	
	///------ Folger 03/13/09 QA80-13262 CONVERT_OBJECT_VARIABLE_OPTIOANL_TO_NEW_IN_XF_DIALOG
	if ( nGetNDialog > 0 )		/// open dialog
		check_convert_optional_outputs_to_new(trGetN);
	///------ End CONVERT_OBJECT_VARIABLE_OPTIOANL_TO_NEW_IN_XF_DIALOG
}
//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 averagexy_event1_ex(TreeNode& trGetN, int nRow, int nEventID, DWORD& dwEnables, LPCSTR lpcszNodeName, WndContainer& DynaCntrlContainer, string& strAux, string& strErrMsg)
{
	return false;
}
