#include <origin.h>
#include <GetNBox.h>
#include <xfutils.h>
enum{
	subgroup_points,
	subgroup_groups,
	subgroup_inc,
};
enum{
	xstats_ave,
	xstats_median,
	xstats_first,
	xstats_last,
};
enum{
	ystats_ave,
	ystats_min,
	ystats_max,
	ystats_median,
	ystats_first,
	ystats_last,
};

//put additional include files here
#include <ReportTree.h>
#include <ocmsp.h>
#include <event_utils.h>

///////////////////////////////////////////////////////////////////////////////////
// Modificaiton Log
//
//  CPY 12/19/08 USE_SHARED_TEMPLATE_FOR_ALL_PREVIEW_XF
//  Kyle 12/22/2008 OPEN_DIALOG_WHEN_THEME_IS_USED_AND_ERROR_HAPPENS
//	Kyle 12/22/2008 CHECK_IF_X_DATA_NONMONOTONIC
// 	Kyle 12/22/2008 OUTPUT_COLUMN_COMMENTS
//	Kyle 01/13/2009 v8.0995d CHECK_IF_NUMBER_OF_BIN_IS_LARGER_THAN_DATA_SIZE
//	Kyle 06/03/2009 GET_SOURCE_GRAPH_SCALE_TYPE
//	Kyle 07/03/2009 GUI_CHANGE
/// Iris 10/13/09 QA70-14403 PREVIEW_GRAPH_SHOULD_NEVER_RESCALE_ON_CHANGE
/// Kyle 10/21/2009 USE_GENERAL_CODE_TO_SET_XYRANGE_DATA
/// Kyle 11/20/2009 QA80-14127-P16 ERROR_CHECK_OUT_OF_XF_BODY_SHOULD_NOT_USE_XF_THROW
/// Kyle 11/24/2009 QA80-14127-P16 START_END_CHECKING_FOR_SUB_GROUP_BY_NUMBER_OF_GROUPS
///	Jasmine 08/13/2010 ORG-172-S2 CENTRALIZE_NOCLICK_BIT_FOR_PREVIEW_IN_OC_TOOL
///////////////////////////////////////////////////////////////////////////////////

//put your own support static functions here
#define REDUCE_REPORT_TABLE	0x00000010
enum _REDUCE_XY_RES_ID
{
	_REDUCE_X	= 0x00010010,
	_REDUCE_Y
	
};

/// Jack 21/10/2008 QA80-12405 REDUCE_DATA_XF
enum
{
	SUB_RANGE_SUCCESS = 0,
	SUB_RANGE_FAILED = -1
};
/// End REDUCE_DATA_XF

///Kyle 12/02/2008 QA80-12405-S1 UPDATE_XF_TO_SHOW_PREVIEW
static bool s_bInit = false;
static string s_strErrMsg = "";

static void _run_reducexy_on_current_data(TreeNode& trGetN, PageBase& pgTemp, Worksheet& wksTemp)
{
	XYRange iy, xyReduced;	
	if(!init_preview_graph(trGetN.iy, pgTemp, wksTemp, NULL, &iy, &xyReduced))
		return;

	vector vX, vY;
	xyReduced.SetData(&vY, &vX, 0, NULL, 0);	// clean data

	int subgroup 	= trGetN.subgroup.nVal;
	int points 		= trGetN.points.nVal;
	double xincr 	= trGetN.xincr.dVal;
	int groups 		= trGetN.groups.nVal;
	string datasizehint = trGetN.datasizehint.strVal;
	double start 	= trGetN.start.dVal;
	double end 		= trGetN.end.dVal;
	int xstats 		= trGetN.xstats.nVal;
	int ystats 		= trGetN.ystats.nVal;

	try {
		reducexy(iy, subgroup, points, xincr, groups, datasizehint, start, end, xstats, ystats, xyReduced);
	}
	catch(int nErr)
	{
	}

	/// Iris 10/13/09 QA70-14403 PREVIEW_GRAPH_SHOULD_NEVER_RESCALE_ON_CHANGE
	/*
	GraphPage gp = pgTemp;
	GraphLayer gl = gp.Layers(0);
	gl.Rescale(ANL_CHK_DATA_OUTSIDE);
	*/
	///end PREVIEW_GRAPH_SHOULD_NEVER_RESCALE_ON_CHANGE
}

