/*------------------------------------------------------------------------------*
 * File Name: DescStats.c	 													*
 * Creation: ML 4/7/03															*
 * Purpose: OriginC Source C file for auto update descriptive statistics.		*
 * Copyright (c) OriginLab Corp.	2003-2007									*
 * All Rights Reserved															*
 * 																				*
 * Modification Log:															*
 * Danice 5/5/04 QA70-6341 v8.0865 SETREPORTTREE_ENABLE_CONTROL					*
 *	CPY 5/6/04 QA70-6367 HISTOGRAM_GRAPHS										*
 *	ML 8/17/2004 QA70-6825 RLOG_QUERY											*
 *  Iris 9/10/04 REPLACE_WITH_GLOBAL_FUNCTION									*
 *  Iris 9/23/04 MOVE_INTERPOLATE_TO_COMPUTATION_BRANCH							*
 *	YuI 10/18/04 QA70-70-60 v7.5151 NON_HIERARCHY_GRID_SHOULD_NOT_ADD_UNWANTED_COLUMNS	*
 *	CPY 11/3/04	QA70-7122 ADD_BOX_CHART_TO_DESC_STATS							*
 *  Iris 11/10/04 CENTRALIZE_CODE_INTO_STATSOPBASE_HEADER						*
 *  Iris 12/20/04 MOVE_TO_COMPCONTROL_BRANCH									*
 *	Echo 1/31/05 OUTPUT_TABLE_TRANSPOSE											*
 *	Echo 2/2/05 BAD_WEIGHT_TREAMENT												*
 *  Iris 3/22/05 FIX_GROUP_DATA_ONLY_ONE_BOX_CHART								*
 *  Iris 3/22/05 UPDATE_COLUMN_LABEL_FOR_GROUP_DATA								*
 *	Thomas 6/1/06 REDEFINE_UPDATEDATASOURCEINREPORTINGHEADER_FOR_DESCSTATS		*
 *  Iris 06/06/06 DIFF_INPUT_FORMAT_FOR_COL_AND_ROW								*
 *  Alex 06/13/06 SET_EXTREME_VALUES_TABLE_OPEN                                 *
 *  Iris 7/11/06 QA70-6367-P5 DIFF_RESULT_SHEET_NAME_FOR_COLS_AND_ROWS			*
 *	CPY 10/14/06 SEPARATE_OUT_OPERATION_BASE_INTO_SEPARATE_HEADER				*
 *  Iris 11/03/06 NO_NEED_PLOTS_FOR_STATS_ON_ROWS								*
 *  Iris 4/18/2007 v8.0603 ADD_OUTPUT_DEST_COL_OPTION_STATS_ON_ROWS				*
 *  Iris 05/14/2007 v8.0617 NOT_OUTPUT_INDEX_TEMP								*
 *	Cheney 2007-5-14 NOT_SUPPORT_SEP_REPORT_IN_STATS_ON_COL						*
 *  Iris 05/18/2007 v8.0621 CORRECT_BAD_LOOP									*
 *	Cheney 2007-5-23 QA70-9805 SPEED_UP_STATISTIC_ON_ROW						*
 *	Cheney 2007-6-7 SHOULD_CHECK_EVENT_ID_IN_EVENT_FUNC							*
 *	Arvin 06/19/07 WRONG_HISTOGRAM_AND_BOXCHART_PLOTS_WHILE_DATA_HAVE_FACTORS	*
 *	Arvin 07/25/07 v8.0667 WRONG_INPUT_DATA_TABLE_FOR_MULTI_DATA_AND_FACTORS	*
 *	Arvin 08/14/07 v8.0681 WRONG_MAX_AND_MIN_INDEX_IN_QUANTILES_WHEN_DATA_HAS_FACTORS
 *	Arvin 08/14/07 WRONG_HISTOGRAM_AND_BOXCHART_PLOT_WHEN_COMBINED_MUTI_AS_SINGLE_DATASET
 *	Arvin 08/22/07 WRONG_HISTOGRAM_SCALE_IN_STATS_ON_COL						*
 *	Arvin 08/24/07 SHOULD_NOT_CREATE_NEW_RESULT_SHEET_FOR_AUTO_UPDATE			*
 *	Cheney 2007-8-31 QA70-10330 CLEAN_UP_PLOT_SETTING_BRANCH_IN_OUTPUT_RESULT_NODE
 *	Arvin 08/31/07 QA70-7651-P17 WRONG_COLUMN_DESIGNATION_TYPE					*
 *	Arvin 08/31/07 PDS_CUSTOM_CAN_NOT_WORK_IN_STATS_ON_ROWS						*
 *	Arvin 09/03/07 WRONG_WEIGHT_LABEL_IN_MASK_AND_MISSING_DATA_TABLE			*
 *	Arvin 11/10/07 XOP_NEED_SUPPORT_CHANGE_FUNCTION								*
 *	Cheney 2007-11-14 STATS_ON_ROW_SHOULD_SUPPORT_MORE_OPTION_AS_MAX_SAID		*
 *	Max 07-11-17 NEED_TO_CHECK_CUSTOMPERCENTILES_NODE							*
 *	Fisher 11/19/07 ADD_MAP_ID_TO_CHM											*
 *	ML 11/20/2007 QA70-10716 INPUT_DATA_NODE_PROPER_LANGUAGE_WHEN_LOADING_OPER	*
 *  Iris 3/26/2008 v8.0832 CLEANUP_OUTPUT_BOOK_SHEET_AREA_TO_CLASS				*
 *	Folger 05/30/08 QA80-11624 SHOW_WARNING_FOR_TURN_OFF_AUTO_UPDATE_IN_STATS_ON_ROWS
 *  Iris 9/11/2008 FIX_SHOW_ERR_MSG_FOR_CONTIGUOUS_MULTI_RANGES_FOR_STATS_ON_ROWS*
 *	Hong 11/19/08 QA80-12558 V8.90875 DESC_STATS_ON_COL_SUPPORT_DATA_FROM_GRAPH	*
 *	Sophy 12/17/2008 v8.0987d  QA80-12784 ADD_BINNING_CONTROL_FOR_HISTOGRAM_PLOT_IN_STATS_TOOLS
 *	Sophy 1/5/2009 v8.0993d QA80-12858 GIVE_USEFUL_INFO_ON_REPORT_GRAPH_WITH_FACTOR_VALUE_FOR_STATS_COLUMN
 *	Folger 01/21/09 RESET_ALL_GRAPHS_FAILS_TO_PLOT_HISTOGRAM_IN_NLFIT			*
 *	Sophy 1/23/2009 v8.0964b CLEAN_UP_PLOT_SETTING_BRANCH_IN_OUTPUT_RESULT_NODE	*
 *  Iris 2/19/2009 QA_FOUND_RUNTIME_ERR_IF_CMOBI_SOURCE_DATA_AND_REPORT_INCLUDED_GRAPH
 *	Sophy 4/3/2009 QA80-13352 SUPPORT_SPECIFY_COLUMN_DESIGNATIONS_IN_REPORT_TABLES
 *  Iris 4/07/2009 QA80-12784 IMPROVE_HISTOGRAM_CONFIG_BRANCH					*
 *  Iris 9/10/2009 QA80-11710-P2 IMPROVE_REPORT_GRAPH_WHEN_PLOT_IN_ONE_GRAPH_WITH_GROUPING_DATA
 *  Iris 10/16/2009 QA80-14484 BOX_HISTOGRAM_ALSO_NEED_KEEP_CUSTOMIZATION_WHEN_RECALCULATION
 *  Iris 10/28/2009 QA81-14546 CHANGE_GUI_REPORT_TABLE_LABEL					*
 *  Iris 11/05/2009 QA81-14599 FIX_STATS_ON_COLS_PLOT_REPORT_GRAPHS_VERY_SLOW	*
 *  Iris 11/09/2009 QA81-14599 IMPROVE_STATS_ON_COLS_CALCULATION_SPEED			*
 *	Hong 11/27/09 QA80-14752 FIX_HISTOGRAM_BAD_RESCALE_IF_GRAPH_SHOWN_BEFORE_RECACULATE_WHEN_DATA_CHANGE
 *	Hong 12/11/09 QA80-14138-P2 FIX_STATS_ON_COL_CHANGE_PARAM_CANNOT_ADD_BACK_MISSING_TABLE
 *  Iris 2/22/2010 QA81-10824 SUPPORT_NON_CONTIGUOUS_RANGES_FOR_STATS_ON_ROWS	*
 *	Folger 03/24/10 QA81-15224 STATS_ON_ROWS_FAILED_TO_UPDATE_COL_HEADERS_WHEN_RECALCULATE
 *	Folger 10/12/2010 ORG-1240-P1 FAILED_TO_SHOW_WEIGHT_DATA_IN_REPORT_INPUT_OTHER_THAN_FIRST_DATA
 *	Folger 10/15/2010 INPUT_DATA_BRANCH_IN_DESC_STATS_SHOULD_BE_OPEN_BE_DEFAULT	*
 *------------------------------------------------------------------------------*/
 
//////////////////////////////////////////////////////////////////////////////////
// Included header files
//////////////////////////////////////////////////////////////////////////////////

// System includes
#include <Origin.h>
#include <o8dlg.h>
#include <event_utils.h> //CPY
#include <report_utils.h>

#ifdef _FOR_SMART_LOADING_ONLY
#include "wksOperation.h" //---- CPY 10/14/06 SEPARATE_OUT_OPERATION_BASE_INTO_SEPARATE_HEADER
#include <analysis_utils.h>
#include <stats_utils.h>
#include "stats_guis.h"
#include "stats_operations.h"
//#include "graph_utils.h" 	///Arvin 03/08/07 AXIS_TITILE_SHOULD_ADD_FACTOR_INFO_IN_HISTOGRAM_GRAPH
#include "nlsf_utils.h" /// Iris 7/08/2008 CLEAN_DUP_CALC_AVE_DATA_CODE_IN_NLSF_PREVIEW_AND_OP
#endif
#include <xfutils.h>
#include "StatsOpCommon.h"
#include "StatsOpBase.h"
#include "graph_utils.h" ///Arvin 03/08/07 AXIS_TITILE_SHOULD_ADD_FACTOR_INFO_IN_HISTOGRAM_GRAPH

#define		STR_NEXT_TO_SOURCE		_L("<next to source>")
//---- CPY 5/6/04 QA70-6367 HISTOGRAM_GRAPHS
#define STR_DESC_STATS_GRAPH_TEMPLATE "ReportDescStats"	
///Cheney 2007-5-23 QA70-9805 SPEED_UP_STATISTIC_ON_ROW
enum{
	DESC_STATS_ON_COLS,
	DESC_STATS_ON_ROWS,
};
///end SPEED_UP_STATISTIC_ON_ROW

typedef struct tagExVals
{  
	int _id(1) 		Index;
	double _id(2) 	Value;
}ExVals;

///Cheney 2007-8-31 QA70-10330 CLEAN_UP_PLOT_SETTING_BRANCH_IN_OUTPUT_RESULT_NODE
static bool _on_input_data_change(TreeNode& tr, int nRow, int nCol, TreeNode& trNode, DWORD nEventInfo, int nCntrlType, WndContainer& getNContainer)
{
	if(!tr)
		return false;
	
	TreeNode trRange = tr.InputData.Range1;
	DataRange drData;
	drData.Create();
	drData.SetTree(trRange, DRTREE_ONE_DATA);
	if (!drData.IsValid())
		return false;

	/// Iris 9/10/2009 QA80-11710-P2 IMPROVE_REPORT_GRAPH_WHEN_PLOT_IN_ONE_GRAPH_WITH_GROUPING_DATA
	//int nNumData = drData.GetNumData(DRR_BAD_WEIGHT_TREATMENT);
	vector<int> vFactorSizes;
	int nNumData = drData.GetNumData(DRR_BAD_WEIGHT_TREATMENT, NULL, NULL, &vFactorSizes);
	///end IMPROVE_REPORT_GRAPH_WHEN_PLOT_IN_ONE_GRAPH_WITH_GROUPING_DATA
	
	/// Iris 10/29/2009 QA81-14546 OP_DLG_NEW_STRUCTURE
	//TreeNode trGraphNumCols = tr.Output.PlotSettings.GraphNumCols;
	TreeNode trGraphNumCols = OP_GUI_GRAPH_ARRANGEMENT_NODE(tr).GraphNumCols;
	///end OP_DLG_NEW_STRUCTURE
	
	///Sophy 5/30/2008 FIX_BOOKNAME_EMPTY_FOR_SOURCE_TYPE_WHEN_NO_DATA_SELECTED_OPEN_DIALOG
	/*
	if(!trGraphNumCols)
		return false;
	
	///Cheney 2007-11-19 ARRANGE_GRAPH_COLS_NUM_NOT_WORK
	//int nAutoCheck = octree_get_auto_support(&trGraphNumCols);
	//if( !(nAutoCheck == 1 && trGraphNumCols.nVal > 0) )
		//trGraphNumCols.nVal = get_report_graph_num_cols(nNumData);
	if(1 == octree_get_auto_support(&trGraphNumCols))
		trGraphNumCols.nVal = get_report_graph_num_cols(nNumData);
	///end ARRANGE_GRAPH_COLS_NUM_NOT_WORK
	*/
	bool	bRet = false;
	if( trGraphNumCols )
	{
		if( 1 == octree_get_auto_support( &trGraphNumCols ) )
		{
			/// Iris 9/10/2009 QA80-11710-P2 IMPROVE_REPORT_GRAPH_WHEN_PLOT_IN_ONE_GRAPH_WITH_GROUPING_DATA
			//trGraphNumCols.nVal = get_report_graph_num_cols( nNumData );
			int nNumFactors = vFactorSizes.GetSize() > 0 ? vFactorSizes[0] : 0;
			/// Iris 10/29/2009 QA81-14546 OP_DLG_NEW_STRUCTURE
			//TreeNode trPlotInOne = tr.Output.PlotSettings.PlotInOneGraph;
			TreeNode trPlotInOne = OP_GUI_GRAPH_ARRANGEMENT_NODE(tr).PlotInOneGraph;
			///end OP_DLG_NEW_STRUCTURE
			bool bPlotInOne = trPlotInOne && trPlotInOne.Show && trPlotInOne.nVal;
			trGraphNumCols.nVal = get_report_graph_num_cols( nNumData, nNumFactors, bPlotInOne );
			///end IMPROVE_REPORT_GRAPH_WHEN_PLOT_IN_ONE_GRAPH_WITH_GROUPING_DATA
		}
		
		bRet = true;
	}
	///end FIX_BOOKNAME_EMPTY_FOR_SOURCE_TYPE_WHEN_NO_DATA_SELECTED_OPEN_DIALOG
	///Cheney 2007-10-16 QA70-10536 CLEAN_CODE_AND_FIX_BUG_OF_ADD_AUTO_FOR_OUTPUT_SETTING
	/// Iris 3/21/2008 v8.0829 QA80-10934 ADD_EDITBOX_TO_SPECIFICATION_BOOK_SHEET_NAME, parameter changed from trOp to trGUI
	//string strSrcPageName = get_source_page_name(tr.Parent());
	string strSrcPageName = get_source_page_name(tr);
	///end ADD_EDITBOX_TO_SPECIFICATION_BOOK_SHEET_NAME
	
#ifndef _MOVE_FIT_OUTPUT_TO_OC_CLASS /// Iris 3/26/2008 v8.0832 CLEANUP_OUTPUT_BOOK_SHEET_AREA_TO_CLASS
	update_output_report_and_curve_setting(tr, strSrcPageName);
#else
	OutputGUIManagerBase* pOutputManager = get_output_GUI_manager_pointer(tr);
	if(pOutputManager)
		///Sophy 04/09/2008 UPDATEOUTPUT_ON_DATA_CHANGE
		//pOutputManager->UpdateOutputReportAndCurveSetting(tr,strSrcPageName);
		pOutputManager->UpdateOutputOnDataChange(tr);
		///End UPDATEOUTPUT_ON_DATA_CHANGE
#endif //_MOVE_FIT_OUTPUT_TO_OC_CLASS
	
	///end CLEAN_CODE_AND_FIX_BUG_OF_ADD_AUTO_FOR_OUTPUT_SETTING
	///Sophy 5/30/2008 FIX_BOOKNAME_EMPTY_FOR_SOURCE_TYPE_WHEN_NO_DATA_SELECTED_OPEN_DIALOG
	//return true;
	return bRet;
	///end FIX_BOOKNAME_EMPTY_FOR_SOURCE_TYPE_WHEN_NO_DATA_SELECTED_OPEN_DIALOG
}
///end CLEAN_UP_PLOT_SETTING_BRANCH_IN_OUTPUT_RESULT_NODE

static int _desc_stats_check_data(TreeNode trRange)
{
	if (!trRange)
		return CER_COL_NUM_TOO_FEW_EX;
	DataRange drData;
	drData.Create();
	drData.SetTree(trRange, DRTREE_ONE_DATA);

	if (drData)
	{
		DWORD dwRules = DRR_BAD_WEIGHT_TREATMENT;
		DWORD dwPlotID;
		int nNumData = drData.GetNumData(dwRules);
		if (nNumData < 1)
			return CER_COL_NUM_TOO_FEW_EX;
			
		int nSize = 0;
		vector vData;
		for (int ii = 0; ii < nNumData; ii++)
		{
			drData.GetData(dwRules, ii, &dwPlotID, NULL, &vData, NULL, NULL, NULL);
			nSize += vData.GetSize();	
		}
		if (0 == nSize)
			return CER_NO_DATA;			
	}
}

//------ Folger 05/30/08 QA80-11624 SHOW_WARNING_FOR_TURN_OFF_AUTO_UPDATE_IN_STATS_ON_ROWS
static	bool	_auto_update_need_turn_off(const DataRange &dr, LPCSTR lpcszBook, LPCSTR lpcszSheet)
{
		string		strRange;
		dr.GetRangeString(strRange);		// only single range is available
		
		string		strBook, strSheet, strObj;
		okutil_parse_complete_range_string(strRange, &strBook, &strSheet, &strObj);
		
		string strC1, strC2, strR1, strR2;
		okutil_parse_range_string(strObj, &strC1, &strR1, &strC2, &strR2);
		
		if ( !strC1.IsEmpty() || !strC2.IsEmpty() )		// case A[1]:B[2]
			return false;
		
		string			strBookSheet1 = okutil_make_book_sheet_string(strBook, strSheet);
		string			strBookSheet2 = okutil_make_book_sheet_string(lpcszBook, lpcszSheet);
		Worksheet		wks1, wks2;
		okxf_resolve_string_get_origin_object(strBookSheet1, &wks1);
		okxf_resolve_string_get_origin_object(strBookSheet2, &wks2);
		
		if ( is_same_layer(wks1, wks2) )
			return true;
	
	return false;
}
//------ End SHOW_WARNING_FOR_TURN_OFF_AUTO_UPDATE_IN_STATS_ON_ROWS

