#include <origin.h>
#include <GetNBox.h>
#include <xfutils.h>
enum{
	method_specify,
	method_range,
	method_snd,
	method_max,
	method_min,
	method_mean,
	method_median,
	method_sd,
	method_norm,
	method_mode,
	method_sum,
};

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

/***************************************************************************************
/// Modification Log :
/// Folger 07/23/08 BETTER_OPREATION_OUTPUT_COLUMN_COMMENTS
/// Folger 09/25/08 QA80-12276 SET_SAMPLING_INTERVAL_FOR_YXRANGE_OUTPUT
/// Max 11/25/08 QA70-12615 v8.0975d SHARE_SAME_FUNC_FOR_NORMALIZE_AND_VNORMALIZE
/// Sophy 8/20/2009 QA80-14087-P9 MORE_CHECH_ON_USER_SETTINGS_BEFORE_EXECUTE
/// Sophy 9/15/2009 IMPROVE_COMMENTS_FOR_NORMALIZE_RESULT_COLUMNS
***************************************************************************************/

//put additional include files here
//#define Y_INDEX_IN_XYRANGE 1

//#define STR_NODE_OPTION "method"	// Max 11/20/08 no need to define if use in one place only
//#define STR_VNORMALIZE_NAME "vnormalize"	// Max 11/20/08 no need to define if use in one place only

#define _NORMALIZE_METHOD_ERROR 0   //temp solution

//put your own support static functions here

///Justin 2007-04-21 qa70-9669 V8.0605 IMPROVE_NORMALIZATION
/*
enum{
	NORMALIZE_BY_MEAN,
	NORMALIZE_BY_MEDIAN,
	NORMALIZE_BY_SD,
	NORMALIZE_BY_NORM,
	NORMALIZE_BY_MODE,
	NORMALIZE_MAX_TO_VALUE,
	NORMALIZE_AREA_TO_VALUE,
};
*/
///End IMPROVE_NORMALIZATION			

/// Max 11/25/08 QA70-12615 v8.0975d SHARE_SAME_FUNC_FOR_NORMALIZE_AND_VNORMALIZE
// no need to use a util func
//static void _initial_method_show(TreeNode& trGetN)
//{
	//switch(trGetN.method.nVal)
	//{
	/////Justin 2007-04-21 qa70-9669 V8.0605 IMPROVE_NORMALIZATION
	///*
		//case NORMALIZE_BY_MEAN:
		//case NORMALIZE_BY_MEDIAN:
		//case NORMALIZE_BY_SD:
		//case NORMALIZE_BY_NORM:
		//case NORMALIZE_BY_MODE:
		//default:
			//trGetN.value.Show = false;
			//break;
		//case NORMALIZE_MAX_TO_VALUE:
		//case NORMALIZE_AREA_TO_VALUE:
			//trGetN.value.Show = true;
			//break;
	//*/
	//case method_specify:
	////case method_Max:
	////case method_Min:
		//trGetN.val.Show = true;
		//break;
	//default:
		//trGetN.val.Show = false;
	/////End IMPROVE_NORMALIZATION			
	//}
//}
// END SHARE_SAME_FUNC_FOR_NORMALIZE_AND_VNORMALIZE