static bool _check_input(TreeNode& trGetN, string& strErrMsg)
{
	///Kyle 11/24/2009 QA80-14127-P16 START_END_CHECKING_FOR_SUB_GROUP_BY_NUMBER_OF_GROUPS
	/*
	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;
	}
	*/
	XYRange xyRange;
	xy_range_from_GetN_data_node(trGetN.iy, xyRange);
	if( !xyRange || xyRange.GetNumData(DRR_GET_DEPENDENT) < 1 )
	{
		strErrMsg = XFERR_AT_LEAST_ONE_XYRANGE;
		return false;
	}

	vector vx, vy;
	xyRange.GetData(vy, vx, NULL, 0, 0);
	int nSize = vx.GetSize();
	if( nSize <= 0 )
	{
		strErrMsg = CER_NO_DATA;
		return false;
	}
	if(!ocmath_is_monotonic(vx, vx.GetSize(), false))
	{
		strErrMsg = CER_NONMONOTONIC_X;
		return false;
	}
	///End START_END_CHECKING_FOR_SUB_GROUP_BY_NUMBER_OF_GROUPS

	double dxMin, dxMax;
	dxMin = trGetN.start.dVal;
	dxMax = trGetN.end.dVal;
	
	///Kyle 11/24/2009 QA80-14127-P16 START_END_CHECKING_FOR_SUB_GROUP_BY_NUMBER_OF_GROUPS
	vector vSubX, vSubY;
	double dRealMin, dRealMax;
	int nRealSize;
	///End START_END_CHECKING_FOR_SUB_GROUP_BY_NUMBER_OF_GROUPS

	if(trGetN.subgroup.nVal != subgroup_points)
	{
		double dxInputMin, dxInputMax;
		get_data_x_scale(trGetN, dxInputMin, dxInputMax);
		if(dxMin > dxMax || dxMin > dxInputMax || dxMax < dxInputMin)
		{
			strErrMsg = XF_REDUCE_START_END_ERROR;
			return false;
		}
		///Kyle 11/24/2009 QA80-14127-P16 START_END_CHECKING_FOR_SUB_GROUP_BY_NUMBER_OF_GROUPS
		int nRet = _get_subrange_of_XY(vx, vy, dxMin, dxMax, vSubX, vSubY);
		if(nRet < 0)
		{
			strErrMsg = XF_REDUCE_FAILED_GET_RANGE;
			return false;
		}
		nRealSize = vSubX.GetSize();
		ASSERT(nRealSize == vSubY.GetSize());

		vSubX.GetMinMax(dRealMin, dRealMax);
		///End START_END_CHECKING_FOR_SUB_GROUP_BY_NUMBER_OF_GROUPS
	}
	///Kyle 11/24/2009 QA80-14127-P16 START_END_CHECKING_FOR_SUB_GROUP_BY_NUMBER_OF_GROUPS
	/*
	///Sophy 6/1/2009 MORE_CHECK_ON_USER_INPUT moved from the end of this funciton, as to use vx and vy;
	XYRange xyRange;
	xy_range_from_GetN_data_node(trGetN.iy, xyRange);
	vector vx, vy;
	xyRange.GetData(vy, vx,NULL, 0, 0);
	if(!ocmath_is_monotonic(vx, vx.GetSize(), false))
	{
		strErrMsg = CER_NONMONOTONIC_X;
		return false;
	}
	///end MORE_CHECK_ON_USER_INPUT
	*/
	///End START_END_CHECKING_FOR_SUB_GROUP_BY_NUMBER_OF_GROUPS
	
	switch(trGetN.subgroup.nVal)
	{
	case subgroup_points:
		if(trGetN.points.nVal > nSize || trGetN.points.nVal < 1)
		{
			strErrMsg = XF_REDUCE_NUM_DATA;
			return false;
		}
		break;
	case subgroup_groups:
		if( trGetN.groups.nVal<2 )
		{
			strErrMsg = XF_REDUCE_BIN_NUM_TOO_SMALL;
			return false;
		}
		if( trGetN.groups.nVal>nSize )
		{
			strErrMsg = XF_REDUCE_BIN_TOO_LARGE;
			return false;
		}
		break;
	case subgroup_inc:
		if( trGetN.xincr.dVal>(dxMax-dxMin) )
		{
			strErrMsg = XF_REDUCE_BIN_TOO_LARGE;
			return false;
		}
		///Kyle 11/24/2009 QA80-14127-P16 START_END_CHECKING_FOR_SUB_GROUP_BY_NUMBER_OF_GROUPS
		/*
		///Sophy 6/1/2009 MORE_CHECK_ON_USER_INPUT
		vector vSubX, vSubY;
		int nRet = _get_subrange_of_XY(vx, vy, dxMin, dxMax, vSubX, vSubY);
		if(nRet<0)
		{
			///Kyle 11/20/2009 QA80-14127-P16 ERROR_CHECK_OUT_OF_XF_BODY_SHOULD_NOT_USE_XF_THROW
			//XF_THROW(XF_REDUCE_FAILED_GET_RANGE);
			strErrMsg = XF_REDUCE_FAILED_GET_RANGE;
			return false;
			///End ERROR_CHECK_OUT_OF_XF_BODY_SHOULD_NOT_USE_XF_THROW
		}
		
		int nRealSize = vSubX.GetSize();
		ASSERT(nRealSize == vSubY.GetSize());
		
		double dRealMin, dRealMax;
		vSubX.GetMinMax(dRealMin, dRealMax);
		*/
		///End START_END_CHECKING_FOR_SUB_GROUP_BY_NUMBER_OF_GROUPS
		if ( trGetN.xincr.dVal <= 0 || ((dRealMax - dRealMin)/trGetN.xincr.dVal)>= nRealSize )
		{
			strErrMsg = XF_REDUCE_INVALID_BIN_INCREMENT;
			return false;
		}
		
		///end MORE_CHECK_ON_USER_INPUT
		///Kyle 11/24/2009 QA80-14127-P16 START_END_CHECKING_FOR_SUB_GROUP_BY_NUMBER_OF_GROUPS, start & end should have been checked before
		/*
		if(trGetN.start.dVal >= trGetN.end.dVal)
		{
			strErrMsg = XF_REDUCE_START_END_ERROR;
			return false;
		}
		*/
		///End START_END_CHECKING_FOR_SUB_GROUP_BY_NUMBER_OF_GROUPS
		break;
	}
	
	///Sophy 6/1/2009 MORE_CHECK_ON_USER_INPUT
	//XYRange xyRange;
	//xy_range_from_GetN_data_node(trGetN.iy, xyRange);
	//vector vx, vy;
	//xyRange.GetData(vy, vx,NULL, 0, 0);
	//if(!ocmath_is_monotonic(vx, vx.GetSize(), false))
	//{
		//strErrMsg = CER_NONMONOTONIC_X;
		//return false;
	//}
	///end MORE_CHECK_ON_USER_INPUT

	return true;
}

static int xstats_option_convert(int iOption)
{
	switch (iOption)
	{
	case xstats_ave:	
		return REDUCE_XY_STATS_MEAN;	
	///Kyle 07/03/2009 GUI_CHANGE, remove min, max, sum, sd for x
	//case xstats_min:
		//return REDUCE_XY_STATS_MIN;
	//case xstats_max:
		//return REDUCE_XY_STATS_MAX;
	//case	xstats_sum:
		//return REDUCE_XY_STATS_SUM;
	//case xstats_sd:
		//return REDUCE_XY_STATS_SD;
	///End GUI_CHANGE
	case xstats_median:
		return REDUCE_XY_STATS_MEDIAN;
	case xstats_first:
		return REDUCE_XY_STATS_FIRST;
	case xstats_last:
		return REDUCE_XY_STATS_LAST;
	default:
		ASSERT(FALSE);
	}	
	return 0;	
}

static int ystats_option_convert(int iOption)
{
	switch (iOption)
	{
	case ystats_ave:	
		return REDUCE_XY_STATS_MEAN;	
	case ystats_min:
		return REDUCE_XY_STATS_MIN;
	case ystats_max:
		return REDUCE_XY_STATS_MAX;
	///Kyle 07/03/2009 GUI_CHANGE, remove sum, sd for y
	//case ystats_sum:
	//	return REDUCE_XY_STATS_SUM;
	//case ystats_sd:
	//	return REDUCE_XY_STATS_SD;
	///End GUI_CHANGE
	case ystats_median:
		return REDUCE_XY_STATS_MEDIAN;
	case ystats_first:
		return REDUCE_XY_STATS_FIRST;
	case ystats_last:
		return REDUCE_XY_STATS_LAST;
	default:
		ASSERT(FALSE);
	}
	return 0;	
}

