#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,
	method_ref,
	method_cell,
};
enum{
	type_min,
	type_max,
	type_mean,
	type_median,
	type_sum,
};

//put additional include files here

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

///--- Hong, for temp
//#define _NORMALIZE_METHOD_ERROR  0  ///temp solution
#define _NORMALIZE_METHOD_ERROR  1  ///temp solution
///---

/// Iris 8/13/2009 QA80-13673-P4 FIX_REF_RANGE_EFFECT_AU_EVEN_IT_IS_HIDDEN
#define STR_REF_COL_OLD_VAL			"RefColValue"
#define STR_REF_CELL_OLD_VAL		"RefCellValue"
///end FIX_REF_RANGE_EFFECT_AU_EVEN_IT_IS_HIDDEN

/***************************************************************************************
/// Modification Log :
/// Hong 06/07/09 QA-13673 ADD_NEW_METHOD_SUM
/// Iris 8/07/2009 QA80-13673-S1 ADD_TOTAL_DATA_INFO_GUI_TREE
/// Hong 08/10/09 QA-13673 ADD_COMMENT_FOR_USE_REFERENCE_COLUMN_METHOD
/// Iris 08/12/09 QA-13673 RNORMALIZE_XF_ADD_USE_REFERENCE_CELL_METHOD
/// Iris 8/13/2009 QA80-13673-P4 FIX_REF_RANGE_EFFECT_AU_EVEN_IT_IS_HIDDEN
/// Iris 8/13/2009 QA80-13763-P5 FIX_AUTO_APPEND_0_FOR_EMPTY_CELL
/// Iris 8/17/2009 QA80-13673-P10 FIX_INC_INPUT_DATA_SIZE_RECALCULATE_NOT_EFFECT_RESULT
/// Iris 8/19/2009 QA80-13673-P12 FIX_SET_OUT_RANGE_OUTSIDE
/// Sophy 8/20/2009 QA80-14087-P5 PASS_VECTORBASE_AS_DOUBLE_POINTER_TO_VC_GET_JUNK_RESULT
/// Sophy 8/20/2009 QA80-14087-P5 REFER_CELL_METHOD_GET_WRONG_RESULT
/// Sophy 8/20/2009 QA80-14087-P9 MORE_CHECH_ON_USER_SETTINGS_BEFORE_EXECUTE
/// Sophy 8/31/2009 FIX_NORMALIZE_WITH_MINUS_VALUE_GET_INCORRECT_RESULT
/// Sophy 9/2/2009 IMPROVE_COMMENTS_FOR_NORMALIZE_RESULT_COLUMNS
/// Max 9/02/09 QA80-14087-P5 MISUNDERSTAND_ON_HOW_REFERENCE_CELL_SHOULD_WORK
/// Sim 09-11-2009 QA81-14087-P1 USE_DATARANGE_REPLICATE_METHOD_INSTEAD_OF_XF_CODES
/// Sophy 9/15/2009 IMPROVE_COMMENTS_FOR_NORMALIZE_RESULT_COLUMNS
/// Iris 10/09/2009 HIDDEN_TOTAL_DATA_INFO_ON_GUI
/// Sophy 10/12/2009 QA80-14087-P17 OUTPUT_DESTINATION_OF_RNORMALIZE_IS_INCORRECT_WHEN_ROW_NUM_CHANGE
/// Folger 10/20/09 QA81-14489-P1 RNORMALIZE_FAILS_TO_REMEMBER_REFERENCE_COLUMN_WHEN_CHANGE_PARAM
/// Kyle 10/22/09 QA80-14087-P18 SET_OUTPUT_COLUMN_DESIGNATION
/// Sophy 11/3/2009 QA80-14087-P22 RESULT_COLUMN_BOUND_ERROR_WHEN_SELECT_MULTIPLE_COLUMNS
/// Sophy 4/9/2010 NEW_COLUMN_FORMAT_FOLLOW_LAST_COL_CAUSE_RUNTIME_ERROR
***************************************************************************************/

//put your own support static functions here