///Joseph 01/29/07	ADD_OPERATION_ERRMSG_LINE
static int descstats_event1(TreeNode& tr, int nRow, int nEvent, DWORD& dwEnables, LPCSTR lpcszNodeName, WndContainer& getNCountainer, string& strAux, string& strErrMsg)
{
	DECLARE_BUTTON_ENABLES
	///Cheney 2007-5-23 QA70-9805 SPEED_UP_STATISTIC_ON_ROW
	//int nErr = check_1_data(tr.InputData.Range1.X, true);
	//if ( !check_conf_level(tr.Quantities.Quantiles.PercentileList.strVal) )
	int nErr = CER_NO_ERROR; 
	/// Sophy 5/08/2008 FIX_BUG_REPORT_BOOK_BLANK_WHEN_NO_DATUM_SELECTED_IN_STATS_ON_COLUMN
	_on_input_data_change( tr,nRow,0,NULL,0,0,getNCountainer);
	/// End FIX_BUG_REPORT_BOOK_BLANK_WHEN_NO_DATUM_SELECTED_IN_STATS_ON_COLUMN
	///Cheney 2007-6-7 SHOULD_CHECK_EVENT_ID_IN_EVENT_FUNC	
	///Cheney 2007-7-6 SHOULD_CHECK_ERR_WHEN_THEME_CHANGE_ALSO
	//if(GETNE_ON_VALUE_CHANGE == nEvent  || GETNE_ON_INIT == nEvent)
	
	/// Iris 4/07/2009 QA80-12784 IMPROVE_HISTOGRAM_CONFIG_BRANCH
	/*
	///Sophy 12/19/2008 v8.0987d  QA80-12784 ADD_BINNING_CONTROL_FOR_HISTOGRAM_PLOT_IN_STATS_TOOLS fix bin config not updated when change input data
	string strNodeName(lpcszNodeName);
	if ( strNodeName.CompareNoCase("X") == 0 )
	{
		TreeNode trHistogramConfig = tr.Output.GetNode(STR_HISTOGRAM_CONFIG_TAGNAME);
		_update_histogram_plot_bin_configuration_by_input(tr, trHistogramConfig);
	}
	///end ADD_BINNING_CONTROL_FOR_HISTOGRAM_PLOT_IN_STATS_TOOLS
	*/	
	_update_histogram_bin_info_in_event1(tr, lpcszNodeName, nEvent);
	///end IMPROVE_HISTOGRAM_CONFIG_BRANCH
	
	bool	bAutoUpdateTurnOff = false;		//------ Folger 05/30/08 QA80-11624 SHOW_WARNING_FOR_TURN_OFF_AUTO_UPDATE_IN_STATS_ON_ROWS
	
	///------ Folger 10/15/2010 INPUT_DATA_BRANCH_IN_DESC_STATS_SHOULD_BE_OPEN_BE_DEFAULT
	/// Easwar suggested that input data branch in Stats On Column should be open by default
	if ( GETNE_ON_INIT == nEvent )
	{
		TreeNode	trRange1 = tr.InputData.Range1;
		if ( trRange1 )
		{
			int		nBranch = 0;
			trRange1.GetAttribute(STR_ATTRIB_BRANCH, nBranch);
			if ( 0 == nBranch )
				trRange1.SetAttribute(STR_ATTRIB_BRANCH, GETNBRANCH_OPEN);
		}
	}
	///------ End INPUT_DATA_BRANCH_IN_DESC_STATS_SHOULD_BE_OPEN_BE_DEFAULT
	
	if(GETNE_ON_VALUE_CHANGE == nEvent  || GETNE_ON_INIT == nEvent || GETNE_ON_THEME == nEvent)
	///end SHOULD_CHECK_ERR_WHEN_THEME_CHANGE_ALSO
	///end SHOULD_CHECK_EVENT_ID_IN_EVENT_FUNC
	{		
		TreeNode trRange = tr.InputData.Range1;
		TreeNode trX = trRange.X;
		if(!trRange)
			nErr = CER_INVALID_TREENODE;
		
		if(nErr == CER_NO_ERROR && DESC_STATS_ON_ROWS != tr.StatsOnRows.nVal)
		{
				nErr = _desc_stats_check_data(trRange);
		}
		else if(nErr == CER_NO_ERROR)
		{
			Range dr;
			bool 	bRet = okxf_resolve_tree_construct_range(&trX, &dr);			
			bool	bIsContiguousRange = dr.ConvertToContiguous(); //-- Iris 9/11/2008 FIX_SHOW_ERR_MSG_FOR_CONTIGUOUS_MULTI_RANGES_FOR_STATS_ON_ROWS
			
			if(nErr == CER_NO_ERROR)
			{
				int nNumData = dr.GetNumData(DRR_GET_MISSING | DRR_NO_FACTORS | DRR_NO_WEIGHTS | DRR_BY_ROWS);
				switch(nNumData)
				{
				case EXTRACTBYROWSERR_MULTIPLE_SHEETS:
					nErr = CER_EXTRACTBYROWSERR_MULTIPLE_SHEETS;
					break;
				case EXTRACTBYROWSERR_UNEVEN_COLUMNS:
					nErr = CER_EXTRACTBYROWSERR_UNEVEN_COLUMNS;
					break;
				default:
				}				
				
				if(nErr == CER_NO_ERROR && nNumData <= 0)
				{
					//as talk to Echo and Max, we don't support Non_contiguous ranges when stats on row
					//-- Iris 9/11/2008 FIX_SHOW_ERR_MSG_FOR_CONTIGUOUS_MULTI_RANGES_FOR_STATS_ON_ROWS
					//if(!trX.strVal.IsEmpty())
						//nErr = CER_NOT_SUPPORT_NON_CONTIGUOUS_RANGES;
					if(!trX.strVal.IsEmpty())
					{
						/// Iris 2/22/2010 QA81-10824 SUPPORT_NON_CONTIGUOUS_RANGES_FOR_STATS_ON_ROWS
						/*
						if(!bIsContiguousRange)
							nErr = CER_NOT_SUPPORT_NON_CONTIGUOUS_RANGES;
						*/
						///End SUPPORT_NON_CONTIGUOUS_RANGES_FOR_STATS_ON_ROWS
					}
					//--
					else
						nErr = CER_NO_DATA;
				}				
				
				/// Iris 2/22/2010 QA81-10824 SUPPORT_NON_CONTIGUOUS_RANGES_FOR_STATS_ON_ROWS
				/*
				//------ Folger 05/30/08 QA80-11624 SHOW_WARNING_FOR_TURN_OFF_AUTO_UPDATE_IN_STATS_ON_ROWS
				//-- Iris 9/11/2008 FIX_SHOW_ERR_MSG_FOR_CONTIGUOUS_MULTI_RANGES_FOR_STATS_ON_ROWS
				//if ( nErr == CER_NO_ERROR && dr.GetNumRanges() > 1 )
				if ( nErr == CER_NO_ERROR && !bIsContiguousRange )
				//--	
					nErr = CER_NOT_SUPPORT_NON_CONTIGUOUS_RANGES;
				//------
				*/
				///End SUPPORT_NON_CONTIGUOUS_RANGES_FOR_STATS_ON_ROWS
			}

			//------ Folger 05/30/08 QA80-11624 SHOW_WARNING_FOR_TURN_OFF_AUTO_UPDATE_IN_STATS_ON_ROWS
			if ( nErr == CER_NO_ERROR )
				bAutoUpdateTurnOff = _auto_update_need_turn_off(dr, tr.Output.Report.BookName.strVal, tr.Output.Report.SheetName.strVal);
			//------
		}
		
		if ( nErr == CER_NO_ERROR && !check_conf_level(tr.Quantities.Quantiles.PercentileList.strVal) )
		///end SPEED_UP_STATISTIC_ON_ROW
		{
			nErr = CER_CONF_LEVS;
		}
		
		///Sophy 4/11/2008 CHECK_REPORT_DATA_BOOK_NAME_DIFFERENT
		string strRet = "";
		if( CER_NO_ERROR == nErr )
		{
			nErr =check_report_book_curve_book( tr, strRet );
		}
		///end CHECK_REPORT_DATA_BOOK_NAME_DIFFERENT
		
		///Sophy 12/17/2008 v8.0987d  QA80-12784 ADD_BINNING_CONTROL_FOR_HISTOGRAM_PLOT_IN_STATS_TOOLS
		if ( CER_NO_ERROR == nErr )
		{
			//if ( !check_histogram_config_bin_min_max(tr) )
				//nErr = CER_MIN_MAX;
			nErr = _check_histogram_plot_bin_configuration(tr, strRet);
		}
		///end ADD_BINNING_CONTROL_FOR_HISTOGRAM_PLOT_IN_STATS_TOOLS
		if (nErr != CER_NO_ERROR)
		{
			bOKEnable = false;
			strErrMsg = nErr;
			if (nErr == CER_COL_NUM_TOO_FEW_EX)
				strErrMsg += ":" + 1;
			///Sophy 4/14/2008 ADD_OUTPUT_ERR_STRING
			else if( !strRet.IsEmpty() )
			{
				strErrMsg = nErr;
				strErrMsg += ":" + strRet;  
			}
			///end ADD_OUTPUT_ERR_STRING
		}
		
		//------ Folger 05/30/08 QA80-11624 SHOW_WARNING_FOR_TURN_OFF_AUTO_UPDATE_IN_STATS_ON_ROWS
		if ( nErr == CER_NO_ERROR && bAutoUpdateTurnOff )
		{
			strErrMsg = WARN_AUTO_UPDATE_TURN_OFF_STATS_ON_ROWS;
			
			/// YuI 06/03/08 need to actually turn it off
			tr.AutoUpdate.nVal=AU_NONE;
			/// end YuI
		}
		//------
	}
	return true;

}///End ADD_OPERATION_ERRMSG_LINE
//////////////////////////////////////////////////////////////////////////////////
// Class DescStats
//////////////////////////////////////////////////////////////////////////////////
class OC_REGISTERED DescStats : public StatsOpBase
{	
///Arvin 11/10/07 XOP_NEED_SUPPORT_CHANGE_FUNCTION
public:	
	//Need call this method from oc code, so move it to public session
	void ClearOutputTables(TreeNode& trOperation)
	{
		StatsOpBase::ClearOutputTables(trOperation);
		
		if(trOperation.Calculation.ExVals)
			trOperation.Calculation.ExVals.Reset(true);
	}
///end XOP_NEED_SUPPORT_CHANGE_FUNCTION

protected:	
	/// Iris 10/28/2009 QA81-14546 CHANGE_GUI_REPORT_TABLE_LABEL
	/*
	/// Iris 4/17/2008 SPECIAL_REPORT_TABLE_NAME_FOR_DIFF_TOOLS
	//virtual	
	string	GetReportTableGUIName(TreeNode& trGUI)
	{
		return STR_OUTPUT_DESC_STATS_REPORT_TABLE;
	}
	///end SPECIAL_REPORT_TABLE_NAME_FOR_DIFF_TOOLS
	*/
	///end CHANGE_GUI_REPORT_TABLE_LABEL
	
protected:	

	// virtual 
	// fisher 11/19/2007 ADD_MAP_ID_TO_CHM
	int GetHelpID()
	{
		Tree trOp;
		GetTree(trOp);
		
		return GetOptionIndex(trOp.GUI)>0 ? IDD_XF_DescStats_1 : IDD_XF_DescStats;
	}

	/**
		Construct tree used when computing descriptive statistics.
	*/
	//virtual 
	BOOL Construct(TreeNode& trOperation, int nOption = 0)
	{
		if( WksReportOperation::Construct(trOperation, nOption) )
		{
			//--- CPY 5/6/04 QA70-6367 HISTOGRAM_GRAPHS
			TreeNode trOut = trOperation.Calculation; // Calculation node should have already been prepared in base class
			trOut.Statistics.ID = IDST_DESC_STATS_RESULTS;
			
			///Iris 01/20/05 CLEANUP_CONSTRUCT_ADD_GRAPH
			//ConstructAddGraph(trOperation);
			//ConstructAddGraph(trOperation, 1);//----- CPY 11/3/04	QA70-7122 ADD_BOX_CHART_TO_DESC_STATS
			///end CLEANUP_CONSTRUCT_ADD_GRAPH

			//trOut.BinWks.ID = IDST_BIN_WKS;	///Iris 11/10/04, move into StatsOpBase.h
			//---
			///Iris 01/20/05 CONSTRUCT_GUI_CLEANUP
			//TreeNode		trGUI = ConstructGUI();
			TreeNode		trGUI = ConstructAddGUI(trOperation);
			///end CONSTRUCT_GUI_CLEANUP
			ConstructDescStatGUITree(trGUI, nOption);
			
			bool	bStatsOnRows = nOption > 0? true : false;
			///Iris 4/06/05 INIT_GRAPH_NUMBER
			//----- CPY 11/3/04	QA70-7122 ADD_BOX_CHART_TO_DESC_STATS	
			//ConstructAddReportCommon(trGUI, REPORT_GRAPHS, IDST_REPORT_OPTIONS_DESC_STATS);
			//ConstructAddReportCommon(trGUI, REPORT_GRAPHS | REPORT_2ND_GRAPHS, IDST_REPORT_OPTIONS_DESC_STATS); ///Iris 01/19/05 ADD_GRAPHNUM_OPTION_TO_CONSTRUCT_REPORT
			//ConstructAddReportCommon(trOperation, 0, IDST_REPORT_OPTIONS_DESC_STATS, true, 2);
			DWORD 	dwOptions = bStatsOnRows? 0 : REPORT_ARRANGE_GRAPHS_TO_COLS | REPORT_PLOT_ALL_PLOTS_IN_ONE_GRAPH;
			ConstructAddReportCommon(trOperation, dwOptions, IDST_REPORT_OPTIONS_DESC_STATS, true);
			//-----	
			
#ifdef OP_DLG_TOTALLY_NEW_STRUCTURE
			if(!bStatsOnRows)
				ConstructAddReportGraphsOptions(trOperation, dwOptions);
#endif
			
			FilterStatsGUI(trOperation);    ///Jim 01/17/06 v8.0358 CREATE_PLOTS_BRANCH_IN_MAIN_NODES
			
			if(bStatsOnRows)
			{
				/// Iris 4/18/2007 v8.0603 ADD_OUTPUT_DEST_COL_OPTION_STATS_ON_ROWS
				TreeNode trLog = trGUI.Output.Report.AddReportToResultsLog;
				if(trLog)
				{
					TreeNode trCol = trGUI.Output.Report.InsertNode(trLog, "Column");
					trCol.DataID = IDE_REPORT_COLUMN;
					trCol.SetAttribute(STR_LABEL_ATTRIB, _L("Column"));	
					string 	strCombo = STR_NEW + "|" + STR_NEXT_TO_SOURCE;
					trCol.SetAttribute(STR_COMBO_ATTRIB, strCombo);
					trCol.strVal = STR_NEW;
				}
				///END ADD_OUTPUT_DEST_COL_OPTION_STATS_ON_ROWS
				
				//--- Iris 11/03/06 NO_NEED_PLOTS_FOR_STATS_ON_ROWS, from Max's suggestion
#ifndef OP_DLG_TOTALLY_NEW_STRUCTURE
				if(trGUI.Plots)
					trGUI.Plots.Show = false;
				//---
				
				///Arvin 11/09/06 NO_NEED_OPTIONAL_REPORT_TABLES_FOR_STATS_ON_ROWS, from Max's suggestion
				if(trGUI.Output.Create)
					trGUI.Output.Create.Show = false;
				///end NO_NEED_OPTIONAL_REPORT_TABLES_FOR_STATS_ON_ROWS
				
#else //OP_DLG_TOTALLY_NEW_STRUCTURE
				OP_GUI_OUTPUT_TABLES_BRANCH(trGUI).Notes.Show = false;
				OP_GUI_OUTPUT_TABLES_BRANCH(trGUI).InputData.Show = false;
				OP_GUI_OUTPUT_TABLES_BRANCH(trGUI).MaskedData.Show = false;
				OP_GUI_OUTPUT_TABLES_BRANCH(trGUI).MissingData.Show = false;
				
				for(int nGraphIndex = 0; nGraphIndex < ConstructGraphNumber(); nGraphIndex++)
				{
					TreeNode trGraph = GetGUIGraphNodes(trOperation, nGraphIndex);
					if( trGraph && trGraph.Show )
						trGraph.Show = false;
				}
#endif //OP_DLG_TOTALLY_NEW_STRUCTURE
			}
			///Cheney 2007-8-31 QA70-10330 CLEAN_UP_PLOT_SETTING_BRANCH_IN_OUTPUT_RESULT_NODE
			else
			{
				/// Sophy 5/08/2008 FIX_BUG_REPORT_BOOK_BLANK_WHEN_NO_DATUM_SELECTED_IN_STATS_ON_COLUMN
				//GETN_SET_EVENT_EX_HANDLER(trGUI.InputData, _on_input_data_change); //move to descstats_event1			
				/// End FIX_BUG_REPORT_BOOK_BLANK_WHEN_NO_DATUM_SELECTED_IN_STATS_ON_COLUMN
				///Sophy 1/23/2009 v8.0964b CLEAN_UP_PLOT_SETTING_BRANCH_IN_OUTPUT_RESULT_NODE
				//trGUI.Output.PasteResultTable.Show = false;
				/// Iris 10/29/2009 QA81-14546 OP_DLG_NEW_STRUCTURE
				//TreeNode trPasteResultTable = trGUI.Output.PlotSettings.PasteResultTable;
				TreeNode trPasteResultTable = OP_GUI_GRAPH_ARRANGEMENT_NODE(trGUI).PasteResultTable;
				///end OP_DLG_NEW_STRUCTURE
				if ( trPasteResultTable )
					trPasteResultTable.Show = false;
				///end CLEAN_UP_PLOT_SETTING_BRANCH_IN_OUTPUT_RESULT_NODE
				
				/// Iris 10/29/2009 QA81-14546 OP_DLG_NEW_STRUCTURE
				//trGUI.Output.PlotSettings.GraphNumCols.nVal = 0; //to tell this value whether from theme or not 
				OP_GUI_GRAPH_ARRANGEMENT_NODE(trGUI).GraphNumCols.nVal = 0; 
				///end OP_DLG_NEW_STRUCTURE
			}
			///end CLEAN_UP_PLOT_SETTING_BRANCH_IN_OUTPUT_RESULT_NODE
			
			///Cheney 2007-5-14 NOT_SUPPORT_SEP_REPORT_IN_STATS_ON_COL	
			//if(bStatsOnRows) // stats on Rows
				//tree_output_branch_mode(trGUI, MDOUT_DISABLE_COMBO);
			//else
				//tree_output_branch_mode(trGUI);
			tree_output_branch_mode(trGUI, MDOUT_DISABLE_COMBO);
			///end NOT_SUPPORT_SEP_REPORT_IN_STATS_ON_COL

			Operation::ConstructAddCommonBottom(trGUI);
			
			return TRUE;
		}

		return FALSE;
	}
	