static double get_data(const vector& vIn, const int iOption)
{
	double dMin, dMax;
	vIn.GetMinMax(dMin, dMax);
	
	DescStatResults dsr;
	int nSize = vIn.GetSize();
	int nRet = ocmath_desc_stats(vIn, nSize, &dsr);
	if (nRet != STATS_NO_ERROR)
		return NANUM;

/// Jack 21/10/2008 QA80-12405 REDUCE_DATA_XF
/*	
	switch (iOption)
	{
	case method_minrow:	
		return vIn[0];
		break;
	case method_maxrow:
		return vIn[nSize - 1];
		break;
	case method_ave:
		return dsr.Mean;
		break;
	case method_min:
		return dMin;
		break;
	case method_max:
		return dMax;
		break;
	case 	method_sum:
		return dsr.Sum;
		break;
	case method_sd:
		return dsr.SD;
		break
	default:
		return NANUM;	
	}
*/
	double dMedian;
	
	switch (iOption)
	{
	case ystats_first:	  /// assert that x and y are paired by each method
//	case xstats_minrow:	
		return vIn[0];
		break;
		
	case ystats_last:
//	case xstats_maxrow:
		return vIn[nSize - 1];
		break;
		
	case ystats_ave:
//	case xstats_ave:
		return dsr.Mean;
		break;
		
	case ystats_min:
//	case xstats_min:
		return dMin;
		break;
		
	case ystats_max:
//	case xstats_max:
		return dMax;
		break;
	///Kyle 07/03/2009 GUI_CHANGE, remove sum, sd for y
	//case 	ystats_sum:
////	case 	xstats_sum:
		//return dsr.Sum;
		//break;
		//
	//case ystats_sd:
////	case xstats_sd:	
		//return dsr.SD;
		//break;
	///End GUI_CHANGE
		
	case ystats_median:
//	case xstats_median:
		ocmath_get_median_in_vector(nSize,vIn,&dMedian);  // there is a sort so only run it when necessary
		return dMedian;
		break;
	default:
		return NANUM;	
	}
	return NANUM;
/// End REDUCE_DATA_XF
}


///Jack 21/10/2008 QA80-12405 REDUCE_DATA_XF
//static bool merge_fixing_dx(const vector& vX, const vector& vData, const double dInc, const int iOption, vector& vMerged)
static bool merge_fixing_increbin(const vector& vX, const vector& vData, const double dInc, const int iOption, vector& vMerged)
///End REDUCE_DATA_XF
{
	/// Jack 21/10/2008 QA80-12405 REDUCE_DATA_XF
	// centralized
	
	//if missing values, cases are excluded pairwise
	/*
	vector<uint> vecIndexX, vecIndexD;
	vX.Find(vecIndexX, NANUM);
	vData.Find(vecIndexD, NANUM);
	
	for (int ii= 0; ii < vecIndexX.GetSize(); ii++)
		vData[vecIndexX[ii]] = NANUM;
	
	for (ii= 0; ii < vecIndexD.GetSize(); ii++)
		vX[vecIndexD[ii]] = NANUM;
		
	vData.Trim();
	vX.Trim();
	*/
//	if(!_trim_missing_values(vX,vData))  // no need as in get data from xyrange the missing value is already trimmed
//		return false;
	/// End REDUCE_DATA_XF
	
	double dMin, dMax, dIncTmp;
	vX.GetMinMax(dMin, dMax);
	
	if (dInc > dMax - dMin)
		return false;
	
	int nBins = (int)((dMax - dMin)/dInc) + 1;
	//vMerged.SetSize(nBins);---- /// Jack 21/10/2008 QA80-12405 REDUCE_DATA_XF
	
	vector vBins;
	vBins.Data(dMin + dInc, dMin + (nBins)* dInc, dInc);
	vector<int> vEnd(nBins);
	int nXSize = vX.GetSize();
	/// Jack 21/10/2008 QA80-12405 REDUCE_DATA_XF
	/*
	int nErr = ocmath_group_xy_by_x(nXSize, vX, vData, nBins, vBins, vEnd);
	if(nErr != 0)
	{
		return false;
	}
	*/
	int nGroups = ocmath_group_xy_by_x_new(nXSize, vX, vData, nBins, vBins, vEnd);
	if(nGroups < 0)
	{
		return false;
	}
	else
	{
		
		vEnd.SetSize(nGroups);
		vMerged.SetSize(nGroups);
	}
	/// End REDUCE_DATA_XF
	
	/// Jack 21/10/2008 QA80-12405 REDUCE_DATA_XF
	/*
	matrix mData(vData);
	matrix mSubData;
	int iBegin, iEnd;
	vector vSubData;
	for (ii = 0; ii < nBins ; ii++)
	{
		iBegin = ii>0 ? vEnd[ii-1]+1:0;
		iEnd = vEnd[ii];
		mData.GetSubMatrix(mSubData,0,-1,iBegin,iEnd);
		mSubData.GetColumn(vSubData, 0);
		vMerged[ii] = get_data(vSubData, iOption);	
	}
	*/
	vector vSubData;
	int iBegin, iEnd;
	for (int ii = 0; ii < nGroups ; ii++)
	{
		iBegin = ii>0 ? vEnd[ii-1]+1:0;
		iEnd = vEnd[ii];
		vData.GetSubVector(vSubData, iBegin, iEnd);
		vMerged[ii] = get_data(vSubData, iOption);
	}
	/// End REDUCE_DATA_XF
	
	return true;
	
}

/*
static bool merge_n_points(const vector& vX, const vector& vData, const int nPoints, const int iOption, vector& vMerged)
{
	int nSize = vX.GetSize();
	int nBins = nSize/nPoints + ((nSize%nPoints)?1:0);
	
	vMerged.SetSize(nBins);
	
	vector vSubData;
	for (int ii = 0; ii < nBins-1 ; ii++)
	{
		vData.GetSubVector(vSubData, ii*nPoints, (ii+1)*nPoints-1);
		vMerged[ii] = get_data(vSubData, iOption);
	}
	vData.GetSubVector(vSubData, nBins*nPoints, nSize-1);
	vMerged[nBins-1] = get_data(vSubData, iOption);	

	return true;
}
*/

