/*------------------------------------------------------------------------------*
 * File Name: ANOVATwoWay				 										*
 * Creation: 																	*
 * Purpose: OriginC Source C file implementing Two Way ANOVA operation			*
 * Copyright (c) ABCD Corp.	2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010		*
 * All Rights Reserved															*
 * 																				*
 * Modification Log:															*
 *	YuI 12/07/04 v7.5172 PICTURE_IN_REPORT_IMPROVEMENT							*
 *  Iris 12/22/04 CLEANUP_AND_USE_BASE_CLASS_FIX								*
 *  Iris 12/30/04 CLEANP_UP_GRAPH_CODES											*
 *  Iris 3/22/05 ADD_MORE_MEAN_COMPARISON_CASE									*
 *	ML 10/20/2005 ANOVA_INPUT_DATA_TO_DATARANGE									*
 *	ML 10/24/2005 ANOVAS_INDEXED_RAW											*
 *	ML 10/25/2005 MUST_CLEAN_UP_CACHED_STUFF									*
 *  Jim 3/10/06 ADD_TABLE_FOOTNOTE												*
 *	CPY 10/14/06 SEPARATE_OUT_OPERATION_BASE_INTO_SEPARATE_HEADER				*
 *  Iris 11/01/06 v8.0502d NO_COL_LABEL_IN_POWER_TABLE							* 
 *	Echo 2/7/07 ADD_ERROR_REPORT												*
 *  Iris 05/11/2007 v8.0616 USE_REAL_FACTOR_COL_NAME_REPLACE_FACTORA_FACTORB    *
 *	Cheney 2007-6-7 SHOULD_CHECK_EVENT_ID_IN_EVENT_FUNC							*
 *	Arvin 07/26/07 v8.0668 THE_WORD_SIGNIFICANTLY_SHOULD_BE_SIGNIFICANT			*
 *	Arvin 08/09/07 QA70-7100 ADD_ERROR_MESSAGE									*
 *	Arvin 08/09/07 QA70-7100 P15-L3 WRONG_POWER_ANALYSIS_TABLE					*
 *	Arvin 09/30/07 HIDE_DOF_COL_FOR_MEAN_COMP_TABLE as max said					*
 *	Arvin 09/30/07 SHOULD_GET_LABEL_WITH_INDEXCOMP_FOR_BONHOLM_AND_SIDAKHOLM as max said
 *	Arvin 10/17/07 CLEAN_ANOVA_TOOLS_CODE										*
 *	Arvin 10/27/07 LOCALIZED_FOOTNOTES_STRINGS									*
 *	Arvin 11/16/07 QA70-10669 IMPROVE_TABLES_ROW_LABELS_FOR_ANOVA_TOOLS			*
 *	Echo 11/28/07 FOOTNOTE_FORMAT_NOT_CORRECT									*
 *	Folger 12/10/07 CLEAN_NEGATIVE_ERROR_MESSAGES								*
 *	Echo 11/27/08 QA70-12862 v8.0981 ANOVA2_RAW_DATA_NOT_REQUIRE_BALANCE_DESIGNED*
 *  Iris 2/25/2009 REPEAT_ID_CAUSE_JUNK_RANGE_STR_AFTER_SET_AU_TO_NONE			*
 *	Hong 09/04/09 QA80-14258 HISTOGRAM_NEED_SPECIAL_HINT_FOR_DOING_NLFITTING	*
 *  Jacky 07/22/10 ORG-102 USER_CAN_SET_SIGNIFICANCE_LEVEL						*
 *------------------------------------------------------------------------------*/
 
#include <Origin.h>
#include <event_utils.h>
#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 "nlsf_utils.h" /// Iris 7/08/2008 CLEAN_DUP_CALC_AVE_DATA_CODE_IN_NLSF_PREVIEW_AND_OP
#include "graph_utils.h" //---- Iris 11/19/2008 v8.0975 QA80-12591-P2 FIX_APPARENT_FIT_ON_GRAPH_CUSTOM_RANGE_GET_INCORRECT_X
#endif

#include <xfutils.h>
#include "StatsOpCommon.h"  ///Iris 12/22/04 CLEANUP_AND_USE_BASE_CLASS_FIX
#include "StatsOpBase.h"
#include "ANOVATwoWay.h"

////////////////////////////////////////////////////////////////////////////////////
// Start your functions here.
enum{ CALC_ACTUAL_POWER, CALC_BOTH_POWER };
enum{ CALC_FACTORA_POWER, CALC_FACTORB_POWER, CALC_INTERACTION_POWER };
enum{ GRAPH_STATS_FACTORA_MEANS, GRAPH_STATS_FACTORB_MEANS, GRAPH_STATS_FACTORAB_MEANS};  ///Iris 12/30/04 CLEANP_UP_GRAPH_CODES

///Cheney 2007-10-27 CLEAN_UP_LOCALIZATION_THINGS
//#define     DESC_FACTORS		"FactorA|FactorB|OverAll|Interaction"
//#define     ANOVA_FACTORS		"FactorA|FactorB|Interaction|Model|Error|Corrected Total"
#define     DESC_FACTORS		_L("FactorA|FactorB|OverAll|Interaction")
#define     ANOVA_FACTORS		_L("FactorA|FactorB|Interaction|Model|Error|Corrected Total")
///end CLEAN_UP_LOCALIZATION_THINGS
#define		ANOVA2_TABLE_SIZE	6

/// Iris 12/27/05 CONSTRUCT_RM_BASE_CLASS  move to base class
/////Iris 12/22/04 CLEANUP_AND_USE_BASE_CLASS_FIX
//BOOL 	ANOVATwoWay::Construct(TreeNode& trOperation, int nOption)
//{
	//if( WksReportOperation::Construct(trOperation, nOption) )
	//{
		//TreeNode 	trOut = trOperation.Calculation; 
		//
		////trOut.DescStat.ID = IDST_ANOVA_DESC_STATS;
		//
		//TreeNode	trGUI = ConstructAddGUI(trOperation);			
//
		///// YuI 09/26/05 ANOVA_DATA_SELECTION_GUI
		////	ConstructTwoWayANOVAGUITree(trGUI, nOption);
		//ConstructTwoWayANOVAGUITree(trGUI, nOption, IsRM());
		///// end ANOVA_DATA_SELECTION_GUI
		//
		/////Iris 4/06/05 INIT_GRAPH_NUMBER
		////ConstructAddReportCommon(trOperation, 0, IDST_OUTPUT_RESULTS_OPTIONS, true, 3);
		////ConstructAddReportCommon(trOperation, 0, IDST_OUTPUT_RESULTS_OPTIONS, true, 0);
		//ConstructAddReportCommon(trOperation, 0, IDST_OUTPUT_RESULTS_OPTIONS, true);
		/////---
		//
		//Operation::ConstructAddCommonBottom(trGUI);
		//
//
		//return TRUE;
	//}
//}
///End CONSTRUCT_RM_BASE_CLASS

///Echo 2/7/07 ADD_ERROR_REPORT

static int anovatwoway_event1(TreeNode& tr, int nRow, int nEvent, DWORD& dwEnables, LPCSTR lpcszNodeName, WndContainer& getNCountainer, string& strAux, string& strErrMsg)
{
	DECLARE_BUTTON_ENABLES   //support more buttons enable/disable
	
	///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)
	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
	{
		DataRange drData;
		drData.Create();
		bool bRaw = tr.InputData.Use;
		int nOption = bRaw ? DRTREE_ANOVA_TWO_WAY_RAW : DRTREE_ANOVA_TWO_WAY_INDEXED;
		drData.SetTree(tr.InputData, nOption);
		
		int nLevels;
		if (tr.InputData.Factor0.Levels && tr.InputData.Factor1.Levels) nLevels = tr.InputData.Factor0.Levels.GetNodeCount()*tr.InputData.Factor1.Levels.GetNodeCount();
		///Echo 11/27/08 QA70-12862 v8.0981 ANOVA2_RAW_DATA_NOT_REQUIRE_BALANCE_DESIGNED
		//int nErr = bRaw ? check_data_in_var(drData, nLevels, true) : anova2_check_data(drData);
		int nErr = bRaw ? check_data_in_var(drData, nLevels, false) : anova2_check_data(drData);
		///end ANOVA2_RAW_DATA_NOT_REQUIRE_BALANCE_DESIGNED
		
		int nRaw = tr.InputData.Use;
		/// Iris 05/10/2007 v8.0615 REMOVE_BRANCH_CHECK_BOX
		//if ( tr.MeansComp.Use && !check_sig_level( tr.MeansComp.SigLevel.dVal) )
		//--- Jacky 07/22/10 ORG-102 USER_CAN_SET_SIGNIFICANCE_LEVEL
		if(CER_NO_ERROR == nErr && !check_sig_level(tr.alpha.dVal))
		{
			nErr = CER_INVALID_SIG_LEV;
		}
		//--- end USER_CAN_SET_SIGNIFICANCE_LEVEL
		int nCount = 0;
		foreach(TreeNode trN in tr.MeansComp.Children)
		{
			if(trN.ID == TRGP_CHECK && 0 != trN.nVal)
			{
				nCount++;
			}
		}
		if(0 != nCount && !check_sig_level( tr.MeansComp.SigLevel.dVal) )
		///end REMOVE_BRANCH_CHECK_BOX
		{
			nErr = CER_INVALID_SIG_LEV;
		}
		
		///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 4/11/2008 ADD_OUTPUT_ERR_STRING
		if (nErr != CER_NO_ERROR)
		{
			bOKEnable = false;
			strErrMsg = nErr;
			if( !strRet.IsEmpty() )
			{
				strErrMsg += ":" + strRet; 
			}
		}
		///end ADD_OUTPUT_ERR_STRING
		
		/// Iris 5/27/2008 UPDATE_REPORT_BOOK_SHEET_COMBO_ON_SOURCE_CHANGE, if source book/sheet changed, source book/sheet name should update relative
		#ifdef _MOVE_FIT_OUTPUT_TO_OC_CLASS 
		OutputGUIManagerBase* 	pOutputManager = get_output_GUI_manager_pointer(tr);
		if(pOutputManager)
			pOutputManager->UpdateOutputOnDataChange(tr);
		#endif //_MOVE_FIT_OUTPUT_TO_OC_CLASS
		///end UPDATE_REPORT_BOOK_SHEET_COMBO_ON_SOURCE_CHANGE

	}
	return true;
	

}