/// Max 11/20/08 QA70-12615 v8.0975d CENTRALIZE_ERR_CHECKING
static int _check_err_condition(TreeNode& trGetN)
{
	
	TreeNode	trInput = trGetN.irng;
	Range 		drInput;
	if ( !okxf_resolve_tree_construct_range(&trInput, &drInput) )
		return CER_FFT_GET_INPUT_FAIL;
	vector		vv;
	if ( 0 == drInput.GetNumData() || !drInput.GetData(vv, 0) || 0 == vv.GetSize() )
		return CER_NO_DATA;
	
	int nErr = CER_NO_ERROR;
	if(method_specify == trGetN.method.nVal && trGetN.val.dVal == 0)
		nErr = XFERR_DIVIDED_BY_ZERO;
	
	if ( CER_NO_ERROR == nErr && method_ref == trGetN.method.nVal )
	{
		Column			ccRef;
		if ( !okxf_resolve_string_get_origin_object(trGetN.refcol.strVal, &ccRef) || !ccRef )
			nErr = XFERR_INVALID_COL_RANGE;
	}
	/// Iris 08/12/09 QA-13673 RNORMALIZE_XF_ADD_USE_REFERENCE_CELL_METHOD
	if ( CER_NO_ERROR == nErr && method_cell == trGetN.method.nVal )
	{
		DataRange drCell;
		TreeNode trCell = trGetN.cell;
		Worksheet wks;
		int r1, c1, r2, c2;
		if( !okxf_resolve_tree_construct_range(&trCell, &drCell) || !drCell.GetRange(0, r1, c1, r2, c2, wks) )
		{
			nErr = XFERR_INVALID_RANGE;
		}
		if( CER_NO_ERROR == nErr && (r1 != r2 || c1 != c2) )
		{
			nErr = CER_NOT_ONE_CELL;
		}
	}
	///end RNORMALIZE_XF_ADD_USE_REFERENCE_CELL_METHOD
	///Sophy 8/20/2009 QA80-14087-P9 MORE_CHECH_ON_USER_SETTINGS_BEFORE_EXECUTE
	if ( CER_NO_ERROR == nErr )
	{
		string strOutRng = trGetN.orng.strVal;
		if ( strOutRng.GetLength() < 5 ) //assume valid range name longer than 5
			nErr = CER_INVALID_OUT_RANGE;
	}
	///end MORE_CHECH_ON_USER_SETTINGS_BEFORE_EXECUTE
	return nErr;
}
/// ------


///--- Hong, for temp
static int _normalize_data(vector& vv, int nMethod, double dVal)
{
	if ( 0 == vv.GetSize() )
		return 0;
	
	double 			dSub = 0.0, dFactor = 1.0;
	if ( !_get_normalize_val(dVal, dSub, vv, nMethod) )
		return _NORMALIZE_METHOD_ERROR;
	
	dFactor = (is_equal(0.0, dVal)) ? NANUM : 1.0 / dVal;	
	vv -= dSub;
	vv *= dFactor;
	
	return 0;
}