/// Jack 21/10/2008 QA80-12405 REDUCE_DATA_XF

static bool _trim_missing_values(vector& vX, vector& vData)
{
	if(vX.GetSize()==0 || vData.GetSize()==0)
		return false;
	
	//if missing values, cases are excluded pairwise
	vector<uint> vecIndexX, vecIndexD;
	vX.Find(vecIndexX, NANUM);
	vData.Find(vecIndexD, NANUM);
	
	for (int ii= 0; ii < vecIndexX.GetSize(); ii++)
		vData[vecIndexX[ii]] = NANUM;
	
	for (ii= 0; ii < vecIndexD.GetSize(); ii++)
		vX[vecIndexD[ii]] = NANUM;
		
	vData.Trim();
	vX.Trim();
	if(vX.GetSize()==0 || vData.GetSize()==0)
		return false;
	else
		return true;
}



static bool merge_fixing_dx_nbins(const vector& vX, const vector& vData, const int iOption, vector& vMerged, int nBins)
{
	//if missing values, cases are excluded pairwise
//	if(!_trim_missing_values(vX,vData))  // no need as in get data from xyrange the missing value is already trimmed
//		return false;
	ASSERT(nBins>=1);

	double dMin, dMax;
	vX.GetMinMax(dMin, dMax);
	

//	double dInc = (dMax - dMin)/(double)(nBins-1);
	double dInc = (dMax - dMin)/(double)(nBins); // make nBins one-offset based

	
	vector vBins;

//	vBins.Data(dMin + dInc, dMin + (nBins)* dInc, dInc);
///	Jack QA80-12405 12/02/2008 SET_THE_SAME_SIZE
//	vBins.Data(dMin + dInc, dMin + (nBins+1)* dInc, dInc); 
	vBins.Data(dMin + dInc, dMax, dInc);  // In princple equiv to vBins.Data(dMin + dInc, dMin + (nBins)* dInc, dInc);
/// End	SET_THE_SAME_SIZE


	
///	Jack QA80-12568 12/02/2008 SET_THE_SAME_SIZE
//	vector<int> vEnd(nBins);
	vector<int> vEnd(vBins.GetSize());
/// End SET_THE_SAME_SIZE
	
	int nXSize = vX.GetSize();
	
	/// Jack 21/10/2008 QA80-12405 REDUCE_DATA_XF
	/*
	int nErr = ocmath_group_xy_by_x(nXSize, vX, vData, nBins, vBins, vEnd);
	if(nErr != 0)
	{
		return false;
	}
	*/ 
///	Jack QA80-12405 12/02/2008 SET_THE_SAME_SIZE
//	int nGroups = ocmath_group_xy_by_x_new(nXSize, vX, vData, nBins, vBins, vEnd); /// nGroups not necessarilly equal to nBins and vEnd keep control points or break points index
	int nGroups = ocmath_group_xy_by_x_new(nXSize, vX, vData, vBins.GetSize(), vBins, vEnd); /// nGroups not necessarilly equal to nBins and vEnd keep control points or break points index
/// End	SET_THE_SAME_SIZE
	if(nGroups < 0)
	{
		return false;
	}
	else
	{
		
		vEnd.SetSize(nGroups);
		vMerged.SetSize(nGroups);
	}
	/// End REDUCE_DATA_XF
	
	vector vSubData;
	int iBegin, iEnd;
	for (int ii = 0; ii < nGroups ; ii++)
	{
		iBegin = ii>0 ? vEnd[ii-1]+1:0;
		iEnd = vEnd[ii];
		vData.GetSubVector(vSubData, iBegin, iEnd);
		vMerged[ii] = get_data(vSubData, iOption);
	}
	return true;
	
}



static void _update_method_show(TreeNode& trGetN)
{
	switch(trGetN.subgroup.nVal)
	{
	case subgroup_points:
		trGetN.points.Show = true;
		trGetN.groups.Show = false;
		trGetN.xincr.Show = false;
		trGetN.start.Show = false;
		trGetN.end.Show = false;
		break;
		
	case subgroup_groups:
		trGetN.points.Show = false;
		trGetN.groups.Show = true;
		trGetN.xincr.Show = false;
		trGetN.start.Show = true;
		trGetN.end.Show = true;
		break;
		
	case subgroup_inc:
		trGetN.points.Show = false;
		trGetN.groups.Show = false;
		trGetN.xincr.Show = true;
		trGetN.start.Show = true;
		trGetN.end.Show = true;
		break;
	}
}


static int _get_subrange_of_XY(const vector& vX, const vector& vY, const double xStart, const double xEnd, vector& vSubX, vector& vSubY)
{
	int nSize = vX.GetSize();
	int xStartIndex, xEndIndex;
	// assume that x is in order  ascending or descending
	int nRet = ocmath_get_lower_upper_bounds_index(nSize, vX, xStart, xEnd, &xStartIndex, &xEndIndex);
	if (nRet<0)
		return SUB_RANGE_FAILED; 
	// here either start or end indice are not found or the data is not in order, i.e: netative number returned 
	/// and so that can get subrange in a strict way
	

	//get subrange in a not strict way
	/*
	if(xStartIndex>=0 && xEndIndex<0)  // xEndIndex not found,  but xStartIndex found, then use data to end of data
	{
		vX.GetSubVector(vSubX, xStartIndex, nSize-1);
		vY.GetSubVector(vSubY, xStartIndex, nSize-1);
		return SUB_RANGE_SUCCESS;
	}
	
	if(xStartIndex<0 && xEndIndex>=0) // xStartIndex not found  but xEndIndex found, then start to end of data
	{
		vX.GetSubVector(vSubX, 0, xEndIndex);
		vY.GetSubVector(vSubY, 0, xEndIndex);
		return SUB_RANGE_SUCCESS;
	}
	*/
	
	
	// get subrange in a strict way
	
	if(xStartIndex>xEndIndex) // swap the two index if the data is descending order
	{
		int TempIndex = xStartIndex;
		xStartIndex = xEndIndex;
		xEndIndex = TempIndex;
	}
	
	
	vX.GetSubVector(vSubX, xStartIndex, xEndIndex);
	vY.GetSubVector(vSubY, xStartIndex, xEndIndex);
	return SUB_RANGE_SUCCESS;
}