/// Max 11/25/08 QA70-12615 v8.0975d SHARE_SAME_FUNC_FOR_NORMALIZE_AND_VNORMALIZE
// move to event_utils.c
/*
static bool _set_data_info(TreeNode& trDataInfo, const TreeNode& trInputXY)
{
	XYRange xyTemp;
	TreeNode trXY = trInputXY;
	if(!okxf_resolve_tree_construct_range(&trXY, &xyTemp) )
		return false;
	
	vector vyIn, vxIn;
	DWORD dwRulesEx = DRR_GET_MISSING | DRR_BAD_WEIGHT_TREATMENT;
	xyTemp.GetData(vyIn, vxIn, NULL, 0, dwRulesEx);

	int nSize, nNonMissing;
	double dMean, dSD, dMedian, dMax, dMin, dNorm;

	nSize = vyIn.GetSize();
	vyIn.GetMinMax(dMin, dMax);
	ocmath_basic_summary_stats(vyIn.GetSize(), vyIn, &nNonMissing, &dMean, &dSD);
	/// Max 11/5/07 SORT_BEFORE_CALCULATE_MEDIAN
	//dMedian = (nSize%2) ? vyIn[nSize/2] : 0.5* ( vyIn[nSize/2] + vyIn[nSize/2-1]);
	vector vySort;
	vySort = vyIn;
	vySort.Sort();
	dMedian = (vySort.GetSize() == 1) ? vySort[0] : ((nSize%2) ? vySort[nSize/2] : 0.5* ( vySort[nSize/2] + vySort[nSize/2-1]));
	/// END SORT_BEFORE_CALCULATE_MEDIAN
	
	vector vTmp;
	vTmp = vyIn * vyIn;
	vTmp.Sum(dNorm);
	dNorm = sqrt(dNorm);
	
	trDataInfo.number.nVal = nSize;
	trDataInfo.missing.nVal = nSize - nNonMissing;	
	trDataInfo.max.dVal = dMax;
	trDataInfo.min.dVal = dMin;
	trDataInfo.mean.dVal = dMean;
	trDataInfo.sd.dVal = dSD;
	trDataInfo.median.dVal = dMedian;
	trDataInfo.norm.dVal = dNorm;
	
	return true;
}
*/
///END v8.0975d SHARE_SAME_FUNC_FOR_NORMALIZE_AND_VNORMALIZE