	//virtual
	void	FilterStatsGUI(TreeNode& trOp) 
	{
		StatsOpBase::FilterStatsGUI(trOp);
		
		//If the tool is Statistics On Rows
		TreeNode trStatsOnRows = trOp.GUI.StatsOnRows;
		if(trStatsOnRows && 1== trStatsOnRows.nVal)
		{
			///Cheney 2007-11-14 STATS_ON_ROW_SHOULD_SUPPORT_MORE_OPTION_AS_MAX_SAID
			//vector<int> vnNodesToHide = {IDE_NUM_MISSING,IDE_VARIANCE,IDE_SKEWNESS,IDE_KURTOSIS,IDE_UNCORSUMSQ,IDE_CORSUMSQ,IDE_COV,
						//IDE_MAD,IDE_SD_X_2,IDE_SD_X_3,IDE_GEO_MEAN,IDE_GEO_SD,IDE_MODE,IDE_WEIGHTSUM,
						//IDE_IMIN,IDE_IMIN,IDE_IMAX,IDE_IQR,IDE_RANGE,IDE_USE_CUSTOM_PERCENTILES,IDE_CUSTOM_PERCENTILES};
			vector<int> vnNodesToHide = {IDE_WEIGHTSUM}
			///end STATS_ON_ROW_SHOULD_SUPPORT_MORE_OPTION_AS_MAX_SAID			
			tree_set_attributes(trOp.GUI, vnNodesToHide, "0");
			
		}	
		///Sophy 12/17/2008 v8.0987d  QA80-12784 ADD_BINNING_CONTROL_FOR_HISTOGRAM_PLOT_IN_STATS_TOOLS add for stats tool(stats column, normality test
		else
		{
			AddHistogramPlotConfigBranch(trOp, trOp.GUI.Output);
		}
		///end ADD_BINNING_CONTROL_FOR_HISTOGRAM_PLOT_IN_STATS_TOOLS
	}
	
	//virtual
	bool SourceRowIndicesNeeded()
	{
		return true;
	}
	
	///Iris 4/06/05 INIT_GRAPH_NUMBER
	//virtual
	int ConstructGraphNumber()
	{
		return 2;
	}
	
	//virtual 
	bool IsEnableInsertResultColumnsToSourceData(int nOption)
	{
		if(nOption > 0)
			return true;
		
		return false;
	}

	//virtual 
	PEVENT_GETN GetNewEventFunction()
	{
		return descstats_event1;
	}
	//virtual 
	int	GetOptionIndex(const TreeNode& trGUI)
	{
		return trGUI.StatsOnRows.nVal;
	}
	
	/// Hong 11/19/08 QA80-12558 V8.90875 DESC_STATS_ON_COL_SUPPORT_DATA_FROM_GRAPH
	//virtual
	BOOL	SetInfoFromXF(int nOption, LPCSTR lpcszClass, StringArray &saOptions, StringArray &saNames, LPCSTR lpcszStr2 = NULL)
	{
		Tree trOp;
		GetTree(trOp);
		
		TreeNode		trSpec = tree_check_get_node(trOp, "SpecInfo");
		string			strClass(lpcszClass);
		trSpec.FitType.nVal = nOption;
		trSpec.ClassName.strVal = strClass;	
			
		trSpec.Options.strVals = saOptions;
		trSpec.Option.nVal = nOption;
		if (0 < saNames.GetSize())
			trSpec.Names.strVals = saNames;
		if (lpcszStr2)
			trSpec.Categ.strVal = lpcszStr2;
		
		SetTree(trOp);
		return TRUE;
	}
	/// end DESC_STATS_ON_COL_SUPPORT_DATA_FROM_GRAPH
	
	// Virtual 
	/// Hong 11/19/08 QA80-12558 V8.90875 DESC_STATS_ON_COL_SUPPORT_DATA_FROM_GRAPH
	//string GetClassName() {return "DescStats";}	
	string GetClassName()
	{
		Tree trOp;
		GetTree(trOp);
		TreeNode		trSpecInfo = tree_check_get_node(trOp, "SpecInfo");
		if ( trSpecInfo && trSpecInfo.ClassName )
			return trSpecInfo.ClassName.strVal;
			
		return "DescStats";
	}
	/// end DESC_STATS_ON_COL_SUPPORT_DATA_FROM_GRAPH
	
	/// Iris 4/07/2008 ADD_DescStats_OUTPUT_CLASS
	//virtual
	bool	InitOutputGUIManagerPointer(const TreeNode& trGUI)
	{
		if(m_pOutputManager)//already init
			return true;
		
		m_pOutputManager = new DescStatsOutputGUIManager;	
		return (NULL != m_pOutputManager);		
	}
	///end ADD_DescStats_OUTPUT_CLASS
	
	/// Iris 5/29/2008 STATS_ON_ROWS_2ND_REPORT_WILL_RESIZE_RESULT_COLS
	//virtual
	bool	IsAutoSizeReport(const TreeNode& trGUI)
	{
		int nOption = GetOptionIndex(trGUI);
		if( nOption > 0 )//on rows
			return false;
		else
			return StatsOpBase::IsAutoSizeReport(trGUI);
	}
	///end STATS_ON_ROWS_2ND_REPORT_WILL_RESIZE_RESULT_COLS
	
	/// Iris 7/11/06 QA70-6367-P5 DIFF_RESULT_SHEET_NAME_FOR_COLS_AND_ROWS
	// virtual
	/// Iris 3/21/2008 v8.0829 QA80-10934 ADD_EDITBOX_TO_SPECIFICATION_BOOK_SHEET_NAME, want GUI tree as input in DescStats::GetResultSheetName
	//string 			GetResultSheetName()
	string 			GetResultSheetName(TreeNode& trGUI)
	///end ADD_EDITBOX_TO_SPECIFICATION_BOOK_SHEET_NAME
	{
		/// Iris 3/21/2008 v8.0829 QA80-10934 ADD_EDITBOX_TO_SPECIFICATION_BOOK_SHEET_NAME
		//Tree trOp;
		//GetTree(trOp);
		///end ADD_EDITBOX_TO_SPECIFICATION_BOOK_SHEET_NAME
		
		string	strSheetName = GetClassName();
		/// Iris 3/21/2008 v8.0829 QA80-10934 ADD_EDITBOX_TO_SPECIFICATION_BOOK_SHEET_NAME
		//int nOption = GetOptionIndex(trOp.GUI);
		int nOption = GetOptionIndex(trGUI);
		///end ADD_EDITBOX_TO_SPECIFICATION_BOOK_SHEET_NAME
		
		if(nOption > 0) //on Rows
			strSheetName += "OnRows1";
		else
			strSheetName += "OnCols1";
		return strSheetName;
	}
	///end DIFF_RESULT_SHEET_NAME_FOR_COLS_AND_ROWS
	
	/// Iris 3/21/2008 v8.0829 QA80-10934 ADD_EDITBOX_TO_SPECIFICATION_BOOK_SHEET_NAME
	//virtual 
	string GetResultBookName(TreeNode& trGUI)
	{
		string strBookName;
		int nOption = GetOptionIndex(trGUI);
		if(nOption > 0) //on Rows
			strBookName = "Row";
		else
			strBookName = "Col";
		strBookName += "Stat1";
		return strBookName;
	}
	///end ADD_EDITBOX_TO_SPECIFICATION_BOOK_SHEET_NAME

	//----- CPY 9/30/07 FIX_CHENEY_MODIFY_TITLE_AS_MAX_SAID
	//virtual
	string GetAnalysisName(int nOption)
	{
		string str = _L("Statistics");
		if(nOption < 0) // short form
			return  str;
		//----- CPY 10/24/07 LOCALIZATION_CLEAN_UP_ON_OPERATION_CODES
		/*
		else if( nOption > 0 )
			return str + " " + _L("on Rows");

		return str + " " + _L("on Columns");
		*/
		if( nOption > 0 )
			return _L("Statistics on Rows");

		return _L("Statistics on Columns");
		//----- end LOCALIZATION_CLEAN_UP_ON_OPERATION_CODES
	}
	//-----
	//virtual 
	string GetDlgDescription(int nOption)
	{
		///Cheney 2007-9-28 MODIFY_TITLE_AS_MAX_SAID
		//string str = "Statistics";
		//
		//if(nOption < 0) // short form
			//return  str;
		//else if( nOption > 0 )
			//return str + " on Rows";
		//
		//return str + " on Columns";
		return _L("Perform Descriptive Statistics");
		///end MODIFY_TITLE_AS_MAX_SAID
	}
	
	/// Iris 10/21/05 CLEANUP_STATS_REPORT_GRAPH_CODES
	/*
	/// YuI 12/07/04 v7.5172 PICTURE_IN_REPORT_IMPROVEMENT
	virtual int	ReportGetPicureIndexFromDataIndex(int nGraphIndex, int nDataIndex)
	{
		switch( ReportGetPlotTypeFromGraphIndex(nGraphIndex) )
		{
		case IDM_PLOT_HISTOGRAM_TYPE:
			return nDataIndex;
			
		case IDM_PLOT_BOX:
			//return 0; //box chart is always one picture
			return nDataIndex;    ///Iris 3/22/05 FIX_GROUP_DATA_ONLY_ONE_BOX_CHART
		}
		
		return -1;
	}
	
	virtual int	ReportGetPlotTypeFromGraphIndex(int nGraphIndex)
	{
		switch( nGraphIndex )
		{
		case 0:
			return IDM_PLOT_HISTOGRAM_TYPE;
			
		case 1:
			return IDM_PLOT_BOX;
		}
		
		return -1;
	}
	/// end PICTURE_IN_REPORT_IMPROVEMENT
	*/
	///End CLEANUP_STATS_REPORT_GRAPH_CODES
	
	///Arvin 11/10/07 XOP_NEED_SUPPORT_CHANGE_FUNCTION	
	//Need call this method from oc code, so move it to public session
	//void ClearOutputTables(TreeNode& trOperation)
	//{
		//StatsOpBase::ClearOutputTables(trOperation);
		//
		//if(trOperation.Calculation.ExVals)
			//trOperation.Calculation.ExVals.Reset(true);
	//}
	///end XOP_NEED_SUPPORT_CHANGE_FUNCTION
	
	//virtual
	void UpdateReportingTables(TreeNode &trOperation, int nTotalNumData, int nExeMode)
	{
		WksReportOperation::UpdateReportingTables(trOperation, nTotalNumData, nExeMode);
		
		updateTableStringMain(trOperation);
	
		//UpdateTableString(trOperation.Calculation.ExVals, true, true, atof(GetTableStringMain(false)) );Alex 06/13/06 SET_EXTREME_VALUES_TABLE_OPEN
		/// Iris 01/15/2007 v8.0541 REMOVE_SUB_TABLE_FROM_ANOVE_MISS_MASK_DATA_TABLE
		//remove sub tables from Extreme value table
		//UpdateTableString(trOperation.Calculation.ExVals, true, true, atof(GetTableStringMain(false)),atof(GetTableStringMain(false)));
		TreeNode trTable = trOperation.Calculation.ExVals;
		if(trTable)
		{
			trTable.SetAttribute(TREE_Table, GetTableStringMain(false) );
		}
		///end REMOVE_SUB_TABLE_FROM_ANOVE_MISS_MASK_DATA_TABLE
	}

	//virtual
	/// Iris 11/16/06 CLEAR_OUT_TABLES_BEFORE_CALC_WHEN_DO_CHANGE_PARAMS
	/*
	void OnBeforeCalculations(TreeNode& trOperation)
	{
		StatsOpBase::OnBeforeCalculations(trOperation);
		
		TreeNode trStatistics = trOperation.Calculation.Statistics;
		if( trStatistics.IsValid())
			trStatistics.RemoveChildrenWithPrefix(CALCULATION_PARAMETER_PREFIX);
	}
	*/
	///end CLEAR_OUT_TABLES_BEFORE_CALC_WHEN_DO_CHANGE_PARAMS
	
	int GetNumberAdditionalRowsOrColumnsInHeading(int nNumData, int numFactors)
	{
		// for desc. stats multiple datasets are already in labels, so only factors can provide
		// additional row/column headers:
		return numFactors;
	}
	
	/// ML 7/15/2004	
	string		updateTableStringMain(TreeNode &trOperation, LPCSTR lpcszSet = NULL, bool bForInserting = false)
	{
		string			strOld;
		TreeNode		trTable = trOperation.Calculation.Statistics;
		
		if (trTable)
		{
			trTable.GetAttribute(TREE_Table, strOld);
			if (lpcszSet)
				trTable.SetAttribute(TREE_Table, lpcszSet);
			else
			{
				string str;
				///Cheney 2007-5-23 QA70-9805 SPEED_UP_STATISTIC_ON_ROW
				//should add an vector to treenode
				//if ( GetDataRules(trOperation) & DRR_BY_ROWS )
				//{
					////bool bTranspose = bForInserting;
					//bool bTranspose = false;
					//str = GetTableStringMain(bTranspose);
					//if(bForInserting)
					//{
						//uint nn = atoi(str);
						//nn |= GETNBRANCH_ROW1_LABEL_OFFSET;
						//str = ftoa(nn);
					//}
				//}
				//else
				///end SPEED_UP_STATISTIC_ON_ROW
				{
					/// Iris 9/12/06 REMOVE_COL_HEADER_FROM_RESULT_TABLE
					/*
					//---- CPY 12/17/04 test allowing user to plot stats results
					//str = GetTableStringMain(true);
					///Echo 1/31/05 OUTPUT_TABLE_TRANSPOSE
					//str = GetTableStringMain(false, true);
					str = GetTableStringMain(true, true);
					///end OUTPUT_TABLE_TRANSPOSE
					//----
					*/
					//--- Iris 06/05/2007 v8.0633 not transpose table on Easwar's suggestion
					//str = GetTableStringMain(true, false);
					if ( GetDataRules(trOperation) & DRR_BY_ROWS )
					{
						str = GetTableStringMain(true, false);
					}
					else
					{
						str = GetTableStringMain(false, false);
					}
					//--- 
					///end REMOVE_COL_HEADER_FROM_RESULT_TABLE
				}
				
				trTable.SetAttribute(TREE_Table, str);
			}
		}
		else
			error_report("Desc Stats found invalid Calculation.Statistics node");			
			
		return strOld;
	}
	/// end ML 7/15/2004	

	
	