/// End REDUCE_DATA_XF
	
/// Jack 21/10/2008 QA80-12405 REDUCE_DATA_XF 
/*
// no longer use ReportData for output
static bool _reducexy_update_report_data(ReportData& outData, const vector& vX, const vector& vY)
{
	if (!outData)
		return false;
	
	int jj = outData.GetNodeCount();
	string strjj = ftoa(jj+1);
	ReportTable rtReduce = outData.CreateTable("Reduced"+strjj,  _L("Reduced XY")+" "+strjj, REDUCE_REPORT_TABLE);
	rtReduce.AddColumn(vX, "X"+strjj, _REDUCE_X+jj, _L("Reduced X"), OKDATAOBJ_DESIGNATION_X);
	rtReduce.AddColumn(vY, "Y"+strjj, _REDUCE_Y+jj, _L("Reduced Y"), OKDATAOBJ_DESIGNATION_Y);
	
	return true;
	
}
*/

///Kyle 10/21/2009 USE_GENERAL_CODE_TO_SET_XYRANGE_DATA
/*
static bool _reducexy_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,  0, NULL, DRS_SET_COL_DESIGNATIONS);
	return true;
}
*/
///End USE_GENERAL_CODE_TO_SET_XYRANGE_DATA

static void update_xstartend_show(TreeNode& trGetN)
{
	if(trGetN.subgroup.nVal != subgroup_inc && trGetN.subgroup.nVal != subgroup_groups)
		return;
		
	TreeNode trxmin = trGetN.start;
	TreeNode trxmax = trGetN.end;
	bool bAutoXmin = octree_get_auto_support(&trxmin)==1?true:false;
	bool bAutoXmax = octree_get_auto_support(&trxmax)==1?true:false;

	//----------- CPY 4/11/07 QA70-9562 BETTER_NOT_ASSUME_YI_AS_INPUT_DATA_NODE
	//double dxMin, dxMax
	double dxMin = 0.1, dxMax = 4.9;// some special value to indicate we dont have the yi node and also I can use these for my QA70-9562 testing
	//bool bRet = true;
	//-----------
	if(bAutoXmin || bAutoXmax)
	{
		//if(!get_data_x_scale(trGetN, dxMin, dxMax))
			//bRet = false;
		get_data_x_scale(trGetN, dxMin, dxMax);
		if(bAutoXmin)
			trGetN.start.dVal = dxMin;
		if(bAutoXmax)
			trGetN.end.dVal = dxMax;
	}
	//return bRet;
}


//static bool update_incre_bin(TreeNode& trGetN, double dMin, double dMax)
//{
	//TreeNode trdx = trGetN.increBin;
	//bool bAutodx = octree_get_auto_support(&trdx)==1?true:false;
	//if(bAutodx)
	//{
		//trGetN.increBin.dVal = 0.05*(dMax-dMin); // hard code auto initilize dx as 5% of dmin and dmax
	//}
	//return true;
//}
//
//static bool update_sample_dx(TreeNode& trGetN, double dMin, double dMax, int nSize)
//{
	//TreeNode trdx = trGetN.dx;
	//bool bAutodx = octree_get_auto_support(&trdx)==1?true:false;
	//if(bAutodx)
	//{
		//trGetN.dx.dVal = (dMax-dMin)/(double)(nSize); // hard code auto initilize dx as 5% of dmin and dmax
	//}
	//return true;
//}
//
//static bool update_binnum(TreeNode& trGetN, int nSize)
//{
	//TreeNode trbin = trGetN.bins;
	//bool bAutobin = octree_get_auto_support(&trbin)==1?true:false;
	//if(bAutobin)
	//{
		//trGetN.bins.nVal = (int)(1.2*nSize); // hard code auto initilize bin num as 1.5 times of nSize   note that bin number can be larger than nSize data
	//}
	//return true;
//}
//
//static bool update_groupnum(TreeNode& trGetN, int nSize)
//{
	//TreeNode trngrps = trGetN.ngrps;
	//bool bAutongrps = octree_get_auto_support(&trngrps)==1?true:false;
	//if(bAutongrps)
	//{
		//trGetN.ngrps.nVal = (int)(0.8*nSize); // hard code auto initilize group num as 80%  nSize   note that although group number can be larger than nSize, but it it meaingless if group size larger than nSize
	//}
	//return true;
//}
static void _update_auto_input(TreeNode& trGetN)
{
	update_xstartend_show(trGetN);
	int nSize =  get_input_xyrange_data_size(trGetN.iy);
	switch(trGetN.subgroup.nVal)
	{
	case subgroup_points:
		TreeNode trPoints = trGetN.points;
		if( 1 == octree_get_auto_support(&trPoints) )
		{
			if(nSize < 10)
				trPoints.nVal = 2;
			else
				trPoints.nVal = 10;
		}
		break;
		
	case subgroup_groups:
		TreeNode trGroups = trGetN.groups;
		if( 1 == octree_get_auto_support(&trGroups) )
		{
			if(nSize < 10)
				trGroups.nVal = nSize / 2;
			else
				trGroups.nVal = nSize / 10;
		}
		break;
		
	case subgroup_inc:
		///Kyle 07/03/2009 GUI_CHANGE, 
		TreeNode trIncr = trGetN.xincr;
		if( 1 == octree_get_auto_support(&trIncr) )
		{
			trIncr.dVal = (trGetN.end.dVal-trGetN.start.dVal) / nSize * 5;
		}
		///End GUI_CHANGE
		break;
	}
}

///End REDUCE_DATA_XF

///Kyle 12/22/2008 OUTPUT_COLUMN_COMMENTS
static	void	_set_output_range_comments(XYRange &oy, const XYRange& iy, int nMethod)
{
	string strMethod;
	switch(nMethod)
	{
	case ystats_ave:
		strMethod = "Average";
		break;
	case ystats_min:
		strMethod = "Min";
		break;
	case ystats_max:
		strMethod = "Max";
		break;
	///Kyle 07/03/2009 GUI_CHANGE
	//case ystats_sum:
		//strMethod = "Sum";
		//break;
	//case ystats_sd:
		//strMethod = "SD";
		//break;
	///End GUI_CHANGE
	case ystats_median:
		strMethod = "Median";
		break;
	case ystats_first:
		strMethod = "First in SubGroup";
		break;
	case ystats_last:
		strMethod = "Last in SubGroup";
		break;
	}
	string strComments;
	strComments.Format(_L("Reduction with %s of %s"), _L(strMethod), get_input_data_range_string(iy));

	if(oy != NULL && oy.IsValid())
		oy.SetOutputComment(strComments);
}
///End OUTPUT_COLUMN_COMMENTS