static bool _get_normalize_val(double& dNormalizeVal, double& dSub, const vector& vv, int nMethod)
{
	int 			nRet = STATS_NO_ERROR;
	double 			dFactor = 1.0;
	switch ( nMethod )
	{
	case method_specify:
		break;
	case method_range:
		double 		dMin, dMax;
		vv.GetMinMax(dMin, dMax);
		dSub = dMin;
		dNormalizeVal = dMax - dMin;
		break;
	case method_snd:
		nRet = ocmath_basic_summary_stats(vv.GetSize(), vv, NULL, &dSub, &dNormalizeVal);
		break;
	case method_max:
		double 		dMin, dMax;
		vv.GetMinMax(dMin, dMax);
		dNormalizeVal = dMax;
		break;
	case method_min:
		double 		dMin, dMax;
		vv.GetMinMax(dMin, dMax);
		dNormalizeVal = dMin;		
		break;
	case method_mean:
		nRet = ocmath_basic_summary_stats(vv.GetSize(), vv, NULL, &dNormalizeVal);
		break;
	case method_median:
		int 		nSize = vv.GetSize();
		vector 		vSort;
		vSort = vv;
		vSort.Sort();
		dNormalizeVal = (vSort.GetSize() == 1) ? vSort[0] : ((nSize%2) ? vSort[nSize/2] : 0.5* ( vSort[nSize/2] + vSort[nSize/2-1]));
		break;
	/// Hong 06/07/09 QA-13673 ADD_NEW_METHOD_SUM
	case method_sum:
		vv.Sum(dNormalizeVal);
		break;
	/// end ADD_NEW_METHOD_SUM
	case method_sd:
		nRet = ocmath_basic_summary_stats(vv.GetSize(), vv, NULL, NULL, &dNormalizeVal);
		break;
	case method_norm:
		double 		dNorm;
		vector 		vTmp;
		vTmp = vv * vv;
		vTmp.Sum(dNorm);
		dNormalizeVal = sqrt(dNorm);
		break;
	case method_mode:
		nRet = ocmath_opt_summary_stats(vv.GetSize(), vv, 0.95, &dNormalizeVal); //Here 0.95 doesn't make sense
		break;
	case method_ref:
		break;	
	/// Iris 08/12/09 QA-13673 RNORMALIZE_XF_ADD_USE_REFERENCE_CELL_METHOD
	case method_cell:
		break;
	///end RNORMALIZE_XF_ADD_USE_REFERENCE_CELL_METHOD
	default:
		return false;
	}
	return (STATS_NO_ERROR == nRet) ? true : false;
}

static double _get_use_column_reference_val(const vector& vv, int nNormalizeTo)
{
	double			dVal = NANUM, dSub;
	switch ( nNormalizeTo )
	{
	case type_min:
		_get_normalize_val(dVal, dSub, vv, method_min);
		break;
	case type_max:
		_get_normalize_val(dVal, dSub, vv, method_max);
		break;
	case type_mean:
		_get_normalize_val(dVal, dSub, vv, method_mean);
		break;
	case type_median:
		_get_normalize_val(dVal, dSub, vv, method_median);
		break;
	case type_sum:
		vv.Sum(dVal);
		break;
	}
	return dVal;
}
///---

/// Iris 08/12/09 QA-13673 RNORMALIZE_XF_ADD_USE_REFERENCE_CELL_METHOD
///Sophy 8/20/2009 QA80-14087-P5 REFER_CELL_METHOD_GET_WRONG_RESULT
//static double _get_use_cell_reference_val(DataRange& drCell)
//{
	//vector vec;
	//drCell.GetData(&vec, 0);
	//return vec.GetSize()>0 ? vec[0] : NANUM;
//}
static	double	_get_ref_cell_value(DataRange& drCell, int& nRowIndex)
{
	int c1, c2, r2;
	Datasheet ds;
	drCell.GetRange(0, nRowIndex, c1, r2, c2, ds);
	vector vec;
	drCell.GetData(&vec, 0);
	return vec.GetSize()>0 ? vec[0] : NANUM;
}
///end REFER_CELL_METHOD_GET_WRONG_RESULT
///end RNORMALIZE_XF_ADD_USE_REFERENCE_CELL_METHOD

/// Iris 8/13/2009 QA80-13673-P4 FIX_REF_RANGE_EFFECT_AU_EVEN_IT_IS_HIDDEN
static void _check_reset_ref_range(TreeNode& trRange, int nCurrentMethod, int nCheckMethod, LPCSTR lpcszOldValAttribte)
{
	if( nCurrentMethod == nCheckMethod )
	{
		string str;
		if( trRange.GetAttribute(lpcszOldValAttribte, str) )
		{
			trRange.strVal = str;
		}
	}
	else
	{
		trRange.strVal = STR_OPTIONAL;
	}
}
///end FIX_REF_RANGE_EFFECT_AU_EVEN_IT_IS_HIDDEN