//virtual 
PEVENT_GETN ANOVATwoWay::GetNewEventFunction()
{
	return anovatwoway_event1;
}
///end ADD_ERROR_REPORT


string ANOVATwoWay::GetClassName()
{
	return "ANOVATwoWay";
}
	
/// Iris 3/21/2008 v8.0829 QA80-10934 ADD_EDITBOX_TO_SPECIFICATION_BOOK_SHEET_NAME, want GUI tree as input in DescStats::GetResultSheetName
//string 	ANOVATwoWay::GetResultSheetName() 
string 		ANOVATwoWay::GetResultSheetName(TreeNode& trGUI)
///end ADD_EDITBOX_TO_SPECIFICATION_BOOK_SHEET_NAME
{
	///Cheney 2007-10-27 CLEAN_UP_LOCALIZATION_THINGS
	//return "ANOVA2Way";
	return STR_ANOVA_2_WAY_REPORT_TABLE_SHEET_NAME;
	///end CLEAN_UP_LOCALIZATION_THINGS
}

//virtual 
string 	ANOVATwoWay::GetResultBookName(TreeNode& trGUI)
{
	return E_STR_ANOVA_2_WAY_REPORT_TABLE_BOOK_SHORT_NAME;
}


int ANOVATwoWay::GetResultCurvesID() { return 0;}

/// Iris 12/27/05 CONSTRUCT_RM_BASE_CLASS, move to base class
///// ML 10/20/2005 ANOVA_INPUT_DATA_TO_DATARANGE
//// virtual
//int		ANOVATwoWay::GetDRTreeOption(TreeNode &trOperation)
//{
	///// ML 10/26/2005 QA70-8225 ESCAPED_OPER_STRINGS_ANOVAS
	///*
	//TreeNode	trInputData = trOperation.GUI.InputData;
	//int			nDRTreeOption = DRTREE_DEFAULT;
	//switch( trInputData.Use )
	//{
	//case ANOVA_RAW_DATA:
		//nDRTreeOption = DRTREE_ANOVA_TWO_WAY_RAW;
		//break;
		//
	//case ANOVA_INDEXED_DATA:
		//nDRTreeOption = DRTREE_ANOVA_TWO_WAY_INDEXED;
		//break;
	//default:
		//ASSERT(FALSE);
	//}
	//
	//return nDRTreeOption;
	//*/
	//
	//int			nDRTreeOption = IsIndexedData(trOperation) ? DRTREE_ANOVA_TWO_WAY_INDEXED : DRTREE_ANOVA_TWO_WAY_RAW;
	//return nDRTreeOption;
	///// end ESCAPED_OPER_STRINGS_ANOVAS
//}
///// end ANOVA_INPUT_DATA_TO_DATARANGE
///End CONSTRUCT_RM_BASE_CLASS

//---- CPY 5/15/05 CONSOLIDATE_INIT_INPUT_DATA_RANGE
/*
// virtual
DWORD GetDataRules(const TreeNode& trOp, bool bIgnoreCombineInfo = false)
{
	DWORD dwRet =  DRR_GET_MISSING;
	return dwRet;
}*/	

//virtual
bool 	ANOVATwoWay::GetCustomGraphTypeName(string& strName, int nIndex)
{			
	switch(nIndex)
	{
	case GRAPH_STATS_FACTORA_MEANS:
		strName = _L("Means plot of Data by FactorA");
		break;
	case GRAPH_STATS_FACTORB_MEANS:
		strName = _L("Means plot of Data by FactorB");
		break;
	case GRAPH_STATS_FACTORAB_MEANS:
		strName = _L("Means plot of Data by FactorA and FactorB");
		break;
	default:
		return false;
	}
	
	return true;
}	


void 	ANOVATwoWay::UpdateReportingTables(TreeNode &trOperation, int nTotalNumData, int nExeMode)
{
	WksReportOperation::UpdateReportingTables(trOperation, nTotalNumData, nExeMode);		
	
	//DescStat
	/// Iris 05/11/1007 v8.0616 STATS_ANOVA_TABLE_SHOULD_BE_OPENED
	//UpdateTableString(trOperation.Calculation.Statistics, true);
	UpdateTableString(trOperation.Calculation.Statistics, true, true, atoi(GetTableStringMain(false)), atoi(GetTableStringMain(false)) );
	///end STATS_ANOVA_TABLE_SHOULD_BE_OPENED
	
	//ANOVA
	/// Iris 05/11/1007 v8.0616 STATS_ANOVA_TABLE_SHOULD_BE_OPENED
	//if(!UpdateTableString(trOperation.Calculation.ANOVAs, true))
	if(!UpdateTableString(trOperation.Calculation.ANOVAs, true, true, atoi(GetTableStringMain(false)), atoi(GetTableStringMain(false))  ))
	///end STATS_ANOVA_TABLE_SHOULD_BE_OPENED
		error_report("ANOVA Two Way found invalid Calculation.ANOVAs node");

	//ANOVA.MeanComp
	UpdateTableString(trOperation.Calculation.ANOVAs.MeanComp, true);

	///Jim 3/15/06 v8.0374 ADD_TABLE_FOOTNOTE
	trOperation.Calculation.ANOVAs.MeanComp.Footnote.RemoveAttribute(TREE_Table);
	///END ADD_TABLE_FOOTNOTE
	
	//ANOVA.Powers
	UpdateTableString(trOperation.Calculation.ANOVAs.Powers, true);
	
	///Iris 12/30/04 CLEANP_UP_GRAPH_CODES
	//Wks data for MeansFactorA, MeansFactorB, MeansFactorAB plot
	TreeNode trTable;
	trTable = trOperation.Calculation.MeanFactorAPlot;
	if(trTable)
		trTable.SetAttribute(TREE_Table, GetTableStringDatasets());
	
	trTable = trOperation.Calculation.MeanFactorBPlot;
	if(trTable)
		trTable.SetAttribute(TREE_Table, GetTableStringDatasets());
	
	trTable = trOperation.Calculation.MeanFactorABPlot;
	if(trTable)
		trTable.SetAttribute(TREE_Table, GetTableStringDatasets());
	///end CLEANP_UP_GRAPH_CODES		
}
///End CLEANUP_AND_USE_BASE_CLASS_FIX


//virtual
BOOL	ANOVATwoWay::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)   
{
	/// ML 10/24/2005 ANOVAS_INDEXED_RAW
	//getDependentData(vData);
	//if(!getFactors(vstrFactors, vData.GetSize()))
	//	return false;
	getDependentData(vData);
	
	if (DRTREE_ANOVA_TWO_WAY_RAW == GetDRTreeOption(trOp))
	{
		// If raw, then factor values are not obtained from the DataRange, but are instead defined by user
		// in GUI and stored in the tree.
		ASSERT(0 == vstrFactors.GetSize());
		vstrFactors.SetSize(2);
		TreeNode	trInput = trOp.GUI.InputData;		
		TreeNode	trLevels0 = trInput.Factor0.Levels;		
		TreeNode	trLevels1 = trInput.Factor1.Levels;		
		int			nLevels0 = trLevels0.GetNodeCount();
		int			nLevels1 = trLevels1.GetNodeCount();
		
		int			nLevel0 = index / nLevels1;
		int			nLevel1 = index % nLevels1;
		
		TreeNode	trLevel0 = trLevels0.Children.Item(nLevel0);
		TreeNode	trLevel1 = trLevels1.Children.Item(nLevel1);
		vstrFactors[0] = trLevel0.strVal;
		vstrFactors[1] = trLevel1.strVal;
	}
	
	///Arvin 08/27/07 TRIM_FACTORS_AND_DATA_ARE_ALL_MISSING_VALUE_ROWS
	if(vData.GetSize() >= 1)
	{
	///end 	TRIM_FACTORS_AND_DATA_ARE_ALL_MISSING_VALUE_ROWS
		if(!getFactors(vstrFactors, vData.GetSize()))
			return false;
	} ///Arvin 08/27/07 TRIM_FACTORS_AND_DATA_ARE_ALL_MISSING_VALUE_ROWS
	/// end ANOVAS_INDEXED_RAW
	
	if(index < nTotalNumData - 1)
	{		
		return TRUE;
	}
	
	addResultsToReportTree(trOp, nTotalNumData);

	return TRUE;		
}