	//virtual 
	bool UpdateInsertedColumns(TreeNode& trOp, const DataRange& rngInput, int nDataIndex, int nTotalNumData, DataRange& rngOutput, int nOutputOption)
	{
		int r1, c1, r2, c2;
		Worksheet wksFirst;
		int nWksCount = find_input_range_bounding_box(rngInput, r1, c1, r2, c2, wksFirst,"X");
		if(nWksCount != 1)
			return error_report("Desc Stats only support all input data from the same worksheet");
		
		/// Iris 4/18/2007 v8.0603 ADD_OUTPUT_DEST_COL_OPTION_STATS_ON_ROWS
		if(trOp.GUI.StatsOnRows.nVal > 0) //stats on rows
		{
			TreeNode 	trOutCol = trOp.GUI.Output.Report.Column;
			if( trOutCol && PDS_NEW == str_to_predefined_type(trOutCol.strVal) )
			{
				c2 = -1;
			}
		}
		///end ADD_OUTPUT_DEST_COL_OPTION_STATS_ON_ROWS
		
		//---- Iris 10/30/06 STATS_ON_ROWS_FAIL_TO_REPORT_INTP_SOURCE
		if(c2<0)
			c2 = wksFirst.Columns.Count()-1;
		//----
		
		string	strCache = updateTableStringMain(trOp, NULL, true);
		/// Iris 9/17/05 QA70-8015-P15 OUTPUT_RESULT_CURVE_TO_WKS
		//bool	bOK = InsertReportToSourceWks(trOp, trOp.Calculation.Statistics, wksFirst, c2 + 1, rngOutput);
		bool	bOK = InsertReportToWks(trOp, trOp.Calculation.Statistics, wksFirst, c2 + 1, rngOutput);
		///End OUTPUT_RESULT_CURVE_TO_WKS
		updateTableStringMain(trOp, strCache, true);
		///Arvin 11/09/06 ADD_COMMENTS_TO_STATSONROWS_RESULT_COLUMNS
		if(rngOutput)
		{
			//---- CPY 10/24/07 OPERATION_CLASS_USING_LOCALIZATION_DLL
			//string strName;
			//strName = "Statistics On Rows of " + rngInput.GetDescription();
			string strName = "Err: str not in oErrMsg";
			ocu_load_msg_str(IDS_STATS_ON_ROWS_OF, strName, rngInput.GetDescription());
			//----
			SetOuputColComments(rngOutput, strName);
		}
		///end ADD_COMMENTS_TO_STATSONROWS_RESULT_COLUMNS
		return bOK;
	}
	///Arvin 11/07/06 STATS_ON_ROW_OUTPUT_RESULTS_TO_SHEET
	/*
	bool PrepareOutputSheet(Datasheet& wksMatLayer, Worksheet& wksInputFirstRange, TreeNode& trOperation, bool& bNewBookCreated, LPCSTR lpcszDefaultSheetName, LPCSTR lpcszDefaultBookName)
	{
		string strReportBook;
		int nSpecialType = PDS_NEW, nSheetSpecialType = PDS_NEW;
		if(wksInputFirstRange)
		{
			strReportBook = GetReportOutputBookName(trOperation.GUI, &nSpecialType);
			bNewBookCreated = (PDS_NEW == nSpecialType && strReportBook.IsEmpty())? true:false;			
		}
		else
			bNewBookCreated = true;
		string strReportSheet = GetReportOutputSheetName(trOperation.GUI, &nSheetSpecialType);
		Page		pg;
		if(wksMatLayer.IsValid())
		{
			wksMatLayer.GetParent(pg);
			bNewBookCreated = false;
		}
		if(!pg)
			pg = Project.Pages(strReportBook);
	
		if( !pg )
		{
			if(PDS_SOURCE == nSpecialType && FALSE == bNewBookCreated) // auto
			{
				wksInputFirstRange.GetParent(pg);
				if( !pg )
					return error_report("PrepareOutput found no workbook to be used");
			}
			else
			{
				bNewBookCreated = true;		
				WorksheetPage wp;
				wp.Create(NULL, CREATE_HIDDEN);
				pg = wp;
	
				if(strReportBook.IsEmpty())
					strReportBook = lpcszDefaultBookName;
					
				if(!strReportBook.IsEmpty())
				{
					pg.SetLongName(strReportBook, false);
					pg.TitleShow = WIN_TITLE_SHOW_BOTH;
				}
			}
		}
	
		if(!strReportSheet.IsEmpty())
		{
			wksMatLayer = pg.Layers(strReportSheet);
			if(wksMatLayer)
				return true; 
		}
		else 
		{
			strReportSheet = lpcszDefaultSheetName;
		}

		int nn = pg.AddLayer(strReportSheet);
		wksMatLayer = pg.Layers(nn);
	
		if( TRUE == bNewBookCreated && nn > 0) 
		{
			Layer layJunk = pg.Layers(0);
			layJunk.Destroy();
		}
		if(wksMatLayer.GetNumCols() > 0)
		{
			wksMatLayer.SetNumRows(0);
		}
		
		return true;
	}
	bool GetDescStatsInputRangeString(const DataRange& rngInput, string& strRange)
	{
		int c1, c2, r1, r2;
		Worksheet wksInput;
		int nWksCount = find_input_range_bounding_box(rngInput, r1, c1, r2, c2, wksInput,"X");
		if(nWksCount != 1)
			return error_report("Desc Stats only support all input data from the same worksheet");
		
		Column col1(wksInput, c1);
		Column col2(wksInput, c2);
		string strInput, strEnd; 
		col1.GetRangeString(strInput);
		strEnd = col2.GetLongName();
		if(strEnd.IsEmpty())
			strEnd = col2.GetName();
		strInput.Replace("Col", "");
		strInput.Remove('(');
		strInput.Remove(')');
		strRange = "StatsOnRows of " + strInput + ":" + strEnd;
		return true;
	}
	*/
	bool SetOuputColComments(const DataRange& rngOutput, string& strComments)
	{
		int numRange = rngOutput.GetNumRanges();
		if(numRange < 0)
			return false;
		for( int ii = 0; ii < numRange; ii++)
		{
			Worksheet sourceWks;
			string strRange;
			int r1, r2, c1, c2;
			rngOutput.GetRange(ii, r1, c1, r2, c2, sourceWks, &strRange);
			for(int jj = c1; jj <= c2; jj++)
				sourceWks.Columns(jj).SetComments(strComments);
		}
		return true;
	}
	
	bool InsertResultToNewSheet(TreeNode& trOp, const DataRange& rngInput, int nDataIndex, int nTotalNumData, int nOutputOption = -1)
	{
		Worksheet	wksInputFirstRange;
		vector<int>	vFactorSizes;
		DWORD dwRules = GetDataRules(trOp);
		int nNumData = rngInput.GetNumData(dwRules, NULL, &wksInputFirstRange, &vFactorSizes);

		bool		bNewBookCreated = false;
		Worksheet	wksOutput;
		
		string strName;
		strName = "Statistics On Rows of " + rngInput.GetDescription();
		
		DataRange	rgResultRange;
		Datasheet*	pdsResultSheet;
		pdsResultSheet = &wksOutput;
		bool bHasOutput = GetOutput(rgResultRange, *pdsResultSheet, WksReportOperation::GetOutputSlot(nDataIndex, false, nOutputOption));
		if(!bHasOutput)
		{
			//--------- CPY 1/19/2007 COMPILE_ERR_DESC_STATS
			//if(!PrepareOutput(wksOutput, wksInputFirstRange, trOp, bNewBookCreated, GetResultSheetName(), "Statistics On Rows") )
			///Sophy 5/29/2008 QA80-10934-P10 CORRECT_STATS_ON_ROWS_RESULT_BOOK_NAME moved from private
			//string strBook = _L("Statistics On Rows");
			string strBook = GetResultBookNameFromGUI( trOp.GUI );
			///end CORRECT_STATS_ON_ROWS_RESULT_BOOK_NAME
			/// Iris 3/21/2008 v8.0829 QA80-10934 ADD_EDITBOX_TO_SPECIFICATION_BOOK_SHEET_NAME
			//string strSheet = GetResultSheetName();
			///Sophy 5/29/2008 QA80-10934-P10 CORRECT_STATS_ON_ROWS_RESULT_BOOK_NAME
			//string strSheet = GetResultSheetName(trOp.GUI);
			string strSheet = GetResultSheetNameFromGUI( trOp.GUI );
			///end CORRECT_STATS_ON_ROWS_RESULT_BOOK_NAME
			///end ADD_EDITBOX_TO_SPECIFICATION_BOOK_SHEET_NAME
			if(!PrepareOutput(wksOutput, wksInputFirstRange, trOp, bNewBookCreated, strSheet, strBook) )
			//---------
				return error_report("Failed in PrepareOutput");
		}
		else
		{
			///Arvin 08/24/07 SHOULD_NOT_CREATE_NEW_RESULT_SHEET_FOR_AUTO_UPDATE
			//WorksheetPage wksPage = pdsResultSheet->GetPage();	
			//wksOutput.Attach(wksPage.GetName());
			rgResultRange.GetParent(wksOutput);
			///end SHOULD_NOT_CREATE_NEW_RESULT_SHEET_FOR_AUTO_UPDATE
		}
		
		///Arvin 08/31/07 PDS_CUSTOM_CAN_NOT_WORK_IN_STATS_ON_ROWS
		int nStartCol = -1;
		TreeNode 	trOutSheet = trOp.GUI.Output.Report.Sheet;
		if( trOutSheet && PDS_CUSTOM == str_to_predefined_type(trOutSheet.strVal) )
			nStartCol = wksOutput.Columns.Count()-1;
		///end 	PDS_CUSTOM_CAN_NOT_WORK_IN_STATS_ON_ROWS
		
		DataRange		rngInsertedColumns;
		string	strCache = updateTableStringMain(trOp, NULL, true);
		///Arvin 08/31/07 PDS_CUSTOM_CAN_NOT_WORK_IN_STATS_ON_ROWS
		//bool	bOK = InsertReportToWks(trOp, trOp.Calculation.Statistics, wksOutput, 0, rngInsertedColumns);
		bool	bOK = InsertReportToWks(trOp, trOp.Calculation.Statistics, wksOutput, nStartCol+1, rngInsertedColumns);
		///end PDS_CUSTOM_CAN_NOT_WORK_IN_STATS_ON_ROWS
		updateTableStringMain(trOp, strCache, true);
		if(!bOK)
			return error_report("Failed in UpdateInsertedColumns");

		if(!bHasOutput)
		{					
			SetOuputColComments(rngInsertedColumns, strName);
			SetOutput(rngInsertedColumns, WksReportOperation::GetOutputSlot(nDataIndex, false, nOutputOption));					
		}
		
		return true;
	}
	///END STATS_ON_ROW_OUTPUT_RESULTS_TO_SHEET

	///------ Folger 01/21/09 RESET_ALL_GRAPHS_FAILS_TO_PLOT_HISTOGRAM_IN_NLFIT
	/*
	///Arvin 06/19/07 WRONG_HISTOGRAM_AND_BOXCHART_PLOTS_WHILE_DATA_HAVE_FACTORS
	//For statistics on column, StatsTree is used for histogram and boxchart, so we should not
	//remove it after histogram plotting
	bool IsStatsTreeRemovable(TreeNode& trOp, int nGraphIndex)
	{
		if(IsCreateHistogramGraph(trOp) && IsCreateBoxChartGraph(trOp) && nGraphIndex == GRAPH_STATS_HISTOGRAM)
			return false;
		
		return true;
	}
	///end WRONG_HISTOGRAM_AND_BOXCHART_PLOTS_WHILE_DATA_HAVE_FACTORS
	*/
	///------ End RESET_ALL_GRAPHS_FAILS_TO_PLOT_HISTOGRAM_IN_NLFIT
	
	///Arvin 09/03/07 WRONG_WEIGHT_LABEL_IN_MASK_AND_MISSING_DATA_TABLE
	virtual	string	GetMaskedOrMissingDataTableErrorWeightColumnName()
	{
		return WKSH_OPERATION_INFO_DATA_WEIGHT;
	}
	///END WRONG_WEIGHT_LABEL_IN_MASK_AND_MISSING_DATA_TABLE
	
protected:
	///Iris 01/22/05 MOVE_DESCSTATS_TO_BASE_CLASS
	///////////////////////////////////////////////////////////////////////
	////virtual
	//BOOL	CalcOneData(TreeNode &trOp, int index, int nTotalNumData, const vector<int> &vFactorSizes,
						//const vector<string> &vstrFactors, vector &vData, vector &vDummy, matrix &mDummy, vector &vWeights, DWORD dwPlotObjUID, int nRowColIndex)
	//{
//
		//TreeNode			trGUI = trOp.GUI;
		//DescStatResults		stRes;
		//vector				vPercents; // Which percentiles to compute; it should come from settings
		//vector				vPercentiles;
		///// YuI 12/07/04 v7.5172 PICTURE_IN_REPORT_IMPROVEMENT
		//vector<bool>		vShow;
		///// end PICTURE_IN_REPORT_IMPROVEMENT
		//QuantileResults		stQuantiles;
		//
		///// Iris 9/21/04 ADD_DEN_FALG_OPTION
		////if ( stats_descriptive(vData, stRes, &vWeights) == STATS_NO_ERROR && calcOneDataPercentilesAndRange(trGUI, vData, vPercents, vPercentiles, stQuantiles))
		////int 				iDenFlag = trGUI.Computation.VarDivisor.nVal;   /// Iris 12/01/04 MOVE_COMPUTER_CONTROL_INSIDE_QUANTITIES
		////int 				iDenFlag = trGUI.Quantities.Moments.VarDivisor.nVal;
		//int 				iDenFlag = trGUI.Computation.VarDivisor.nVal;   ///Iris 12/20/04 MOVE_TO_COMPCONTROL_BRANCH
		///// YuI 12/07/04 v7.5172 PICTURE_IN_REPORT_IMPROVEMENT
		////	if ( stats_descriptive(vData, stRes, &vWeights, SU_DEFAULT_CONF_LEVEL, iDenFlag) == STATS_NO_ERROR && calcOneDataPercentilesAndRange(trGUI, vData, vPercents, vPercentiles, stQuantiles))
		//if ( stats_descriptive(vData, stRes, &vWeights, SU_DEFAULT_CONF_LEVEL, iDenFlag) == STATS_NO_ERROR && CalcOneDataPercentilesAndRange(trOp, vData, vPercents, vPercentiles, vShow, stQuantiles))
		///// end PICTURE_IN_REPORT_IMPROVEMENT
		//{
			//string			strDataLabel;
			////GetEscapedMainDataString(strDataLabel, index + 1);
			//GetOneDataLabel(trOp, index, nRowColIndex, strDataLabel);
			//
			//TreeNode		trTable = tree_check_get_node(trOp.Calculation, "Statistics", IDST_DESC_STATS_RESULTS);
			//
			//TreeNode		trRow = check_add_enumerated_node(trTable, CALCULATION_PARAMETER_PREFIX, index + 1, IDST_TEMP_ONE_SET, STR_LABEL_ATTRIB, strDataLabel);
			////////////////////
			//// Factor values:
			//tree_add_more_labels(trRow, vstrFactors);
						//
			////////////////////
			//// Main statistics results:
			//trRow += stRes;
//
			//
			////////////////////
			//// Quantiles:
			//trRow += stQuantiles;
			//
			////////////////////
			//// Percentiles:
			///// YuI 12/07/04 v7.5172 PICTURE_IN_REPORT_IMPROVEMENT
			///*
			//string strTemp;
			//for (int iperc = 0; iperc < vPercentiles.GetSize(); iperc++)
			//{
				//strTemp.Format("P%s", ftoa(vPercents[iperc]));
				//TreeNode	trPerc = check_add_enumerated_node(trRow, CALCULATION_PERCENTILE_PREFIX, iperc+1, IDE_CUSTOM_PERCENTILES + iperc, STR_LABEL_ATTRIB, strTemp);
				//trPerc.dVal = vPercentiles[iperc];
			//}
			//*/
			//SetPercentilesToTree(trRow, vPercents, vPercentiles, vShow);
			///// end PICTURE_IN_REPORT_IMPROVEMENT
//
			///// ML 8/17/2004 QA70-6825 RLOG_QUERY
			////trRow.ID = IDST_DESC_STATS_ONE_SET + index;// restore ID, struct assignment will wipe out ID, see struct assignments above
			//trRow.ID = make_one_set_ID(IDST_DESC_STATS_ONE_SET, index);// restore ID, struct assignment will wipe out ID, see struct assignments above
			///// end RLOG_QUERY
//
			////-------- CPY 12/31/04 PICTURE_IN_REPORT_IN_BASE_CLASS
			///*
			/////////////////////////
			//// Histogram graphs			
			////addBinDataAndMakeHistogramGraphs(trOp, index, vData, vstrFactors, strDataLabel);  /// Iris 11/09/04 CENTRALIZE_CODE_INTO_STATSOPBASE_HEADER
			//AddBinDataHistogramGraph(trOp, index, vData, vstrFactors, 0, strDataLabel);
			//
			/////////////////////////
			//// Box Chart
			////addPercentilesAndMakeBoxCharts(trOp, index, vData, vstrFactors, strDataLabel);   /// Iris 11/09/04 CENTRALIZE_CODE_INTO_STATSOPBASE_HEADER
			//AddPercentilesAndMakeBoxCharts(trOp, index, vData, vstrFactors, 1, strDataLabel);
			//*/
			//AddBinDataTableAndGraphNodes(trOp, index, vData, vstrFactors, strDataLabel);
			////-------- end PICTURE_IN_REPORT_IN_BASE_CLASS
			//return TRUE;
		//}
		//return FALSE;
	//}
	//*/
	BOOL	CalcOneData(TreeNode &trOp, int index, int nTotalNumData, const vector<int> &vFactorSizes,
						const vector<string> &vstrFactors, vector &vData, vector &vDummy, matrix &mDummy, vector &vWeights, DWORD dwPlotObjUID, int nRowColIndex, const vector<int>& vintRowsInSource = NULL)
	{
		string			strDataLabel;
		///Iris 3/22/05 UPDATE_COLUMN_LABEL_FOR_GROUP_DATA
		GetOneDataLabel(trOp, index, nRowColIndex, strDataLabel);
		//GetOneDataLabel(trOp, index, nRowColIndex, strDataLabel, vstrFactors);
		///end UPDATE_COLUMN_LABEL_FOR_GROUP_DATA
		bool 			bMultiModes;
		///Arvin 08/14/07 v8.0681 WRONG_MAX_AND_MIN_INDEX_IN_QUANTILES_WHEN_DATA_HAS_FACTORS
		//if( AddDescStatsTable(trOp, index, vData, strDataLabel, vWeights, vstrFactors, true, true, &bMultiModes))
		if( AddDescStatsTable(trOp, index, vData, strDataLabel, vWeights, vstrFactors, true, true, &bMultiModes, vintRowsInSource))
		///END 	WRONG_MAX_AND_MIN_INDEX_IN_QUANTILES_WHEN_DATA_HAS_FACTORS
		{			
			//adding footnode for the notice of Mod
			if(bMultiModes && index == nTotalNumData - 1)
			{
				addMultiModesFootnote(trOp, nTotalNumData, vstrFactors);
			}	
			
			if(trOp.GUI.Quantities.ExVal.nVal)
			{
				/// Iris 05/14/2007 v8.0617 EXTREME_VALUE_NEED_MORE_GROUP_LABELS
				//addExtremeValuesTable(trOp, index, vData, strDataLabel);
				/// Iris 05/17/2007 v8.0619 GET_ROW_INDEX_FOR_STATS_EXTREME_VAL_TABLE
				//addExtremeValuesTable(trOp, index, vData, strDataLabel, vstrFactors);
				addExtremeValuesTable(trOp, index, vData, vintRowsInSource, strDataLabel, vstrFactors);
				///end GET_ROW_INDEX_FOR_STATS_EXTREME_VAL_TABLE
				/// end EXTREME_VALUE_NEED_MORE_GROUP_LABELS
			}
			///Arvin 06/19/07 WRONG_HISTOGRAM_AND_BOXCHART_PLOTS_WHILE_DATA_HAVE_FACTORS
			ConvertEscapedString(strDataLabel);
			///end WRONG_HISTOGRAM_AND_BOXCHART_PLOTS_WHILE_DATA_HAVE_FACTORS

			/// Iris 11/09/2009 QA81-14599 IMPROVE_STATS_ON_COLS_CALCULATION_SPEED
			if( IsPlotStatsGraph(trOp) )
			///end IMPROVE_STATS_ON_COLS_CALCULATION_SPEED
			{
				AddBinDataTableAndGraphNodes(trOp, index, vData, vstrFactors, strDataLabel);
			}
			//return TRUE;
		}

		return TRUE;		
	}							
	///end MOVE_DESCSTATS_TO_BASE_CLASS
	
	enum
	{
		DESC_STATS_WEIGHT_DIRECT_WEIGHTING,
		DESC_STATS_WEIGHT_INSTRUMENTAL,
		DESC_STATS_WEIGHT_STATISTICAL
	};