///Justin 2007-04-21 qa70-9669 V8.0605 IMPROVE_NORMALIZATION
/*
//Divided data by mean
void _normalize_by_mean(vector& vyIn)
{
	double dSum;
	vyIn.Sum(dSum);
	double mean=dSum/vyIn.GetSize();
	if (is_equal(mean, 0))
	{
		XF_THROW(XFERR_DIVIDED_BY_ZERO);
	}
	vyIn/=mean;
}

//Divided data by median
void _normalize_by_median(vector& vyIn)
{
	vector tempVector;
	double median;
	tempVector=vyIn;
	int nSize=tempVector.GetSize();
	tempVector.Sort();
	if(nSize%2)
		median=tempVector[(nSize-1)/2];
	else
		median=(tempVector[nSize/2]+tempVector[nSize/2-1])/2.0;
	if (is_equal(median, 0))
	{
		XF_THROW(XFERR_DIVIDED_BY_ZERO);
	}
	vyIn/=median;
}

//Divided data by standard deviation
void _normalize_by_sd(vector& vyIn)
{
	vector tempVector;
	double dSum,sd;
	tempVector=vyIn;
	tempVector.Sum(dSum);
	double mean=dSum/tempVector.GetSize();
	tempVector-=mean;
	tempVector*=tempVector;
	tempVector.Sum(dSum);
	sd=sqrt(dSum/tempVector.GetSize());
	if (is_equal(sd, 0))
	{
		XF_THROW(XFERR_DIVIDED_BY_ZERO);
	}
	vyIn/=sd;
}

//Divided data by norm
void _normalize_by_norm(vector& vyIn)
{
	vector tempVector;
	double norm;
	tempVector=vyIn;
	tempVector*=tempVector;
	tempVector.Sum(norm);
	norm/=tempVector.GetSize();
	if (is_equal(norm, 0))
	{
		XF_THROW(XFERR_DIVIDED_BY_ZERO);
	}
    vyIn/=norm;
}

//Divided data by mode
void _normalize_by_mode(vector& vyIn)
{
	vector tempVector;
	vector<int> countVector;
	vector<int> tempCount;
	int index1=1;
	int index2=1;
	int count=0;
	tempVector=vyIn;
	
	int nSize=tempVector.GetSize();
	double tempElement=tempVector[0];
	tempVector.Sort();
	while(index1<nSize)
	{
		if(tempVector[index1]==tempElement)
			index2++;
		else
		{
			tempElement=tempVector[index1];
			countVector.InsertAt(count,index2);
			count++;
			index2=1;
		}
		index1++;
	}
	countVector.InsertAt(count,index2);
	
	tempCount=countVector;
	nSize=countVector.GetSize();
	countVector.Sort();
	
	if(countVector[nSize-1]==1)
	{
		XF_THROW(XFERR_NO_MODE);
	}
	if(nSize>1)
	{
		if(countVector[nSize-1]==countVector[nSize-2])
		{
			XF_THROW(XFERR_MORE_MODE);
		}
	}
	
	double min,max;
	int imin,imax;
	int modeIndex=0;
	tempCount.GetMinMax(min,max,&imin,&imax);
	
	for(int ii=0;ii<=imax;ii++)
		modeIndex+=tempCount[ii];
	double mode=tempVector[modeIndex-1];
	if (is_equal(mode, 0))
	{
		XF_THROW(XFERR_DIVIDED_BY_ZERO);
	}
	vyIn=vyIn/mode;		
}

//Normalize max to a user-specified value
void _normalize_max_to_value(vector& vyIn,const double& value)
{
	double min,max;
	vyIn.GetMinMax(min,max);
	if (is_equal(max, 0))
	{
		XF_THROW(XFERR_DIVIDED_BY_ZERO);
	}
	vyIn*=value/max;
}

//Normalize area under the curve to a user-specified value
void _normalize_area_to_value(vector& vyIn,vector& vxIn,const double& value)
{
 	vector vIntegrated;
	int nFrom = 0, nTo = vyIn.GetUpperIndex();	//	integration index
	vIntegrated.SetSize(nTo+1);	// size = last_index + 1
	IntegrationResult result;
	double area;
	
	if(OE_NOERROR ==ocmath_integrate(vxIn, vyIn, nFrom, nTo, &result, vIntegrated))
	{
		area=result.Area;
		if (is_equal(area, 0))
		{
			XF_THROW(XFERR_DIVIDED_BY_ZERO);
		}
		vyIn*=value/area;
	}
	else
	{
		XF_THROW(XFERR_INTEG_FAILED);
	}	
}
*/
///End IMPROVE_NORMALIZATION

///Cheney 2007-6-7 ADD_AN_ERR_CHECK_FUNC
static int _check_err_condition(TreeNode& trGetN)
{
	int nErr = CER_NO_ERROR;
	
	if(get_input_xyrange_num(trGetN.iy) != 1) 
		nErr = CER_NOT_ONE_XYRANGE;
	
	if(nErr == CER_NO_ERROR && method_specify == trGetN.method.nVal && trGetN.val.dVal == 0) //if(nErr == CER_NO_ERROR && trGetN.value.dVal == 0)
		nErr = XFERR_DIVIDED_BY_ZERO;
	
	///Sophy 8/20/2009 QA80-14087-P9 MORE_CHECH_ON_USER_SETTINGS_BEFORE_EXECUTE
	if ( nErr == CER_NO_ERROR && trGetN.oy.Range1.X.IsEmpty() && trGetN.oy.Range1.Y.IsEmpty() )
		nErr = CER_INVALID_OUT_RANGE;
	///end MORE_CHECH_ON_USER_SETTINGS_BEFORE_EXECUTE
	return nErr;
}
///end ADD_AN_ERR_CHECK_FUNC