/// ML 10/25/2005 MUST_CLEAN_UP_CACHED_STUFF
// virtual
void	ANOVATwoWay::OnAfterCalculations(TreeNode& trOp)
{
	ANOVAReportOperation::OnAfterCalculations(trOp);
	
	m_vnFactorA.SetSize(0);
	m_vnFactorB.SetSize(0);
	m_vData.SetSize(0);
	m_vsFactors.SetSize(0);
	m_vnFactorB.SetSize(0);
}
/// end MUST_CLEAN_UP_CACHED_STUFF

void	ANOVATwoWay::getDependentData(const vector& vData)
{
	m_vData.Append(vData);
}	


bool	ANOVATwoWay::getFactors(const vector<string> &vstrFactors, int nDataSize)
{
	if(0 == vstrFactors.GetSize())
		return false;
	int nLoop;
	
	int nFactorA = m_vsFactors.Find(vstrFactors[0]);
	if( -1 == nFactorA)
		nFactorA = m_vsFactors.Add(vstrFactors[0]);
	for( nLoop=0; nLoop<nDataSize; nLoop++)
		m_vnFactorA.Add(nFactorA+1);
	
	int nFactorB = m_vsFactors2.Find(vstrFactors[1]);
	if(-1 == nFactorB)
		nFactorB = m_vsFactors2.Add(vstrFactors[1]);
	for( nLoop=0; nLoop<nDataSize; nLoop++)
		m_vnFactorB.Add(nFactorB+1);
	
	return true;
	
}


BOOL	ANOVATwoWay::addResultsToReportTree(TreeNode &trOp, int nDataGroups)
{	
	ANOVA2Table*	parANOVA2Table = (ANOVA2Table*) calloc(ANOVA2_TABLE_SIZE, sizeof(ANOVA2Table));

	GetFactors(trOp); 	/// Iris 05/11/2007 v8.0616 USE_REAL_FACTOR_COL_NAME_REPLACE_FACTORA_FACTORB

	if( 1 != addDescStatsTable(trOp, parANOVA2Table))  //1: fail to calc ANOVA2Table
	{
		addANOVAsTable(trOp, parANOVA2Table, ANOVA2_TABLE_SIZE, nDataGroups);
		
		/// Iris 05/10/2007 v8.0615 REMOVE_BRANCH_CHECK_BOX
		//if( trOp.GUI.PowerBranch.Use )
		///end REMOVE_BRANCH_CHECK_BOX
			addPowersResult(trOp, parANOVA2Table, nDataGroups);
	}

	free(parANOVA2Table);
	return TRUE;
}

void	ANOVATwoWay::addANOVAsTable(TreeNode &trOp, ANOVA2Table*	parANOVA2Table, int nSize, int nDataGroups)
{
	addOverallANOVA(trOp, parANOVA2Table, nSize);		
	
	addANOVATwoWayMeansComparison(trOp, parANOVA2Table, nSize);
	
	//addPowersResult(trOp, parANOVA2Table, nDataGroups);
	
}

void 	ANOVATwoWay::sortFactors()
{
 	Worksheet wks;
 	wks.Create("origin", CREATE_HIDDEN);
	wks.AddCol();
    Dataset dsFactorA(wks,0);
    Dataset dsFactorB(wks,1);
    Dataset dsData(wks,2);
    
    dsFactorA = m_vnFactorA;
    dsFactorB = m_vnFactorB;
    dsData = m_vData;
    vector<int> vnCol = {0, 1};
    vector<int> vnSort = {SORT_ASCENDING, SORT_ASCENDING};
    wks.Sort(vnCol, vnSort);
    
    m_vnFactorA = dsFactorA;
    m_vnFactorB = dsFactorB;
    m_vData = dsData;
	
    wks.Destroy();    	
}