///------ Folger 10/20/09 QA81-14489-P1 RNORMALIZE_FAILS_TO_REMEMBER_REFERENCE_COLUMN_WHEN_CHANGE_PARAM
static	void	_check_update_old_ref_range_attrib(TreeNode& trGetN)
{
	if ( PDS_OPTIONAL != okutil_cvt_str_to_predefined_type(trGetN.refcol.strVal) )
		trGetN.refcol.SetAttribute(STR_REF_COL_OLD_VAL, trGetN.refcol.strVal);
	if ( PDS_OPTIONAL != okutil_cvt_str_to_predefined_type(trGetN.cell.strVal) )
		trGetN.cell.SetAttribute(STR_REF_CELL_OLD_VAL, trGetN.cell.strVal);
}
///------ End RNORMALIZE_FAILS_TO_REMEMBER_REFERENCE_COLUMN_WHEN_CHANGE_PARAM


void rnormalize(const Range& irng, const TreeNode& datainfo, const int& method, const double& val, const Column& refcol, const int& type, const Range& cell, Range& orng)
{
	if ( 0 == irng.GetNumRanges() )
		XF_THROW(XFERR_INVALID_RANGE);
	
	if ( 0 == orng.GetNumRanges() )
		XF_THROW(XFERR_INVALID_RANGE);
	
	if ( method_ref == method && !refcol )
		XF_THROW(XFERR_INVALID_COL_RANGE);
		
	bool			bOutputToInput = false, bAutoExpand = false;
	DWORD			pwResults;
	if ( irng.IsIntersect(orng, NULL, NULL, &pwResults) && RNGINTSCT_FULL == pwResults )
		bOutputToInput = true;
	///---Sim 09-11-2009 QA81-14087-P1 USE_DATARANGE_REPLICATE_METHOD_INSTEAD_OF_XF_CODES
	//else if ( CER_NO_ERROR == check_1_cell(orng) )
		//bAutoExpand = true;
	///---END QA81-14087-P1 USE_DATARANGE_REPLICATE_METHOD_INSTEAD_OF_XF_CODES
	
	Worksheet		wksDest;
	int				nDestR1, nDestR2, nDestC1, nDestC2, nDectCurr;
	///Sophy 10/12/2009 QA80-14087-P17 OUTPUT_DESTINATION_OF_RNORMALIZE_IS_INCORRECT_WHEN_ROW_NUM_CHANGE
	int				nResultRngR1, nResultRngR2;
	///end OUTPUT_DESTINATION_OF_RNORMALIZE_IS_INCORRECT_WHEN_ROW_NUM_CHANGE
	if ( !bOutputToInput )
	{
		orng.GetRange(0, nDestR1, nDestC1, nDestR2, nDestC2, wksDest);
		///---Sim 09-11-2009 QA81-14087-P1 USE_DATARANGE_REPLICATE_METHOD_INSTEAD_OF_XF_CODES
		if ( CER_NO_ERROR == check_1_cell(orng) )
		{
			irng.Replicate(orng, wksDest, nDestR1, nDestC1);
			orng.GetRange(0, nDestR1, nDestC1, nDestR2, nDestC2, wksDest);
		}
		///---END QA81-14087-P1 USE_DATARANGE_REPLICATE_METHOD_INSTEAD_OF_XF_CODES
		///Sophy 10/12/2009 QA80-14087-P17 OUTPUT_DESTINATION_OF_RNORMALIZE_IS_INCORRECT_WHEN_ROW_NUM_CHANGE
		nResultRngR1 = nDestR1;
		nResultRngR2 = nDestR2;
		///end OUTPUT_DESTINATION_OF_RNORMALIZE_IS_INCORRECT_WHEN_ROW_NUM_CHANGE
		if ( -1 == nDestR2 )
		{
			nDestR2 = wksDest.GetNumRows() - 1;
			///Sophy 4/13/2010 AUTO_RESIZE_WORKSHEET_WHEN_OUTPUT_TO_FULL_ROW_RANGE
			bAutoExpand = true;
			///end AUTO_RESIZE_WORKSHEET_WHEN_OUTPUT_TO_FULL_ROW_RANGE
		}
		nDectCurr = nDestC1;
	}
	
	double			dRefVal;
	if ( method_ref == method )
	{
		vectorbase&	vbRef = refcol.GetDataObject();
		///Sophy 8/20/2009 QA80-14087-P5 PASS_VECTORBASE_AS_DOUBLE_POINTER_TO_VC_GET_JUNK_RESULT
		//dRefVal = _get_use_column_reference_val(vbRef, type);
		vector vRef;
		vRef = vbRef;
		dRefVal = _get_use_column_reference_val(vRef, type);
		///end PASS_VECTORBASE_AS_DOUBLE_POINTER_TO_VC_GET_JUNK_RESULT
	}
	/// Iris 08/12/09 QA-13673 RNORMALIZE_XF_ADD_USE_REFERENCE_CELL_METHOD
	///Sophy 8/20/2009 QA80-14087-P5 REFER_CELL_METHOD_GET_WRONG_RESULT
	//if( method_cell == method )
	//{
		//dRefVal = _get_use_cell_reference_val(cell);
	//}
	int nRowIndex = -1;
	if ( method_cell == method )
	{
		dRefVal = _get_ref_cell_value(cell, nRowIndex);
	}
	///end REFER_CELL_METHOD_GET_WRONG_RESULT
	///end RNORMALIZE_XF_ADD_USE_REFERENCE_CELL_METHOD
	
	for ( int nn = 0; nn < irng.GetNumRanges(); nn++ )
	{
		Worksheet	wksSrc;
		int			nSrcR1, nSrcR2, nSrcC1, nSrcC2;
		irng.GetRange(nn, nSrcR1, nSrcC1, nSrcR2, nSrcC2, wksSrc);
		if ( -1 == nSrcC2 )
			nSrcC2 = wksSrc.GetNumCols() -1;
		if ( -1 == nSrcR2 )
			nSrcR2 = wksSrc.GetNumRows() -1;
		
		int nSelectedR2 = nSrcR2;	///Sophy 11/3/2009 QA80-14087-P22 RESULT_COLUMN_BOUND_ERROR_WHEN_SELECT_MULTIPLE_COLUMNS
	
		bool		bFinish = false;
		for ( int ii = nSrcC1; ii <= nSrcC2; ii++ )
		{
			Column		ccSrc(wksSrc, ii);
			ASSERT(ccSrc);
			
			/// Iris 8/13/2009 QA80-13763-P5 FIX_AUTO_APPEND_0_FOR_EMPTY_CELL
			///Sophy 11/3/2009 QA80-14087-P22 RESULT_COLUMN_BOUND_ERROR_WHEN_SELECT_MULTIPLE_COLUMNS
			//nSrcR2 = min(nSrcR2, ccSrc.GetUpperBound());
			nSrcR2 = (nResultRngR2 < 0) ? ccSrc.GetUpperBound() : min(nSelectedR2, ccSrc.GetUpperBound());
			///end RESULT_COLUMN_BOUND_ERROR_WHEN_SELECT_MULTIPLE_COLUMNS
			///end FIX_AUTO_APPEND_0_FOR_EMPTY_CELL
			
			vectorbase&	vb = ccSrc.GetDataObject();
			vector		vv;
			vb.GetSubVector(vv, nSrcR1, nSrcR2);
			/// Hong 08/10/09 FIX_RUNTIME_ERR_WHEN_USE_REFERENCE_COLUMN_METHOD
			//double		dVal = val;
			//if ( method_ref == method )
			double		dVal;
			/// Iris 08/12/09 QA-13673 RNORMALIZE_XF_ADD_USE_REFERENCE_CELL_METHOD
			//if ( method_ref != method )
			if ( method_cell == method )
			{
				/// Max 9/02/09 QA80-14087-P5 MISUNDERSTAND_ON_HOW_REFERENCE_CELL_SHOULD_WORK
				/*
				///Sophy 8/20/2009 QA80-14087-P5 REFER_CELL_METHOD_GET_WRONG_RESULT
				//dVal = dRefVal;
				dVal = (is_equal(0.0, dRefVal) || nRowIndex >= vv.GetSize())? NANUM : vv[nRowIndex] / dRefVal;
				///end REFER_CELL_METHOD_GET_WRONG_RESULT
				*/
				dVal = dRefVal;
				/// END MISUNDERSTAND_ON_HOW_REFERENCE_CELL_SHOULD_WORK
			}
			else if ( method_ref != method )
			///end RNORMALIZE_XF_ADD_USE_REFERENCE_CELL_METHOD
			{
				if ( NULL == val )
					XF_THROW(XFERR_INVALID_ARG);
				dVal = val;
			} 
			else
			/// end FIX_RUNTIME_ERR_WHEN_USE_REFERENCE_COLUMN_METHOD
			{
				///Sophy 8/31/2009 FIX_NORMALIZE_WITH_MINUS_VALUE_GET_INCORRECT_RESULT
				//dVal = _get_use_column_reference_val(vv, type);
				dVal = _get_use_column_reference_val(vv, type);
				if ( type == type_min && dVal * dRefVal < 0 )
					dVal = _get_use_column_reference_val(vv, type_max);
				else if ( type == type_max && dVal * dRefVal < 0 )
					dVal = _get_use_column_reference_val(vv, type_min);
				///end FIX_NORMALIZE_WITH_MINUS_VALUE_GET_INCORRECT_RESULT
				dVal = (is_equal(0.0, dRefVal)) ? NANUM : dVal / dRefVal;
			}
			int			nRet = _normalize_data(vv, method, dVal);
			if ( 0 != nRet )
				XF_THROW(nRet);
	
			/// Hong 08/10/09 QA-13673 ADD_COMMENT_FOR_USE_REFERENCE_COLUMN_METHOD
			//string 		strMethod = normalize_get_method_string(method, dVal);
			///Sophy 9/2/2009 IMPROVE_COMMENTS_FOR_NORMALIZE_RESULT_COLUMNS
			//string 		strMethod = normalize_get_method_string(method, dVal, type);
			///Sophy 9/15/2009 IMPROVE_COMMENTS_FOR_NORMALIZE_RESULT_COLUMNS
			//string 		strMethod = normalize_get_method_string(method, dVal, type, refcol, XF_RNORMALIZE);
			DataRange drCol;
			drCol.Add(wksSrc, ii, "Range1");
			string 		strComments = normalize_get_method_string(get_input_data_range_string(drCol), method, dVal, type, refcol, XF_RNORMALIZE);
			///end IMPROVE_COMMENTS_FOR_NORMALIZE_RESULT_COLUMNS
			///end IMPROVE_COMMENTS_FOR_NORMALIZE_RESULT_COLUMNS
			/// end ADD_COMMENT_FOR_USE_REFERENCE_COLUMN_METHOD
			
			/// Iris 8/13/2009 QA80-13673-P7 CHANGE_COMMENT_REPLACE_FULLRANGE_BY_COLNAME centrliaze code into normalize_get_method_string 
			//string		strComments, strColRange;
			//ccSrc.GetRangeString(strColRange);
			//strComments.Format("%s of %s", strMethod, strColRange);
			///Sophy 9/15/2009 IMPROVE_COMMENTS_FOR_NORMALIZE_RESULT_COLUMNS
			//DataRange drCol;
			//drCol.Add(wksSrc, ii, "Range1");
			//string strComments;
			//strComments.Format("%s of %s", strMethod, get_input_data_range_string(drCol));
			///end IMPROVE_COMMENTS_FOR_NORMALIZE_RESULT_COLUMNS
			///end CHANGE_COMMENT_REPLACE_FULLRANGE_BY_COLNAME
			
			if ( bOutputToInput )
			{
				vb.SetSubVector(vv, nSrcR1);
				ccSrc.SetComments(strComments);
			}
			else
			{
				nDestC2 = max(nDestC2, nDectCurr);
				if ( nDectCurr >= wksDest.GetNumCols() )
				{
					if ( bAutoExpand )
					{
						wksDest.SetSize(-1, nDectCurr+1);// Iris 8/18/2009: nDectCurr+1 is to convert col index(0 offset) to size
					}
					else
					{
						nDestC2 = wksDest.GetNumCols() - 1; /// Iris 8/19/2009 QA80-13673-P12 FIX_SET_OUT_RANGE_OUTSIDE
						bFinish = true;
						break;
					}
				}
				Column			ccDest(wksDest, nDectCurr++);
				ASSERT(ccDest);
				///Sophy 4/9/2010 NEW_COLUMN_FORMAT_FOLLOW_LAST_COL_CAUSE_RUNTIME_ERROR
				int nIndex = ccDest.GetIndex();	//in VC level, when there are too many columns in current worksheet, new generated column format will follow the last column...
				if ( nIndex >= 'Z' - 'A' )	//it is not safe to change VC level code(very old), so I just make an OC workaround by updating its format
					ccDest.SetFormat(OKCOLTYPE_TEXT_NUMERIC);
				///end NEW_COLUMN_FORMAT_FOLLOW_LAST_COL_CAUSE_RUNTIME_ERROR
				vectorbase&		vbDest = ccDest.GetDataObject();
				
				if ( !bAutoExpand )
				{
					/// Iris 8/13/2009 QA80-13763-P5 FIX_AUTO_APPEND_0_FOR_EMPTY_CELL
					// if not auto expand, if new size > current size, then should do nothing
					//vv.SetSize(nDestR2 - nDestR1 + 1);
					int nNewSize = nDestR2 - nDestR1 + 1;
					if( vv.GetSize() < nNewSize )
					{
						// do nothing
					}
					else
					{
						vv.SetSize(nNewSize);
					}
					///end FIX_AUTO_APPEND_0_FOR_EMPTY_CELL
				}
				else
					nDestR2 = max(nDestR2, nDestR1 + vv.GetSize());
				if ( nDestR1 >= vbDest.GetSize() )
					vbDest.SetSize(vv.GetSize() + nDestR1);
				vbDest.SetSize(vv.GetSize() + nDestR1); /// Iris 8/17/2009 QA80-13673-P10 FIX_INC_INPUT_DATA_SIZE_RECALCULATE_NOT_EFFECT_RESULT
				vbDest.SetSubVector(vv, nDestR1);
				ccDest.SetComments(strComments);
				ccDest.SetType(ccSrc.GetType());				///Kyle 10/22/09 QA80-14087-P18 SET_OUTPUT_COLUMN_DESIGNATION
			}
		}
		if ( bFinish )
			break;
	}
	if ( !bOutputToInput )
	{
		///Sophy 10/12/2009 QA80-14087-P17 OUTPUT_DESTINATION_OF_RNORMALIZE_IS_INCORRECT_WHEN_ROW_NUM_CHANGE
		//orng.SetRange(0, wksDest, nDestR1, nDestC1, nDestR2, nDestC2);
		orng.SetRange(0, wksDest, nResultRngR1, nDestC1, nResultRngR2, nDestC2); //if input is whole column, output should correspond to input
		///end OUTPUT_DESTINATION_OF_RNORMALIZE_IS_INCORRECT_WHEN_ROW_NUM_CHANGE
		for ( int ii = orng.GetNumRanges() - 1; ii > 0; ii-- )
			;//orng.RemoveRange(ii);  // Hong, for temp, wait for VC support
	}
}