//------ Folger 07/23/08 BETTER_OPREATION_OUTPUT_COLUMN_COMMENTS
static	void	_set_output_range_comments(XYRange &oy, const XYRange& iy, int nMethod, double rValue)
{
	/// Max 11/25/08 QA70-12615 v8.0975d SHARE_SAME_FUNC_FOR_NORMALIZE_AND_VNORMALIZE
	/*
	vector<string>		vsMethods = {
		"Divided by ",
		"Normalize to [0, 1]",
		"Transfer to N(0, 1)",
		"Divided by Max",
		"Divided by Min",
		"Divided by Mean",
		"Divided by Median",
		"Divided by SD",
		"Divided by Norm",
		"Divided by Mode"
	};
	
	string strMethod = vsMethods[nMethod];
	if ( nMethod == 0 )
		strMethod += ftoa(rValue);
	*/
	///Sophy 9/15/2009 IMPROVE_COMMENTS_FOR_NORMALIZE_RESULT_COLUMNS
	//string strMethod = normalize_get_method_string(nMethod, rValue);
	string strComments = normalize_get_method_string(get_input_data_range_string(iy), nMethod, rValue);
	///end IMPROVE_COMMENTS_FOR_NORMALIZE_RESULT_COLUMNS
	/// END SHARE_SAME_FUNC_FOR_NORMALIZE_AND_VNORMALIZE
	
	///Sophy 9/15/2009 IMPROVE_COMMENTS_FOR_NORMALIZE_RESULT_COLUMNS
	//string	strComments;
	//strComments.Format("%s of %s", strMethod, get_input_data_range_string(iy));
	///end IMPROVE_COMMENTS_FOR_NORMALIZE_RESULT_COLUMNS
	oy.SetOutputComment(strComments);
}
//------ End BETTER_OPREATION_OUTPUT_COLUMN_COMMENTS