static void _update_data_size_hint_label(TreeNode& trGetN)
{
	string strHintLabel;
	int nSize =  get_input_xyrange_data_size(trGetN.iy);
	if(nSize > 0)
	{
		int nNewSize = 0;
		
		switch(trGetN.subgroup.nVal)
		{
		case subgroup_points:
			{
				int nPoints = trGetN.points.nVal;
				///Sophy 6/1/2009 MORE_CHECK_ON_USER_INPUT
				if ( nPoints < 1 )
				{
					ASSERT(FALSE);
					return;
				}
				///end MORE_CHECK_ON_USER_INPUT
				nNewSize = nSize/nPoints + ((nSize%nPoints)?1:0);
			}
			break;
		case subgroup_groups:
			nNewSize = trGetN.groups.nVal;
			break;
		case subgroup_inc:
			{
				double dMin, dMax;
				vector vx, vy;
				XYRange xyTemp;
				if( !xy_range_from_GetN_data_node(trGetN.iy, xyTemp))
				{
					///Kyle 11/20/2009 QA80-14127-P16 ERROR_CHECK_OUT_OF_XF_BODY_SHOULD_NOT_USE_XF_THROW
					//XF_THROW(1);
					return;
					///End ERROR_CHECK_OUT_OF_XF_BODY_SHOULD_NOT_USE_XF_THROW
				}
				
				int nNumRanges = xyTemp.GetNumData(DRR_NO_WEIGHTS | DRR_GET_DEPENDENT | DRR_NO_FACTORS);
				if( 1 == nNumRanges )
				{
					xyTemp.GetData(vy, vx, NULL, 0);
					///Sophy 6/1/2009 MORE_CHECK_ON_USER_INPUT
					//vx.GetMinMax(dMin, dMax);
					//double dInx = trGetN.xincr.dVal;
					//nNewSize = (int)((dMax - dMin)/dInx) + 1;
					double dStart = trGetN.start.dVal;
					double dEnd = trGetN.end.dVal;
					double dIncX = trGetN.xincr.dVal;

					vector vSubX, vSubY;
					int nRet = _get_subrange_of_XY(vx, vy, dStart, dEnd, vSubX, vSubY);
					if(nRet<0)
					{
						///Kyle 11/20/2009 QA80-14127-P16 ERROR_CHECK_OUT_OF_XF_BODY_SHOULD_NOT_USE_XF_THROW
						//XF_THROW(XF_REDUCE_FAILED_GET_RANGE);
						return;
						///End ERROR_CHECK_OUT_OF_XF_BODY_SHOULD_NOT_USE_XF_THROW
					}
					
					vSubX.GetMinMax(dMin, dMax);
					nNewSize = (int)((dMax - dMin)/dIncX) + 1;
					///end MORE_CHECK_ON_USER_INPUT
				}
			}
			break;
		default:
			ASSERT(FALSE);
		}
		
		
		//strHintLabel.Format("Input Number of Points:%d, Output Number of Points: %d", nSize, nNewSize);
		string		str;
		ocu_load_err_msg_str(XFINFO_REDUCE_INPUT_OUTPUT_NUMBER, str);
		strHintLabel.Format(str, nSize, nNewSize);
		
	}
	trGetN.datasizehint.SetAttribute(STR_LABEL_ATTRIB, strHintLabel);
}