int 	ANOVATwoWay::addDescStatsTable(TreeNode &trOp, ANOVA2Table* parANOVA2Table)
{
 	int		iInteractions = trOp.GUI.Interactions.nVal;
 	int		iLevelsA = m_vsFactors.GetSize();
 	int		iLevelsB = m_vsFactors2.GetSize();
 	
 	//calc descriptive
 	ANOVA2DescStats*		pstDescStatsA;
 	pstDescStatsA = (ANOVA2DescStats*)calloc(iLevelsA, sizeof(ANOVA2DescStats) );
 	
 	ANOVA2DescStats*		pstDescStatsB;
 	pstDescStatsB = (ANOVA2DescStats*)calloc(iLevelsB, sizeof(ANOVA2DescStats) );
 	
 	ANOVA2DescStats			stDescStatsTo;
 	
 	ANOVA2DescStats*		pstDescStatsAB;
 	pstDescStatsAB = (ANOVA2DescStats*)calloc(iLevelsA * iLevelsB, sizeof(ANOVA2DescStats) );

 	///Echo 3/31/07 SORT_DATA_TO_BE_CORRECT_ORDER
    sortFactors();
    ///end SORT_DATA_TO_BE_CORRECT_ORDER
    
 	int nRet;
 	nRet = stats_anova_two_way_compute_anova_table(iInteractions, m_vnFactorA, iLevelsA, 
 					m_vnFactorB, iLevelsB,	m_vData, pstDescStatsA, pstDescStatsB, 
 					stDescStatsTo, pstDescStatsAB, parANOVA2Table);
 	
 	
 	//setup DescStat table
 	TreeNode 	trSubLevel = tree_check_get_node(trOp.Calculation, TABLE_DESC_STATS, IDST_ANOVA2_DESC_STATS_SUBLEVEL, STR_LABEL_ATTRIB, _L("Descriptive Statistics"));
 	
 	if(0 != nRet)
 	{
 		//Err info function
 		///Arvin 08/09/07 QA70-7100 ADD_ERROR_MESSAGE
 		//addErrInfoDescSrtats(trSubLevel, IDST_ANOVA2_DESC_STATS_SUBLEVEL ,nRet); //if error happen, make DescStat node as table
 		TreeNode trTable = tree_check_get_node(trSubLevel, "Error", IDST_ANOVA2_DESC_STATS_SUBLEVEL, STR_LABEL_ATTRIB, _L("Attention!"));
 		///Arvin 10/17/07 CLEAN_ANOVA_TOOLS_CODE
 		//addErrInfoDescSrtats(trTable, IDST_ANOVA2_DESC_STATS_SUBLEVEL ,nRet); //if error happen, make DescStat node as table
 		AddErrInfoToTable(trTable, IDST_ANOVA2_DESC_STATS_SUBLEVEL, nRet, false); //if error happen, make DescStat node as table
		///end CLEAN_ANOVA_TOOLS_CODE
 		///end ADD_ERROR_MESSAGE
 		free(pstDescStatsA);
 		free(pstDescStatsB);
 		free(pstDescStatsAB);	 		
 		return 1; 	//fail to calc
 	}
 	
	if(  !trOp.GUI.DescStats.FactorA.nVal &&
		 !trOp.GUI.DescStats.FactorB.nVal &&
		 !trOp.GUI.DescStats.Overall.nVal &&
		 !trOp.GUI.DescStats.Interaction.nVal )
	{
		trOp.Calculation.RemoveChild(trSubLevel);
		free(pstDescStatsA);
 		free(pstDescStatsB);
 		free(pstDescStatsAB); 
	 	return 2;	//no need desc stats table
	}	 	
 	
 	vector<string> vsFactors;
 	string strFactors = DESC_FACTORS;
 	strFactors.GetTokens(vsFactors, '|');
 	
 	TreeNode	trTable, trRow;
 	int			nRow;
 	
 	//Add FactorA Table
 	if( trOp.GUI.DescStats.FactorA.nVal )
 	{
	 	trTable = tree_check_get_node(trSubLevel, vsFactors[0], IDST_ANOVA2_DESC_STATS_FACTORA_TABLE, STR_LABEL_ATTRIB, m_strFactor);
	 	for(nRow=0; nRow<iLevelsA; nRow++)
	 	{
		 	trRow = check_add_enumerated_node(trTable, "Row", nRow+1, IDST_TEMP_ONE_SET, STR_LABEL_ATTRIB, m_vsFactors[nRow]);
		 	trRow += pstDescStatsA[nRow];
		 	trRow.ID = make_one_set_ID(IDST_ANOVA2_DESC_STATS_FACTORA_TABLE, nRow);
			///Sophy 3/30/2009 QA80-13352 SUPPORT_SPECIFY_COLUMN_DESIGNATIONS_IN_REPORT_TABLES
			tree_set_attribute_to_all_nodes(trRow, STR_COL_DESIGNATION_ATTRIB, (string)OKDATAOBJ_DESIGNATION_Y);
			if ( trRow.SD )
				trRow.SD.SetAttribute(STR_COL_DESIGNATION_ATTRIB, OKDATAOBJ_DESIGNATION_ERROR);
			if ( trRow.SEM )
				trRow.SEM.SetAttribute(STR_COL_DESIGNATION_ATTRIB, OKDATAOBJ_DESIGNATION_ERROR);
			///end SUPPORT_SPECIFY_COLUMN_DESIGNATIONS_IN_REPORT_TABLES

		 	updateDescTableLabels(trRow);
	 	}
	 	
	 	addWksTableMeanFactorA(trOp, pstDescStatsA, iLevelsA, isCreateGraph(trOp, GRAPH_STATS_FACTORA_MEANS));
	 	
 	}
 	
 	//Add FactorB Table
 	if( trOp.GUI.DescStats.FactorB.nVal )
 	{
	 	trTable = tree_check_get_node(trSubLevel, vsFactors[1], IDST_ANOVA2_DESC_STATS_FACTORB_TABLE, STR_LABEL_ATTRIB, m_strFactor2);
	 	for(nRow=0; nRow<iLevelsB; nRow++)
	 	{
		 	trRow = check_add_enumerated_node(trTable, "Row", nRow+1, IDST_TEMP_ONE_SET, STR_LABEL_ATTRIB, m_vsFactors2[nRow]);
		 	trRow += pstDescStatsB[nRow];
		 	trRow.ID = IDST_ANOVA2_DESC_STATS_FACTORB_TABLE + nRow;
			///Sophy 3/30/2009 QA80-13352 SUPPORT_SPECIFY_COLUMN_DESIGNATIONS_IN_REPORT_TABLES
			tree_set_attribute_to_all_nodes(trRow, STR_COL_DESIGNATION_ATTRIB, (string)OKDATAOBJ_DESIGNATION_Y);
			if ( trRow.SD )
				trRow.SD.SetAttribute(STR_COL_DESIGNATION_ATTRIB, OKDATAOBJ_DESIGNATION_ERROR);
			if ( trRow.SEM )
				trRow.SEM.SetAttribute(STR_COL_DESIGNATION_ATTRIB, OKDATAOBJ_DESIGNATION_ERROR);
			///end SUPPORT_SPECIFY_COLUMN_DESIGNATIONS_IN_REPORT_TABLES
		 	updateDescTableLabels(trRow);
	 	}
	 	addWksTableMeanFactorB(trOp, pstDescStatsB, iLevelsB, isCreateGraph(trOp, GRAPH_STATS_FACTORB_MEANS));
 	}
 	
 	//Add Overall Table
 	if( trOp.GUI.DescStats.Overall.nVal )
 	{
	 	trTable = tree_check_get_node(trSubLevel, vsFactors[2], IDST_ANOVA2_DESC_STATS_FACTORTO_TABLE, STR_LABEL_ATTRIB, _L("Overall"));
		trRow = tree_check_get_node(trTable, "Row", IDST_TEMP_ONE_SET, STR_LABEL_ATTRIB, " ");
	 	trRow += stDescStatsTo;
	 	trRow.ID = IDST_ANOVA2_DESC_STATS_FACTORTO_TABLE + 1;
		///Sophy 3/30/2009 QA80-13352 SUPPORT_SPECIFY_COLUMN_DESIGNATIONS_IN_REPORT_TABLES
		tree_set_attribute_to_all_nodes(trRow, STR_COL_DESIGNATION_ATTRIB, (string)OKDATAOBJ_DESIGNATION_Y);
		if ( trRow.SD )
			trRow.SD.SetAttribute(STR_COL_DESIGNATION_ATTRIB, OKDATAOBJ_DESIGNATION_ERROR);
		if ( trRow.SEM )
			trRow.SEM.SetAttribute(STR_COL_DESIGNATION_ATTRIB, OKDATAOBJ_DESIGNATION_ERROR);
		///end SUPPORT_SPECIFY_COLUMN_DESIGNATIONS_IN_REPORT_TABLES
	 	updateDescTableLabels(trRow);
 	}
 	
 	//Add FactorA * Factor B Table
 	if( trOp.GUI.DescStats.Interaction.nVal )
 	{
	 	trTable = tree_check_get_node(trSubLevel, vsFactors[3], IDST_ANOVA2_DESC_STATS_FACTORAB_TABLE, STR_LABEL_ATTRIB, _L("Interaction"));
	 	for(nRow=0; nRow<iLevelsA; nRow++)
	 		for(int nSubRow=0; nSubRow<iLevelsB; nSubRow++)
		 	{
		 		int index = nRow* iLevelsB + nSubRow;
			 	trRow = check_add_enumerated_node(trTable, "Row", index+1, IDST_TEMP_ONE_SET, STR_LABEL_ATTRIB, m_vsFactors[nRow]);
			 	tree_add_one_label(trRow, m_vsFactors2[nSubRow], 0);
			 	trRow += pstDescStatsAB[index];
			 	trRow.ID = IDST_ANOVA2_DESC_STATS_FACTORAB_TABLE + index +1;
				///Sophy 3/30/2009 QA80-13352 SUPPORT_SPECIFY_COLUMN_DESIGNATIONS_IN_REPORT_TABLES
				tree_set_attribute_to_all_nodes(trRow, STR_COL_DESIGNATION_ATTRIB, (string)OKDATAOBJ_DESIGNATION_Y);
				if ( trRow.SD )
					trRow.SD.SetAttribute(STR_COL_DESIGNATION_ATTRIB, OKDATAOBJ_DESIGNATION_ERROR);
				if ( trRow.SEM )
					trRow.SEM.SetAttribute(STR_COL_DESIGNATION_ATTRIB, OKDATAOBJ_DESIGNATION_ERROR);
				///end SUPPORT_SPECIFY_COLUMN_DESIGNATIONS_IN_REPORT_TABLES
			 	updateDescTableLabels(trRow);
		 	}
	 	addWksTableMeanFactorAB(trOp, pstDescStatsAB, iLevelsA * iLevelsB, isCreateGraph(trOp, GRAPH_STATS_FACTORAB_MEANS));
 	}	 	
 	
	free(pstDescStatsA);
	free(pstDescStatsB);
	free(pstDescStatsAB);
	
	return 0;	 
}

void 	ANOVATwoWay::updateDescTableLabels(TreeNode& trRow)
{
	trRow.N.SetAttribute(STR_LABEL_ATTRIB, _L("N"));
	trRow.Mean.SetAttribute(STR_LABEL_ATTRIB, _L("Mean"));
	trRow.SD.SetAttribute(STR_LABEL_ATTRIB, _L("SD"));
	trRow.SEM.SetAttribute(STR_LABEL_ATTRIB, _L("SEM"));
	trRow.VAR.SetAttribute(STR_LABEL_ATTRIB, _L("Variance"));
	trRow.Missing.SetAttribute(STR_LABEL_ATTRIB, _L("Missing"));
	trRow.NonMissing.SetAttribute(STR_LABEL_ATTRIB, _L("NonMissing"));
	
}
///Iris 2/16/05 BASE_CALSS_FUNCTION_INSTEAD_ADD_DESCSTAT_TABLE
/*
void    addOverallANOVAHeaderLabel(TreeNode& trRow)
{
	vector<string> vsLabels = {"DoF", "Sum of Squares", "Mean Square", "F Value", "P Value"};
	if(trRow.Children.Count() != vsLabels.GetSize())
		return;
	
	int 	index = 0;
	foreach(TreeNode tr in trRow.Children)
	{
		tr.SetAttribute(STR_LABEL_ATTRIB, vsLabels[index++]);
	}
	
}	
*/
///End BASE_CALSS_FUNCTION_INSTEAD_ADD_DESCSTAT_TABLE

///Arvin 11/16/07 QA70-10669 IMPROVE_TABLES_ROW_LABELS_FOR_ANOVA_TOOLS
int	ANOVATwoWay::getOverallANOVATableRowLabels(vector<string>& vstrLabels)
{
	vstrLabels.SetSize(0);
	vstrLabels.Add(m_strFactor);
	vstrLabels.Add(m_strFactor2);
	vstrLabels.Add(_L("Interaction"));
	vstrLabels.Add(_L("Model"));
	vstrLabels.Add(_L("Error"));
	vstrLabels.Add(_L("Corrected Total"));
	return vstrLabels.GetSize();
}
///end 	IMPROVE_TABLES_ROW_LABELS_FOR_ANOVA_TOOLS