void normalize(const XYRange& iy, const TreeNode& datainfo, const int& method, const double& val, XYRange& oy)
{
	
	vector vxIn,vyIn;
	
	DWORD dwRulesEx = DRR_GET_MISSING | DRR_BAD_WEIGHT_TREATMENT;
	
	if(!iy.IsValid() || !iy.GetData(vyIn, vxIn, NULL, 0, dwRulesEx))	
		XF_THROW(CER_NOT_ONE_XYRANGE)
	
	///Justin 2007-04-21 qa70-9669 V8.0605 IMPROVE_NORMALIZATION 
	/*
	vector vTemp;
	vector<uint> vyIndices;
	vTemp = vyIn;
	vTemp*=vTemp;
	vTemp.Sort(SORT_DESCENDING, FALSE, vyIndices);
	
	vxIn.Trim();
	vyIn.Trim();
	int tOptions=method;
	
	switch (tOptions)
	{	
	case NORMALIZE_BY_MEAN:
		_normalize_by_mean(vyIn);
		break;
	case NORMALIZE_BY_MEDIAN:
		_normalize_by_median(vyIn);
		break;
	case NORMALIZE_BY_SD:
		_normalize_by_sd(vyIn);
		break;
	case NORMALIZE_BY_NORM:
		_normalize_by_norm(vyIn);
		break;
	case NORMALIZE_BY_MODE:
		_normalize_by_mode(vyIn);
		break;
	case NORMALIZE_MAX_TO_VALUE:
		_normalize_max_to_value(vyIn,value);
		break;
	case NORMALIZE_AREA_TO_VALUE:
		_normalize_area_to_value(vyIn,vxIn,value);
		break;	
	}
	int xSize = vxIn.GetSize();
	int ySize = vyIn.GetSize();
	if( xSize > ySize)
	{
		for( int ii = ySize; ii < xSize; ii++)
		{
			vyIn.InsertAt(vyIndices[ii], NANUM);
		}
	}
	if(!oy.SetData(&vyIn,&vxIn))
		XF_THROW(XFERR_FAIL_IN_SET_XYRANGE_DATA);
	*/
		
	///Justin 2007-04-24 qa70-9669 V8.0607 CALL_VNORMALIZE_TO_AVOID_DUPLICATION_OF_CODE
	/*
	double dNormValue;
	int nSize = vyIn.GetSize();
	switch(method)
	{
	case method_specify:
		dNormValue = value;
		break;
	case method_Mean:
		dNormValue = ocmath_d_mean_variance(vyIn, vyIn.GetSize(), NULL);
		break;
	case method_Median:
		dNormValue = (nSize%2) ? vyIn[nSize/2] : 0.5* ( vyIn[nSize/2] + vyIn[nSize/2-1]);
		break;
	case method_SD:
		ocmath_basic_summary_stats(vyIn.GetSize(), vyIn, NULL, NULL, &dNormValue);
		break;
	case method_Norm:
		///here need to study clearly what is norm.
		vector vTmp;
		vTmp = vyIn * vyIn;
		vTmp.Sum(dNormValue);
		dNormValue /= vTmp.GetSize();
		break;
	case method_Mode:
		ocmath_opt_summary_stats(vyIn.GetSize(), vyIn, 0.95, &dNormValue); //Here 0.95 doesn't make sense
		break;
	case method_Max:
		double dMin;
		vyIn.GetMinMax(dMin, dNormValue);
		dNormValue /= value;
		break;
	case method_Min:
		double dMax;
		vyIn.GetMinMax(dNormValue, dMax);
		dNormValue /= value;
		break;	
	default:
		XF_THROW(_NORMALIZE_METHOD_ERROR)
	}
	dNormValue = 1.0/dNormValue;
	vyIn *= dNormValue; 
	*/
	
	//XFBase	xf(STR_VNORMALIZE_NAME);
	XFBase	xf("vnormalize");
	if ( !xf )
		XF_THROW(XFERR_FAIL_LOAD_XF);
	if ( !xf.SetArgs(vyIn, datainfo, method, val, vyIn) ) //if ( !xf.SetArgs(vyIn, sub, method, value, vyIn) )
		XF_THROW(XFERR_FAIL_SET_ARG);
	if ( !xf.Evaluate() )
		XF_THROW(XFERR_BSPLINE_INTERP_FAILED);
	
	//DWORD		dwMatching;
	//BOOL		bXShared = oy.IsIntersect(iy, "X", NULL, &dwMatching);
	//BOOL		bYShared = oy.IsIntersect(iy, "Y");
	///END CALL_VNORMALIZE_TO_AVOID_DUPLICATION_OF_CODE
	
	//------ Folger 09/25/08 QA80-12276 SET_SAMPLING_INTERVAL_FOR_YXRANGE_OUTPUT
	/*
	//vector* pX = bXShared? NULL : &vxIn; 
	vector* pX = &vxIn;
	if(bXShared) pX = NULL;
	if(!oy.SetData(&vyIn, pX))
	*/
	if( !set_xyrange_data_ex(oy, &vyIn, &vxIn, 0, iy) )
	//------ End SET_SAMPLING_INTERVAL_FOR_YXRANGE_OUTPUT
		XF_THROW(XFERR_INVLIAD_XY);
	///END IMPROVE_NORMALIZATION
	
	///Arvin 08/29/07 QA70-10073 KEEP_OUTPUT_CURVE_CUSTOMIZATION_AFTER_RECALCULATE_FOR_XF
	//oy.MakePlot(iy);
	xf_check_plot_output_rng_in_source_rng_graph(iy, oy);
	///end KEEP_OUTPUT_CURVE_CUSTOMIZATION_AFTER_RECALCULATE_FOR_XF
	/// Max 5/16/07 QA70-9715 NEW_NAME_CREATION
	/*
	if(!bYShared)  ///Justin 2007-04-21 qa70-9669 V8.0605 IMPROVE_NORMALIZATION
	{
		Worksheet wks;
		int r1, r2, c1, c2;
		// Max 11/17/06 RUNTIME_ERROR_IF_NO_X_COLUMN
		//string strName = range_get_col_name(iy, Y_INDEX_IN_XYRANGE);
		int nYindex = get_first_y_col_index(iy);
		string strName = range_get_col_name(iy, nYindex);
		// END RUNTIME_ERROR_IF_NO_X_COLUMN
		
		if(strName == NULL)
			strName = STR_NORMAL_RESULT1;
		else
			strName = STR_NORMAL_RESULT2 + strName;
		oy.GetRange(get_first_y_col_index(oy), r1, c1, r2, c2, wks);  //oy.GetRange(Y_INDEX_IN_XYRANGE, r1, c1, r2, c2, wks); ///Justin 2007-04-21 qa70-9669 V8.0605 IMPROVE_NORMALIZATION
		wks.Columns(c1).SetLongName(strName);
	}
	*/
	/// END NEW_NAME_CREATION
	
	//------ Folger 07/23/08 BETTER_OPREATION_OUTPUT_COLUMN_COMMENTS
	_set_output_range_comments(oy, iy, method, val);
	//------
	
}