void reducexy(const XYRange& iy, const int& subgroup, const int& points, const double& xincr, const int& groups, string& datasizehint, const double& start, const double& end, const int& xstats, const int& ystats, XYRange& oy)
{
	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, vDataCol, vMergedX, vMergedY;
	for( int ii = 0; ii < nNumRanges; ii++ )
	{
		
		iy.GetData(vY, vX, NULL,  ii);  //// 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);
		}
		
		int nSize = vX.GetSize();
		ASSERT(nSize == vY.GetSize());
		
		double dstart = start, dend = end;
		
		switch(subgroup)
		{
			case subgroup_inc:
			{
	
				ASSERT(xincr>0);
				vector vSubX, vSubY; // default set xStart as the min of x, xEnd as the max of x
				int nRet = _get_subrange_of_XY(vX, vY, start, end, vSubX, vSubY);
				if(nRet<0)
					XF_THROW(XF_REDUCE_FAILED_GET_RANGE);
				
				nSize = vSubX.GetSize();
				ASSERT(nSize == vSubY.GetSize());
				
				vMergedY.SetSize(nSize);
				int nSizeNew = ocmath_reducexy_fixing_increbin(vSubX, vSubY, nSize, ystats_option_convert(ystats), vMergedY, xincr);
				if( nSizeNew < 0 )
					XF_THROW(1);
				vMergedY.SetSize(nSizeNew);					
				
				vMergedX.SetSize(nSize);
				nSizeNew = ocmath_reducexy_fixing_increbin(vSubX, vSubX, nSize, xstats_option_convert(xstats), vMergedX, xincr);
				if( nSizeNew < 0 )
					XF_THROW(1);
				vMergedX.SetSize(nSizeNew);
				
				/*
				ASSERT(xincr>0);
				vector vSubX, vSubY; // default set xStart as the min of x, xEnd as the max of x
				int nRet = _get_subrange_of_XY(vX, vY, start, end, vSubX, vSubY);
				if(nRet<0)
					XF_THROW(XF_REDUCE_FAILED_GET_RANGE);
				if (!merge_fixing_increbin(vSubX, vSubY, xincr, ystats, vMergedY) || !merge_fixing_increbin(vSubX, vSubX, xincr, xstats, vMergedX))
					XF_THROW(XF_REDUCE_BIN_INTERVAL);
				*/
				
				
				break;
			}
			case subgroup_groups:
			{
				ASSERT(groups>0);
				
				vector vSubX, vSubY; // default set xStart as the min of x, xEnd as the max of x
				int nRet = _get_subrange_of_XY(vX, vY, start, end, vSubX, vSubY);	
				if(nRet<0)
					XF_THROW(XF_REDUCE_FAILED_GET_RANGE);		
					
				nSize = vSubX.GetSize();
				ASSERT(nSize == vSubY.GetSize());
	
				vMergedY.SetSize(nSize);
				int nSizeNew = ocmath_reducexy_n_groups(vSubX, vSubY, nSize, ystats_option_convert(ystats), vMergedY, groups);
				if( nSizeNew < 0 )
					XF_THROW(1);
				vMergedY.SetSize(nSizeNew);					
				
				vMergedX.SetSize(nSize);
				nSizeNew = ocmath_reducexy_n_groups(vSubX, vSubX, nSize, xstats_option_convert(xstats), vMergedX, groups);
				if( nSizeNew < 0 )
					XF_THROW(1);
				vMergedX.SetSize(nSizeNew);
			
			
				/*
				ASSERT(groups>0);
				vector vSubX, vSubY; // default set xStart as the min of x, xEnd as the max of x
				int nRet = _get_subrange_of_XY(vX, vY, start, end, vSubX, vSubY);
				
				if(nRet<0)
					XF_THROW(XF_REDUCE_FAILED_GET_RANGE);
				
				if (!merge_fixing_dx_nbins(vSubX, vSubY, ystats, vMergedY, groups) || !merge_fixing_dx_nbins(vSubX, vSubX, xstats, vMergedX, groups))
					XF_THROW(XF_REDUCE_BIN);
				*/
				
				break;
			}
			case subgroup_points:
			{
				
				ASSERT(points>0);
				
				vMergedX.SetSize(nSize);				
				int nSizeNew = ocmath_reducexy_n_points(vX, vMergedX, nSize, points, xstats_option_convert(xstats));
				if( nSizeNew <= 0 )
					XF_THROW(1);
				vMergedX.SetSize(nSizeNew);
				
				vMergedY.SetSize(nSizeNew);
				ocmath_reducexy_n_points(vY, vMergedY, nSize, points, ystats_option_convert(ystats));
				
				/*
				ASSERT(points>0);
				
				if (!merge_n_points(vX, vY, points, ystats, vMergedY) || !merge_n_points(vX, vX, points, xstats, vMergedX))
					XF_THROW(XF_REDUCE_BIN);				
				*/
				
				break;
			}
			default:
				ASSERT(FALSE);
		}
		/// End REDUCE_DATA_XF
		
		if(!oy)  // if not specified an output range, create one for it
		{
			Worksheet wks;
			wks.Create();
			wks.SetSize(-1, 2);
			oy.Create();
			xy_range_from_wks_cols(oy,wks,0,1);
		}
		///Kyle 10/21/2009 USE_GENERAL_CODE_TO_SET_XYRANGE_DATA
		//_reducexy_set_data_range(oy,&vMergedX, &vMergedY);
		set_xyrange_data_ex(oy, &vMergedY, &vMergedX, 0, iy, NULL, SXYDC_RECALCULATE_SAMPLING_INTERVAL);
		///End USE_GENERAL_CODE_TO_SET_XYRANGE_DATA
		//_reducexy_update_report_data(rd, vMergedX, vMergedY);
		///Kyle 12/04/2008 ADD_PLOT_TO_GRAPH_IF_FROM_GRAPH
		xf_check_plot_output_rng_in_source_rng_graph(iy, oy);
		///End ADD_PLOT_TO_GRAPH_IF_FROM_GRAPH
		
		///Kyle 12/22/2008 OUTPUT_COLUMN_COMMENTS
		_set_output_range_comments(oy, iy, ystats);
		///End OUTPUT_COLUMN_COMMENTS
	}
}

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

}

int reducexy_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 reducexy_before_execute(TreeNode& trGetN, int nGetNDialog, int& nRet, int dwCntrl)
{
	///Kyle 12/02/2008 QA80-12405-S1 UPDATE_XF_TO_SHOW_PREVIEW
	if(is_xf_startup(nGetNDialog, dwCntrl))
	{
		///Sophy 6/1/2009 IMPROVE_PERFORMANCE_WHEN_NO_DIALOG_OPEN
		//_update_method_show(trGetN); /// for showing different setting for different reduce method (or group method)
		if ( nGetNDialog != 0 )
			_update_method_show(trGetN); /// for showing different setting for different reduce method (or group method)
		///end IMPROVE_PERFORMANCE_WHEN_NO_DIALOG_OPEN
	
		///Kyle 12/10/2008 SHOULD_CHECK_IF_AUTO_WHILD_SET_START_END_VALUE
		//double dxMin, dxMax;
		//if(get_data_x_scale(trGetN, dxMin, dxMax))
		//{
			//trGetN.start.dVal = dxMin;
			//trGetN.end.dVal = dxMax;
		//}
		//update_xstartend_show(trGetN);	// init base on "Auto"
		_update_auto_input(trGetN);
		///End SHOULD_CHECK_IF_AUTO_WHILD_SET_START_END_VALUE
		///Kyle 12/22/2008 OPEN_DIALOG_WHEN_THEME_IS_USED_AND_ERROR_HAPPENS
		//_update_data_size_hint_label(trGetN);///Sophy 6/1/2009 IMPROVE_PERFORMANCE_ON_NO_DIALOG_OPEN should update after check
		if ( (dwCntrl&LTXF_THEME_USED) && nGetNDialog <= 0 )
		{
			string strErrMsg;
			if(!_check_input(trGetN, strErrMsg))
				nRet = XFEVT_PROCEED_WITH_DLG;
		}
	
		///Sophy 6/1/2009 IMPROVE_PERFORMANCE_WHEN_NO_DIALOG_OPEN
		//_update_data_size_hint_label(trGetN);///Sophy 6/1/2009 IMPROVE_PERFORMANCE_ON_NO_DIALOG_OPEN
		if ( nGetNDialog != 0 )
			_update_data_size_hint_label(trGetN);///Sophy 6/1/2009 IMPROVE_PERFORMANCE_ON_NO_DIALOG_OPEN
		///end IMPROVE_PERFORMANCE_WHEN_NO_DIALOG_OPEN
		///End OPEN_DIALOG_WHEN_THEME_IS_USED_AND_ERROR_HAPPENS
	}
	///End UPDATE_XF_TO_SHOW_PREVIEW
	
}
//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 reducexy_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);
	
	_update_data_size_hint_label(trGetN);

	if(bOKEnable)
	{
		Worksheet wks = wksTemp;
		wks.SetSize(-1, 2);
		wks.SetColDesignations("XY");
		wks.Columns(1).SetLongName("Reduced");
	}
	s_bInit = false;
	s_strErrMsg = strErrMsg;
	bUpdateGraph = bOKEnable;

}

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