BOOL	ANOVATwoWay::addOverallANOVA(TreeNode &trOp, ANOVA2Table* parANOVA2Table, int nSize)
{
	TreeNode	trANOVA = tree_check_get_node(trOp.Calculation, "ANOVAs", IDST_ANOVAS, STR_LABEL_ATTRIB, _L("ANOVA"));
	TreeNode 	trTable = tree_check_get_node(trANOVA, "OverallANOVA", IDST_ANOVA2_OVERALL_TABLE, STR_LABEL_ATTRIB, _L("Overall ANOVA"));		
	
	vector<string> vsFactors;
	///Arvin 11/16/07 QA70-10669 IMPROVE_TABLES_ROW_LABELS_FOR_ANOVA_TOOLS
	//string 		strFactors = ANOVA_FACTORS;
	//int 		nFactorSize = strFactors.GetTokens(vsFactors, '|');
	//if( nSize != nFactorSize)
	//	return FALSE;
	int nFactorSize = getOverallANOVATableRowLabels(vsFactors);
	if(nSize != nFactorSize)
		return FALSE;
	///end IMPROVE_TABLES_ROW_LABELS_FOR_ANOVA_TOOLS
	
	TreeNode trInteraction = trOp.GUI.Interactions;
	for(int nRow = 0; nRow < nFactorSize; nRow++)
	{
		//if Interaction check box is unchecked, then no need show Interaction row in the table
		///Arvin 11/16/07 QA70-10669 IMPROVE_TABLES_ROW_LABELS_FOR_ANOVA_TOOLS
		//if(0 == vsFactors[nRow].Compare("Interaction") && 0 == trInteraction.nVal)
		if(compare_string_localization(vsFactors[nRow], "Interaction", true) && 0 == trInteraction.nVal)
		///end 	IMPROVE_TABLES_ROW_LABELS_FOR_ANOVA_TOOLS
			continue;
		
		///Arvin 11/16/07 QA70-10669 IMPROVE_TABLES_ROW_LABELS_FOR_ANOVA_TOOLS
		
		TreeNode trRow = tree_check_get_node( trTable, "Row"+nRow, IDST_TEMP_ONE_SET, STR_LABEL_ATTRIB, vsFactors[nRow]);
		trRow += parANOVA2Table[nRow];
		trRow.ID = make_one_set_ID(IDST_ANOVA2_OVERALL_TABLE, nRow+1);
		///Sophy 3/30/2009 QA80-13352 SUPPORT_SPECIFY_COLUMN_DESIGNATIONS_IN_REPORT_TABLES
		tree_set_attribute_to_all_nodes(trTable, STR_COL_DESIGNATION_ATTRIB, (string)OKDATAOBJ_DESIGNATION_Y);
		if ( trTable.SD )
			trTable.SD.SetAttribute(STR_COL_DESIGNATION_ATTRIB, OKDATAOBJ_DESIGNATION_ERROR);
		///end SUPPORT_SPECIFY_COLUMN_DESIGNATIONS_IN_REPORT_TABLES

		UpdateOverallANOVAColumnLabel(trRow);			
	}
	
	///Jim 3/10/06 v8.0373 ADD_TABLE_FOOTNOTE
	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 = "";
	///Arvin 10/27/07 LOCALIZED_FOOTNOTES_STRINGS
	//String strSign;
	string strSign1, strSign2;
	///end LOCALIZED_FOOTNOTES_STRINGS
	double dPValue;
	///Arvin 10/27/07 LOCALIZED_FOOTNOTES_STRINGS
	//vector<string> vsAB = {_L("A"), _L("B")};
	vector<string> vsAB;
	///Arvin 11/16/07 QA70-10669 IMPROVE_TABLES_ROW_LABELS_FOR_ANOVA_TOOLS
	//vsAB.Add(_L("A"));
	//vsAB.Add(_L("B"));
	vsAB.Add(m_strFactor);
	vsAB.Add(m_strFactor2);
	/// Iris 5/28/2008 V8.0872 FIX_ESCAPED_STR_IN_OVERALL_ANOVA_FOOTNOTE
	ConvertEscapedString(vsAB[0]);
	ConvertEscapedString(vsAB[1]);
	///end FIX_ESCAPED_STR_IN_OVERALL_ANOVA_FOOTNOTE
	///end IMPROVE_TABLES_ROW_LABELS_FOR_ANOVA_TOOLS
	///end LOCALIZED_FOOTNOTES_STRINGS
	for(nRow = 0; nRow <= 2; nRow++)
	{
		///Arvin 11/16/07 QA70-10669 IMPROVE_TABLES_ROW_LABELS_FOR_ANOVA_TOOLS
		//if(0 == vsFactors[nRow].Compare("Interaction") && 0 == trInteraction.nVal)
		//if(0 == vsFactors[nRow].Compare("Interaction") && 0 == trInteraction.nVal)
		if(compare_string_localization(vsFactors[nRow], "Interaction", true) && 0 == trInteraction.nVal)
		///end 	IMPROVE_TABLES_ROW_LABELS_FOR_ANOVA_TOOLS
			continue;
		TreeNode trRow = tree_check_get_node(trTable, "Row"+nRow);
		dPValue = trRow.PValue.dVal;
		///Arvin 10/27/07 LOCALIZED_FOOTNOTES_STRINGS
		//if(dPValue < 0.05)
		//{	
			//strSign = "significantly";
		//}
		//else
		//{
			//strSign = "not significantly";
		//}
		//--- Jacky 07/22/10 ORG-102 USER_CAN_SET_SIGNIFICANCE_LEVEL 
		//if(dPValue < 0.05)
		double dAlpha = GetAlphaValue();
		if(dPValue < dAlpha)
		//--- end USER_CAN_SET_SIGNIFICANCE_LEVEL
		{	
			strSign1 = _L("significantly");
			strSign2 = _L("significant");
		}
		else
		{
			strSign1 = _L("not significantly");
			strSign2 = _L("not significant");
		}
		///end LOCALIZED_FOOTNOTES_STRINGS
		if(0 != nRow)
			trFooter.strVal += "\n";
		if(0 == nRow || 1 == nRow)
		///Arvin 10/27/07 LOCALIZED_FOOTNOTES_STRINGS
			//trFooter.strVal += "At the 0.05 level, the population means of Factor " + vsAB[nRow] + " are " + strSign + " different.";
		{
			string strFooter;
			////------ Folger 12/10/07 CLEAN_NEGATIVE_ERROR_MESSAGES
			////ocu_load_msg_str(FOOTNOTE_OVER_ALL_1, &strFooter, vsAB[nRow], NULL, strSign1);
			//--- Jacky 07/22/10 ORG-102 USER_CAN_SET_SIGNIFICANCE_LEVEL 
			//ocu_load_msg_str(dPValue < 0.05 ? FOOTNOTE_OVER_ALL_1 : FOOTNOTE_OVER_ALL_1_NEGATIVE, &strFooter, vsAB[nRow]);
			ocu_load_err_msg_str(dPValue < dAlpha ? FOOTNOTE_OVER_ALL_1 : FOOTNOTE_OVER_ALL_1_NEGATIVE, &strFooter);
			strFooter.Format(strFooter,dAlpha,vsAB[nRow]);
			//--- end USER_CAN_SET_SIGNIFICANCE_LEVEL
			////------
			trFooter.strVal += strFooter;
		}
		///end LOCALIZED_FOOTNOTES_STRINGS
		if(2 == nRow)
		///Arvin 07/26/07 v8.0668 THE_WORD_SIGNIFICANTLY_SHOULD_BE_SIGNIFICANT	
			//trFooter.strVal += "At the 0.05 level, the interaction between Factor A and Factor B is " + strSign + ".";
		{
			///Arvin 10/27/07 LOCALIZED_FOOTNOTES_STRINGS
			//strSign.TrimRight("ly");
			//trFooter.strVal += "At the 0.05 level, the interaction between Factor A and Factor B is " + strSign + ".";
			string strFooter;
			///Arvin 11/16/07 QA70-10669 IMPROVE_TABLES_ROW_LABELS_FOR_ANOVA_TOOLS
			//ocu_load_msg_str(FOOTNOTE_OVER_ALL_2, &strFooter, strSign2);
			///Echo 11/28/07 FOOTNOTE_FORMAT_NOT_CORRECT
			//ocu_load_msg_str(FOOTNOTE_OVER_ALL_2, &strFooter, vsAB[0], NULL, vsAB[1]);
			//strFooter += strSign2;///Echo 11/28/07 FOOTNOTE_FORMAT_NOT_CORRECT	
			//------ Folger 12/10/07 CLEAN_NEGATIVE_ERROR_MESSAGES
			//ocu_load_err_msg_str(FOOTNOTE_OVER_ALL_2, &strFooter);
			//--- Jacky 07/22/10 ORG-102 USER_CAN_SET_SIGNIFICANCE_LEVEL 
			//ocu_load_err_msg_str(dPValue < 0.05 ? FOOTNOTE_OVER_ALL_2 : FOOTNOTE_OVER_ALL_2_NEGATIVE, &strFooter);
			ocu_load_err_msg_str(dPValue < dAlpha ? FOOTNOTE_OVER_ALL_2 : FOOTNOTE_OVER_ALL_2_NEGATIVE, &strFooter);
			//--- end USER_CAN_SET_SIGNIFICANCE_LEVEL
			//strFooter.Format(strFooter, vsAB[0], vsAB[1], strSign2);
			//--- Jacky 07/22/10 ORG-102 USER_CAN_SET_SIGNIFICANCE_LEVEL
			//strFooter.Format(strFooter, vsAB[0], vsAB[1]);
			strFooter.Format(strFooter, dAlpha, vsAB[0], vsAB[1]);	
			//--- end USER_CAN_SET_SIGNIFICANCE_LEVEL			
			////------
			///end FOOTNOTE_FORMAT_NOT_CORRECT
			///end IMPROVE_TABLES_ROW_LABELS_FOR_ANOVA_TOOLS
			trFooter.strVal += strFooter;
			///end LOCALIZED_FOOTNOTES_STRINGS
			
		}
		///end THE_WORD_SIGNIFICANTLY_SHOULD_BE_SIGNIFICANT
	}
	///END ADD_TABLE_FOOTNOTE
	
	return TRUE;
}	