//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 normalize_event1(TreeNode& trGetN, int nRow, int nEventID, DWORD& dwEnables, LPCSTR lpcszNodeName, WndContainer& DynaCntrlContainer, string& strAux, string& strErrMsg)
{
	if( xf_is_extended_event(nEventID) )
		return normalize_event1_ex(trGetN, nRow, nEventID, dwEnables, lpcszNodeName, DynaCntrlContainer, strAux, strErrMsg);
	DECLARE_BUTTON_ENABLES
	
	
	bool bIsChangingData = lstrcmpi(lpcszNodeName,"iy") == 0? true:false;
	if(GETNE_ON_INIT == nEventID || bIsChangingData)
	{
		/// Max 11/25/08 v8.0975d SHARE_SAME_FUNC_FOR_NORMALIZE_AND_VNORMALIZE
		//_set_data_info(trGetN.dataInfo, trGetN.iy);
		XYRange xyTemp;
		TreeNode trXY = trGetN.iy;
		if(okxf_resolve_tree_construct_range(&trXY, &xyTemp) )
		{	
			vector vyIn, vxIn;
			DWORD dwRulesEx = DRR_GET_MISSING | DRR_BAD_WEIGHT_TREATMENT;
			xyTemp.GetData(vyIn, vxIn, NULL, 0, dwRulesEx);
		
			normalize_set_datainfo(vyIn, trGetN.datainfo);
		}
		/// END SHARE_SAME_FUNC_FOR_NORMALIZE_AND_VNORMALIZE
	}
	
	//bool bIsChangingOption = lstrcmpi(lpcszNodeName,STR_NODE_OPTION) == 0? true:false;
	bool bIsChangingOption = lstrcmpi(lpcszNodeName, "method") == 0? true:false;
	/*
	if(GETNE_ON_INIT == nEventID || bIsChangingData1 || bIsChangingData2)
	{
		// we should disable OK button whenever data is not specified
		XYRange xyTemp;
		bOKEnable = xy_range_from_GetN_data_node(trGetN.iy, xyTemp);
		switch(trGetN.method.nVal)
		{
		case NORMALIZE_BY_MEAN:
		case NORMALIZE_BY_MEDIAN:
		case NORMALIZE_BY_SD:
		case NORMALIZE_BY_NORM:0
		case NORMALIZE_BY_MODE:
			trGetN.value.Show = false;
			break;
		case NORMALIZE_MAX_TO_VALUE:
		case NORMALIZE_AREA_TO_VALUE:
			trGetN.value.Show = true;
			break;
		}
	}
	*/
	//if(GETNE_ON_INIT == nEventID || bIsChangingOption)
	if(GETNE_ON_INIT == nEventID || GETNE_ON_THEME == nEventID || bIsChangingOption) // should consider theme case
		//_initial_method_show(trGetN);
		trGetN.val.Show = (trGetN.method.nVal == method_specify) ? true : false;	/// Max 11/25/08 v8.0975d SHARE_SAME_FUNC_FOR_NORMALIZE_AND_VNORMALIZE
	
	int nErr = CER_NO_ERROR;
	
	///Cheney 2007-6-7 ADD_AN_ERR_CHECK_FUNC
	//if(get_input_xyrange_num(trGetN.iy) != 1) 
		//nErr = CER_NOT_ONE_XYRANGE;
	//
	//if(nErr == CER_NO_ERROR && method_specify == trGetN.method.nVal && trGetN.val.dVal == 0) //if(nErr == CER_NO_ERROR && trGetN.value.dVal == 0)
		//nErr = XFERR_DIVIDED_BY_ZERO;
	nErr = _check_err_condition(trGetN);
	///end ADD_AN_ERR_CHECK_FUNC
	
	if(nErr != CER_NO_ERROR)
	{
		bOKEnable = false;
		strErrMsg = nErr;
	}
	
	return true;

}