	//virtual 
	DWORD	GetDataRules(const TreeNode& trOp, bool bIgnoreCombineInfo = false )
	{
		/// Iris 06/06/06 DIFF_INPUT_FORMAT_FOR_COL_AND_ROW
		/////Echo 2/2/05 DRR_BAD_WEIGHT_TREATMENT
		////DWORD dwRet =  DRR_GET_MISSING;
		//DWORD dwRet =  DRR_GET_MISSING | DRR_BAD_WEIGHT_TREATMENT;	
		/////end DRR_BAD_WEIGHT_TREATMENT
		int 	nOption = trOp.GUI.StatsOnRows.nVal;
		DWORD 	dwRet;
		if( 1 != nOption) 
			dwRet =  DRR_GET_MISSING | DRR_BAD_WEIGHT_TREATMENT; //on Columns
		else
			dwRet = DRR_GET_MISSING | DRR_NO_FACTORS | DRR_NO_WEIGHTS; //on Rows
		///End DIFF_INPUT_FORMAT_FOR_COL_AND_ROW		

		if(GetOptionIndex(trOp.GUI))
			dwRet |= DRR_BY_ROWS;
		/// Iris 5/04/2009 QA80-11982 STATS_ON_COL_ADD_WEIGHT_METHOD
		else
		{
			if( trOp.GUI.Computation.WeightMethod )
			{
				int nWMethod = trOp.GUI.Computation.WeightMethod.nVal;
				switch(nWMethod)
				{
				case DESC_STATS_WEIGHT_DIRECT_WEIGHTING:
					break;
				case DESC_STATS_WEIGHT_INSTRUMENTAL:
					dwRet |= DRR_DEPERR_TO_WEIGHT;
					break;
				case DESC_STATS_WEIGHT_STATISTICAL:
					dwRet |= DRR_DEPERR_TO_WEIGHT | DRR_DEPERR_TO_WEIGHT_STATISTICAL;
					break;
				}
			}
		}
		///end STATS_ON_COL_ADD_WEIGHT_METHOD
		return CheckDataRules(trOp, dwRet, bIgnoreCombineInfo);
	}
	
	///Sophy 1/5/2009 v8.0993d QA80-12858 GIVE_USEFUL_INFO_ON_REPORT_GRAPH_WITH_FACTOR_VALUE_FOR_STATS_COLUMN
	//virtual
	bool	UpdateReportGraphLabel(TreeNode& trOp, TreeNode& trLabel, int nGraphIndex, int nPicRow, int nPicCol, int nNumPicCols)
	{
		if ( !trOp || !trLabel )
			return false;
		
		int 	nOption = trOp.GUI.StatsOnRows.nVal;
		if ( 1 != nOption ) //stats on column
		{
			DataRange drInput;
			GetInput(drInput);
			if ( drInput )
			{
				/// Iris 9/10/2009 QA80-11710-P2 IMPROVE_REPORT_GRAPH_WHEN_PLOT_IN_ONE_GRAPH_WITH_GROUPING_DATA
				/*
				int c1, c2, r1, r2;
				Worksheet wks;
				int nNumDataset = 0;
				int nNumRanges = drInput.GetNumRanges();
				string strName;
				
				/// Iris 2/19/2009 QA_FOUND_RUNTIME_ERR_IF_CMOBI_SOURCE_DATA_AND_REPORT_INCLUDED_GRAPH
				if( IsCombinedMultiAsSingle(trOp) )
					nNumDataset = 1;
				else
				///end QA_FOUND_RUNTIME_ERR_IF_CMOBI_SOURCE_DATA_AND_REPORT_INCLUDED_GRAPH
				{
					for ( int nSub = 0; nSub < nNumRanges; nSub++)
					{
						DataRange drSub;
						drInput.GetRange(nSub, r1, c1, r2, c2, wks, &strName);
						if ( strName.CompareNoCase("X") == 0 )  //data range, not grouping range
						{
							nNumDataset += c2 - c1 + 1; //in stats on column, when one range cross multi-columns, shoult treat it as muilti-dataset
						}
					}
				}
				if ( nNumDataset < 1 )
					return false;
				int nFactors = GetTotalNumPictureForOneGraphType(trOp, nGraphIndex) / nNumDataset;
				*/
				int nFactors = GetNumFactors(trOp);
				if( nFactors > 0 )
				///end IMPROVE_REPORT_GRAPH_WHEN_PLOT_IN_ONE_GRAPH_WITH_GROUPING_DATA
				{
					int nFactorIndex = (nNumPicCols * nPicRow + nPicCol) % nFactors;
					vector<string> vsFactors ;
					drInput.GetData(GetDataRules(trOp), nFactorIndex, NULL, NULL, NULL, NULL, NULL, &vsFactors);
					if ( vsFactors.GetSize() > 0 ) //if has factor, should display its value on graph label
					{
						/// Iris 9/10/2009 QA80-11710-P2 IMPROVE_REPORT_GRAPH_WHEN_PLOT_IN_ONE_GRAPH_WITH_GROUPING_DATA					
						if( IsPlotAllPlotsInOneGraph(trOp) ) // only show data label
						{						
							int nPlotIndex = (nNumPicCols * nPicRow + nPicCol) * nFactors;
							string strDataLabel;
							GetEscapedMainDataString(trOp, strDataLabel, nPlotIndex + 1);
							ConvertEscapedString(strDataLabel);
							trLabel.strVal = strDataLabel;							
						}
						else // display data label with factor string
						///end IMPROVE_REPORT_GRAPH_WHEN_PLOT_IN_ONE_GRAPH_WITH_GROUPING_DATA
						{					
							ConvertEscapedStrings(trLabel);
							string strLabel = trLabel.strVal;
							string strFactors;
							strFactors.SetTokens(vsFactors, ',');
							strLabel += " (" + strFactors + ")";
							trLabel.strVal = strLabel;
						}
					}
				}
			}
		}
		return true;
	}
	///end GIVE_USEFUL_INFO_ON_REPORT_GRAPH_WITH_FACTOR_VALUE_FOR_STATS_COLUMN

	// virtual
	string	GetMaskedDataTableErrorColumnName()
	{
		return WKSH_OPERATION_INFO_DATA_WEIGHT;
	}
	
	///Arvin 12/04/06 STATS_ON_ROW_OUTPUT_RESULTS_TO_SHEET
	virtual bool IsOutputDataResultsToNewSheet(const TreeNode& trGUI) 
	{
		return GetOptionIndex(trGUI);
	}
	///end STATS_ON_ROW_OUTPUT_RESULTS_TO_SHEET
	
	///Arvin    03/08/07 SHOULD_NOT_RESCALE_IF_NOT_PLOT_ALL_HISTOGRAMS_IN_ONE_GRAPH_WHEN_HAS_FACTOR by max's suggestion
	int ReportGraphGetRescaleOption(TreeNode& trOp, int nGraphIndex)
	{
		/// Iris 11/05/2009 QA81-14599 FIX_STATS_ON_COLS_PLOT_REPORT_GRAPHS_VERY_SLOW
		// Rescale on Box and Histogram plot, will be separately done in SetupPlotDetails below.
		// SetupPlotDetails will do rescale for each layer for histogram plot when plot all in one graph.
		/*
		if(ReportGetPlotTypeFromGraphIndex(nGraphIndex) == IDM_PLOT_HISTOGRAM_TYPE && !IsPlotAllPlotsInOneGraph(trOp))
			return -1;	
		*/
		return -1;
		///end FIX_STATS_ON_COLS_PLOT_REPORT_GRAPHS_VERY_SLOW
		
		return WksReportOperation::ReportGraphGetRescaleOption(trOp, nGraphIndex);
	}
	///end SHOULD_NOT_RESCALE_IF_NOT_PLOT_ALL_HISTOGRAMS_IN_ONE_GRAPH_WHEN_HAS_FACTOR
	
	///Arvin    03/09/07 SHOULD_SET_AXIS_X_FROM_TO_AND_TITLE_WHEN_USE_DATARANGE_WITH_FACTOR_TO_PLOT_HISTOGRAM by max's suggestion
	bool SetAxisXTitleWithFactor(const TreeNode& trOp, const DataRange dr, GraphLayer& gl, int nDataIndex)
	{
		DWORD dwRules = GetDataRules(trOp);
		vector vData;
		vector<string> vstrFactors;
		bool bGetData = GetDataAndFactorValues(trOp, dr, nDataIndex, vData, vstrFactors);
		if( bGetData && vstrFactors.GetSize() > 0 )
		{
			string strXTitle;
			if(!get_axis_title(gl, strXTitle, 0))
				error_report("Failed to get title of X axis");
			
			string strXSuf, strXPre;
			strXPre = strXTitle;
			strXPre.Delete(0, 5);
			
			if(IsPlotAllPlotsInOneGraph(trOp))
				legend_update(gl, ALM_COMMENT);
			else
				strXSuf = "_" + vstrFactors[0]; 
				
			if(!strXPre.IsEmpty())
			{
				strXTitle.Replace(strXPre, strXSuf);
				strXSuf = "";
			}
			
			strXTitle = strXTitle + strXSuf;
			
			if(!set_axis_title(gl, strXTitle, 0))
				error_report("Failed to set title of X axis");
			
			gl.Rescale();
			return true;
		}
		
		return false;
	}
	
	bool SetAxisXFromTo(const TreeNode& trOp, const DataRange dr, GraphLayer& gl, int nDataIndex)
	{
		DWORD dwRules = GetDataRules(trOp);
		vector vData;
		vector<string> vstrFactors;
		bool bGetData = GetDataAndFactorValues(trOp, dr, nDataIndex, vData, vstrFactors);
		if( bGetData)
		{
			double dMin, dMax, dBinSize;
			vData.GetMinMax(dMin, dMax);
			//int nBins = 0.5 + sqrt(vData.GetSize() + 1);
			gl.Rescale();
			RoundLimits(&dMin, &dMax, &dBinSize);
			double dAbMargin = abs(dMax-dMin)*0.08;
			gl.X.From = dMin - dAbMargin;
			gl.X.To = dMax + dAbMargin;
			return true;
		}
		
		return false;
	}
	
	bool SetupPlotDetails(const TreeNode& trOp, GraphLayer& gl, int nFittedPlot, int nNumPlots = 1, int nGraphIndex = 0, int nDataIndex = 0, bool bIsSourceGraph = false, bool bUpdateExistedReportGraph = false)
	{		
		/// Iris 11/28/2008 HISTOGRAM_SCALE_NOT_GOOD_WHEN_RECALCULATE
		//if( !bUpdateExistedReportGraph ) /// Iris 08/10/2007 QA70-10073 TO_KEEP_CUSTOMIC_SETTINGS_IN_REPORT_GRAPH
		///end HISTOGRAM_SCALE_NOT_GOOD_WHEN_RECALCULATE
		{
			///Arvin 08/22/07 WRONG_HISTOGRAM_SCALE_IN_STATS_ON_COL
			//DataRange dr;
			//GetInput(dr);
			//if(HasFactor(trOp, nDataIndex) && ReportGetPlotTypeFromGraphIndex(nGraphIndex) == IDM_PLOT_HISTOGRAM_TYPE)
			//	SetAxisXTitleWithFactor(trOp, dr, gl, nDataIndex);
			
			//if(ReportGetPlotTypeFromGraphIndex(nGraphIndex) == IDM_PLOT_HISTOGRAM_TYPE && !IsPlotAllPlotsInOneGraph(trOp))
			//	SetAxisXFromTo(trOp, dr, gl, nDataIndex);
			
			/// Iris 11/05/2009 QA81-14599 FIX_STATS_ON_COLS_PLOT_REPORT_GRAPHS_VERY_SLOW
			//gl.Rescale();
			bool bRescale = true;
			if( IsPlotAllPlotsInOneGraph(trOp, nGraphIndex) && IDM_PLOT_BOX == ReportGetPlotTypeFromGraphIndex(nGraphIndex) && nFittedPlot != GetNumPlotsInOneGraph(trOp, nGraphIndex) - 1 )
			{
				bRescale = false;
			}
			if( bRescale )
			{
				/// Hong 11/27/09 QA80-14752 FIX_HISTOGRAM_BAD_RESCALE_IF_GRAPH_SHOWN_BEFORE_RECACULATE_WHEN_DATA_CHANGE
				GraphPage		gp;
				gl.GetParent(gp);
				gp.Refresh(TRUE); // Hong, MUST be TRUE
				/// end FIX_HISTOGRAM_BAD_RESCALE_IF_GRAPH_SHOWN_BEFORE_RECACULATE_WHEN_DATA_CHANGE
				gl.Rescale();
			}
			///END WRONG_HISTOGRAM_SCALE_IN_STATS_ON_COL
		}
		
		return WksReportOperation::SetupPlotDetails(trOp, gl, nFittedPlot, nNumPlots, nGraphIndex, nDataIndex, bIsSourceGraph, bUpdateExistedReportGraph);		
	}

private:
	/// Iris 5/26/2008 WRONG_RESULT_CURVE_SHEET_NAME_SAME_AS_REPORT_SHEET
	/*
	///Arvin 06/19/07 WRONG_HISTOGRAM_AND_BOXCHART_PLOTS_WHILE_DATA_HAVE_FACTORS
	void getGUIResultCurveNode(const TreeNode& trGUI, TreeNode& trResultCurve, int nOutputIndex = OUTPUT_RESULT_CURVE_FIT_CURVES_SHEET)
	{
		if(nOutputIndex == OUTPUT_RESULT_CURVE_FIT_CURVES_SHEET)
			trResultCurve = trGUI.Output.Report;
	}
	///end WRONG_HISTOGRAM_AND_BOXCHART_PLOTS_WHILE_DATA_HAVE_FACTORS
	*/
	//virtual
	string GetCurveOutputBookName(const TreeNode& trGUI, int nOutputIndex, int* pnSpecialType = NULL, Worksheet* pwksReport = NULL)
	{
		string	strBook;
		if(NULL != pwksReport)
		{
			///Sophy 9/3/2008 FIX_RUNTIME_ON_NO_REPORT_BOOK_WHEN_DO_STATS_ON_COLUMN
			//strBook = pwksReport->GetPage().GetName();
			if( pwksReport->IsValid() )
				strBook = pwksReport->GetPage().GetName();
			///end FIX_RUNTIME_ON_NO_REPORT_BOOK_WHEN_DO_STATS_ON_COLUMN
		}
		return strBook;
	}
	
	//virtual 
	void 	GetResultCurveBookSheetName(TreeNode& trOperation, string& strBookName, string& strSheetName, int nIndex = 0, int nOption = OUTPUT_RESULT_CURVE_FIT_CURVES_SHEET, bool bSeparateSheetForDataset = false, int nSheetNameIndex = 0)
	{
		strSheetName = _LE(E_STR_DEST_STATS_CURVE_SHEET_NAME);
	}
	///end WRONG_RESULT_CURVE_SHEET_NAME_SAME_AS_REPORT_SHEET
	
	void	addMultiModesFootnote(const TreeNode& trOp, int nTotalNumData, const vector<string> &vstrFactors)
	{
		//----- CPY 10/24/07 LOCALIZATION_CLEAN_UP_ON_OPERATION_CODES
		//string 	strFooter = "Multiple modes exist. The smallest value is shown."; //for only one data case
		string 	strFooter = "Err: not in oErrMsg->Multiple modes exist. The smallest value is shown.";
		ocu_load_msg_str(IDS_MULTI_MODES_EXIST_NO_ARG, strFooter);
		//-----
		if( nTotalNumData > 1 )
		{			
			if(vstrFactors && vstrFactors.GetSize() > 0)//for the case that includes multiple data with grouping data format
			{
				DataRange 	dr;
				dr.Create(trOp.GUI.InputData, false);
				if(dr)
				{				
					int 		r1,c1,r2,c2;
					Worksheet 	wks;
					dr.GetRange("X", r1, c1, r2, c2, wks); //"X", the range name of Input Data, the range name of grouping data is "F"
					Column 		col = wks.Columns(r1);
					if(col)
					{
						//----- CPY 10/24/07 LOCALIZATION_CLEAN_UP_ON_OPERATION_CODES
						//strFooter = "Multiple modes exist in " + col.GetName() + ".The smallest value is shown";
						ocu_load_msg_str(IDS_MULTI_MODES_EXIST, strFooter, col.GetName());
						//-----
					}
				}
			}
			else  // for the case that includes multiple data without grouping data format
			{
				string 	strDataLabelList;
				for(int ii=0; ii<nTotalNumData; ii++)
				{
					int		nRowColIndex;
					string 	strDataLabel;
					GetOneDataLabel(trOp, ii, nRowColIndex, strDataLabel);
					ConvertEscapedString(strDataLabel);
					strDataLabelList += strDataLabel + ",";
				}
				strDataLabelList.TrimRight(',');
				//----- CPY 10/24/07 LOCALIZATION_CLEAN_UP_ON_OPERATION_CODES
				//strFooter = "Multiple modes exist in " + strDataLabelList + ". The smallest value is shown.";
				ocu_load_msg_str(IDS_MULTI_MODES_EXIST, strFooter, strDataLabelList);
				//-----
				
			}
		}
		TreeNode trTable = tree_get_node_by_id(trOp.Calculation, IDST_DESC_STATS_RESULTS, true);
		TreeNode trFooter = tree_check_get_node(trTable, "Footnote", IDE_FOOTNOTE_BEGIN, TREE_Footnote, "1"); // just need the TREE_Footnote attribute, value does not matter, so 1 is good
		trFooter.strVal = strFooter;				
	}
	
	void	updateExtremeValuesTableLabel(TreeNode& trRow)
	{
		trRow.Index.SetAttribute(STR_LABEL_ATTRIB, "Index");
		trRow.Value.SetAttribute(STR_LABEL_ATTRIB, "Value");
	}
	