BOOL	ANOVATwoWay::addOneMeanComparisonResult(TreeNode &trOp, const int nIntervalType, ANOVA2Table* parANOVA2Table, int nSize)
{		
	string 			strNode;
	string			strLabel;
	int				nID;
	///Iris 3/22/05 ADD_MORE_MEAN_COMPARISON_CASE
	/*
	switch(nIntervalType)
	{
	case ANOVA_BONFERRON:
		strNode = "Bonferr";
		strLabel = "Bonferroni Test";
		nID = IDST_ANOVA2_MEAN_COMPARE_BONF_TABLE;
		break;
	case ANOVA_TUKEY:
		strNode = "Turey";
		strLabel = "Tukey Test";
		nID = IDST_ANOVA2_MEAN_COMPARE_TUK_TABLE;
		break;
	case ANOVA_SCHEFFE:
		strNode = "Scheffe";
		strLabel = "Scheffe Test";
		nID = IDST_ANOVA2_MEAN_COMPARE_SCHE_TABLE;
		break;
	case ANOVA_DUNNETT:
		strNode = "Dunnett";
		strLabel = "Dunnett Test";
		nID = IDST_ANOVA2_MEAN_COMPARE_DUNN_TABLE;
		break;	
	default:
		return FALSE;
	}
	*/
	GetMeanCompNodeInfo(strNode, strLabel, nID, nIntervalType);
	///end ADD_MORE_MEAN_COMPARISON_CASE
	
	string strFactors = ANOVA_FACTORS;
	vector<string> vsFactors;
	strFactors.GetTokens(vsFactors, '|');
	addMeanCompStatsTable(trOp, nIntervalType, m_vnFactorA, m_vsFactors, strNode, strLabel, nID, vsFactors[0], m_strFactor, 1, parANOVA2Table, nSize);
	addMeanCompStatsTable(trOp, nIntervalType, m_vnFactorB, m_vsFactors2, strNode, strLabel, nID, vsFactors[1], m_strFactor2, 2, parANOVA2Table, nSize);
	
	return TRUE;	 
}


BOOL	ANOVATwoWay::addMeanCompStatsTable(TreeNode &trOp, const int iTestType, const vector<int> &vFactor, 
		const vector<string>& vsFactors, string strTypeName, string strTypeLabel, int nID, 
		string strFactor, string strFactorName, int index, ANOVA2Table* parANOVA2Table, int nSize)
{
	int				iLevels = vsFactors.GetSize();
	///Iris 3/22/05 ADD_MORE_MEAN_COMPARISON_CASE
	//int 			nSizeMeanComp = iLevels*(iLevels-1);
	int 			nSizeMeanComp = (iLevels*(iLevels-1))/2;
	MeanCompStats*	pstMeanCompStats;		
	pstMeanCompStats = (MeanCompStats*)calloc(nSizeMeanComp, sizeof(MeanCompStats));

	double dSigLevel = trOp.GUI.MeansComp.SigLevel.dVal;
	
	int nRet = stats_anova_two_way_means_comparison(iTestType, vFactor, iLevels, m_vData, parANOVA2Table, dSigLevel, pstMeanCompStats, nSizeMeanComp);

	TreeNode	trRoot = tree_check_get_node(trOp.Calculation, "ANOVAs", IDST_ANOVAS, STR_LABEL_ATTRIB, _L("ANOVA"));
	
	TreeNode 	trMeanComp = tree_check_get_node(trRoot, "MeanComp", IDST_ANOVA2_MEAN_COMPARE_SUBLEVEL, STR_LABEL_ATTRIB, _L("Means Comparisons"));
	
	TreeNode 	trType = tree_check_get_node(trMeanComp, strTypeName, nID, STR_LABEL_ATTRIB, strTypeLabel);
	
	/// Iris 2/25/2009 REPEAT_ID_CAUSE_JUNK_RANGE_STR_AFTER_SET_AU_TO_NONE
	//TreeNode	trTable = tree_check_get_node(trType, strFactor, nID+index, STR_LABEL_ATTRIB, strFactorName);
	TreeNode	trTable = tree_check_get_node(trType, strFactor, make_one_set_ID(nID, index), STR_LABEL_ATTRIB, strFactorName);
	///end REPEAT_ID_CAUSE_JUNK_RANGE_STR_AFTER_SET_AU_TO_NONE
	
	trTable.SetAttribute(TREE_Table, GetTableStringSupport(false));			
	
	if(0 != nRet)
	{
		free(pstMeanCompStats);
		///Arvin 10/17/07 CLEAN_ANOVA_TOOLS_CODE
		//addErrInfoMeanComparison(trTable, nID, nRet);
		AddErrInfoToTable(trTable, nID, nRet, false);
		///end CLEAN_ANOVA_TOOLS_CODE
		return false;
	}
	
	///Arvin 10/17/07 CLEAN_ANOVA_TOOLS_CODE
	/*
	vector<string>	vsCompLabels;
	///Iris 02/16/05 BASE_CALSS_FUNCTION_INSTEAD_ADD_DESCSTAT_TABLE
	//getMeanCompColLabels(vsFactors, vsCompLabels);
	GetMeanCompColumnLabels(vsFactors, vsCompLabels);
	///End BASE_CALSS_FUNCTION_INSTEAD_ADD_DESCSTAT_TABLE
	
	for(int nRow=0; nRow < nSizeMeanComp; nRow++)
	{
		///Arvin 09/30/07 SHOULD_GET_LABEL_WITH_INDEXCOMP_FOR_BONHOLM_AND_SIDAKHOLM as max said
		//TreeNode trRow = tree_check_get_node(trTable, "Row" + nRow, IDST_TEMP_ONE_SET, STR_LABEL_ATTRIB, vsCompLabels[nRow]);  //Use Row as temp label 
		int nLabelRow = nRow;
		if(iTestType == ANOVA_BONHOLM || iTestType == ANOVA_SIDAKHOLM)
		{
			nLabelRow = pstMeanCompStats[nRow].IndexComp;	
			if(nLabelRow >= vsCompLabels.GetSize())
				return false;
		}
		TreeNode trRow = tree_check_get_node(trTable, "Row" + nRow, IDST_TEMP_ONE_SET, STR_LABEL_ATTRIB, vsCompLabels[nLabelRow]);  //Use Row as temp label 
		///end SHOULD_GET_LABEL_WITH_INDEXCOMP_FOR_BONHOLM_AND_SIDAKHOLM
		trRow += pstMeanCompStats[nRow];
		trRow.ID = nID + nRow + 1;
		//--- Iris 11/2/0/06 the node only used to debug, so commented out it
		if(trRow.IndexComp)
			trRow.IndexComp.Show = 0;
		//---
		///Arvin 09/30/07 HIDE_DOF_COL_FOR_MEAN_COMP_TABLE as max said
		if(trRow.DOF)
			trRow.DOF.Show = false;
		///end HIDE_DOF_COL_FOR_MEAN_COMP_TABLE
		
	}
	
	SetupMeanCompasionTableRows(trTable, iTestType);
	UpdateMeanCompasionStatRowName(trTable, iTestType);
	
	free(pstMeanCompStats);
	
	return TRUE;
	*/
	return AddMeanComparisonRows(trOp, trTable, vsFactors, pstMeanCompStats, nSizeMeanComp, nID, iTestType);
	///end CLEAN_ANOVA_TOOLS_CODE
}

///Jim 3/15/06 v8.0374 ADD_TABLE_FOOTNOTE
///Arvin 10/17/07 CLEAN_ANOVA_TOOLS_CODE
/*
bool ANOVATwoWay::addMeanComparisonFootnote(TreeNode &trOp)
{
	TreeNode	trRoot = tree_check_get_node(trOp.Calculation, "ANOVAs", IDST_ANOVAS);
	TreeNode 	trMeanComp = tree_check_get_node(trRoot, "MeanComp", IDST_ANOVAS_MEAN_COMP, STR_LABEL_ATTRIB, "Means Comparisons");
	TreeNode 	trFooter = tree_check_get_node(trMeanComp, "Footnote", IDE_FOOTNOTE_BEGIN, TREE_Footnote, "1"); // just need the TREE_Footnote attribute, value does not matter, so 1 is good
	string strSigLevel;
	///Arvin 07/24/07 v8.0661 WRONG_DOUBLE_PRESION_NUMBER
	//strSigLevel.Format("%f",trOp.GUI.MeansComp.SigLevel.dVal);
	double dSigLevel = trOp.GUI.MeansComp.SigLevel.dVal;
	strSigLevel = ftoa(dSigLevel);
	///end WRONG_DOUBLE_PRESION_NUMBER
	trFooter.strVal = "Sig equals 1 indicates that the means difference is significant at the " + strSigLevel + " level.\n";
	trFooter.strVal += "Sig equals 0 indicates that the means difference is not significant at the " + strSigLevel + " level.";
	return true;
}
*/
///end CLEAN_ANOVA_TOOLS_CODE
///END ADD_TABLE_FOOTNOTE

///Iris 02/16/05 BASE_CALSS_FUNCTION_INSTEAD_ADD_DESCSTAT_TABLE
/*
void		getMeanCompColLabels(const vector<string>& vsFactors, vector<string>& vsCompLabels)
{	
	int iLevels = vsFactors.GetSize();
	for(int ii=0; ii<iLevels; ii++)
		for(int jj=0; jj<iLevels; jj++)
		{
			if(ii == jj) continue;
			string strTemp;
			strTemp.Format("%s  %s", vsFactors[ii], vsFactors[jj]);
			vsCompLabels.Add(strTemp);
		}
}	
*/
///End BASE_CALSS_FUNCTION_INSTEAD_ADD_DESCSTAT_TABLE