int normalize_make_tree(TreeNode& tr, LPCSTR lpcszVarName)
{
	/// Max 11/25/08 QA70-12615 v8.0975d SHARE_SAME_FUNC_FOR_NORMALIZE_AND_VNORMALIZE
	/*
	if ( 0 == lstrcmp(lpcszVarName, "datainfo") )
	{
		GETN_USE(tr)
		GETN_NUM(number, _L("Number of Points"), 0)
		GETN_READ_ONLY_EX(2)
		
		GETN_NUM(missing, _L("Number of Missing Values"), 0)
		GETN_READ_ONLY_EX(2)
		
		GETN_NUM(max, _L("Maximum"), 0)
		GETN_READ_ONLY_EX(2)
		
		GETN_NUM(min, _L("Minimum"), 0)		
		GETN_READ_ONLY_EX(2)
		
		GETN_NUM(mean, _L("Mean"), 0)		
		GETN_READ_ONLY_EX(2)
		
		GETN_NUM(sd, _L("Standard Deviation"), 0)		
		GETN_READ_ONLY_EX(2)
		
		GETN_NUM(median, _L("Median"), 0)		
		GETN_READ_ONLY_EX(2)
		
		GETN_NUM(norm, _L("Norm"), 0)		
		GETN_READ_ONLY_EX(2)
		
		//GETN_NUM(mode, _L("Mode"), 0)	  ///it's slow to find mode, so comment it	
		//GETN_READ_ONLY_EX(2)
		return 0;
	}	
	
	return -1;
	return false;
	*/
	return normalize_make_datainfo_tree(tr, lpcszVarName);
	/// END SHARE_SAME_FUNC_FOR_NORMALIZE_AND_VNORMALIZE
	
}
//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 normalize_before_execute(TreeNode& trGetN, int nGetNDialog, int& nRet, int dwCntrl)
{
	
	//------ fisher 11/16/07 ADD_MAP_ID_TO_CHM
	if(is_use_origin_chm())
		trGetN.SetAttribute(STR_HELPID_ATTRIB, IDD_XF_normalize);	
	
	///Cheney 2007-6-7 ADD_AN_ERR_CHECK_FUNC
	///Cheney 2007-6-14 PROCEED_WITH_DLG_SHOULD_IF_ERR
	//if(0 == nGetNDialog && (dwCntrl&LTXF_THEME_USED) && _check_err_condition(trGetN) != CER_NO_ERROR)
	if(0 == nGetNDialog && (dwCntrl&LTXF_THEME_USED) && (dwCntrl&LTXF_FROM_GUI_MENU)
		&& _check_err_condition(trGetN) != CER_NO_ERROR)
	///end PROCEED_WITH_DLG_SHOULD_IF_ERR
		nRet = XFEVT_PROCEED_WITH_DLG;	
	///end ADD_AN_ERR_CHECK_FUNC
	
}
//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 normalize_event1_ex(TreeNode& trGetN, int nRow, int nEventID, DWORD& dwEnables, LPCSTR lpcszNodeName, WndContainer& DynaCntrlContainer, string& strAux, string& strErrMsg)
{
	return false;
}