	bool 	addExtremeValuesTable(TreeNode& trOp, int index, const vector& vData, const vector<int>& vintRowsInSource, LPCSTR lpcszDataLabel, vector<string>& vstrFactors)
	{		
		vector 			vDataTemp;
		vDataTemp = vData;
		vector<int>		vnIndex;
		vnIndex = vintRowsInSource;
		
		// sort and remove missing values
		vector<uint> vnIndeces;
		vDataTemp.Sort(SORT_ASCENDING, true, vnIndeces);
		vnIndex.Reorder(vnIndeces);
		/// Iris 05/18/2007 v8.0621 CORRECT_BAD_LOOP
		//while(vDataTemp.GetSize() > 0 && is_missing_value(vDataTemp[0]) )
		//{			
			//vDataTemp.RemoveAt(0);
			//vnIndex.RemoveAt(0);
		//}
		int 	nNumOfTrim = vDataTemp.TrimLeft(true);
		vDataTemp.GetSubVector(vDataTemp, nNumOfTrim, vDataTemp.GetSize());
		vnIndeces.GetSubVector(vnIndeces, nNumOfTrim, vnIndeces.GetSize());
		///end CORRECT_BAD_LOOP
		
		// check and get the row of extreme value in table
		int nDataSize = vDataTemp.GetSize();
		int nRow = 5;
		if( nDataSize < 10 )
		{
			nRow = nDataSize / 2;
		}
		if( nRow < 2 )
			return false;		
		
		ExVals *pstExHighVals, *pstExLowVals;
		pstExHighVals = (ExVals*)calloc(nRow, sizeof(ExVals));
		pstExLowVals = (ExVals*)calloc(nRow, sizeof(ExVals));
		
		if( getExtremeVals(vDataTemp, vnIndex, pstExHighVals, pstExLowVals, nRow))
		{		
			TreeNode 	trTable = tree_check_get_node(trOp.Calculation, "ExVals", IDST_DESC_STATS_EXTREME_VALS, STR_LABEL_ATTRIB, "Extreme Values" );
			/// Iris 01/15/2007 v8.0541 REMOVE_SUB_TABLE_FROM_ANOVE_MISS_MASK_DATA_TABLE
			/*
			TreeNode	trOneSet = check_add_enumerated_node(trTable, CALCULATION_REPORT_TABLE_COL_PREFIX, index + 1, IDST_TEMP_ONE_SET, STR_LABEL_ATTRIB, lpcszDataLabel);
			trOneSet.ID = IDST_DESC_STATS_EXTREME_VALS + index + 1;
			
			int nRows=0;
			for(int ii=0; ii<nRow; ii++)
			{
				TreeNode trRow = tree_check_get_node(trOneSet, "row" + nRows, IDST_TEMP_ONE_SET, STR_LABEL_ATTRIB, "Highest");
				trRow += pstExHighVals[ii];
				trRow.ID = make_one_set_ID(IDST_DESC_STATS_EXTREME_VALS, index + nRows);
				updateExtremeValuesTableLabel(trRow);
				nRows++;
			}
			
			for(ii=0; ii<nRow; ii++)
			{
				TreeNode trRow = tree_check_get_node(trOneSet, "row" + nRows, IDST_TEMP_ONE_SET, STR_LABEL_ATTRIB, "Lowest");
				trRow += pstExLowVals[ii];
				trRow.ID = make_one_set_ID(IDST_DESC_STATS_EXTREME_VALS, index + nRows);
				updateExtremeValuesTableLabel(trRow);
				nRows++;
			}
			*/			
			addRowToExtremeValueTable(trTable, pstExHighVals, nRow, lpcszDataLabel, vstrFactors, "Highest");
			addRowToExtremeValueTable(trTable, pstExLowVals, nRow, lpcszDataLabel, vstrFactors, "Lowest");
			///end REMOVE_SUB_TABLE_FROM_ANOVE_MISS_MASK_DATA_TABLE
		}
		free(pstExHighVals);
		free(pstExLowVals);
		
		return true;
	}

	bool 	addRowToExtremeValueTable(TreeNode& trTable, ExVals* pExVals, int nRows, LPCSTR lpcszDataLabel, const vector<string>& vstrFactors, LPCSTR lpcszRowLabel) 
	{
		int 	nRow = trTable.GetNodeCount();
		for(int ii=0; ii<nRows; ii++)
		{
			TreeNode 	trRow = tree_check_get_node(trTable, CALCULATION_REPORT_TABLE_ROW_PREFIX + (nRow+1), IDST_TEMP_ONE_SET, STR_LABEL_ATTRIB, lpcszDataLabel);
			/// Iris 05/14/2007 v8.0617 EXTREME_VALUE_NEED_MORE_GROUP_LABELS
			//tree_add_one_label(trRow, lpcszRowLabel, 0);
			tree_add_more_labels(trRow, vstrFactors);
			tree_add_one_label(trRow, lpcszRowLabel, vstrFactors.GetSize());
			///end EXTREME_VALUE_NEED_MORE_GROUP_LABELS
			trRow.ID = make_one_set_ID(IDST_DESC_STATS_EXTREME_VALS, nRow);
			
			for(int col=0; col<2; col++)
			{
				string 		strColLabel = 0 == col? "Index" : "Value";
				TreeNode 	trCol = tree_check_get_node(trRow, strColLabel, col + 1, STR_LABEL_ATTRIB, strColLabel);
				if(0 == col)
					trCol.dVal = pExVals[ii].Index;
				else
					trCol.dVal = pExVals[ii].Value;
			}
			
			nRow++;
		}
		return true;
		
	}
	
	bool 	getExtremeVals(const vector& vData, const vector<int>& vIndex, ExVals *pstExHighVals, ExVals *pstExLowVals, int nSize)
	{		
		int 	ii, index=0;
		for(ii=0; ii<nSize; ii++)
		{
			pstExLowVals[index].Index = vIndex[ii];
			pstExLowVals[index].Value = vData[ii];
			index++
		}
		
		index=0;
		for(ii=vData.GetSize()-1; ii>=vData.GetSize()-nSize; ii--)
		{
			pstExHighVals[index].Index = vIndex[ii];
			pstExHighVals[index].Value = vData[ii];
			index++;
		}		
		
		
		return true;
	}
	
	/// Hong 08/13/09 QA80-14138 REDUCE_OPERATION_SIZE_OF_STATS_ON_COLS
#ifdef		__REDUCE_STATS_ON_COLS_OP_MEM_CONSUME__
	//virtual 
	/// Hong 12/11/09 QA80-14138-P2 FIX_STATS_ON_COL_CHANGE_PARAM_CANNOT_ADD_BACK_MISSING_TABLE
	///// Iris 9/03/2009 QA80-14138 FIX_STATS_ON_COL_CHANGE_PARAM_CANNOT_ADD_MISSING_TABLE
	bool	isFilterNeedCloneTree() { return false; }
	//bool isResetHiddenTable() { return true; }
	/////end FIX_STATS_ON_COL_CHANGE_PARAM_CANNOT_ADD_MISSING_TABLE
	/// end FIX_STATS_ON_COL_CHANGE_PARAM_CANNOT_ADD_BACK_MISSING_TABLE
#endif		//__REDUCE_STATS_ON_COLS_OP_MEM_CONSUME__
	/// end REDUCE_OPERATION_SIZE_OF_STATS_ON_COLS

/// Thomas 6/1/06 REDEFINE_UPDATEDATASOURCEINREPORTINGHEADER_FOR_DESCSTATS

protected:
	
	///Arvin 08/17/07 ADD_WEIGHT_DATA_TABLE_IN_INPUT_DATA_TABLE
	virtual bool IsDatasetHasWeight(TreeNode& trInput, int nIndex = 0, string& strWeight = NULL)
	{
		///------ Folger 10/12/2010 ORG-1240-P1 FAILED_TO_SHOW_WEIGHT_DATA_IN_REPORT_INPUT_OTHER_THAN_FIRST_DATA
		/*
		int ii = 0;
		foreach(TreeNode trRange in trInput.Children)
		{
			if(ii == nIndex)
			{
				if(trRange.W && !trRange.W.IsEmpty() )
				{
					if(strWeight)
						strWeight = trRange.W.strVal;
					
					return true;
				}
				else
					return false;
			}
			
			ii++;
		}			
		*/
		TreeNode	trWeight = trInput.Range1.W;
		if ( trWeight && !trWeight.IsEmpty() )
		{
			if ( strWeight )
				strWeight = trWeight.strVal;
			return true;
		}
		///------ End FAILED_TO_SHOW_WEIGHT_DATA_IN_REPORT_INPUT_OTHER_THAN_FIRST_DATA
		return false;
	}	
	///end ADD_WEIGHT_DATA_TABLE_IN_INPUT_DATA_TABLE
	
	///Arvin 08/14/07 WRONG_HISTOGRAM_AND_BOXCHART_PLOT_WHEN_COMBINED_MUTI_AS_SINGLE_DATASET
	bool	IsCombinedMultiAsSingle(const TreeNode& trOp)
	{	
		DataRange dr;
		GetInput(dr);
		DWORD	dwRules = GetDataRules(trOp);
		dwRules &= ~DRR_COMBINED_SIMPLE;
		
		int 	nNumData = dr.GetNumData(dwRules);
		int	modeMDInput = tree_get_oper_multidata_modes(trOp.GUI);
		if(modeMDInput == MDINPUT_CMBND_SIMPLE && nNumData > 1)
			return true;
		
		return false;
	}
	///end WRONG_HISTOGRAM_AND_BOXCHART_PLOT_WHEN_COMBINED_MUTI_AS_SINGLE_DATASET
	
	///Arvin 06/19/07 WRONG_HISTOGRAM_AND_BOXCHART_PLOTS_WHILE_DATA_HAVE_FACTORS
	bool IsOutputSeparateResultCurveSheet(const TreeNode& trOp) 
	{
		///Arvin 08/14/07 WRONG_HISTOGRAM_AND_BOXCHART_PLOT_WHEN_COMBINED_MUTI_AS_SINGLE_DATASET
		//if(HasFactor(trOp))
		if(HasFactor(trOp) || IsCombinedMultiAsSingle(trOp))
		///end 	WRONG_HISTOGRAM_AND_BOXCHART_PLOT_WHEN_COMBINED_MUTI_AS_SINGLE_DATASET
		{
			int nOption = GetOptionIndex(trOp.GUI);
			if(nOption <= 0)
			{
				foreach(TreeNode trPlot in trOp.GUI.Plots.Children)
				{
					//if(trPlot.nVal)
					if(tree_is_true(trPlot))
						return true;
				}
			}
		}
		
		return false;
	}
	
	TreeNode GetResultCuveOutputBranch(const TreeNode& trOp)
	{
		TreeNode 	trCurveBranch = trOp.GUI.Output.Report;
		return 		trCurveBranch;
	}
	///end 	WRONG_HISTOGRAM_AND_BOXCHART_PLOTS_WHILE_DATA_HAVE_FACTORS
	// virtual
	///Arvin 07/25/07 v8.0667 WRONG_INPUT_DATA_TABLE_FOR_MULTI_DATA_AND_FACTORS
	/*
	void UpdateDataSourceInReportingHeader(TreeNode &trInputTable, const vector<string> &vstrFactors, int ii, LPCSTR lpcszXLabel = NULL, int numSubRanges = 0, DWORD dwRules = 0)
	{
		if(!vstrFactors.GetSize())
			WksReportOperation::UpdateDataSourceInReportingHeader(trInputTable, vstrFactors, ii, lpcszXLabel, numSubRanges, dwRules);
		else {
			if (0 != ii)
				return;	
			int	indexRow = 0;
			int	numFcts = vstrFactors.GetSize();
			AddOneRowToInputDataTable(trInputTable, indexRow++, 'D');
			AddOneRowToInputDataTable(trInputTable, indexRow++, 'F', numFcts < 2 ? -1 : 0);	
		}
	}
	*/
	void UpdateDataSourceInReportingHeader(TreeNode& trOp, vector<string>&vstrFactors, Worksheet& wksInputData, int nIndex, int numSubRanges = 0, DWORD dwRules = 0) ///Arvin 07/19/07 v8.0662 WRONG_INPUT_DATA_TABLE_FOR_ROCCURVE
	{
		if(nIndex != 0)
			return;
		
		///Sophy 7/10/2008 FIX_WRONG_INPUT_INFORMATION_WHEN_COMBINE_AS_SINGLE_DATASET_WHILE_STATS_ON_COLUMN
		//reset dwRules to care the combine bit. 
		dwRules = GetDataRules( trOp );
		///end FIX_WRONG_INPUT_INFORMATION_WHEN_COMBINE_AS_SINGLE_DATASET_WHILE_STATS_ON_COLUMN
		string strDataLabel= _L("Data"), strFactorLabel = _L("Group");
		AddMultiInputDataWithFactorSourceTable(trOp, strDataLabel, strFactorLabel, dwRules); 
		
	}
	///END WRONG_INPUT_DATA_TABLE_FOR_MULTI_DATA_AND_FACTORS
/// End REDEFINE_UPDATEDATASOURCEINREPORTINGHEADER_FOR_DESCSTATS

	///Cheney 2007-5-23 QA70-9805 SPEED_UP_STATISTIC_ON_ROW
	//virtual
	bool	CalcMultiData(TreeNode& trOp, DataRange& dr, int &nTotalNumData, int nExeMode, DWORD dwExecCntrl = 0)
	{
		int 	nOption = trOp.GUI.StatsOnRows.nVal;
		if( DESC_STATS_ON_ROWS != nOption) 
			return WksReportOperation::CalcMultiData(trOp, dr, nTotalNumData, nExeMode,dwExecCntrl);
		
		TreeNode		trAdditionalData = tree_check_get_node(trOp,TREE_INPUTRANGE_ADDITIONAL_DATA_NODE_NAME); 
		DWORD			dwRules = GetDataRules(trOp);
		int 			nNumData = dr.GetNumData(dwRules, trAdditionalData);
		
		if(!checkStatsOnRowErr(nNumData))
			return false;
	
		SetTree(trOp);	
		
		/// Iris 2/22/2010 QA81-10824 SUPPORT_NON_CONTIGUOUS_RANGES_FOR_STATS_ON_ROWS
		/*
		matrix		mData;
		vector		vWeight;
		DWORD		ouidAux;
		vector<int>	vintRowIndices;
		Worksheet	wks;
		int			nn = dr.GetData(dwRules, 0, &ouidAux, NULL, NULL, NULL, &mData, NULL, &vWeight,
		                               NULL, NULL, &wks, NULL, &vintRowIndices);
		if(nn < 0)
			return error_report("failed to GetData from input");		
		*/				
		matrix		mData;
		/// Iris 3/16/2010 QA81-10824 SUPPORT_NON_CONTIGUOUS_RANGES_FOR_STATS_ON_ROWS_MORE
		//vector<int>	vintRowIndices;		
		///End SUPPORT_NON_CONTIGUOUS_RANGES_FOR_STATS_ON_ROWS_MORE
		bool	bIsContiguousRange = dr.ConvertToContiguous();
		if( bIsContiguousRange )
		{
			/// Iris 3/16/2010 QA81-10824 SUPPORT_NON_CONTIGUOUS_RANGES_FOR_STATS_ON_ROWS_MORE
			/*
			int			nn = dr.GetData(dwRules, 0, NULL, NULL, NULL, NULL, &mData, NULL, NULL,
                               NULL, NULL, NULL, NULL, &vintRowIndices);
			if(nn < 0)
				return error_report("failed to GetData from input");
			*/
			matrix		mTemp;
			vector<int>	vintRowIndices;
			int			nn = dr.GetData(dwRules, 0, NULL, NULL, NULL, NULL, &mTemp, NULL, NULL,
			                               NULL, NULL, NULL, NULL, &vintRowIndices);
			if(nn < 0)
				return error_report("failed to GetData from input");
			
			int r1 = vintRowIndices[0] - 1;
			if( vintRowIndices.GetSize() > 0 && r1 > 0 ) // range not from 1st row
			{				
				mData.SetSize(r1 + mTemp.GetNumRows(), mTemp.GetNumCols());
				mData = NANUM;
				
				mData.SetSubMatrix(mTemp, 0, r1);
			}
			else
			{
				mData = mTemp;
			}			
			///End SUPPORT_NON_CONTIGUOUS_RANGES_FOR_STATS_ON_ROWS_MORE
		}
		else
		{
			/// Iris 3/16/2010 QA81-10824 SUPPORT_NON_CONTIGUOUS_RANGES_FOR_STATS_ON_ROWS_MORE
			/*
			int nNumRanges = dr.GetNumRanges();
			int nNumCols = 0;
			for(int nRange = 0; nRange < nNumRanges; nRange++)
			{
				vector		vTemp;
				vector<int>	vintRowIndicesTemp;
				int			nn = dr.GetData(DRR_GET_MISSING | DRR_NO_FACTORS | DRR_NO_WEIGHTS, nRange, NULL, NULL, vTemp, NULL, NULL, NULL, NULL,
				                               NULL, NULL, NULL, NULL, &vintRowIndicesTemp);
				                               
				if( nn >= 0 && vTemp.GetSize() > 0 )
				{
					nNumCols++;
					if( 0 == nRange )
					{
						vintRowIndices = vintRowIndicesTemp;
						mData.SetSize(vintRowIndices.GetSize(), nNumRanges);
					}
					
					if( 0 == nRange	|| vintRowIndicesTemp.GetSize() == vintRowIndices.GetSize() && vintRowIndicesTemp.GetSize() > 0 
						&& vintRowIndicesTemp[0] == vintRowIndices[0] )
					{					
						mData.SetColumn(vTemp, nRange);
					}
				}
			}
			if( nNumCols <= 0 )
				return error_report("failed to GetData from input");
			
			if( nNumCols < nNumRanges ) // may exist empty range string in DataRange obj
				mData.SetSize(vintRowIndices.GetSize(), nNumCols, true);
			*/
			if(!get_data_from_dr_to_mat(dr, mData, MATRIX_FROM_RANGE_REMOVE_MISSING_FROM_LAST_SEL_ROW))
				return error_report("failed to GetData from input");
			///End SUPPORT_NON_CONTIGUOUS_RANGES_FOR_STATS_ON_ROWS_MORE
		}
		/// Iris 3/16/2010 QA81-10824 SUPPORT_NON_CONTIGUOUS_RANGES_FOR_STATS_ON_ROWS_MORE
		//CalcOneDataOnRow(trOp, mData, vintRowIndices);
		CalcOneDataOnRow(trOp, mData);
		///End SUPPORT_NON_CONTIGUOUS_RANGES_FOR_STATS_ON_ROWS_MORE
		///End SUPPORT_NON_CONTIGUOUS_RANGES_FOR_STATS_ON_ROWS

		
		return true;
	}
	