//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 rnormalize_event1(TreeNode& trGetN, int nRow, int nEventID, DWORD& dwEnables, LPCSTR lpcszNodeName, WndContainer& DynaCntrlContainer, string& strAux, string& strErrMsg)
{
	if( xf_is_extended_event(nEventID) )
		return rnormalize_event1_ex(trGetN, nRow, nEventID, dwEnables, lpcszNodeName, DynaCntrlContainer, strAux, strErrMsg);
	DECLARE_BUTTON_ENABLES
	
	/// Iris 10/09/2009 HIDDEN_TOTAL_DATA_INFO_ON_GUI
	/*
	/// Iris 8/07/2009 QA80-13673-S1 ADD_TOTAL_DATA_INFO_GUI_TREE
	bool bIsChangingData = lstrcmpi(lpcszNodeName,"irng") == 0? true:false;
	if(GETNE_ON_INIT == nEventID || bIsChangingData)
	{
		Range dr;
		TreeNode trIn = trGetN.irng;
		okxf_resolve_tree_construct_range(&trIn, &dr);
	
		vector vTotal;
		int nNumData = dr.GetNumRanges();
		for(int nn=0; nn < nNumData; nn++)
		{
			vector vData;
			dr.GetData(vData, nn);
			vTotal.Append(vData);
		}		
		normalize_set_datainfo(vTotal, trGetN.datainfo);		
	}
	///end ADD_TOTAL_DATA_INFO_GUI_TREE
	*/
	///end HIDDEN_TOTAL_DATA_INFO_ON_GUI
	
	///------ Folger 10/20/09 QA81-14489-P1 RNORMALIZE_FAILS_TO_REMEMBER_REFERENCE_COLUMN_WHEN_CHANGE_PARAM
	if ( GETNE_ON_INIT == nEventID )
	{
		_check_update_old_ref_range_attrib(trGetN);
	}
	///------ End RNORMALIZE_FAILS_TO_REMEMBER_REFERENCE_COLUMN_WHEN_CHANGE_PARAM
	
	/// Iris 8/13/2009 QA80-13673-P4 FIX_REF_RANGE_EFFECT_AU_EVEN_IT_IS_HIDDEN
	if( !lstrcmp(lpcszNodeName, "refcol") )
	{		
		trGetN.refcol.SetAttribute(STR_REF_COL_OLD_VAL, trGetN.refcol.strVal);
	}
	
	if( !lstrcmp(lpcszNodeName, "cell") )
	{		
		trGetN.cell.SetAttribute(STR_REF_CELL_OLD_VAL, trGetN.cell.strVal);
	}
	///end FIX_REF_RANGE_EFFECT_AU_EVEN_IT_IS_HIDDEN
	
	bool bIsChangingOption = lstrcmpi(lpcszNodeName,"method") == 0? true:false;
	
	if( (0 > nEventID &&  GETNE_ON_OK != nEventID )|| bIsChangingOption)
	{
		trGetN.val.Show = (trGetN.method.nVal == method_specify) ? true : false;
		bool		bUseRefCol = (trGetN.method.nVal == method_ref) ? true : false;
		trGetN.refcol.Show = bUseRefCol;
		trGetN.type.Show = bUseRefCol;
		trGetN.cell.Show = (trGetN.method.nVal == method_cell); /// Iris 08/12/09 QA-13673 RNORMALIZE_XF_ADD_USE_REFERENCE_CELL_METHOD
		
		/// Iris 8/13/2009 QA80-13673-P4 FIX_REF_RANGE_EFFECT_AU_EVEN_IT_IS_HIDDEN
		_check_reset_ref_range(trGetN.refcol, trGetN.method.nVal, method_ref, STR_REF_COL_OLD_VAL);
		_check_reset_ref_range(trGetN.cell, trGetN.method.nVal, method_cell, STR_REF_CELL_OLD_VAL);		
		///end FIX_REF_RANGE_EFFECT_AU_EVEN_IT_IS_HIDDEN
	}
	
	int nErr = _check_err_condition(trGetN);
	if(nErr != CER_NO_ERROR)
	{
		bOKEnable = false;
		strErrMsg = nErr;
	}
	
	return true;
	

}

int rnormalize_make_tree(TreeNode& tr, LPCSTR lpcszVarName)
{
	
	return normalize_make_datainfo_tree(tr, lpcszVarName);
	
}
//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 rnormalize_before_execute(TreeNode& trGetN, int nGetNDialog, int& nRet, int dwCntrl)
{
	if(0 == nGetNDialog && (dwCntrl&LTXF_THEME_USED) && (dwCntrl&LTXF_FROM_GUI_MENU) && (CER_NO_ERROR != _check_err_condition(trGetN)) )
		nRet = XFEVT_PROCEED_WITH_DLG;	
	
	trGetN.datainfo.Show = false; /// Iris 10/09/2009 HIDDEN_TOTAL_DATA_INFO_ON_GUI
	
}
//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 rnormalize_event1_ex(TreeNode& trGetN, int nRow, int nEventID, DWORD& dwEnables, LPCSTR lpcszNodeName, WndContainer& DynaCntrlContainer, string& strAux, string& strErrMsg)
{
	return false;
}