void 	ANOVATwoWay::addANOVATwoWayMeansComparison(TreeNode &trOp, ANOVA2Table*	parANOVA2Table, int nSize)
{	
	/// Iris 05/10/2007 v8.0615 REMOVE_BRANCH_CHECK_BOX
	//if(!trOp.GUI.MeansComp.Use)
	//	return;
	///end REMOVE_BRANCH_CHECK_BOX
	
	if(trOp.GUI.MeansComp.Bonferroni.nVal)
		addOneMeanComparisonResult(trOp, ANOVA_BONFERRON, parANOVA2Table, nSize);
	
	if(trOp.GUI.MeansComp.Scheffe.nVal)
		addOneMeanComparisonResult(trOp, ANOVA_SCHEFFE, parANOVA2Table, nSize);
	
	if(trOp.GUI.MeansComp.Tukey.nVal)
		addOneMeanComparisonResult(trOp, ANOVA_TUKEY, parANOVA2Table, nSize);
	
	///Iris 3/22/05 ADD_MORE_MEAN_COMPARISON_CASE
	if(trOp.GUI.MeansComp.DunnSidak.nVal)
		addOneMeanComparisonResult(trOp, ANOVA_SIDAK, parANOVA2Table, nSize);
	
	if(trOp.GUI.MeansComp.FisherLSD.nVal)
		addOneMeanComparisonResult(trOp, ANOVA_FISHER, parANOVA2Table, nSize);
	
	if(trOp.GUI.MeansComp.HolmBonf.nVal)
		addOneMeanComparisonResult(trOp, ANOVA_BONHOLM, parANOVA2Table, nSize);
	
	if(trOp.GUI.MeansComp.HolmSidak.nVal)
		addOneMeanComparisonResult(trOp, ANOVA_SIDAKHOLM, parANOVA2Table, nSize);
	///end ADD_MORE_MEAN_COMPARISON_CASE
	
	if(trOp.GUI.MeansComp.Dunnett && trOp.GUI.MeansComp.Dunnett.Use)		
		addOneMeanComparisonResult(trOp, ANOVA_DUNNETT, parANOVA2Table, nSize);
	
	///Jim 3/15/06 v8.0374 ADD_TABLE_FOOTNOTE 
	TreeNode trMeansComp = trOp.Calculation.ANOVAs.MeanComp;
	if( trMeansComp )
	{
		///Arvin 10/17/07 CLEAN_ANOVA_TOOLS_CODE
		//addMeanComparisonFootnote(trOp);
		AddMeanComparisonFootnote(trOp);
		///end CLEAN_ANOVA_TOOLS_CODE
	}
	///END ADD_TABLE_FOOTNOTE
}	

void	ANOVATwoWay::addPowersResult(TreeNode &trOp, ANOVA2Table* parANOVA2Table, int nSize)
{	
	/// Iris 05/10/2007 v8.0615 REMOVE_BRANCH_CHECK_BOX
	//if( !trOp.GUI.PowerBranch.Use )
		//return;
		
	//int nHypotPower = trOp.GUI.PowerBranch.HypotPower.nVal;		
	//int iPower = ( 1 == nHypotPower)? 1 : 0;
	///Arvin 10/17/07 CLEAN_ANOVA_TOOLS_CODE
	//bool	bActualPower = trOp.GUI.PowerBranch.ActualPower.nVal;
	//bool	bHypotPower = trOp.GUI.PowerBranch.HypotPower.nVal;
	//int		iPower = 0;
	//if( !bActualPower && !bHypotPower )
	//	return;
	//if( bActualPower )
	//	iPower |= ANOVA2_POWER_ACTUAL; 
	//if( bHypotPower )
	//	iPower |= ANOVA2_POWER_HYPOTHESIS; 
	int iPower = GetPowerInfo(trOp);
	if(iPower <= 0)
		return;
	///end CLEAN_ANOVA_TOOLS_CODE
	///end REMOVE_BRANCH_CHECK_BOX
	
	
	int iInteractions = trOp.GUI.Interactions.nVal;
	
	updateOnePowerTable(trOp, 0 ,m_vnFactorA.GetSize(), iPower, iInteractions, CALC_FACTORA_POWER, parANOVA2Table, nSize);		
	updateOnePowerTable(trOp, 1, m_vnFactorB.GetSize(),iPower, iInteractions, CALC_FACTORB_POWER, parANOVA2Table, nSize);		
	if( iInteractions )
		updateOnePowerTable(trOp, 2, m_vnFactorA.GetSize() + m_vnFactorB.GetSize(), iPower, iInteractions, CALC_INTERACTION_POWER, parANOVA2Table, nSize);		
	
}

void	ANOVATwoWay::updateOnePowerTable(TreeNode &trOp, int iFactorIndex, int iLevels, int iPower, const int iInteractions, int iSource, ANOVA2Table* parANOVA2Table, int nDataGroup)
{
	//prepare input argument
	string strFactors = ANOVA_FACTORS;
	vector<string> vsFactors;
	strFactors.GetTokens(vsFactors, '|');
	
	int 	nID = IDST_ANOVA2_POWER_TABLE + iFactorIndex;
	string  strFactor = vsFactors[iFactorIndex];
	double 	dSigLevel = trOp.GUI.PowerBranch.SigLevel.dVal;	
	vector	vSampleSizes, vPowers;
	///Arvin 10/17/07 CLEAN_ANOVA_TOOLS_CODE
	//if(ANOVA2_POWER_ACTUAL & iPower) 
	//{
	//	vSampleSizes.Add(iLevels);
	//}
	//
	//if(ANOVA2_POWER_HYPOTHESIS & iPower)
	//{
	//	string 			strSamples = trOp.GUI.PowerBranch.HypotSizes.strVal;
	//	vector		 	vsTemp;
	//	strSamples.GetTokens(vsTemp, ' ');
	//	vSampleSizes.Append(vsTemp);
	//}
	GetSampleSizeByPowerType(trOp, iPower, iLevels, vSampleSizes);
	///end CLEAN_ANOVA_TOOLS_CODE
	//---CPY 5/11/07 COMPILE_ERR_WITH_ANOVA_TWO_WAY
    //int 	nRet = stats_anova_two_way_power(iPower, iInteractions, dSigLevel, parANOVA2Table, vSampleSizes, vPowers, iSource);			    
    int 	nRet = stats_anova_two_way_power(iInteractions, dSigLevel, parANOVA2Table, vSampleSizes, vPowers, iSource);
    //----
	
    TreeNode	trANOVA = tree_check_get_node(trOp.Calculation, "ANOVAs", IDST_ANOVAS, STR_LABEL_ATTRIB, _L("ANOVA"));		
	TreeNode	trPowers = tree_check_get_node(trANOVA, "Powers", IDST_ANOVA2_POWER_TABLE, STR_LABEL_ATTRIB, _L("Powers"));
	/// Iris 05/11/2007 v8.0616 USE_REAL_FACTOR_COL_NAME_REPLACE_FACTORA_FACTORB
	//TreeNode	trTable = tree_check_get_node(trPowers, strFactor, nID, STR_LABEL_ATTRIB, strFactor);
	string		strSubTableLabel;
	switch(iFactorIndex)
	{
	case 0:
		strSubTableLabel = m_strFactor;
		break;
	case 1:		
		strSubTableLabel = m_strFactor2;
		break;
	default:
		strSubTableLabel = strFactor;
		break;
	}
	TreeNode	trTable = tree_check_get_node(trPowers, strFactor, nID, STR_LABEL_ATTRIB, strSubTableLabel);	
	///end USE_REAL_FACTOR_COL_NAME_REPLACE_FACTORA_FACTORB	

    if( 0 != nRet)
    {
    	///Arvin 08/09/07 QA70-7100 P15-L3 WRONG_POWER_ANALYSIS_TABLE
    	//As Echo said, set powers as missing values
    	//addErrInfoANOVAPower(trTable, nID, nRet);
    	//return;
    	vPowers.SetSize(vSampleSizes.GetSize());
    	vPowers = NANUM;
    	///end WRONG_POWER_ANALYSIS_TABLE
    }
    
	//if( ANOVA2_POWER_HYPOTHESIS | ANOVA2_POWER_ACTUAL == iPower ) // Actual Power and Hypot Power
	//	vSampleSizes.InsertAt(0, iLevels);
	
	//transpose result to structure from vectors
	///Arvin 10/17/07 CLEAN_ANOVA_TOOLS_CODE
	/*
	PowerResults*	pstPowers;
	pstPowers = (PowerResults*)calloc(vPowers.GetSize(), sizeof(PowerResults));	
	stats_power_output(vPowers, vSampleSizes, dSigLevel, pstPowers, vPowers.GetSize());
	
    
	for(int nRow=0; nRow<vPowers.GetSize(); nRow++)
	{
		/// Iris 05/10/2007 v8.0615 REMOVE_BRANCH_CHECK_BOX
		//string strLabel = (0 == nRow)? "Actual Power" : "Hypothesis Powers";
		string strLabel = (0 == nRow && ANOVA2_POWER_HYPOTHESIS != iPower)? "Actual Power" : "Hypothesis Powers";
		///end REMOVE_BRANCH_CHECK_BOX
			
		TreeNode	trRow = tree_check_get_node(trTable, "Row" + nRow, IDST_TEMP_ONE_SET, STR_LABEL_ATTRIB, strLabel);
		trRow += pstPowers[nRow];
		trRow.ID = make_one_set_ID( nID, nRow);	
		//----Iris 11/01/06 v8.0502d NO_COL_LABEL_IN_POWER_TABLE
		trRow.Alpha.SetAttribute(STR_LABEL_ATTRIB, "Alpha");
		trRow.SampleSize.SetAttribute(STR_LABEL_ATTRIB, "Sample Size");
		trRow.Power.SetAttribute(STR_LABEL_ATTRIB, "Power");
		//----		
	}
	///Arvin 08/09/07 QA70-7100 P15-L3 WRONG_POWER_ANALYSIS_TABLE
     if( 0 != nRet)
     	///Arvin 10/17/07 CLEAN_ANOVA_TOOLS_CODE
     	//addErrInfoANOVAPower(trTable, nID, nRet);
     	AddErrInfoToTable(trTable, nID, nRet, false);
     	///end CLEAN_ANOVA_TOOLS_CODE
     ///END WRONG_POWER_ANALYSIS_TABLE
    free(pstPowers);
    */
    AddPowerTableRows(trTable, vPowers, vSampleSizes, dSigLevel, iPower, nID, nRet);
	///end CLEAN_ANOVA_TOOLS_CODE
}	