	//just for stats on row
	/// Iris 3/16/2010 QA81-10824 SUPPORT_NON_CONTIGUOUS_RANGES_FOR_STATS_ON_ROWS_MORE
	//bool	CalcOneDataOnRow(TreeNode& trOp, matrix& mData, vector<int>& vintRowIndices)
	bool	CalcOneDataOnRow(TreeNode& trOp, matrix& mData)
	///End SUPPORT_NON_CONTIGUOUS_RANGES_FOR_STATS_ON_ROWS_MORE
	{
		int nRows = mData.GetNumRows(), nCols = mData.GetNumCols();
		
		TreeNode trVarDivisor = trOp.GUI.Computation.VarDivisor;
		if(!trVarDivisor)
			return false;
		
		//Moments
		TreeNode trMoments = trOp.GUI.Quantities.Moments;
		if(!trMoments)
			return false;
		
		bool bComputeMoments = false; //check if need to compute Moments
		///Cheney 2007-11-14 STATS_ON_ROW_SHOULD_SUPPORT_MORE_OPTION_AS_MAX_SAID
		//if(trMoments.Mean.nVal || trMoments.N.nVal || trMoments.SD.nVal || trMoments.SEM.nVal
		//	 || trMoments.LCL.nVal || trMoments.UCL.nVal || trMoments.Sum.nVal)
		if(trMoments.N.nVal || trMoments.Missing.nVal || trMoments.Mean.nVal
			 || trMoments.SD.nVal || trMoments.SEM.nVal || trMoments.LCL.nVal
			 || trMoments.UCL.nVal || trMoments.Variance.nVal || trMoments.Sum.nVal
			 || trMoments.Skewness.nVal || trMoments.Kurtosis.nVal || trMoments.UncorSumSq.nVal
			 || trMoments.CorSumSq.nVal || trMoments.COV.nVal || trMoments.MAD.nVal
			 || trMoments.SDx2.nVal || trMoments.SDx3.nVal || trMoments.GeoMean.nVal
			 || trMoments.GeoSD.nVal || trMoments.Mode.nVal)	 
		///end STATS_ON_ROW_SHOULD_SUPPORT_MORE_OPTION_AS_MAX_SAID
			bComputeMoments = true;
		
		vector vMean(nRows), vSd(nRows), vSem(nRows), vMin(nRows), vMax(nRows), vSum(nRows),
				vN(nRows), vLCL(nRows), vUCL(nRows);
		///Cheney 2007-11-14 STATS_ON_ROW_SHOULD_SUPPORT_MORE_OPTION_AS_MAX_SAID
		//if(bComputeMoments && ocmath_row_desc_stats(nRows, nCols, mData, vMean, vSd, vSem, vMin, vMax, vSum, vN, vLCL, vUCL, trVarDivisor.nVal))
		//{
			//string strErr;
			//if( ocu_load_err_msg_str(CER_FAILED_GET_MOMENTS, &strErr) )
				//okoc_out_msg(strErr);
		//}
		vector vVariance(nRows), vSkewness(nRows), vKurtosis(nRows),
				vUncorSumSq(nRows), vCorSumSq(nRows), vCOV(nRows), vMAD(nRows), 
				vSDx2(nRows), vSDx3(nRows), vGeoMean(nRows), vGeoSD(nRows), vMode(nRows);
		vector<int> vnMissing(nRows);
		vector *pMean = NULL, *pSd = NULL, *pSem = NULL, *pSum = NULL, *pN = NULL, 
				*pLCL = NULL, *pUCL = NULL, *pVariance = NULL, *pSkewness = NULL, 
				*pKurtosis = NULL, *pUncorSumSq = NULL, *pCorSumSq = NULL, *pCOV = NULL, 
				*pMAD = NULL, *pSDx2 = NULL, *pSDx3 = NULL, *pGeoMean = NULL, *pGeoSD = NULL, *pMode = NULL;
		vector<int>* pMissing = NULL;
		if(trMoments.N.nVal) pN = &vN;
		if(trMoments.Missing.nVal) pMissing = &vnMissing;
		if(trMoments.Mean.nVal) pMean = &vMean;
		if(trMoments.SD.nVal) pSd = &vSd;
		if(trMoments.SEM.nVal) pSem = &vSem;
		if(trMoments.LCL.nVal) pLCL = &vLCL;
		if(trMoments.UCL.nVal) pUCL = &vUCL;
		if(trMoments.Variance.nVal) pVariance = &vVariance;
		if(trMoments.Sum.nVal) pSum = &vSum;
		if(trMoments.Skewness.nVal) pSkewness = &vSkewness;
		if(trMoments.Kurtosis.nVal) pKurtosis = &vKurtosis;
		if(trMoments.UncorSumSq.nVal) pUncorSumSq = &vUncorSumSq;
		if(trMoments.CorSumSq.nVal) pCorSumSq = &vCorSumSq;
		if(trMoments.COV.nVal) pCOV = &vCOV;
		if(trMoments.SDx2.nVal) pSDx2 = &vSDx2;
		if(trMoments.SDx3.nVal) pSDx3 = &vSDx3;
		if(trMoments.MAD.nVal) pMAD = &vMAD;
		if(trMoments.GeoMean.nVal) pGeoMean = &vGeoMean;
		if(trMoments.GeoSD.nVal) pGeoSD = &vGeoSD;
		if(trMoments.Mode.nVal) pMode = &vMode;
		if(bComputeMoments)
		{
			if(ocmath_row_desc_stats_ex(nRows, nCols, mData, *pMean, *pSd,  
						*pSem, NULL, NULL, *pSum, *pN, *pLCL, *pUCL, *pVariance,
						*pSkewness, *pKurtosis, *pUncorSumSq, *pCorSumSq, *pCOV, *pMAD, *pMissing, *pGeoMean, 
						*pMode, NULL, *pGeoSD, *pSDx2, *pSDx3, trVarDivisor.nVal) )
			{
				string strErr;
				if( ocu_load_err_msg_str(CER_FAILED_GET_MOMENTS, &strErr) )
					okoc_out_msg(strErr);
			}	
		}
		///end STATS_ON_ROW_SHOULD_SUPPORT_MORE_OPTION_AS_MAX_SAID
		
		TreeNode trInterpolate = trOp.GUI.Computation.Interpolate;
		if(!trInterpolate)
			return false;
		
		//Quantiles
		TreeNode trQuantiles = trOp.GUI.Quantities.Quantiles;
		if(!trQuantiles)
			return false;
		
		bool bComputeQuantiles = false; //check if need to compute Quantiles
		/// Max 07-11-17 NEED_TO_CHECK_CUSTOMPERCENTILES_NODE
		/////Cheney 2007-11-14 STATS_ON_ROW_SHOULD_SUPPORT_MORE_OPTION_AS_MAX_SAID
		////if(trQuantiles.Min.nVal || trQuantiles.Q1.nVal || trQuantiles.Median.nVal 
		////		|| trQuantiles.Q3.nVal || trQuantiles.Max.nVal)
		//if(trQuantiles.Min.nVal || trQuantiles.Q1.nVal || trQuantiles.Median.nVal 
				//|| trQuantiles.Q3.nVal || trQuantiles.Max.nVal || trQuantiles.iMin.nVal
				//|| trQuantiles.iMax.nVal || trQuantiles.IQR.nVal || trQuantiles.Range.nVal || trQuantiles.PercentileList.nVal)		
		/////end STATS_ON_ROW_SHOULD_SUPPORT_MORE_OPTION_AS_MAX_SAID
		if(trQuantiles.Min.nVal || trQuantiles.Q1.nVal || trQuantiles.Median.nVal 
				|| trQuantiles.Q3.nVal || trQuantiles.Max.nVal || trQuantiles.iMin.nVal
				|| trQuantiles.iMax.nVal || trQuantiles.IQR.nVal || trQuantiles.Range.nVal || (trQuantiles.CustomPercentiles.nVal && trQuantiles.PercentileList.nVal))
		/// END NEED_TO_CHECK_CUSTOMPERCENTILES_NODE
			bComputeQuantiles = true;
			
		vector vQ1(nRows), vMedian(nRows), vQ3(nRows);
		///Cheney 2007-11-14 STATS_ON_ROW_SHOULD_SUPPORT_MORE_OPTION_AS_MAX_SAID
		//if(bComputeQuantiles && ocmath_row_quantiles(nRows, nCols, mData, vMin, vMax, vQ1, vMedian, vQ3, trInterpolate.nVal) )
		//{
			//string strErr;
			//if( ocu_load_err_msg_str(CER_FAILED_GET_QUANTITIES, &strErr) )
				//okoc_out_msg(strErr);
		//}
		vector vIQR(nRows), vRange(nRows), vPercents, vPercentiles;
		vector<int> vniMin(nRows), vniMax(nRows);
		vector *pQ1 = NULL, *pMedian = NULL, *pQ3 = NULL, *pIQR = NULL, 
				*pRange = NULL, *pMin = NULL, *pMax =NULL, *pMatPercentiles = NULL;
		vector<int> *piMin = NULL, *piMax = NULL;
		bool *pShow = NULL;
		vector<bool> vbShow;
		double *pPercents = NULL; 
		if(trQuantiles.Min.nVal) pMin = &vMin;
		if(trQuantiles.Max.nVal) pMax = &vMax;
		if(trQuantiles.Q1.nVal) pQ1 = &vQ1;
		if(trQuantiles.Median.nVal) pMedian = &vMedian;
		if(trQuantiles.Q3.nVal) pQ3 = &vQ3;
		if(trQuantiles.iMin.nVal) piMin = &vniMin;
		if(trQuantiles.iMax.nVal) piMax = &vniMax;
		if(trQuantiles.IQR.nVal) pIQR = &vIQR;
		if(trQuantiles.Range.nVal) pRange = &vRange;
		
		uint nPercentsSize = 0;
		if(trQuantiles.CustomPercentiles.nVal)
		{
			string strCustomPercents = trQuantiles.PercentileList.strVal;
			vector<bool> vShow;
			GetPercentsForPercentiles(trOp, strCustomPercents, vPercents, vbShow);
			if(vbShow.GetSize() != vPercents.GetSize() )
				return false;
			pPercents = vPercents;
			nPercentsSize = vPercents.GetSize();
			vPercentiles.SetSize(nRows*nPercentsSize);
			pMatPercentiles = &vPercentiles;
			pShow = vbShow;
		}
		
		if(bComputeQuantiles)
		{
			if( ocmath_row_quantiles_ex(nRows, nCols, mData, *pMin, *pMax, *pQ1, *pMedian, *pQ3, 
				*piMin, *piMax, *pIQR, *pRange, pPercents, nPercentsSize, *pMatPercentiles, trInterpolate.nVal) )
			{
				string strErr;
				if( ocu_load_err_msg_str(CER_FAILED_GET_QUANTITIES, &strErr) )
					okoc_out_msg(strErr);
			}
			if(piMin) *piMin += 1;
			if(piMax) *piMax += 1;
		}
		///end STATS_ON_ROW_SHOULD_SUPPORT_MORE_OPTION_AS_MAX_SAID
		
		///Cheney 2007-11-14 STATS_ON_ROW_SHOULD_SUPPORT_MORE_OPTION_AS_MAX_SAID
		////if no out put, not need to do computing and add result
		//bool bRet = true;
		//if(bComputeMoments || bComputeQuantiles)
			//bRet = AddDescStatsTableOnRow(trOp, vintRowIndices, vMean, vSd, vSem, vMin, vMax, 
				//vSum, vN, vLCL, vUCL, vQ1, vMedian, vQ3) ;
				//
		//return bRet;
		//support insert row
		/// Iris 3/16/2010 QA81-10824 SUPPORT_NON_CONTIGUOUS_RANGES_FOR_STATS_ON_ROWS_MORE
		/*
		vector		vtemp(vintRowIndices[vintRowIndices.GetSize() - 1]);
		vtemp		= NANUM;
		int 		nInsertCol = vintRowIndices[0] - 1;
		*/
		vector		vtemp(mData.GetNumRows());
		vtemp		= NANUM;
		int			nInsertCol = 0;
		///End SUPPORT_NON_CONTIGUOUS_RANGES_FOR_STATS_ON_ROWS_MORE
		TreeNode	trTable 	= tree_check_get_node(trOp.Calculation, TABLE_DESC_STATS, IDST_DESC_STATS_RESULTS, STR_LABEL_ATTRIB, OUTPUT_DESC_STATS);		
		///------ Folger 03/24/10 QA81-15224 STATS_ON_ROWS_FAILED_TO_UPDATE_COL_HEADERS_WHEN_RECALCULATE
		trTable.SetAttribute(STR_REPORT_TREE_ALWAYS_UPDATE_COLUMN_LABELS_ATTRIB, 1);
		///------ End STATS_ON_ROWS_FAILED_TO_UPDATE_COL_HEADERS_WHEN_RECALCULATE
		int 		nID			= IDST_TEMP_ONE_SET;
		
		if(bComputeMoments)
		{
			if( !AddDescStatsTableOnRowMoments(trTable, vtemp, nInsertCol, nID,
					pMean, pSd, pSem, pSum, pN, pLCL, pUCL, pVariance, pSkewness, 
					pKurtosis, pUncorSumSq, pCorSumSq, pCOV, pMAD, pMissing, pGeoMean, pMode, pGeoSD, pSDx2, pSDx3) )
				return error_report("failed to add Moments to report table for StatsOnRow");
		}
		if(bComputeQuantiles)
		{
			if( !AddDescStatsTableOnRowQuantiles(trTable, vtemp, nInsertCol, nID,
					pMin, pMax, pQ1, pMedian, pQ3, piMin, piMax, pIQR, pRange, nRows, nPercentsSize, pPercents, pShow, pMatPercentiles) )
				return error_report("failed to add Quantiles to report table for StatsOnRow");
		}
		///end STATS_ON_ROW_SHOULD_SUPPORT_MORE_OPTION_AS_MAX_SAID
		return true;
	}
	