// 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
	///Kyle 12/02/2008 QA80-12405-S1 UPDATE_XF_TO_SHOW_PREVIEW
	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
	///End UPDATE_XF_TO_SHOW_PREVIEW

}

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

static void GetNGraphPreview_OnUpdateGraph(TreeNode& trGetN, PageBase& pgTemp, Datasheet& wksTemp, PictureControl& pict)
{

	Worksheet wks = wksTemp;
	if(!s_bInit)
	{
		Worksheet wks = wksTemp;
		wks.SetSize(0,-1, true);
		///Kyle 06/03/2009 GET_SOURCE_GRAPH_SCALE_TYPE
		//init_preview_graph(trGetN.iy, pgTemp, wks, "CurvePreview");
		init_preview_graph(trGetN.iy, pgTemp, wks, "CurvePreview", NULL, NULL, 0, 0, 1, PREVIEW_LAYER_FORMAT_SCALE_TYPE);
		///End GET_SOURCE_GRAPH_SCALE_TYPE
		GraphPage gp = pgTemp;
		gp.Refresh(true);
		s_bInit = true;
	}
	_run_reducexy_on_current_data(trGetN, pgTemp, wks);

}

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

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
	//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
	///Kyle 12/02/2008 QA80-12405-S1 UPDATE_XF_TO_SHOW_PREVIEW, centralize code to _check_input
	//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;
	////	else if (trGetN.dx.nVal > nSize)
	////		nErr = XF_REDUCE_DX;
	//
	//
	//
	///// Jack 21/10/2008 QA80-12405 REDUCE_DATA_XF
	//_update_method_show(trGetN); /// for showing different setting for different reduce method (or group method)
	//double dxMin, dxMax;
	//get_data_x_scale(trGetN, dxMin, dxMax);
	//
	//
	//
	//if(trGetN.subgroup.nVal == subgroup_inc)  // increBin 
	//{
		//update_xstartend_show(trGetN); // auto intilize start end
	////		update_incre_bin(trGetN, dxMin, dxMax); // auto intilize bin incre
	//}
	//if(trGetN.increbin.dVal>(dxMax-dxMin) && trGetN.subgroup.nVal == subgroup_inc)
	//{
		//bOKEnable = false;
		//strErrMsg = XF_REDUCE_BIN_TOO_LARGE;  /// todo: proper error message in RC file
	//}
	//if(trGetN.subgroup.nVal == subgroup_bin)
	//{
		//update_binnum(trGetN, nSize);
	//}
	//
	//if(trGetN.subgroup.nVal == subgroup_bin)  // increBin 
	//{
		//update_xstartend_show(trGetN); // auto intilize start end
	//}
	///// End REDUCE_DATA_XF
	//
	/////Kyle 12/02/2008 QA80-12405-S1 UPDATE_XF_TO_SHOW_PREVIEW, to check start & end
	//if(trGetN.start.dVal > trGetN.end.dVal )
	//{
		//bOKEnable = false;
		//strErrMsg = XF_REDUCE_START_END_ERROR;
	//}
	/////End UPDATE_XF_TO_SHOW_PREVIEW
	//
	///// Jack 21/10/2008 QA80-12405 REDUCE_DATA_XF
	//if(trGetN.subgroup.nVal == subgroup_inc && (trGetN.start.dVal>=trGetN.end.dVal)) // check error and assumption
	//{
		//bOKEnable = false;
		//strErrMsg = XF_REDUCE_START_END_ERROR; ///"Improper start end range"
	//}
	//
	//if(trGetN.bins.nVal<2 && trGetN.subgroup.nVal == subgroup_bin)
	//{
		//bOKEnable = false;
		//strErrMsg = XF_REDUCE_BIN_NUM_TOO_SMALL;  /// "Too Small bin numbers"
	//}
	//
	/////End REDUCE_DATA_XF
	//
	//if(nErr != CER_NO_ERROR)
	//{
		//bOKEnable = false;
		//strErrMsg = nErr;
	//}
	///Kyle 09/22/2009 QA80-14127-P10 SHOULD_UPDATE_DIALOG_SHOW_HIDE_IF_FROM_THEME_UPDATED
	//if(trNode && trNode.tagName=="subgroup")
	if(!trNode || trNode.tagName=="subgroup")
	///End SHOULD_UPDATE_DIALOG_SHOW_HIDE_IF_FROM_THEME_UPDATED
		_update_method_show(trGetN); /// for showing different setting for different reduce method (or group method)
	//if(trGetN.subgroup.nVal == subgroup_inc)  // increBin 
	//{
		//update_xstartend_show(trGetN); // auto intilize start end
	//}
	////if(trGetN.subgroup.nVal == subgroup_bin)
	//if(trGetN.subgroup.nVal == subgroup_groups)
	//{
		//int nSize =  get_input_xyrange_data_size(trGetN.iy);
		//update_binnum(trGetN, nSize);
	//}
	//if(trGetN.subgroup.nVal == subgroup_groups)  // increBin 
	//{
		//update_xstartend_show(trGetN); // auto intilize start end
	//}
	_update_auto_input(trGetN);
	//_update_data_size_hint_label(trGetN);///Sophy 6/1/2009 MORE_CHECK_ON_USER_INPUT should update after check

	bOKEnable = _check_input(trGetN, strErrMsg);
	_update_data_size_hint_label(trGetN);///Sophy 6/1/2009 MORE_CHECK_ON_USER_INPUT
	bUpdateGrid = true;
	///End UPDATE_XF_TO_SHOW_PREVIEW

	///Kyle 12/02/2008 QA80-12405-S1 
	if (trNode && (trNode.tagName =="iy"))
	{
		s_bInit = false;
	}
	
	if(!bOKEnable)
		dwUpdateGraph = UPDATE_GRAPH_INVALID; //nUpdateGraph = UPDATE_GRAPH_ERROR;
	else
		bUpdateGraph = bOKEnable;
	///End UPDATE_XF_TO_SHOW_PREVIEW

}

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

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