void 	ANOVATwoWay::addNodeToMeanWksTable(TreeNode& trTable, vector<string> vsNames, vector<string> vsLabels, int nBaseID)
{		
	for(int index=0; index<vsNames.GetSize(); index++)
	{
		tree_check_get_node(trTable, vsNames[index], nBaseID+index+1 );
	}
}

void 	ANOVATwoWay::addMeansWksTable(TreeNode& trOp, ANOVA2DescStats* pstDescStats, int DescStatsSize, bool bCreateGraph,
	string strTable, int nID, bool bIsSD)
{
	TreeNode	trTable = tree_check_get_node(trOp.Calculation, strTable, nID);
	tree_check_set_hidden(trTable, bCreateGraph? false:true);
	
	vector<string> vsNames = {"Num", "Mean", "SD"};
	addNodeToMeanWksTable(trTable, vsNames, vsNames, nID);	
	
	vector<int> vnNum;
	vector		vMeans;
	vector		vSTD;
	for(int nRow; nRow<DescStatsSize; nRow++)
	{			
		vnNum.Add(nRow+1);
		vMeans.Add(pstDescStats[nRow].Mean);
		if(bIsSD)
			vSTD.Add(pstDescStats[nRow].SD);
		else
			vSTD.Add(pstDescStats[nRow].SEM);				
	}
	TreeNode trNum = trTable.GetNode(vsNames[0]);
	TreeNode trMean = trTable.GetNode(vsNames[1]);
	TreeNode trSTD = trTable.GetNode(vsNames[2]);
	///Sophy 3/30/2009 QA80-13352 SUPPORT_SPECIFY_COLUMN_DESIGNATIONS_IN_REPORT_TABLES
	tree_set_attribute_to_all_nodes(trTable, STR_COL_DESIGNATION_ATTRIB, (string)OKDATAOBJ_DESIGNATION_Y);
	if ( trTable.SD )
		trTable.SD.SetAttribute(STR_COL_DESIGNATION_ATTRIB, OKDATAOBJ_DESIGNATION_ERROR);
	///end SUPPORT_SPECIFY_COLUMN_DESIGNATIONS_IN_REPORT_TABLES

	if(trNum) 	trNum.nVals = vnNum;
	if(trMean)	trMean.dVals = vMeans;
	if(trSTD)	trSTD.dVals = vSTD;		
	
}

//temporary function, should move _get_graph_tag_name from Operation.c to Analysis_utils.h and use it.
bool	ANOVATwoWay::isCreateGraph(TreeNode& trOp, int nGraphIndex)
{
	///Iris 6/03/05 CENTRALIZE_TO_GET_GRAPH_GUI_NODE
	//TreeNode 	trGraph = trOp.GUI.Output.Report.Create.GetNode("Graph"+(++nGraphIndex));
	TreeNode 	trGraph = GetGUIGraphNodes(trOp, nGraphIndex);
	///-----
	return trGraph? trGraph.nVal : false;			
}

void 	ANOVATwoWay::addWksTableMeanFactorA(TreeNode& trOp, ANOVA2DescStats*	pstDescStatsA, int nSizeFactorA, bool bCreateGraph)
{		
	addMeansWksTable(trOp, pstDescStatsA, nSizeFactorA, bCreateGraph, "MeanFactorAPlot", IDST_ANOVA2_MEAN_FACTORA_PLOT);
}

void 	ANOVATwoWay::addWksTableMeanFactorB(TreeNode& trOp, ANOVA2DescStats*	pstDescStatsB, int nSizeFactorB, bool bCreateGraph)
{
	addMeansWksTable(trOp, pstDescStatsB, nSizeFactorB, bCreateGraph, "MeanFactorBPlot", IDST_ANOVA2_MEAN_FACTORB_PLOT,false);
}

void 	ANOVATwoWay::addWksTableMeanFactorAB(TreeNode& trOp, ANOVA2DescStats* pstDescStatsAB, int nSizeFactorAB, bool bCreateGraph)
{
	addMeansWksTable(trOp, pstDescStatsAB, nSizeFactorAB, bCreateGraph, "MeanFactorABPlot", IDST_ANOVA2_MEAN_FACTORAB_PLOT, false);
}

///Arvin 10/17/07 CLEAN_ANOVA_TOOLS_CODE
/*
void 	ANOVATwoWay::addErrorRowToTable(TreeNode& trTable, string strError, int nID)
{
	TreeNode    trRow = tree_check_get_node(trTable, "Error", nID, STR_LABEL_ATTRIB, "Attention!");
	trRow.strVal = strError;
}

///Arvin 08/09/07 QA70-7100 ADD_ERROR_MESSAGE
static string _get_error_msg(int nErr)
{
	string strErr;
	strErr = "Error(" + ftoa(nErr)+ "): Two-Way ANOVA computational error.";
	return strErr;
}
///end ADD_ERROR_MESSAGE

void	ANOVATwoWay::addErrInfoDescSrtats(TreeNode& trTable, int nID, int nErr)
{
	string 		strError; //need wait Echo add related error info
	///Arvin 08/09/07 QA70-7100 ADD_ERROR_MESSAGE
	strError = _get_error_msg(nErr);
	///end ADD_ERROR_MESSAGE
	addErrorRowToTable(trTable, strError, nID);
}

void 	ANOVATwoWay::addErrInfoMeanComparison(TreeNode& trTable, int nID, int nErr)
{
	string 		strError; //need wait Echo add related error info
	///Arvin 08/09/07 QA70-7100 ADD_ERROR_MESSAGE
	strError = _get_error_msg(nErr);
	///end ADD_ERROR_MESSAGE
	addErrorRowToTable(trTable, strError, nID);
}

void 	ANOVATwoWay::addErrInfoANOVAPower(TreeNode& trTable, int nID, int nErr)
{
	string 		strError; //need wait Echo add related error info
	///Arvin 08/09/07 QA70-7100 ADD_ERROR_MESSAGE
	strError = _get_error_msg(nErr);
	///end ADD_ERROR_MESSAGE
	addErrorRowToTable(trTable, strError, nID);
}	
*/
///end CLEAN_ANOVA_TOOLS_CODE
///Cheney 2007-9-28 MODIFY_TITLE_AS_MAX_SAID
string	ANOVATwoWay::GetDlgDescription(int nOption)
{
	return _L("Perform Two-Way ANOVA");
}
///end MODIFY_TITLE_AS_MAX_SAID

///Cheney 2007-10-25 ANOVA_TOOLS_HANDLE_AUTO_WRONG
//virtual
bool		ANOVATwoWay::GetAnovaToolsOption(bool bRow, int& nOption)
{
	nOption = bRow? DRTREE_ANOVA_TWO_WAY_RAW : DRTREE_ANOVA_TWO_WAY_INDEXED;
	return true;
}
///end ANOVA_TOOLS_HANDLE_AUTO_WRONG

/// YuI 09/26/05 ANOVA_DATA_SELECTION_GUI
/// Hong 09/04/09 QA80-14258 HISTOGRAM_NEED_SPECIAL_HINT_FOR_DOING_NLFITTING
//bool	ANOVATwoWay::InitFromSelection(TreeNode &trOperation)
int		ANOVATwoWay::InitFromSelection(TreeNode &trOperation)
/// end HISTOGRAM_NEED_SPECIAL_HINT_FOR_DOING_NLFITTING
{
	return true; // data structure is too complictaed to deduct from selection
}

//--- Jacky 07/22/10 ORG-102 USER_CAN_SET_SIGNIFICANCE_LEVEL 	
double		ANOVATwoWay::GetAlphaValue()
{
	Tree trOperation;
	GetTree(trOperation);
	double dAlpha = trOperation.GUI.alpha ? trOperation.GUI.alpha.dVal : 0.05;
	return dAlpha;
}
//--- end USER_CAN_SET_SIGNIFICANCE_LEVEL