	///Cheney 2007-11-14 STATS_ON_ROW_SHOULD_SUPPORT_MORE_OPTION_AS_MAX_SAID
	////just for stats on row
	//bool 	AddDescStatsTableOnRow(TreeNode& trOp, const vector<int>& vintRowIndices,
				//const vector& vMean, const vector& vSd, const vector& vSem, const vector& vMin, 
				//const vector& vMax, const vector& vSum, const vector& vN, const vector& vLCL, 
				//const vector& vUCL, const vector& vQ1, const vector& vMedian, const vector& vQ3) 
	//{
		////support insert row
		//vector		vtemp(vintRowIndices[vintRowIndices.GetSize() - 1]);
		//vtemp		= NANUM;
		//int 		nInsertCol = vintRowIndices[0] - 1;
		//
		//TreeNode	trTable 	= tree_check_get_node(trOp.Calculation, TABLE_DESC_STATS, IDST_DESC_STATS_RESULTS, STR_LABEL_ATTRIB, _L("Descriptive Statistics"));		
		//int 		nID			= IDST_TEMP_ONE_SET;
		//TreeNode	trRow;
		//
		/////Cheney 2007-6-7 CLEAN_UP_OWN_CODE
		////N
		//addDestStatsOnRowsOneResult(trTable, "N", nID, STR_DESC_STATIS_GUI_LABEL_SAMPLE_SIZE, IDE_SAMPLE_SIZE, vN, nInsertCol, vtemp);
		//
		////Mean
		//addDestStatsOnRowsOneResult(trTable, "Mean", nID, STR_DESC_STATIS_GUI_LABEL_MEAN, IDE_MEAN, vMean, nInsertCol, vtemp);
		//
		////SD
		/////Arvin 08/31/07 QA70-7651-P17 WRONG_COLUMN_DESIGNATION_TYPE
		////addDestStatsOnRowsOneResult(trTable, "SD", nID, STR_DESC_STATIS_GUI_LABEL_SD, IDE_SD, vSd, nInsertCol, vtemp);
		//addDestStatsOnRowsOneResult(trTable, "SD", nID, STR_DESC_STATIS_GUI_LABEL_SD, IDE_SD, vSd, nInsertCol, vtemp, OKDATAOBJ_DESIGNATION_ERROR);
		/////end WRONG_COLUMN_DESIGNATION_TYPE
		//
		////SEM
		/////Arvin 08/31/07 QA70-7651-P17 WRONG_COLUMN_DESIGNATION_TYPE
		////addDestStatsOnRowsOneResult(trTable, "SEM", nID, STR_DESC_STATIS_GUI_LABEL_SEM, IDE_SEM, vSem, nInsertCol, vtemp);
		//addDestStatsOnRowsOneResult(trTable, "SEM", nID, STR_DESC_STATIS_GUI_LABEL_SEM, IDE_SEM, vSem, nInsertCol, vtemp, OKDATAOBJ_DESIGNATION_ERROR);
		/////end WRONG_COLUMN_DESIGNATION_TYPE
		//
		////LCL
		//addDestStatsOnRowsOneResult(trTable, "LCL", nID, STR_DESC_STATIS_GUI_LABEL_LCL, IDE_LCL, vLCL, nInsertCol, vtemp);
			//
		////UCL
		//addDestStatsOnRowsOneResult(trTable, "UCL", nID, STR_DESC_STATIS_GUI_LABEL_UCL, IDE_UCL, vUCL, nInsertCol, vtemp);
		//
		////Sum
		//addDestStatsOnRowsOneResult(trTable, "Sum", nID, STR_DESC_STATIS_GUI_LABEL_SUM, IDE_SUM, vSum, nInsertCol, vtemp);
//
		////Min
		//addDestStatsOnRowsOneResult(trTable, "Min", nID, STR_DESC_STATIS_GUI_LABEL_MIN, IDE_MIN, vMin, nInsertCol, vtemp);
		//
		////Q1
		//addDestStatsOnRowsOneResult(trTable, "Q1", nID, STR_DESC_STATIS_GUI_LABEL_P25, IDE_P25, vQ1, nInsertCol, vtemp);
		//
		////Median
		//addDestStatsOnRowsOneResult(trTable, "Median", nID, STR_DESC_STATIS_GUI_LABEL_MEDIAN, IDE_MEDIAN, vMedian, nInsertCol, vtemp);
		//
		////Q3
		//addDestStatsOnRowsOneResult(trTable, "Q3", nID, STR_DESC_STATIS_GUI_LABEL_P75, IDE_P75, vQ3, nInsertCol, vtemp);
		//
		////Max
		//addDestStatsOnRowsOneResult(trTable, "Max", nID, STR_DESC_STATIS_GUI_LABEL_MAX, IDE_MAX, vMax, nInsertCol, vtemp);
		/////end CLEAN_UP_OWN_CODE
		//
		//return true;
	//}
	bool 	AddDescStatsTableOnRowMoments(TreeNode& trTable, vector& vec, int nInsertCol, int& nID,
				const vector* pMean = NULL, const vector* pSd = NULL, const vector* pSem = NULL, 
				const vector* pSum = NULL, const vector* pN = NULL, const vector* pLCL = NULL, 
				const vector* pUCL = NULL, const vector* pVariance = NULL, const vector* pSkewness = NULL, 
				const vector* pKurtosis = NULL, const vector* pUncorSumSq = NULL, 
				const vector* pCorSumSq = NULL, const vector* pCOV = NULL, const vector* pMAD = NULL, 
				const vector<int>* pMissing = NULL, const vector* pGeoMean = NULL, const vector* pMode = NULL, 
				const vector* pGeoSD = NULL, const vector* pSDx2 = NULL, const vector* pSDx3 = NULL)
	{
		//N
		checkAddDestStatsOnRowsOneResult(trTable, "N", nID, STR_DESC_STATIS_GUI_LABEL_SAMPLE_SIZE, pN, nInsertCol, vec, IDE_SAMPLE_SIZE);

		//Missing
		checkAddDestStatsOnRowsOneResult(trTable, "Missing", nID, STR_DESC_STATIS_GUI_LABEL_NUM_MISSING, pMissing, nInsertCol, vec, IDE_NUM_MISSING);

		//Mean
		checkAddDestStatsOnRowsOneResult(trTable, "Mean", nID, STR_DESC_STATIS_GUI_LABEL_MEAN, pMean, nInsertCol, vec, IDE_MEAN);
		
		//SD
		checkAddDestStatsOnRowsOneResult(trTable, "SD", nID, STR_DESC_STATIS_GUI_LABEL_SD, pSd, nInsertCol, vec, IDE_SD, OKDATAOBJ_DESIGNATION_ERROR);
		
		//SEM
		checkAddDestStatsOnRowsOneResult(trTable, "SEM", nID, STR_DESC_STATIS_GUI_LABEL_SEM, pSem, nInsertCol, vec, IDE_SEM, OKDATAOBJ_DESIGNATION_ERROR);
			
		//LCL
		checkAddDestStatsOnRowsOneResult(trTable, "LCL", nID, STR_DESC_STATIS_GUI_LABEL_LCL, pLCL, nInsertCol, vec, IDE_LCL);
			
		//UCL
		checkAddDestStatsOnRowsOneResult(trTable, "UCL", nID, STR_DESC_STATIS_GUI_LABEL_UCL, pUCL, nInsertCol, vec, IDE_UCL);
		
		//Variance
		checkAddDestStatsOnRowsOneResult(trTable, "Variance", nID, STR_DESC_STATIS_GUI_LABEL_VARIANCE, pVariance, nInsertCol, vec, IDE_VARIANCE);
		
		//Sum
		checkAddDestStatsOnRowsOneResult(trTable, "Sum", nID, STR_DESC_STATIS_GUI_LABEL_SUM, pSum, nInsertCol, vec, IDE_SUM);
		
		//Skewness
		checkAddDestStatsOnRowsOneResult(trTable, "Skewness", nID, STR_DESC_STATIS_GUI_LABEL_SKEWNESS, pSkewness, nInsertCol, vec, IDE_SKEWNESS);
		
		//Kurtosis
		checkAddDestStatsOnRowsOneResult(trTable, "Kurtosis", nID, STR_DESC_STATIS_GUI_LABEL_KURTOSIS, pKurtosis, nInsertCol, vec, IDE_KURTOSIS);
		
		//UncorSumSq
		checkAddDestStatsOnRowsOneResult(trTable, "UncorSumSq", nID, STR_DESC_STATIS_GUI_LABEL_UNCORSUMSQ, pUncorSumSq, nInsertCol, vec, IDE_UNCORSUMSQ);
		
		//CorSumSq
		checkAddDestStatsOnRowsOneResult(trTable, "CorSumSq", nID, STR_DESC_STATIS_GUI_LABEL_CORSUMSQ, pCorSumSq, nInsertCol, vec, IDE_CORSUMSQ);
		
		//COV
		checkAddDestStatsOnRowsOneResult(trTable, "COV", nID, STR_DESC_STATIS_GUI_LABEL_COV, pCOV, nInsertCol, vec, IDE_COV);
		
		//MAD
		///Sophy 4/3/2009 QA80-13352 SUPPORT_SPECIFY_COLUMN_DESIGNATIONS_IN_REPORT_TABLES
		//checkAddDestStatsOnRowsOneResult(trTable, "MAD", nID, STR_DESC_STATIS_GUI_LABEL_MAD, pMAD, nInsertCol, vec, IDE_MAD);
		checkAddDestStatsOnRowsOneResult(trTable, "MAD", nID, STR_DESC_STATIS_GUI_LABEL_MAD, pMAD, nInsertCol, vec, IDE_MAD, OKDATAOBJ_DESIGNATION_ERROR);
		///end SUPPORT_SPECIFY_COLUMN_DESIGNATIONS_IN_REPORT_TABLES
		
		//SDx2
		///Sophy 4/3/2009 QA80-13352 SUPPORT_SPECIFY_COLUMN_DESIGNATIONS_IN_REPORT_TABLES
		//checkAddDestStatsOnRowsOneResult(trTable, "SDx2", nID, STR_DESC_STATIS_GUI_LABEL_SD_X_2, pSDx2, nInsertCol, vec, IDE_SD_X_2);
		checkAddDestStatsOnRowsOneResult(trTable, "SDx2", nID, STR_DESC_STATIS_GUI_LABEL_SD_X_2, pSDx2, nInsertCol, vec, IDE_SD_X_2, OKDATAOBJ_DESIGNATION_ERROR);
		///end SUPPORT_SPECIFY_COLUMN_DESIGNATIONS_IN_REPORT_TABLES
		
		//SDx3
		///Sophy 4/3/2009 QA80-13352 SUPPORT_SPECIFY_COLUMN_DESIGNATIONS_IN_REPORT_TABLES
		//checkAddDestStatsOnRowsOneResult(trTable, "SDx3", nID, STR_DESC_STATIS_GUI_LABEL_SD_X_3, pSDx3, nInsertCol, vec, IDE_SD_X_3);
		checkAddDestStatsOnRowsOneResult(trTable, "SDx3", nID, STR_DESC_STATIS_GUI_LABEL_SD_X_3, pSDx3, nInsertCol, vec, IDE_SD_X_3, OKDATAOBJ_DESIGNATION_ERROR);
		///end SUPPORT_SPECIFY_COLUMN_DESIGNATIONS_IN_REPORT_TABLES
		
		//GeoMean
		checkAddDestStatsOnRowsOneResult(trTable, "GeoMean", nID, STR_DESC_STATIS_GUI_LABEL_GEO_MEAN, pGeoMean, nInsertCol, vec, IDE_GEO_MEAN);
				
		//GeoSD
		///Sophy 4/3/2009 QA80-13352 SUPPORT_SPECIFY_COLUMN_DESIGNATIONS_IN_REPORT_TABLES
		//checkAddDestStatsOnRowsOneResult(trTable, "GeoSD", nID, STR_DESC_STATIS_GUI_LABEL_GEO_SD, pGeoSD, nInsertCol, vec, IDE_GEO_SD);
		checkAddDestStatsOnRowsOneResult(trTable, "GeoSD", nID, STR_DESC_STATIS_GUI_LABEL_GEO_SD, pGeoSD, nInsertCol, vec, IDE_GEO_SD, OKDATAOBJ_DESIGNATION_ERROR);
		///end SUPPORT_SPECIFY_COLUMN_DESIGNATIONS_IN_REPORT_TABLES
		
		//Mode
		checkAddDestStatsOnRowsOneResult(trTable, "Mode", nID, STR_DESC_STATIS_GUI_LABEL_MODE, pMode, nInsertCol, vec, IDE_MODE);

		return true;
	}
	
	bool 	AddDescStatsTableOnRowQuantiles(TreeNode& trTable, vector& vec, int nInsertCol, int& nID,
				const vector* pMin = NULL, const vector* pMax = NULL, const vector* pQ1 = NULL, 
				const vector* pMedian = NULL, const vector* pQ3 = NULL, const vector<int>* piMin = NULL, 
				const vector<int>* piMax = NULL, const vector* pIQR = NULL, const vector* pRange = NULL,
				uint nRows = 0, uint nPercentsSize = 0, const double* pPecents = NULL, bool* pShow = NULL, const vector* pMatPercentiles = NULL)
	{
		//Min
		checkAddDestStatsOnRowsOneResult(trTable, "Min", nID, STR_DESC_STATIS_GUI_LABEL_MIN, pMin, nInsertCol, vec, IDE_MIN);
		
		//iMin
		checkAddDestStatsOnRowsOneResult(trTable, "iMin", nID, STR_DESC_STATIS_GUI_LABEL_IMIN, piMin, nInsertCol, vec, IDE_IMIN);

		//Q1
		checkAddDestStatsOnRowsOneResult(trTable, "Q1", nID, STR_DESC_STATIS_GUI_LABEL_P25, pQ1, nInsertCol, vec, IDE_P25);
		
		//Median
		checkAddDestStatsOnRowsOneResult(trTable, "Median", nID, STR_DESC_STATIS_GUI_LABEL_MEDIAN, pMedian, nInsertCol, vec, IDE_MEDIAN);
		
		//Q3
		checkAddDestStatsOnRowsOneResult(trTable, "Q3", nID, STR_DESC_STATIS_GUI_LABEL_P75, pQ3, nInsertCol, vec, IDE_P75);
		
		//Max
		checkAddDestStatsOnRowsOneResult(trTable, "Max", nID, STR_DESC_STATIS_GUI_LABEL_MAX, pMax, nInsertCol, vec, IDE_MAX);
		
		//iMax
		checkAddDestStatsOnRowsOneResult(trTable, "iMax", nID, STR_DESC_STATIS_GUI_LABEL_IMAX, piMax, nInsertCol, vec, IDE_IMAX);
		
		//IQR
		checkAddDestStatsOnRowsOneResult(trTable, "IQR", nID, STR_DESC_STATIS_GUI_LABEL_IQR, pIQR, nInsertCol, vec, IDE_IQR);
		
		//Range
		checkAddDestStatsOnRowsOneResult(trTable, "Range", nID, STR_DESC_STATIS_GUI_LABEL_RANGE, pRange, nInsertCol, vec, IDE_RANGE);
		
		//Percentiles
		if(pMatPercentiles)
		{
			if( nRows < 1 || nPercentsSize < 1 || !pPecents || !pShow )
				return false;
			
			matrix mattemp;
			mattemp.SetSize(nRows, nPercentsSize);
			mattemp.SetByVector( *pMatPercentiles);
			
			for(int ii = 0; ii < nPercentsSize; ii++)
			{
				if(!pShow[ii])
					continue;
				
				vector vSub;
				mattemp.GetColumn( vSub, ii );
				string strTemp;
				double dPecents = pPecents[ii];
				strTemp.Format("P%s", ftoa(dPecents));
				checkAddDestStatsOnRowsOneResult(trTable, CALCULATION_PERCENTILE_PREFIX+(ii+1), IDE_CUSTOM_PERCENTILES + ii, strTemp, &vSub, nInsertCol, vec, NULL, OKDATAOBJ_DESIGNATION_Y, true, &dPecents );
			}
		}
		
		return true;
	}
	///end STATS_ON_ROW_SHOULD_SUPPORT_MORE_OPTION_AS_MAX_SAID
	
 	//virtual 
 	TreeNode GetResultLogTree(TreeNode& trOp)
 	{ 
 		int 	nOption = trOp.GUI.StatsOnRows.nVal;
		if( DESC_STATS_ON_ROWS != nOption) 
 			return trOp.Calculation;
		
		//if stats on row, should not out put any statistic result
		TreeNode trNode = trOp.Calculation.Clone();
		TreeNode trStatistics = trNode.Statistics;
		if(trStatistics)
			trStatistics.Remove();
		
		return trNode;
 	}

	
private:
	bool checkStatsOnRowErr(int nErr)
	{
		string strErr;
		switch(nErr)
		{
		case EXTRACTBYROWSERR_MULTIPLE_SHEETS:
			ocu_load_err_msg_str(CER_EXTRACTBYROWSERR_MULTIPLE_SHEETS, &strErr);
			break;
		case EXTRACTBYROWSERR_UNEVEN_COLUMNS:
			ocu_load_err_msg_str(CER_EXTRACTBYROWSERR_UNEVEN_COLUMNS, &strErr);
			break;
		default:	
		}
		
		if(strErr.IsEmpty() && nErr <= 0)
			ocu_load_err_msg_str(CER_NO_DATA, &strErr);
		
		if(!strErr.IsEmpty())
		{
			okoc_out_msg(strErr);
			return false;
		}
		
		return true;
	}
	
	void setDescStatResults(DescStatResults& stDescStats, double dMean, double dSd, double dSem, 
						double dSum, int N, double dLCL,double  dUCL)
	{
		stDescStats.N 		= N;
		stDescStats.Mean 	= dMean;
		stDescStats.SD 		= dSd;
		stDescStats.SEM 	= dSem;
		stDescStats.LCL 	= dLCL;
		stDescStats.UCL 	= dUCL;
		stDescStats.Sum 	= dSum;
	}
	
	void setQuantileResults(QuantileResults& stQuantiles, double dMin, double dMax, double dQ1, 
						double dMedian, double dQ3)
	{
		stQuantiles.Min		= dMin;
		stQuantiles.Q1		= dQ1;
		stQuantiles.Median	= dMedian;
		stQuantiles.Q3		= dQ3;
		stQuantiles.Max		= dMax;	
	}
	 
	///Arvin 08/31/07 QA70-7651-P17 WRONG_COLUMN_DESIGNATION_TYPE
	//void addDestStatsOnRowsOneResult(TreeNode& trTable, LPCSTR lpcszTagName, int& nID, 
	//		LPCSTR lpcszLabel, int nDataID, vector& vStatsResult, int nInsertCol, vector& vInsertStatsResult)
	///Cheney 2007-11-14 STATS_ON_ROW_SHOULD_SUPPORT_MORE_OPTION_AS_MAX_SAID
	//void addDestStatsOnRowsOneResult(TreeNode& trTable, LPCSTR lpcszTagName, int& nID, 
	//		LPCSTR lpcszLabel, int nDataID, vector& vStatsResult, int nInsertCol, vector& vInsertStatsResult, int nDesignation = OKDATAOBJ_DESIGNATION_Y)
	void checkAddDestStatsOnRowsOneResult(TreeNode& trTable, LPCSTR lpcszTagName, int& nID, 
			LPCSTR lpcszLabel, vectorbase* pStatsResult, int nInsertCol, vector& vInsertStatsResult, 
			int& nDataID = NULL, int nDesignation = OKDATAOBJ_DESIGNATION_Y,
			bool bPecentile = false, double* pPercentsAttrib = NULL)
	///end STATS_ON_ROW_SHOULD_SUPPORT_MORE_OPTION_AS_MAX_SAID
	///END WRONG_COLUMN_DESIGNATION_TYPE
	{
		///Cheney 2007-11-14 STATS_ON_ROW_SHOULD_SUPPORT_MORE_OPTION_AS_MAX_SAID
		if(!pStatsResult)
			return;
		///end STATS_ON_ROW_SHOULD_SUPPORT_MORE_OPTION_AS_MAX_SAID
		
		TreeNode trRow 			= tree_check_get_node(trTable, lpcszTagName, nID++, STR_LABEL_ATTRIB, lpcszLabel);
		///Cheney 2007-11-14 STATS_ON_ROW_SHOULD_SUPPORT_MORE_OPTION_AS_MAX_SAID
		//trRow.DataID			=	nDataID;
		//vInsertStatsResult.SetSubVector( vStatsResult, nInsertCol );
		if(nDataID)
			trRow.DataID		= nDataID;
		vInsertStatsResult.SetSubVector( *pStatsResult, nInsertCol );
		///end STATS_ON_ROW_SHOULD_SUPPORT_MORE_OPTION_AS_MAX_SAID
		trRow.dVals				= vInsertStatsResult;
		///Arvin 08/31/07 QA70-7651-P17 WRONG_COLUMN_DESIGNATION_TYPE
		trRow.SetAttribute(STR_COL_DESIGNATION_ATTRIB, nDesignation);
		///END WRONG_COLUMN_DESIGNATION_TYPE
		///Cheney 2007-11-14 STATS_ON_ROW_SHOULD_SUPPORT_MORE_OPTION_AS_MAX_SAID
		if(bPecentile && pPercentsAttrib)
			trRow.SetAttribute(DOUBLE_PERCENTILE_PERCENT_ATTRIBUTE, *pPercentsAttrib);
		///end STATS_ON_ROW_SHOULD_SUPPORT_MORE_OPTION_AS_MAX_SAID
	}
	///end SPEED_UP_STATISTIC_ON_ROW
};

void mkdsdata(int npts = 100, bool b2Factor=true)
{
	Worksheet wks = Project.ActiveLayer();
	wks.SetSize(npts, b2Factor? 3:2);
	
	Dataset aa(wks, 0);
	aa.SetSize(npts);
	string str;
	double r1;
	for(int ii = 0; ii < npts; ii++)
	{
		r1 = rnd();
		aa[ii] = 100 * rnd() + ii * 0.1;
		str = r1 > 0.5? "Male" : "Female";
		if(r1 > 0.5)
			aa[ii] += 15*rnd();
		wks.SetCell(ii, 1, str);
		if(b2Factor)
		{
			r1 = rnd();
			str = r1 > 0.5? "40-69" : "20-39";
			wks.SetCell(ii, 2, str);
			if(r1 < 0.5)
				aa[ii] += 10*rnd();				
		}
	}
	Column ca(wks, 0);
	ca.SetLongName("Driver Safety Index");
	Column cb(wks, 1);
	cb.SetLongName("Gender");
	if(b2Factor)
	{
		Column cc(wks, 2);
		cc.SetLongName("Age Group");
	}
}


