/*------------------------------------------------------------------------------*
 * File Name:report_utils.c														*
 * Creation: Echo 5/10/06 														*
 * Purpose: OriginC Source C file containing funtion for report tree and 		*
 * 			report data in X-function											*
 * Copyright (c) OriginLab Corp.	2003, 2004, 2005, 2006, 2007, 2008, 2009	*
 * All Rights Reserved															*
 * 																				*
 * Modification Log:															*
 * Echo 5/15/06 STANDARDIZE_TEMPLATE_NAME										*
 * Echo 6/19/06 NPH_STATS_OUTPUT_ERROR											*
 * Echo 6/20/06 QA70-7074-P9 ADD_DELIMITER_CHECK								*
 * Nicole 07/05/2007 v8.0655 REMOVE_SPACE_FOR_LOCATION_STRING						*
 *	YuI 09/20/07 QA70-10397 SHOULD_ALLOW_SETREPORTTREE_TO_MOVE_EMBEDDED_GRAPH_TO_DIFFERENT_LOCATION*
 *	ML 9/25/2007 QA70-10336 MUST_REMOVE_REDUNDANT_DATAPLOTS_IN_SCATTERPLOTMATRIX*
 *	Max 9/26/07 USE_ENUM_TO_CHECK_TAIL											*
 *	Echo 11/1/07 NOT_COMPARE_STR												*
 *	Folger 11/08/07 CATEGORY_NEEDED_WHEN_LOCALIZE								*
 *	ML 1/9/2008 QA70-10917 MAKE_XFVERSION_USED_WHEN_XFOP_WAS_RUN_LAST_TIME_AVAILABLE_TO_ORIGINC
 *	Echo 1/12/08 QA70-10917 NEW_MATHNISM_SET_PLOTID								*
 *	Echo 3/17/08 QA70-11268 V8.0825 MW_ADD_EXACT_P								*
 *	Echo 3/26/08 QA70-11315 v8.0832b WRONG_SA_PLOT_LEGEND_IN_GJ					*
 *	Echo 4/29/08 QA70-11268 V8.0851 KS2_ADD_EXACT_P_LB							*
 *	Echo 08/5/20 QA70-10975 v8.0867 FITCMP_RUNTIME_ERROR						*
 *	Echo 5/29/08 v8.0873 CORR_ENABLE_EMPTY_COL									*
 *	Echo 7/28/08 v8.0911 DELETE_HIDE_ZERO_FOR_COPY_TABLE						*
 *	Kyle 11/05/2008 HANDLE_WHOLE_WORKSHEET_SELECTED								*
 *	Kyle 12/18/2008 ADD_MESSAGE_TO_DISCRIBE_SIGNIFICANCE_RESULT_FOR_CORRELEATION_COEFFICIENT
 *	Folger 12/26/08 QA80-12642 v8.0991 CONSISTENT_SHOW_LN_ONLY_IF_EXIST_FOR_STATISTICAL_TOOLS
 *	Folger 12/26/08 QA80-12642-P3 v8.0991 CONSISTENT_SHOW_LN_WITH_DOUBLE_QUOTES_IN_REPORT_SHEET
 *	Kyle 12/30/2008 FIX_GETTING_THE_WRONG_FACTORS								*
 *	Kyle 01/05/2009 CORR_OUTPUT_MESSAGE_ABOUT_COLUMNS_MISSING_VALUES			*
 *	Kyle 01/07/2009 PLOT_MATRIX_HANDLE_COLUMN_ALL_TEXT							*
 *  Iris 4/13/2009 QA80-13392-P1 FIX_EMPTY_LABEL_AFTER_COPY_TABLE_AS_NEW_SHEET	*
 *	Folger 04/22/09 QA80-13420 PARETOCHART_XF_BASED_PLOTTING					*
 *	Kyle 05/15/2009 FIX_COLOR_CHANGE_WHEN_RECAL_WHILE_THE_COLOR_SETTING_FROM_TEMPLATE
 *	Folger 05/20/09 QA80-13639 FIT_COMPARE_MODEL_RESULTS_ARE_FILPPED_WHEN_DOF_OF_2ND_MODEL_IS_LARGER
 *  Iris 6/25/2009 QA80-13289-S1 CENTRLIZE_CODE_FOR_WIND_ROSE_PLOT				*
 *  Iris 7/08/2009 PLOT_PROB_XF													*
 *	Kyle 07/09/2009 QA80-13902-S1 FREQUENCY_SUPPORT_FRACTION_AND_PERCENT		*
 *	Kyle 07/09/2009 QA80-13902-P1 DISCRETE_FREQUENCY_SET_DATA_AS_CATEGORICAL_AUTOMATICALLY
 *	Kyle 07/10/2009 QA80-13521-P1 SHOULD_SKIP_OR_EXTEND_THE_LAST_BIN_BEFORE_CHECKING_PERIODICAL
 *	Kyle 07/17/2009 USE_ENUM_COLUMN_NAME_SINCE_IT_WILL_BE_CUT_OFF_IF_THE_BOOK_NAME_IS_TOO_LONG
 *  Iris 7/23/2009 REMOVE_YBIN_CONTROL_FROM_PLOT_WINDROSE						*
 *  Iris 8/05/2009 FIX_MISS_ONE_BIN_IN_TWODBINNING								*
 *  Iris 8/11/2009 FIX_QQ_PLOT_REFERENCE_LINE_NOT_SAME_AS_SPSS					*
 *	Hong 09/09/09 QA90-14287 2DBINNING_SUPPORT_HANDLE_MIN_MAX					*
 *	Sim 09-11-2009 QA81-14287 WIND_ROSE_NEED_INCLUDE_SEPARATE_BIN_FOR_MIN		*
 *	Kyle 11/02/2009 QA80-13902 DISCRETE_FREQUENCY_COPY_SOURCE_COLUMN_FORMAT		*
 *  Iris 1/19/2010 FIX_PARETO_PLOT_NOT_GOOD_SCALE_AFTER_AUTO_UPDATE				*
 *  Iris 1/25/2010 PARETO_CHAR_ADD_LABEL_PLOT									*
 *  Iris 1/28/2010 SET_PARETO_CHAR_LABEL_SIZE_AND_OFFSET						*
 *	Kyle 04/19/2010 FORCE_TO_UPDATE_REPORT_COLUMN_LABELS						*
 *	Kyle 06/30/2010 ORG-209 EXPAND_2D_BINNING_TO_SUPPORT_ADDITIONAL_Y_COLUMN	*
 *	Kyle 06/30/2010 ORG-209-P1 FIX_WRONG_OUT_RIGHT_BIN_ON_SEPARATE_COUNT_MAX_CHECKED
 *	Jacky 07/22/10 ORG-102 USER_CAN_SET_SIGNIFICANCE_LEVEL						*
 *	Echo 8/20/10 ORG-861-P1 	PLOT_CURVE_TO_FULL_X_RANGE						*
 *	Folger 09/27/2010 ORG-1151-P1 SAVE_AS_ANALYSIS_TEMPLATE_FAILED_TO_CLEAN_GRAPHS_EMEBEDED_IN_WKS
 *	Folger 10/09/2010 ORG-1228-P1 FIT_COMPARE_MODEL_EMPTY_FUNCTION_NAME_FOR_LINEAR_AND_POLYNOMIAL
 *	Folger 10/18/2010 ORG-1178 USE_MODEL_ONE_TWO_INSTEAD_OF_FUNCTION_NAME_FOR_TESTING_IN_FIT_COMAPRE_MODELS
 *------------------------------------------------------------------------------*/
 
////////////////////////////////////////////////////////////////////////////////////
// Including the system header file Origin.h should be sufficient for most Origin
// applications and is recommended. Origin.h includes many of the most common system
// header files and is automatically pre-compiled when Origin runs the first time.
// Programs including Origin.h subsequently compile much more quickly as long as
// the size and number of other included header files is minimized. All NAG header
// files are now included in Origin.h and no longer need be separately included.
//
// Right-click on the line below and select 'Open "Origin.h"' to open the Origin.h
// system header file.
#include <Origin.h>
#include <report_utils.h>		// Prototypes for report functions
#include <event_utils.h>		// Prototypes for report functions

#include <ReportTree.h>
#include <xfutils.h>
#include <..\Originlab\graph_utils.h> ///Iris 1/28/2010 SET_PARETO_CHAR_LABEL_SIZE_AND_OFFSET

//------ Folger 11/08/07 CATEGORY_NEEDED_WHEN_LOCALIZE
#define STR_CAT_STATS "Statistics"
#define STR_POWER _LC("Power", STR_CAT_STATS)
//------ End CATEGORY_NEEDED_WHEN_LOCALIZE

///Echo 4/29/08 QA70-11268 V8.0851 KS2_ADD_EXACT_P_LB
#define	KS2_EXACT_CON1	2500
#define	KS2_EXACT_CON2	10000
///END KS2_ADD_EXACT_P_LB

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


///Eric 2006/4/17
/*
bool report_tree_create(ReportTree& outRT, LPCSTR lpsczLabel)
{
	return init_report_tree_common_tables(outRT, lpsczLabel, lpsczLabel, _L("r"));
}
*/
///Jake 06/07/07 REPORT_TREE_SURPORT_MATRIX
bool report_tree_create(ReportTree& outRT, LPCSTR lpsczLabel, LPCTSTR lpcszInputName)
{
 if ( NULL == lpcszInputName )
  lpcszInputName = "r";
 return init_report_tree_common_tables(outRT, lpsczLabel, lpsczLabel, lpcszInputName);
}
///end REPORT_TREE_SURPORT_MATRIX
bool add_note(ReportTree& rtOut, LPCSTR lpsczNote)
{
	if ( !rtOut )
		return false;
	
	TreeNode 	trTemp = tree_get_node_by_id(rtOut, IDST_REPORT_NOTES);	
	ReportTable rtNote(trTemp);	
	rtNote.AddRow("Attention", _L("Attention"), lpsczNote, IDE_NOTES_ATTN);
	
	return true;
}

void set_nph_desc_stats_opt(DescStatOptions& stDescOpt, QuantileOptions& stQuanOpt)
{
	
	stDescOpt.N = true;
	stQuanOpt.Median = true;
	stQuanOpt.Min = true;
	stQuanOpt.Q1 = true;
	stQuanOpt.Q3 = true;
	stQuanOpt.Max = true;
	stQuanOpt.Interpolate = INTERPOLATE_WEIGHT_AVER_RIGHT;
	
}

bool rt_add_nph_descriptive(ReportTree& outRT, const DescStatResults *pDescStats, const QuantileResults *pQuantiles, const vector<string>& vstrGroup, LPCSTR lpsczColLabel)
{
	int nGroups = vstrGroup.GetSize();
	if (!outRT || 0 >= nGroups)
		return false;
	
	DescStatOptions stDescOpt;
	QuantileOptions stQuanOpt;
	set_nph_desc_stats_opt(stDescOpt, stQuanOpt);
		
	for (int ii = 0; ii < nGroups; ii++)
	{
		bool bErr;
		if (lpsczColLabel)
			bErr = rt_add_desc_stats(outRT, &stDescOpt, &stQuanOpt, &pDescStats[ii], &pQuantiles[ii], vstrGroup[ii], lpsczColLabel);
		else
			bErr = rt_add_desc_stats(outRT, &stDescOpt, &stQuanOpt, &pDescStats[ii], &pQuantiles[ii], vstrGroup[ii]);
			
		if (!bErr)
			return bErr;
	}
	
	return true;
	//return rt_add_desc_stats(outRT, &stDescOpt, &stQuanOpt, pDescStats, pQuantiles, vstrGroup, lpsczColLabel);
	
}

static void _get_summary(SASummary stSASumStats, vector& vSummary)
{
	vSummary.SetSize(4);
	vSummary[0] = stSASumStats.Total;
	vSummary[1] = stSASumStats.Events;
	vSummary[2] = stSASumStats.NumCen;
	vSummary[3] = stSASumStats.PerCen;
}

void rt_add_sa_summary(ReportTree& outRT, SASummary stSASumStats, const vector vCensored, LPCSTR lpsczLab, const int nIndex)
{
	ReportTable rtSummary = outRT.CreateTable("Summary", _L("Summary of Event and Censored Values"), 0x00202015);  //IDST_DESC_SUMMARY_RESULTS);	
	vector<string> vstrSummaryLabels(4), vstrSummaryTagName;
	vstrSummaryLabels[0] = _L("Total");
	vstrSummaryLabels[1] = _L("Events");
	vstrSummaryLabels[2] = _L("Censored");	
	vstrSummaryLabels[3] = _L("Percent Censored");
	string strSummaryTagName = SA_SUMMARY;
	strSummaryTagName.GetTokens(vstrSummaryTagName, '|');
		
	vector vSummary;
	_get_summary(stSASumStats, vSummary);
	string strLab = "";
	if (lpsczLab)	strLab = lpsczLab;
	
	string strRowName = "Summary" + ftoa(nIndex+1);
	rtSummary.AddRow(strRowName, vSummary, strLab, vstrSummaryLabels, vstrSummaryTagName, 0x00202015+nIndex); //IDST_DESC_SUMMARY_RESULTS+nIndex);		
	///Sophy 3/30/2009 QA80-13352 SUPPORT_SPECIFY_COLUMN_DESIGNATIONS_IN_REPORT_TABLES
	TreeNode trRow = rtSummary.GetNode(strRowName);
	if ( trRow )
		tree_set_attribute_to_all_nodes(trRow, STR_COL_DESIGNATION_ATTRIB, (string)OKDATAOBJ_DESIGNATION_Y);
	///end SUPPORT_SPECIFY_COLUMN_DESIGNATIONS_IN_REPORT_TABLES
	
	// add footnote
	string strCensor;
	vector_to_str_list(vCensored, strCensor, true, true, ',');
	/// Nicole 07/05/2007 v8.0655 REMOVE_SPACE_FOR_LOCATION_STRING
	//string strFootNote = _L("Censored Value(s): ") + strCensor;
	string strFootNote = _L("Censored Value(s):") + " " + strCensor;
	/// END REMOVE_SPACE_FOR_LOCATION_STRING
	TreeNode trFooter = tree_check_get_node(rtSummary, "Footer", IDE_FOOTNOTE_BEGIN, TREE_Footnote, "1"); // just need the TREE_Footnote attribute, value does not matter, so 1 is good
	trFooter.strVal = strFootNote;		
			
}

static int 	_surv_get_rt_id(const int nGroupIndex, const int nPlotType)
{
	return  REPORT_TABLE + nPlotType ;
}

static int _surv_get_curve_id(const int nGroupIndex)
{
	return IDST_FIT_Y + (nGroupIndex+1) * 5;
}


string surv_get_long_name(const int iPlotType, const bool bInGroup, LPCSTR lpsczGroup)
{
	string strTmp, strName;

	switch(iPlotType)
	{
	case SURV_PLOT_SF:
		strName= _L("Survival Function");
		break;
	case SURV_PLOT_OMSF:
		strName=_L("One Minus Survival Function");	
		break;
	case SURV_PLOT_LSF:
		strName=_L("Log Survival Function");	
		break;
	case SURV_PLOT_HAZARD:
		strName=_L("Hazard Function");
		break;
	}
	
	if (lpsczGroup && bInGroup)
	{
		strTmp.Format("(%s)", lpsczGroup);
		strName += strTmp;
	}
	
	return strName;
}

static string _surv_get_name(const int iPlotType)
{
	string strName;
	switch(iPlotType)
	{
	case SURV_PLOT_SF:
		strName="SF";
		break;
	case SURV_PLOT_OMSF:
		strName="OMSF";	
		break;
	case SURV_PLOT_LSF:
		strName="LSF";	
		break;
	case SURV_PLOT_HAZARD:
		strName="HAZARD";
		break;
	}
	
	return strName;
}

static bool _surv_rd_set_data(ReportData& outData, const vector& vTime, const vector& vSurv, const int nIndex, const vector<string> vstrGroup, const int nPlotType)
{
	if (!outData)
		return false;
	
	int nTableID =  _surv_get_rt_id(nIndex, nPlotType);
	string strName = _surv_get_name(nPlotType);
	string strLongName = surv_get_long_name(nPlotType);
	ReportTable rtSFCurves = outData.CreateTable(strName, strLongName, nTableID);
	string strTmp = "";
	if (" " != vstrGroup[nIndex])	strTmp.Format("(%s)", vstrGroup[nIndex]);
	rtSFCurves.AddColumn(vTime, "Time"+ftoa(nIndex), _surv_get_curve_id(nIndex)+1, _L("Time"), OKDATAOBJ_DESIGNATION_X);
	rtSFCurves.AddColumn(vSurv, "Survival"+ftoa(nIndex), _surv_get_curve_id(nIndex)+2, _L("Survival")+strTmp, OKDATAOBJ_DESIGNATION_Y);	
	
	return true;
}

/// Iris 7/13/2009 QA80-8440 ADD_PLOT_WEIBULL_XF, moved from kaplanmeier XF
void get_surv_plot_data(const int nSurvivEstim, const SAEstim *pSurvivEstim, vector& vX, vector& vY, vector& vErrors)
{
	vX.SetSize(nSurvivEstim+1);
	vY.SetSize(nSurvivEstim+1);
	vErrors.SetSize(nSurvivEstim+1);
	vX[0] = 0;
	vY[0] = 1;
	//vErrors[0] = 1;
	vErrors[0] = 0;
	
	for (int ii = 0; ii < nSurvivEstim; ii++)
	{
		vX[ii+1] = pSurvivEstim[ii].Time;
		vY[ii+1] = pSurvivEstim[ii].Surv;
		vErrors[ii+1] = pSurvivEstim[ii].SD;
		
	}
}
///end ADD_PLOT_WEIBULL_XF

bool  surv_update_report_data(ReportData& outData, const double dConf, const vector& vX, const vector& vY, const vector& vErrors, const int nIndex, const vector<string> vstrGroup, const bool bSF, const bool bHazard, const bool bSFCI, const bool bOMSF, const bool bLSF)
{
	if( vX.GetSize() <= 1 )
		return FALSE;
	
	vector vTime, vSurv;
	vTime.SetSize(vX.GetSize());
	vSurv.SetSize(vY.GetSize());
	    
	if(bSF)
	{
		vTime = vX;
	    vSurv = vY;
		_surv_rd_set_data(outData, vTime, vSurv, nIndex, vstrGroup, SURV_PLOT_SF);
		
		if(bSFCI)
		{
			vector vUpperConf, vLowerConf;
			vUpperConf.SetSize(vX.GetSize());
			vLowerConf.SetSize(vX.GetSize());
		    for(int ii=0; ii<vSurv.GetSize(); ii++)
		    {
		       	vUpperConf[ii] = vSurv[ii] + (norminv((dConf+1)/2)) * vErrors[ii];
		       	vLowerConf[ii] = vSurv[ii] - (norminv((dConf+1)/2)) * vErrors[ii];
		    }
			TreeNode 	trTemp = tree_get_node_by_id(outData, _surv_get_rt_id(nIndex, SURV_PLOT_SF));		
			ReportTable rtSFCurves(trTemp);		
    		string strUCI, strLCI;
    		strUCI.Format("%s UCI", ftoa(dConf*100)+"%");
    		strLCI.Format("%s LCI", ftoa(dConf*100)+"%");
    		rtSFCurves.AddColumn(vUpperConf, "UCI"+ftoa(nIndex), _surv_get_curve_id(nIndex)+3, strUCI, OKDATAOBJ_DESIGNATION_Y);
    		rtSFCurves.AddColumn(vLowerConf, "LCI"+ftoa(nIndex), _surv_get_curve_id(nIndex)+4, strLCI, OKDATAOBJ_DESIGNATION_Y);
		}
	}
	
	if(bOMSF)
	{
		vTime = vX;
		vSurv = 1-vY;
		_surv_rd_set_data(outData, vTime, vSurv, nIndex, vstrGroup, SURV_PLOT_OMSF);
	}	
	if(bHazard)
	{
		vTime = vX;
		vSurv[0] = 0;
		for(int ii = 1; ii < vY.GetSize(); ii++)
			vSurv[ii] = (vY[ii]>0) ? -log(vY[ii]) : NANUM;

 		_surv_rd_set_data(outData, vTime, vSurv, nIndex, vstrGroup, SURV_PLOT_HAZARD);
		
	}
	if(bLSF)
	{
		vTime = vX;
		vSurv[0] = 0;
		for(int ii = 1; ii < vY.GetSize(); ii++)
			vSurv[ii] = (vY[ii]>0) ? log(vY[ii]) : NANUM;

 		_surv_rd_set_data(outData, vTime, vSurv, nIndex, vstrGroup, SURV_PLOT_LSF);
 		
	}

	return TRUE;
}

int get_plot_number(const TreeNode& trGetN)
{
	int nPlot = trGetN.sf.nVal;
	nPlot += trGetN.hazard.nVal;
	if (trGetN.omsf) nPlot += trGetN.omsf.nVal;
	if (trGetN.lsf) nPlot += trGetN.lsf.nVal;
	return nPlot;
}

static bool _dp_set_style_color(DataPlot& dp, int iStyle, int iColor)
{
	TreeNode tr=dp.GetFormat(FPB_ALL, FOB_ALL, true, true);
	tr.Root.Line.Style.nVal = iStyle;
	dp.ApplyFormat(tr, true, true);
	dp.SetColor(iColor);	
	return true;
}

static string _legend_descp_line_style(const int nGroupIndex)
{
	string str;
	if (nGroupIndex != 0) str += "\n";
	string strLine;
	strLine.Format("\l(%d)", nGroupIndex+1);
	str += strLine;
	return str;	
}

static bool _survival_ploting(vector<string>& vsLabel, int iPlotType, int nGroupIndex, bool bInOneLayer, GraphPage & gp, ReportData& rd)
{
	XFExeContext	*pxfexectxt = Project.GetCurrentXFExeCtxt();
	int nPlotID = SURV_PLOT_BEGIN+(iPlotType+1)*10000 * ((int)bInOneLayer + 100); 
	if (!bInOneLayer || 0 == nGroupIndex) nPlotID += nGroupIndex;
	gp = pxfexectxt->GetGraph(nPlotID); 
	int nGroups = vsLabel.GetSize();
	
	//bool bAddLNGName = !(!bInOneLayer&&1<nGroups);
	bool bAddLNGName = 1<nGroups;
    string strTemplate = (iPlotType==SURV_PLOT_SF||iPlotType==SURV_PLOT_OMSF) ? "SurvivalSF" : "SurvivalPlot";
    
	GraphLayer gl;
	if (gp)
	{
		gl = gp.Layers(0);
		//if (!pxfexectxt->IsAddPlots())
		//{
			//for(int ii = gl.DataPlots.Count(); ii > 0; ii--)
				//gl.RemovePlot(0);  
		//}
	}else
	{
		gp.Create(strTemplate, CREATE_HIDDEN);
		gp.SetLongName(surv_get_long_name(iPlotType, bAddLNGName, vsLabel[nGroupIndex]));
		gp.SetName(_surv_get_name(iPlotType), OCD_ENUM_NEXT);
		gp.TitleShow = WIN_TITLE_SHOW_LABEL;
		gl = gp.Layers(0);
	}
	
	if (gl)
	{
		int nXID = _surv_get_curve_id(nGroupIndex)+1;
		int nYID = _surv_get_curve_id(nGroupIndex)+2;
		
		///Echo 3/26/08 QA70-11315 v8.0832b WRONG_SA_PLOT_LEGEND_IN_GJ
		//GraphObject	goKey= gl.GraphObjects("Key");
		//if (goKey)
		//{
			//string strLegend = goKey.Text;
			//if (!strLegend.Compare("\l(1) Survivorship Function")) 
				//goKey.Text = "";
		//}
		///END WRONG_SA_PLOT_LEGEND_IN_GJ
		
		DataRange drPlot;
		DataPlot dp;
		int nPlot;
		int nIDReportDdata = _surv_get_rt_id(nGroupIndex, iPlotType);
		int nLineIndex = bInOneLayer ? nGroupIndex : 0;
		if (0 != rd.GetDataRange(drPlot,nIDReportDdata , nXID, &nYID))
		{
			vector<int> 	vnPlotIndices;
			if( !check_has_plotted_in_graph(drPlot, gl, vnPlotIndices) )
			{
				nPlot = gl.AddPlot(drPlot, IDM_PLOT_LINE);
				dp = gl.DataPlots(nPlot);
				_dp_set_style_color(dp, 0, nLineIndex);
				///Echo 8/20/10 ORG-861-P1 	PLOT_CURVE_TO_FULL_X_RANGE
				int nn = 1; 
				dp.LabTalk("lm", &nn);
				///END PLOT_CURVE_TO_FULL_X_RANGE
				///Echo 3/26/08 QA70-11315 v8.0832b WRONG_SA_PLOT_LEGEND_IN_GJ
				//goKey.Text += _legend_descp_line_style(nLineIndex) + surv_get_long_name(iPlotType, bAddLNGName, vsLabel[nGroupIndex]);
			}
			
		}else
			return error_report("fail to create plot");
	
		
		nYID = _surv_get_curve_id(nGroupIndex)+3;
		if (0 != rd.GetDataRange(drPlot, nIDReportDdata, nXID, &nYID) && find_plot_index_by_key(gl, "UCI") == -1)
		{
			nPlot = gl.AddPlot(drPlot, IDM_PLOT_LINE);
			dp = gl.DataPlots(nPlot);
			_dp_set_style_color(dp, 2, 1);
			//goKey.Text += "\n" + _L("\l(2) Confindence Band");///Echo 3/26/08 QA70-11315 v8.0832b WRONG_SA_PLOT_LEGEND_IN_GJ
		}
	
		nYID = _surv_get_curve_id(nGroupIndex)+4;
		if (0 != rd.GetDataRange(drPlot, nIDReportDdata, nXID, &nYID) && find_plot_index_by_key(gl, "LCI") == -1)
		{
			nPlot = gl.AddPlot(drPlot, IDM_PLOT_LINE);
			dp = gl.DataPlots(nPlot);
			_dp_set_style_color(dp, 2, 1);
		}
		
		gl.Rescale();
		///Echo 3/26/08 QA70-11315 v8.0832b WRONG_SA_PLOT_LEGEND_IN_GJ
		legend_update(gl);
	}
	pxfexectxt->SetGraph(gp, nPlotID);
	
	return true;
    
	
}

bool survival_rd_plotting(const ReportData& rd, vector<string>& vsLabel, ReportTree& rtPlot, const bool bSF, const bool bHazard, const bool bSFCI, const bool  bOMSF, const bool bLSF, const bool bInOneLayer, const bool bCox)
{
	
	int nPlots = bSF + bHazard + bOMSF + bLSF;
	rtPlot.ID = IDST_XF_RT_PLOT;
	int nGroup = vsLabel.GetSize();
	string strRTName = (bCox) ? _L("Survival Plots at Mean of Covariates") : _L("Survival Plots"); 
	ReportTable grt = rtPlot.CreateTable("Graph", strRTName, IDST_RESULT_GRAPHS, nGroup, nPlots);
	int iPosition = -1;
	if(bSF)
	{
		iPosition++;
		for(int ii = 0; ii < nGroup; ii++)
		{

		    GraphPage gp;
			if ( !_survival_ploting(vsLabel,SURV_PLOT_SF, ii, bInOneLayer, gp, rd) )
				return false;
			
			string strLabel = (bInOneLayer) ? "" : vsLabel[ii];
			if (bInOneLayer && 0 != ii)	continue;
			/// YuI 09/20/07 QA70-10397 SHOULD_ALLOW_SETREPORTTREE_TO_MOVE_EMBEDDED_GRAPH_TO_DIFFERENT_LOCATION
			//	grt.SetCell(ii, iPosition, gp);
			grt.SetCell(ii, iPosition, gp, EMBEDGRAPH_MOVE_IF_ALREADY_EMBEDDED);
			/// end SHOULD_ALLOW_SETREPORTTREE_TO_MOVE_EMBEDDED_GRAPH_TO_DIFFERENT_LOCATION
			grt.SetCell(ii, -1,strLabel);
		}
		grt.SetCell(-1, iPosition, surv_get_long_name(SURV_PLOT_SF));
	}
	if(bOMSF)
	{
		iPosition++;
		for(int ii = 0; ii < nGroup; ii++)
		{
		    GraphPage gp;
			if ( !_survival_ploting(vsLabel,SURV_PLOT_OMSF, ii, bInOneLayer,gp, rd) )
				return false;
			string strLabel = (bInOneLayer) ? "" : vsLabel[ii];
			if (bInOneLayer && 0 != ii)	continue;
			/// YuI 09/20/07 QA70-10397 SHOULD_ALLOW_SETREPORTTREE_TO_MOVE_EMBEDDED_GRAPH_TO_DIFFERENT_LOCATION
			//	grt.SetCell(ii, iPosition, gp);
			grt.SetCell(ii, iPosition, gp, EMBEDGRAPH_MOVE_IF_ALREADY_EMBEDDED);
			/// end SHOULD_ALLOW_SETREPORTTREE_TO_MOVE_EMBEDDED_GRAPH_TO_DIFFERENT_LOCATION
			grt.SetCell(ii, -1,strLabel);
		}
		grt.SetCell(-1, iPosition, surv_get_long_name(SURV_PLOT_OMSF));
	}
	if(bHazard)
	{
		iPosition++;
		for(int ii = 0; ii < nGroup; ii++)
		{
		    GraphPage gp;
			if ( !_survival_ploting(vsLabel,SURV_PLOT_HAZARD, ii, bInOneLayer, gp, rd) )
				return false;
			string strLabel = (bInOneLayer) ? "" : vsLabel[ii];
			if (bInOneLayer && 0 != ii)	continue;
			/// YuI 09/20/07 QA70-10397 SHOULD_ALLOW_SETREPORTTREE_TO_MOVE_EMBEDDED_GRAPH_TO_DIFFERENT_LOCATION
			//	grt.SetCell(ii, iPosition, gp);
			grt.SetCell(ii, iPosition, gp, EMBEDGRAPH_MOVE_IF_ALREADY_EMBEDDED);
			/// end SHOULD_ALLOW_SETREPORTTREE_TO_MOVE_EMBEDDED_GRAPH_TO_DIFFERENT_LOCATION
			grt.SetCell(ii, -1,strLabel);
		}
		grt.SetCell(-1, iPosition, surv_get_long_name(SURV_PLOT_HAZARD));
	}
	if(bLSF)
	{
		iPosition++;
		for(int ii = 0; ii < nGroup; ii++)
		{
		    GraphPage gp;
			if ( !_survival_ploting(vsLabel,SURV_PLOT_LSF, ii, bInOneLayer, gp, rd) )
				return false;
			string strLabel = (bInOneLayer) ? "" : vsLabel[ii];
			if (bInOneLayer && 0 != ii)	continue;
			/// YuI 09/20/07 QA70-10397 SHOULD_ALLOW_SETREPORTTREE_TO_MOVE_EMBEDDED_GRAPH_TO_DIFFERENT_LOCATION
			//	grt.SetCell(ii, iPosition, gp);
			grt.SetCell(ii, iPosition, gp, EMBEDGRAPH_MOVE_IF_ALREADY_EMBEDDED);
			/// end SHOULD_ALLOW_SETREPORTTREE_TO_MOVE_EMBEDDED_GRAPH_TO_DIFFERENT_LOCATION
			grt.SetCell(ii, -1,strLabel);
		}
		grt.SetCell(-1, iPosition, surv_get_long_name(SURV_PLOT_LSF));
	}
	
	
	return true;		
}

static void _get_ranks(NPHRanks *pRanks, int ii, vector &vRanks)
{
	vRanks.SetSize(3);
	vRanks[0] = pRanks[ii].N;
	vRanks[1] = pRanks[ii].MeanRank;
	vRanks[2] = pRanks[ii].SumRank;	
}

void rt_add_nph_ranks(ReportBase& outRT, const NPHRanks *Ranks, const vector<string> &vstrGroup, LPCSTR lpsczCols)
{
	
	int nGroups = vstrGroup.GetSize();
	
	TreeNode trRanks= tree_get_node_by_id(outRT, IDST_NPH_SCORES_RESULT, true);
	ReportTable rtRanks(trRanks);
	if (!trRanks)
		rtRanks = outRT.CreateTable("Ranks", _L("Ranks"), IDST_NPH_SCORES_RESULT);
	
	int nCounts = (trRanks) ? trRanks.GetNodeCount() : 0;
		
	vector<string> vRankLabels(3);
	vRankLabels[0] = _L("N");
	vRankLabels[1] = _L("Mean Rank");
	vRankLabels[2] = _L("Sum Rank");
	
	vector<string> vstrTagName;
	string strTagName = NPH_RANK;
	strTagName.GetTokens(vstrTagName, '|');
	
	
	vector vRanks;
	for (int ii = 0; ii < nGroups; ii++)
	{
		_get_ranks(Ranks, ii, vRanks);
		string strRow = "Rank" + ftoa(nCounts+ii+1);
		if (lpsczCols)
			rtRanks.AddRow(strRow, vRanks, lpsczCols, vRankLabels, vstrTagName, make_one_set_ID(IDST_NPH_SCORES_RESULT, ii+nCounts), vstrGroup[ii] );		
		else
			rtRanks.AddRow(strRow, vRanks, vstrGroup[ii], vRankLabels, vstrTagName, make_one_set_ID(IDST_NPH_SCORES_RESULT, ii+nCounts));		
		///Sophy 3/30/2009 QA80-13352 SUPPORT_SPECIFY_COLUMN_DESIGNATIONS_IN_REPORT_TABLES
		TreeNode trRow = rtRanks.GetNode(strRow);
		if ( trRow )
			tree_set_attribute_to_all_nodes(trRow, STR_COL_DESIGNATION_ATTRIB, (string)OKDATAOBJ_DESIGNATION_Y);
		///end SUPPORT_SPECIFY_COLUMN_DESIGNATIONS_IN_REPORT_TABLES

	}
}


/*
#define KW_FOOTER1			"At the 0.05 level, the populations ARE significantly different"
#define KW_FOOTER2			"At the 0.05 level, the populations are NOT significantly different"
*/

///Echo 6/19/06 NPH_STATS_OUTPUT_ERROR
//static void get_nph_stats(NPHStats &stStats, vector &vNPHStats)
void get_nph_stats(NPHStats &stStats, vector &vNPHStats, bool bNPHTwoSample)
{
	vNPHStats.SetSize(3);
	vNPHStats[0] = stStats.Stat;
	//vNPHStats[1] = stStats.Z;
	vNPHStats[1] = bNPHTwoSample ? stStats.Z : stStats.DOF;
	vNPHStats[2] = stStats.Prob;	
	
}

bool rt_add_friedman_stats(ReportBase& outRT, const NPHStats &Stats, const vector<string> &vstrGroup, const string& strFooter1, const string& strFooter2, const string& strHYPT)
{
	if (!outRT)
		return false;
	
	int ii;
	ReportTable rtNPHStats = outRT.CreateTable("Stats", _L("Test Statistics"), IDST_NONPARAMETRIC_TTEST_RESULT);
	
	vector<string> vstrNPHStatsLabels, vstrNPHStatsTagNames;	
	string str = NPH_K_SAMP_STATS;
	str.GetTokens(vstrNPHStatsLabels, '|');
	
	str = TEST_STATS_TABLE;
	str.GetTokens(vstrNPHStatsTagNames, '|');
	
	vector vNPHStats;
	get_nph_stats(Stats, vNPHStats, false);
	rtNPHStats.AddRow("Stats",vNPHStats, " ", vstrNPHStatsLabels, vstrNPHStatsTagNames, IDST_NONPARAMETRIC_TTEST_RESULT);
	
	return true;
}
///Echo 6/19/06 NPH_STATS_OUTPUT_ERROR
///Statistic of NPH K Sample and NPH Two Sample is different
//void rt_add_nph_stats(ReportBase& outRT, const NPHStats &Stats, const vector<string> &vstrGroup, const string& strFooter1, const string& strFooter2, const string& strHYPT, const vector<string>& vstrStatsLabels)
//--- Jacky 07/22/10 ORG-102 USER_CAN_SET_SIGNIFICANCE_LEVEL
//void rt_add_nph_stats(ReportBase& outRT, const NPHStats &Stats, const vector<string> &vstrGroup, const string& strFooter1, const string& strFooter2, const string& strHYPT, const vector<string>& vstrStatsLabels, const bool bNPHTwoSample, LPCSTR lpsczCols)
void rt_add_nph_stats(ReportBase& outRT, const NPHStats &Stats, const vector<string> &vstrGroup, const string& strFooter1, const string& strFooter2, const string& strHYPT, const vector<string>& vstrStatsLabels, const bool bNPHTwoSample, LPCSTR lpsczCols,double dAlpha)
//--- end USER_CAN_SET_SIGNIFICANCE_LEVEL
{
	//int ii;
	//ReportTable rtNPHStats = outRT.CreateTable("Stats", _L("Test Statistics"), IDST_NONPARAMETRIC_TTEST_RESULT);

	TreeNode trNPHStats = tree_get_node_by_id(outRT, IDST_NONPARAMETRIC_TTEST_RESULT, true);
	ReportTable rtNPHStats(trNPHStats);
	if (!trNPHStats)
		rtNPHStats = outRT.CreateTable("Stats", _L("Test Statistics"), IDST_NONPARAMETRIC_TTEST_RESULT);
	
	int ii = (trNPHStats) ? trNPHStats.GetNodeCount() : 0;
	
	
	vector<string> vstrNPHStatsLabels;
	if(vstrStatsLabels!=NULL)
	{
		vstrNPHStatsLabels = vstrStatsLabels;
	}
	else
	{
		string str = bNPHTwoSample ? NPH_2_SAMP_STATS : NPH_K_SAMP_STATS;
		str.GetTokens(vstrNPHStatsLabels, '|');
	}
	
	vector vNPHStats;
	get_nph_stats(Stats, vNPHStats, bNPHTwoSample);
	string strLabel = (lpsczCols) ? lpsczCols : " ";
	rtNPHStats.AddRow("Stats",vNPHStats, strLabel, vstrNPHStatsLabels, NULL, make_one_set_ID(IDST_NONPARAMETRIC_TTEST_RESULT, ii));
	///Sophy 3/30/2009 QA80-13352 SUPPORT_SPECIFY_COLUMN_DESIGNATIONS_IN_REPORT_TABLES
	tree_set_attribute_to_all_nodes(rtNPHStats.Stats, STR_COL_DESIGNATION_ATTRIB, (string)OKDATAOBJ_DESIGNATION_Y);
	///end SUPPORT_SPECIFY_COLUMN_DESIGNATIONS_IN_REPORT_TABLES
	string strResult, strFootNote;
	if (Stats.Prob == NANUM)
		ocu_load_err_msg_str(FOOTNOTE_NO_CONCLUSION, &strResult);
	else
	{
		//--- Jacky 07/22/10 ORG-102 USER_CAN_SET_SIGNIFICANCE_LEVEL
		//if (Stats.Prob >= 0.05)
		if (Stats.Prob >= dAlpha)
		//--- end USER_CAN_SET_SIGNIFICANCE_LEVEL
			strResult = strFooter2;
		else
			strResult = strFooter1;
	}
	//--- Jacky 07/22/10 ORG-102 USER_CAN_SET_SIGNIFICANCE_LEVEL
	strResult.Format(strResult,dAlpha);
	//--- end USER_CAN_SET_SIGNIFICANCE_LEVEL
	strFootNote = strHYPT + strResult;
	TreeNode trFooter = tree_check_get_node(rtNPHStats, "Footer", IDE_FOOTNOTE_BEGIN, TREE_Footnote, "1"); // just need the TREE_Footnote attribute, value does not matter, so 1 is good
	trFooter.strVal = strFootNote;		
}

static void _get_freqs(NPHFreqs *pFreqs, int ii, vector &vFreqs)
{
	vFreqs.SetSize(3);
	vFreqs[0] = pFreqs[ii].N;
	vFreqs[1] = pFreqs[ii].GTMd;
	vFreqs[2] = pFreqs[ii].LEMd;
}
void rt_add_nph_freq(ReportBase& outRT, const NPHFreqs *Freqs, const vector<string> &vstrGroup, LPCSTR lpsczColLabels)
{
	//int ii;
	
	//int nGroups=vstrGroup.GetSize();
	
	int nGroups = vstrGroup.GetSize();
	
	TreeNode trFreqs= tree_get_node_by_id(outRT, IDST_NPH_SCORES_RESULT, true);
	ReportTable rtFreqs(trFreqs);
	if (!trFreqs)
		rtFreqs = outRT.CreateTable("Freqs", _L("Frequencies"), IDST_NPH_SCORES_RESULT);
	
	int nCounts = (trFreqs) ? trFreqs.GetNodeCount() : 0;
		
	vector<string> vFreqLabels(3);
	vFreqLabels[0] = _L("N");	
	vFreqLabels[1] = _L(">Median");
	vFreqLabels[2] = _L("<=Median");

	vector<string> vstrTagName;
	string strTagName = NPH_MEDIAN_FREQ;
	strTagName.GetTokens(vstrTagName, '|');
	
	vector vFreqs;
	//int nCols = (vstrColLabels) ? vstrColLabels.GetSize() - 1 : 0;
	//for (int jj = 0; jj <= nCols; jj++)
	for (int ii = 0; ii < nGroups; ii++)
	{
		_get_freqs(Freqs, ii, vFreqs);
		string strRow = "Freq" + ftoa(nCounts+ii+1);
		if (lpsczColLabels)
			rtFreqs.AddRow(strRow, vFreqs, lpsczColLabels, vFreqLabels, vstrTagName, make_one_set_ID(IDST_NPH_SCORES_RESULT, ii+nCounts), vstrGroup[ii]);		
		else
			rtFreqs.AddRow(strRow, vFreqs, vstrGroup[ii], vFreqLabels, vstrTagName, make_one_set_ID(IDST_NPH_SCORES_RESULT, ii+nCounts));		
		///Sophy 3/30/2009 QA80-13352 SUPPORT_SPECIFY_COLUMN_DESIGNATIONS_IN_REPORT_TABLES
		TreeNode trRow = rtFreqs.GetNode(strRow);
		if ( trRow )
			tree_set_attribute_to_all_nodes(trRow, STR_COL_DESIGNATION_ATTRIB, (string)OKDATAOBJ_DESIGNATION_Y);
		///end SUPPORT_SPECIFY_COLUMN_DESIGNATIONS_IN_REPORT_TABLES
	}
}

///Kyle 01/05/2009 CORR_OUTPUT_MESSAGE_ABOUT_COLUMNS_MISSING_VALUES
//bool corr_get_data(const Range& r, matrix& mData, vector<string>& vstrFactors, int nExcludeMissing)
bool corr_get_data(const Range& r, matrix& mData, vector<string>& vstrFactors, vector<string>& vstrFactorsMissingVal, int nExcludeMissing)
///End CORR_OUTPUT_MESSAGE_ABOUT_COLUMNS_MISSING_VALUES
{
	if (!r.IsValid())
		return false;
	
	DWORD dwRules = DRR_NO_WEIGHTS;
	int nData = r.GetNumData(dwRules);
	if (0 >= nData)
		return false;
	///Kyle 12/30/2008 FIX_GETTING_THE_WRONG_FACTORS
	//if(!get_data_from_dr_to_mat(r, mData))
	if(!get_data_from_dr_to_mat(r, mData, true, false))
	///End FIX_GETTING_THE_WRONG_FACTORS
		return false;

	///Kyle 12/30/2008 FIX_GETTING_THE_WRONG_FACTORS
	//if (CORR_EXCLUDE_MISSING_LISTWISE == nExcludeMissing)
	//{
		//mData.RemoveEmptyRows(false);
	//}
	///End FIX_GETTING_THE_WRONG_FACTORS
	
	int nCols = mData.GetNumCols();
	if (0 == nCols || 0 == mData.GetNumRows())
		return false;
	
	///Echo 5/29/08 v8.0873 CORR_ENABLE_EMPTY_COL
	/*
	vstrFactors.SetSize(nCols);	
	for (int ii = 0; ii < nCols; ii++)
	{
		vstrFactors[ii] =  range_get_col_name(r, ii);
	}
	*/
	///Kyle 01/07/2009 PLOT_MATRIX_HANDLE_COLUMN_ALL_TEXT
	//int jj = 0;	
	///End PLOT_MATRIX_HANDLE_COLUMN_ALL_TEXT
	///Kyle 01/05/2009 CORR_OUTPUT_MESSAGE_ABOUT_COLUMNS_MISSING_VALUES
	if(vstrFactorsMissingVal)
		vstrFactorsMissingVal.SetSize(0);
	///End CORR_OUTPUT_MESSAGE_ABOUT_COLUMNS_MISSING_VALUES
	vstrFactors.SetSize(nCols);	
	for (int ii = 0; ii < nData; ii++)
	{
		///Kyle 01/07/2009 PLOT_MATRIX_HANDLE_COLUMN_ALL_TEXT
		//if (100 != dr_get_col_percent_text(r, ii, true))
		//{
			/////------ Folger 12/26/08 QA80-12642 v8.0991 CONSISTENT_SHOW_LN_ONLY_IF_EXIST_FOR_STATISTICAL_TOOLS
			////vstrFactors[jj] =  range_get_col_name(r, ii);
			//vstrFactors[jj] =  range_get_col_name(r, ii, TRUE);
			/////------ End CONSISTENT_SHOW_LN_ONLY_IF_EXIST_FOR_STATISTICAL_TOOLS
			//jj++;
			//if (jj >= nCols)
				//break;
		//}
		// get all factors, those no used (factor for column all text ect) will be removed
		vstrFactors[ii] =  range_get_col_name(r, ii, TRUE);
		///End PLOT_MATRIX_HANDLE_COLUMN_ALL_TEXT
	}	
	///end CORR_ENABLE_EMPTY_COL

	///Kyle 12/30/2008 FIX_GETTING_THE_WRONG_FACTORS
	// remove missing cols
	ASSERT(mData.GetNumCols() == vstrFactors.GetSize());
	vector<uint> vnIndices;
	mData.Transpose();
	mData.RemoveEmptyRows(true, vnIndices);
	mData.Transpose();
	
	for(ii=vnIndices.GetSize()-1; ii>=0; ii--)
	{
		ASSERT(vstrFactors.GetSize() > vnIndices[ii]);
		///Kyle 01/05/2009 CORR_OUTPUT_MESSAGE_ABOUT_COLUMNS_MISSING_VALUES
		if(vstrFactorsMissingVal)
			vstrFactorsMissingVal.InsertAt(0, vstrFactors[ vnIndices[ii] ]);
		///End CORR_OUTPUT_MESSAGE_ABOUT_COLUMNS_MISSING_VALUES
		vstrFactors.RemoveAt(vnIndices[ii]);
	}
	if (CORR_EXCLUDE_MISSING_LISTWISE == nExcludeMissing)
	{
		mData.RemoveEmptyRows(false);
	}
	///End FIX_GETTING_THE_WRONG_FACTORS
	
	return true;
}

void corr_get_data(const Range& r, vector& vData, vector<int>& vLevels, vector<string>& vstrFactors, int& nNumRanges) 
{
	if (!r.IsValid())
	    XF_THROW(ERR_NO_DATA_SELEC);
	
	vector vSubData;
	DWORD dwRules = DRR_NO_WEIGHTS;
	DWORD dwPlotID;
	
	///*** Get Data
	nNumRanges = r.GetNumData(dwRules);
	vLevels.SetSize(nNumRanges);
	vstrFactors.SetSize(nNumRanges);
	matrix mTemp;
	///Kyle 12/30/2008 FIX_GETTING_THE_WRONG_FACTORS
	//if(!get_data_from_dr_to_mat(r, mTemp))
	if(!get_data_from_dr_to_mat(r, mTemp, true, false))
	///End FIX_GETTING_THE_WRONG_FACTORS
		return;

	int ii;
	for (ii = 0; ii < nNumRanges; ii++)
	{
		///------ Folger 12/26/08 QA80-12642 v8.0991 CONSISTENT_SHOW_LN_ONLY_IF_EXIST_FOR_STATISTICAL_TOOLS
		//vstrFactors[ii] =  range_get_col_name(r, ii);
		vstrFactors[ii] =  range_get_col_name(r, ii, TRUE);
		///------ End CONSISTENT_SHOW_LN_ONLY_IF_EXIST_FOR_STATISTICAL_TOOLS
	}
	
	///Kyle 12/30/2008 FIX_GETTING_THE_WRONG_FACTORS
	// remove missing cols
	ASSERT(mTemp.GetNumCols() == vstrFactors.GetSize());
	vector<uint> vnIndices;
	mTemp.Transpose();
	mTemp.RemoveEmptyRows(true, vnIndices);
	mTemp.Transpose();
	
	for(ii=vnIndices.GetSize()-1; ii>=0; ii--)
	{
		ASSERT(vstrFactors.GetSize() > vnIndices[ii]);
		vstrFactors.RemoveAt(vnIndices[ii]);
	}
	///End FIX_GETTING_THE_WRONG_FACTORS

	mTemp.RemoveEmptyRows(false);
	
	for (ii = 0; ii < nNumRanges; ii++)
	{
 		mTemp.GetColumn(vSubData, ii);
 		vData.Append(vSubData);
		vLevels[ii] = vSubData.GetSize();
	}

}

///Kyle 12/18/2008 ADD_MESSAGE_TO_DISCRIBE_SIGNIFICANCE_RESULT_FOR_CORRELEATION_COEFFICIENT
//void rt_add_corr_coef_table(ReportTree& outRT, matrix mCorr, matrix mSig, vector<string> vstrFactors, string strTableName, string strFuncName, int nBaseID)
void rt_add_corr_coef_table(ReportTree& outRT, matrix mCorr, matrix mSig, vector<string> vstrFactors, string strTableName, string strFuncName, int nBaseID, bool bFlag)
///End ADD_MESSAGE_TO_DISCRIBE_SIGNIFICANCE_RESULT_FOR_CORRELEATION_COEFFICIENT
{
	//////////////////////////////////////////////////////////////////
	// Correlation Coefficients
	//////////////////////////////////////////////////////////////////
	/// Nicole 07/05/2007 v8.0655 REMOVE_SPACE_FOR_LOCATION_STRING
	//ReportTable rtStats = outRT.CreateTable(strTableName, strFuncName+_L(" Correlations"), nBaseID);
	string strLabel;
	strLabel.Format(_L("%s Correlations"), strFuncName);
	ReportTable rtStats = outRT.CreateTable(strTableName, strLabel, nBaseID);
	/// END REMOVE_SPACE_FOR_LOCATION_STRING
	
	vector vCorr;
	vector vSig;
	int nSigMarked = 0;		///Kyle 12/18/2008 ADD_MESSAGE_TO_DISCRIBE_SIGNIFICANCE_RESULT_FOR_CORRELEATION_COEFFICIENT, no need to output message string if no marked
	for (int ii = 0; ii < mCorr.GetNumCols(); ii++)
	{
		mCorr.GetRow(vCorr, ii);
		///Kyle 12/18/2008 ADD_MESSAGE_TO_DISCRIBE_SIGNIFICANCE_RESULT_FOR_CORRELEATION_COEFFICIENT
		//int id = make_one_set_ID(nBaseID, ii);
		///// Nicole 07/05/2007 v8.0655 REMOVE_SPACE_FOR_LOCATION_STRING
		////rtStats.AddRow(_L("Corr"+ftoa(ii+1)), vCorr, vstrFactors[ii], vstrFactors, NULL, id, strFuncName+_L(" Corr."));		
		//rtStats.AddRow("Corr"+ftoa(ii+1), vCorr, vstrFactors[ii], vstrFactors, NULL, id, strFuncName+ " " + _L("Corr."));		
		///// END REMOVE_SPACE_FOR_LOCATION_STRING
		///End ADD_MESSAGE_TO_DISCRIBE_SIGNIFICANCE_RESULT_FOR_CORRELEATION_COEFFICIENT
		mSig.GetRow(vSig, ii);
		///Kyle 12/18/2008 ADD_MESSAGE_TO_DISCRIBE_SIGNIFICANCE_RESULT_FOR_CORRELEATION_COEFFICIENT
		int id = make_one_set_ID(nBaseID, ii);
		if(bFlag)
		{
			vector<string> vsCorr;
			convert_double_vector_to_string_vector(vCorr, vsCorr, vCorr.GetSize());
			for(int jj = 0; jj < vSig.GetSize(); jj++)
			{
				if(!is_missing_value(vSig[jj]) && fabs(vSig[jj])<0.05)
				{
					vsCorr[jj] += "*";
					nSigMarked++;
				}
			}
			rtStats.AddRow("Corr"+ftoa(ii+1), vsCorr, vstrFactors[ii], vstrFactors, NULL, id, strFuncName+ " " + _L("Corr."));
		}
		else
		{
			rtStats.AddRow("Corr"+ftoa(ii+1), vCorr, vstrFactors[ii], vstrFactors, NULL, id, strFuncName+ " " + _L("Corr."));
		}
		///End ADD_MESSAGE_TO_DISCRIBE_SIGNIFICANCE_RESULT_FOR_CORRELEATION_COEFFICIENT
		id = make_one_set_ID(nBaseID, 100*(ii+1));
		rtStats.AddRow("Sig"+ftoa(ii+1), vSig, vstrFactors[ii], vstrFactors, NULL, id, _L("Sig."));		
	}
	TreeNode trFooter = tree_check_get_node(rtStats, "Footer", IDE_FOOTNOTE_BEGIN, TREE_Footnote, "1"); // just need the TREE_Footnote attribute, value does not matter, so 1 is good
	///Kyle 12/18/2008 ADD_MESSAGE_TO_DISCRIBE_SIGNIFICANCE_RESULT_FOR_CORRELEATION_COEFFICIENT
	//trFooter.strVal = _L("2-tailed test of significance is used");		
	string strFooter = _L("2-tailed test of significance is used");
	if(nSigMarked > 0)
		strFooter += "\n" + _L("*:Correlation is significant at the 0.05 level");
	trFooter.strVal = strFooter;
	///End ADD_MESSAGE_TO_DISCRIBE_SIGNIFICANCE_RESULT_FOR_CORRELEATION_COEFFICIENT
	

}

bool rt_add_desc_stats(ReportTree& outRT, const DescStatOptions* pDescOpts, const QuantileOptions* pQuanOpts, const DescStatResults *pDescStats, const QuantileResults *pQuantiles, const vector<string>& vstrGroup, const vector<string>& vstrCols)
{
	int nCols = (vstrCols) ? vstrCols.GetSize() -1 : 0; 
	int nGroup = vstrGroup.GetSize();
	int nNumPerGroup = nGroup / (nCols + 1);
	int jj = 0, nCounts = 0;
	//for (int jj = 0; jj <= nCols; jj++)
	for (int ii = 0; ii < nGroup; ii++)
	{
		nCounts++;
		if (nCounts > nNumPerGroup)
		{
			nCounts = 0;
			jj++;
		}
		bool bErr;
		if (vstrCols)
			bErr = rt_add_desc_stats(outRT, pDescOpts, pQuanOpts, &pDescStats[ii], &pQuantiles[ii], vstrGroup[ii], vstrCols[jj]);
		else
			bErr = rt_add_desc_stats(outRT, pDescOpts, pQuanOpts, &pDescStats[ii], &pQuantiles[ii], vstrGroup[ii]);
			
		if (!bErr)
			return bErr;
	}
	

	return true;	
}

bool rt_add_desc_stats(ReportTree& outRT, const DescStatOptions* pDescOpts, const QuantileOptions* pQuanOpts, const DescStatResults *pDescStats, const QuantileResults *pQuantiles, LPCSTR lpsczGroup, LPCSTR lpsczColLabel)
{
	if (!outRT)
		return false;
	
	if (!pDescOpts && !pQuanOpts)
		return false;
	
	if (!pDescStats && !pQuantiles)
		return false;
	
	TreeNode trStats = tree_get_node_by_id(outRT, IDST_DESC_STATS_RESULTS, true);
	
	ReportTable rtStats(trStats);
	if ( !trStats )
		rtStats = outRT.CreateTable("DescStats", _L("Descriptive Statistics"), IDST_DESC_STATS_RESULTS);
	
	rtStats.SetAttribute(STR_ATTRIB_BRANCH, GETNBRANCH_KEEP_SIZE_ON_COLLAPSE);
		
	int ii = (trStats) ? trStats.GetNodeCount() : 0;
	
	Tree trOptions;
	if(pDescOpts) trOptions += *pDescOpts;
	if(pQuanOpts) trOptions += *pQuanOpts;
	
	int nDataID = make_one_set_ID(IDST_DESC_STATS_RESULTS, ii+1);
	string strRow = "R" + ftoa(ii+1);
	/// Iris 4/13/2009 QA80-13392-P1 FIX_EMPTY_LABEL_AFTER_COPY_TABLE_AS_NEW_SHEET
	//TreeNode trRow = tree_check_get_node(rtStats, strRow, nDataID, STR_LABEL_ATTRIB, lpsczColLabel);
	string strLabel = NULL == lpsczColLabel? lpsczGroup : lpsczColLabel;
	string strMoreLabel = NULL == lpsczColLabel? "" : lpsczGroup;
	TreeNode trRow = tree_check_get_node(rtStats, strRow, nDataID, STR_LABEL_ATTRIB, strLabel);
	///end FIX_EMPTY_LABEL_AFTER_COPY_TABLE_AS_NEW_SHEET
	trRow.DataID = nDataID;	
	if (pDescOpts && pDescStats) trRow += *pDescStats;
	if (pQuanOpts && pQuantiles) trRow += *pQuantiles;
	
	foreach(TreeNode trN in trRow.Children)
	{
		string	strLabel;
		strLabel = trN.tagName;	
		trN.SetAttribute(STR_LABEL_ATTRIB, _L(strLabel));
	}
	///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);
	
	if ( trRow.MAD )
		trRow.MAD.SetAttribute(STR_COL_DESIGNATION_ATTRIB, OKDATAOBJ_DESIGNATION_ERROR);
	
	if ( trRow.SDx2 )
		trRow.SDx2.SetAttribute(STR_COL_DESIGNATION_ATTRIB, OKDATAOBJ_DESIGNATION_ERROR);
	
	if ( trRow.SDx3 )
		trRow.SDx3.SetAttribute(STR_COL_DESIGNATION_ATTRIB, OKDATAOBJ_DESIGNATION_ERROR);
	
	if ( trRow.GeoSD )
		trRow.GeoSD.SetAttribute(STR_COL_DESIGNATION_ATTRIB, OKDATAOBJ_DESIGNATION_ERROR);	
	///end SUPPORT_SPECIFY_COLUMN_DESIGNATIONS_IN_REPORT_TABLES
	tree_copy_values_to_attributes(trOptions, trRow);
	octree_delete_nodes_by_attribute(&trRow, STR_SHOW_ATTRIB, false);
	
	/// Iris 4/13/2009 QA80-13392-P1 FIX_EMPTY_LABEL_AFTER_COPY_TABLE_AS_NEW_SHEET
	//tree_add_one_label(trRow, lpsczGroup, 0);
	if( !strMoreLabel.IsEmpty() )
		tree_add_one_label(trRow, strMoreLabel, 0);
	///end FIX_EMPTY_LABEL_AFTER_COPY_TABLE_AS_NEW_SHEET
	
	return true;
}
/*
void one_sample_test_set_footer(const int tail, const double dTestMean, LPCSTR lpsczStat, const double dProb, string& strHYPT, string& strConclusion, LPCSTR lpsczColLabel)
{
	String strSign;
	
	strSign = (dProb < 0.05) ? "significantly" : "not significantly";
	string strTmp;
	string strStat = lpsczStat;
	switch (tail)
	{
		case TAILED_TEST_TWO:
		default:
			strHYPT.Format("Null Hypothesis: %s = %g \nAlternative Hypothesis: %s <> %g \n", strStat, dTestMean, strStat,dTestMean);
			strStat.MakeLower();
			strTmp.Format("At the 0.05 level, the population %s is %s different with the test %s (%g).\n", strStat, strSign, strStat, dTestMean);
			break;
		case TAILED_TEST_UPPER:
			strHYPT.Format("Null Hypothesis: %s <= %g \nAlternative Hypothesis: %s > %g \n", strStat, dTestMean, strStat,dTestMean);
			strTmp.Format("At the 0.05 level, the population %s is %s greater than the test %s (%g).\n", strStat, strSign, strStat, dTestMean);
			break;
		case TAILED_TEST_LOWER:
			strHYPT.Format("Null Hypothesis: %s >= %g \nAlternative Hypothesis: %s < %g \n", strStat, dTestMean, strStat,dTestMean);
			strTmp.Format("At the 0.05 level, the population %s is %s less than the test %s (%g).\n", strStat, strSign, strStat, dTestMean);
			break;
	}
	
	if ( dProb == NANUM)
		ocu_load_err_msg_str(FOOTNOTE_NO_CONCLUSION, &strTmp);
	
	if (lpsczColLabel)
		strConclusion += _L(lpsczColLabel) + ": " + strTmp;
	else
		strConclusion += strTmp;
}
*/
void set_ttest_desc_stats_opt(const DescStatOptions& stDescOpt)
{
	stDescOpt.N = true;
	stDescOpt.Mean = true;
	stDescOpt.SD = true;
	stDescOpt.SEM = true;	
}

bool rt_add_ttest_desc_stats(ReportTree& outRT, const DescStatResults *pDescStats, const vector<string>& vstrGroup)
{
	if (!outRT || 0 >= vstrGroup.GetSize())
		return false;
	
	DescStatOptions stDescOpt;
	QuantileOptions stQuanOpt;
	set_ttest_desc_stats_opt(stDescOpt);
	
	rt_add_desc_stats(outRT, &stDescOpt, NULL, pDescStats, NULL, vstrGroup);
	
	if (vstrGroup.GetSize() > 1)
	{
		TreeNode trStats = tree_get_node_by_id(outRT, IDST_DESC_STATS_RESULTS, true);
		ReportTable rtStats(trStats);
		
		DescStatResults stDescStats;
		stDescStats.Mean = pDescStats[0].Mean - pDescStats[1].Mean;
		int nDataID = make_one_set_ID(IDST_DESC_STATS_RESULTS, 3);
		TreeNode trRow = tree_check_get_node(rtStats,  _L("Difference"), nDataID, STR_LABEL_ATTRIB);		
		trRow.DataID = nDataID;	
		trRow += stDescStats;
		Tree trOptions;
		trOptions = stDescOpt;
		tree_copy_values_to_attributes(trOptions, trRow);
		///Echo 7/28/08 v8.0911 DELETE_HIDE_ZERO_FOR_COPY_TABLE
		octree_delete_nodes_by_attribute(&trRow, STR_SHOW_ATTRIB, false, false);

		tree_add_one_label(trRow, _L("Difference"), 0);
		///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);
		///end SUPPORT_SPECIFY_COLUMN_DESIGNATIONS_IN_REPORT_TABLES
		outRT.DescStats.Difference.N.Remove();
		outRT.DescStats.Difference.SD.Remove();
		outRT.DescStats.Difference.SEM.Remove();
	}		
	
	return true;
	
}

/// Set test statistics to vector for Two-Sample t-Test & Paired-Sample t-Test
void set_ttest_stats_to_vector(const tTestMean2SampleResults stTTStats, vector &vTTStats)
{
	vTTStats.SetSize(3);
	vTTStats[0] = stTTStats.tValue;
	vTTStats[1] = stTTStats.DOF;
	vTTStats[2] = stTTStats.Prob;	
}

/// Set footer for Two-Sample t-Test & Paired-Sample t-Test
//void ttest2_set_footer(const int nTail, const double dTestMean, const tTestMean2SampleResults tRes, string& strHYPT, string& strConclusion)//string& strFooter1, string& strFooter2)
//{
	//String strSign;
	//
	//strSign = (tRes.Prob < 0.05) ? "significantly" : "not significantly";
//
	//switch (nTail)
	//{
		//case TAILED_TEST_TWO:
		//default:			
			//strHYPT.Format("Null Hypothesis: mean1-mean2 = %g \nAlternative Hypothesis: mean1-mean2 <> %g \n", dTestMean, dTestMean);
			//strConclusion.Format("At the 0.05 level, the difference of the population means is %s different with the test difference (%g).", strSign, dTestMean);
			//break;
		//case TAILED_TEST_UPPER:
			//strHYPT.Format("Null Hypothesis: mean1-mean2 <= %g \nAlternative Hypothesis: mean1-mean2 > %g \n", dTestMean, dTestMean);
			//strConclusion.Format("At the 0.05 level, the difference of the population means is %s greater than the test difference (%g).", strSign, dTestMean);
			//break;
		//case TAILED_TEST_LOWER:
			//strHYPT.Format("Null Hypothesis: mean1-mean2 >= %g \nAlternative Hypothesis: mean1-mean2 < %g \n", dTestMean, dTestMean);
			//strConclusion.Format("At the 0.05 level, the difference of the population means is %s less than the test difference (%g).", strSign, dTestMean);			
			//break;		
	//}
	//
//
	//if (tRes.Prob == NANUM)
			//ocu_load_err_msg_str(FOOTNOTE_NO_CONCLUSION, &strConclusion);
//}

/// Set test statistics labels for t-Tests
void _set_ttest_stats_label(const int nTail, vector<string> &vTTStatsLabels)
{
	vTTStatsLabels.SetSize(3);
	vTTStatsLabels[0] = _L("t Statistic");
	vTTStatsLabels[1] = _L("DF");
	switch (nTail)
	{
		case TAILED_TEST_TWO:
		default:
			vTTStatsLabels[2] = _L("Prob>|t|");
			break;
		case TAILED_TEST_UPPER:
			vTTStatsLabels[2] = _L("Prob>t");
			break;
		case TAILED_TEST_LOWER:
			vTTStatsLabels[2] = _L("Prob<t");
			break;
	}
}

/// Add test statistics to reporttree for One-Sample t-Test & Paired-Sample t-Test
void rt_add_test_stats(ReportBase& outRT, const int nTail, const vector& vTTStats, LPCSTR strHYPT, LPCSTR strConclusion, LPCSTR lpsczColLabel, vector<string>* pvStatsLabels)
{
	
	TreeNode trTTStats = tree_get_node_by_id(outRT, IDST_T_TEST_RESULT, true);
	ReportTable rtTTStats(trTTStats);
	if (!trTTStats)
		rtTTStats = outRT.CreateTable("Stats", _L("Test Statistics"), IDST_T_TEST_RESULT);
	
	int jj = (trTTStats) ? trTTStats.GetNodeCount() : 0;
	
	vector<string> vTTStatsLabels, vstrColTagName;
	if (pvStatsLabels)
	{
		vTTStatsLabels = *pvStatsLabels;
		int nSize = vTTStatsLabels.GetSize();
		vstrColTagName.SetSize(nSize);
		for (int ii = 0; ii < nSize; ii++ )
			vstrColTagName[ii] = "C" + ftoa(ii+1);
	}
	else
	{
		_set_ttest_stats_label(nTail, vTTStatsLabels);
		string strColTagName = TEST_STATS_TABLE;
		strColTagName.GetTokens(vstrColTagName, '|');
	
	}
	
	rtTTStats.AddRow("Stats"+ftoa(jj), vTTStats, lpsczColLabel, vTTStatsLabels, vstrColTagName, IDST_T_TEST_RESULT+jj);
	///Sophy 3/30/2009 QA80-13352 SUPPORT_SPECIFY_COLUMN_DESIGNATIONS_IN_REPORT_TABLES
	string strRow = "Stats" + ftoa(jj);
	TreeNode trRow = rtTTStats.GetNode(strRow);
	if ( trRow )
		tree_set_attribute_to_all_nodes(trRow, STR_COL_DESIGNATION_ATTRIB, (string)OKDATAOBJ_DESIGNATION_Y);
	///end SUPPORT_SPECIFY_COLUMN_DESIGNATIONS_IN_REPORT_TABLES
		
	string strResult;
	strResult.Format("%s%s", strHYPT, strConclusion);	

	TreeNode trFooter = tree_check_get_node(rtTTStats, "Footer", IDE_FOOTNOTE_BEGIN, TREE_Footnote, "1"); // just need the TREE_Footnote attribute, value does not matter, so 1 is good
	trFooter.strVal = strResult;
}

/// Add test statistics to report tree for Two-Sample t-Test
void rt_add_ttest2_stats(ReportTree& outRT, const int nTail, const vector& vTTStats, const vector& vStatsUnEql, LPCSTR strHYPT, LPCSTR strConclusion)
{
	ReportTable rtTTStats = outRT.CreateTable("Stats", _L("t-Test Statistics"), IDST_T_TEST_RESULT);
	
	vector<string> vTTStatsLabels;
	_set_ttest_stats_label(nTail, vTTStatsLabels);
	
	vector<string> vstrColTagName;
	string strColTagName = TEST_STATS_TABLE;
	strColTagName.GetTokens(vstrColTagName, '|');
	
	rtTTStats.AddRow("Stats",vTTStats, _L("Equal Variance Assumed"), vTTStatsLabels, vstrColTagName, IDST_T_TEST_RESULT+1);
	rtTTStats.AddRow("StatsUnEql",vStatsUnEql, _L("Equal Variance NOT Assumed"), vTTStatsLabels, vstrColTagName, IDST_T_TEST_RESULT+2);
	///Sophy 3/30/2009 QA80-13352 SUPPORT_SPECIFY_COLUMN_DESIGNATIONS_IN_REPORT_TABLES
	tree_set_attribute_to_all_nodes(rtTTStats.Stats, STR_COL_DESIGNATION_ATTRIB, (string)OKDATAOBJ_DESIGNATION_Y);
	tree_set_attribute_to_all_nodes(rtTTStats.StatsUnEql, STR_COL_DESIGNATION_ATTRIB, (string)OKDATAOBJ_DESIGNATION_Y);
	///end SUPPORT_SPECIFY_COLUMN_DESIGNATIONS_IN_REPORT_TABLES

	string strTemp, strResult;	
	strTemp = ((vTTStats[2] >= 0.05 && vStatsUnEql[2] >= 0.05) || (vTTStats[2] < 0.05 && vStatsUnEql[2] < 0.05)) ? strConclusion : "";
	strResult.Format("%s%s", strHYPT, strTemp);
	
	TreeNode trFooter = tree_check_get_node(rtTTStats, "Footer", IDE_FOOTNOTE_BEGIN, TREE_Footnote, "1"); // just need the TREE_Footnote attribute, value does not matter, so 1 is good
	trFooter.strVal = strResult;		
}

static void _get_conf_limits(const vector vLevels, const vector vLCLs, const vector vUCLs, const int ii, vector& vConfLimits)
{
	vConfLimits.SetSize(3);
	vConfLimits[0] =  vLevels[ii];
	vConfLimits[1] =  vLCLs[ii];
	vConfLimits[2] =  vUCLs[ii];
	
}
bool rt_add_conf_intvl(ReportTree& outRT, const vector& vLevels, const vector& vLCLs, const vector& vUCLs, LPCSTR lpsczTest, LPCSTR lpsczColLabel)
{
	if ( !outRT )
		return false;
	
	TreeNode trConfLimits = tree_get_node_by_id(outRT, IDST_T_TEST_MEAN_1SAMPLE_RESULTS, true);
	ReportTable rtConfLimits(trConfLimits);
	if (!trConfLimits)
	{
		/// Nicole 07/05/2007 v8.0655 REMOVE_SPACE_FOR_LOCATION_STRING
		//LPCSTR strDescription = _L("Confidence Intervals for ") + lpsczTest;
		LPCSTR strDescription = _L("Confidence Intervals for") + " " + lpsczTest;
		/// END REMOVE_SPACE_FOR_LOCATION_STRING
		rtConfLimits = outRT.CreateTable("ConfLimits", strDescription, IDST_T_TEST_MEAN_1SAMPLE_RESULTS);
	}
	
	int jj = (trConfLimits) ? trConfLimits.GetNodeCount() : 0;
	int nLevels = vLevels.GetSize();
		
	vector<string> vstrConfInvLabels;
	vstrConfInvLabels.SetSize(3);
    vstrConfInvLabels[0] = _L("Conf. Levels in %");
	vstrConfInvLabels[1] = _L("Lower Limits");
	vstrConfInvLabels[2] = _L("Upper Limits");
	
	vector<string> vstrColTagName;
	string strColTagName = CONF_LEV_TABLE;
	strColTagName.GetTokens(vstrColTagName, '|');
		
	vector vConfLimits;
	for (int ii = 0; ii < nLevels; ii++)
	{
		_get_conf_limits(vLevels, vLCLs, vUCLs, ii, vConfLimits);
		int nID = make_one_set_ID(IDST_T_TEST_MEAN_1SAMPLE_RESULTS, ii) + jj;
		string strRow = "Conf" + ftoa(jj/nLevels+1) + ftoa(ii+1);
		rtConfLimits.AddRow(strRow, vConfLimits, lpsczColLabel, vstrConfInvLabels, vstrColTagName, nID);		
		///Sophy 3/30/2009 QA80-13352 SUPPORT_SPECIFY_COLUMN_DESIGNATIONS_IN_REPORT_TABLES
		TreeNode trRow = rtConfLimits.GetNode(strRow);
		if ( trRow )
			tree_set_attribute_to_all_nodes(trRow, STR_COL_DESIGNATION_ATTRIB, (string)OKDATAOBJ_DESIGNATION_Y);
		///end SUPPORT_SPECIFY_COLUMN_DESIGNATIONS_IN_REPORT_TABLES
	}
	
	return true;

}

bool rt_add_ttest_conf_intvl(ReportTree& outRT, const vector& vLevels, const vector& vLCLs, const vector& vUCLs)
{
	return rt_add_conf_intvl(outRT, vLevels, vLCLs, vUCLs, _L("Mean"));	
}

static void _get_power_row(const double dSigLevel, const vector& vSampleSizes, const vector& vPowers, const int ii, vector& vPowerRows)
{
	vPowerRows.SetSize(3);
	vPowerRows[0] = dSigLevel;
	vPowerRows[1] = vSampleSizes[ii];	
	vPowerRows[2] = vPowers[ii];	
}

void rt_add_ttest_power(ReportTree& outRT, const double dSigLevel, const vector& vSampleSizes, const vector& vPowers, int nActlPower, int nHyptPower, LPCSTR lpsczColLabel)
{
	TreeNode trPower = tree_get_node_by_id(outRT, IDST_T_TEST_POWERS_1SAMPLE_RESULTS, true);
	ReportTable rtPower(trPower);
	if (!trPower)
		rtPower= outRT.CreateTable("Powers", _L("Powers"), IDST_T_TEST_POWERS_1SAMPLE_RESULTS);
	
	int jj = (trPower) ? trPower.GetNodeCount() : 0;
	
	vector<string> vstrPowers;
	vstrPowers.SetSize(3);
    vstrPowers[0] = _L("Alpha");
    vstrPowers[1] = _L("Sample Size");
    //------ Folger 11/08/07 CATEGORY_NEEDED_WHEN_LOCALIZE
    //vstrPowers[2] = _L("Power");
    vstrPowers[2] = STR_POWER;
    //------ End CATEGORY_NEEDED_WHEN_LOCALIZE

 	vector<string> vstrColTagName;
	string strColTagName = PSS_TABLE;
	strColTagName.GetTokens(vstrColTagName, '|');
	//for (int kk = 0; kk < vstrColTagName.GetSize(); kk++)
		//vstrColTagName[kk] = vstrColTagName[kk] + ftoa(jj+1);
    
   	int nPowers = vPowers.GetSize();
   	
    vector vPowerRows;
    int nID;
    if (nActlPower)
    {
    	_get_power_row(dSigLevel, vSampleSizes, vPowers, 0, vPowerRows);
		nID = make_one_set_ID(IDST_T_TEST_POWERS_1SAMPLE_RESULTS, 0) + jj;
		/// Iris 03/08/2007 POWER_TABLE_MISSED_LABEL_ATTRIBUTE
		//rtPower.AddRow(_L(""), vPowerRows, lpsczColLabel, vstrPowers, vstrColTagName, nID, _L("Actual Power"));		
	    string	strColLabel(lpsczColLabel);
		if(strColLabel.IsEmpty())
			//------ Folger 11/08/07 CATEGORY_NEEDED_WHEN_LOCALIZE
			//strColLabel = _L("Actual Power");
			strColLabel = _LC("Actual Power", STR_CAT_STATS);
			//------ End CATEGORY_NEEDED_WHEN_LOCALIZE
		rtPower.AddRow("ActualPower"+ftoa(jj/nPowers+1), vPowerRows, strColLabel, vstrPowers, vstrColTagName, nID);
		///end POWER_TABLE_MISSED_LABEL_ATTRIBUTE
		///Sophy 3/30/2009 QA80-13352 SUPPORT_SPECIFY_COLUMN_DESIGNATIONS_IN_REPORT_TABLES
		string strRow = "ActualPower"+ftoa(jj/nPowers+1);
		TreeNode trRow = rtPower.GetNode(strRow);
		if ( trRow )
			tree_set_attribute_to_all_nodes(trRow, STR_COL_DESIGNATION_ATTRIB, (string)OKDATAOBJ_DESIGNATION_Y);
		///end SUPPORT_SPECIFY_COLUMN_DESIGNATIONS_IN_REPORT_TABLES

    }
    
    if (nHyptPower)
    {
	    for (int ii = 1; ii < nPowers; ii++)
	    {
	    	_get_power_row(dSigLevel, vSampleSizes, vPowers, ii, vPowerRows);
			nID = make_one_set_ID(IDST_T_TEST_POWERS_1SAMPLE_RESULTS, ii) + jj;
			/// Iris 03/08/2007 POWER_TABLE_MISSED_LABEL_ATTRIBUTE
			//rtPower.AddRow(_L(""), vPowerRows, lpsczColLabel, vstrPowers, vstrColTagName, nID, _L("Hypo. Power"));		
		    string	strColLabel(lpsczColLabel);
			if(strColLabel.IsEmpty())
				//------ Folger 11/08/07 CATEGORY_NEEDED_WHEN_LOCALIZE
				//strColLabel = _L("Hypo. Power");
				strColLabel = _LC("Hypo. Power", STR_CAT_STATS);
				//------ End CATEGORY_NEEDED_WHEN_LOCALIZE
			string strRow = "HyptPower" + ftoa(jj/nPowers+1) + ftoa(ii);
			rtPower.AddRow(strRow, vPowerRows, strColLabel, vstrPowers, vstrColTagName, nID);
			///end POWER_TABLE_MISSED_LABEL_ATTRIBUTE
			///Sophy 3/30/2009 QA80-13352 SUPPORT_SPECIFY_COLUMN_DESIGNATIONS_IN_REPORT_TABLES
			TreeNode trRow = rtPower.GetNode(strRow);
			if ( trRow )
				tree_set_attribute_to_all_nodes(trRow, STR_COL_DESIGNATION_ATTRIB, (string)OKDATAOBJ_DESIGNATION_Y);
			///end SUPPORT_SPECIFY_COLUMN_DESIGNATIONS_IN_REPORT_TABLES
	    }
    }
	
}

static void _set_corr_desc_stats_opts(DescStatOptions& stDescOpt, QuantileOptions& stQuanOpt)
{
	stDescOpt.N = true;
	stDescOpt.Mean = true;
	stDescOpt.SD = true;
	stDescOpt.Sum = true;
	stQuanOpt.Min = true;
	stQuanOpt.Max = true;
	
}
///Kyle 01/05/2009 CORR_OUTPUT_MESSAGE_ABOUT_COLUMNS_MISSING_VALUES
//bool rt_add_corr_desc_stats(ReportTree& outRT, const DescStatResults *pDescStats, const QuantileResults *pQuantiles, const vector<string>& vstrGroup)
bool rt_add_corr_desc_stats(ReportTree& outRT, const DescStatResults *pDescStats, const QuantileResults *pQuantiles, const vector<string>& vstrGroup, LPCSTR lpsczFooter)
///End CORR_OUTPUT_MESSAGE_ABOUT_COLUMNS_MISSING_VALUES
{
	if (!outRT || 0 >= vstrGroup.GetSize())
		return false;
	
	DescStatOptions stDescOpt;
	QuantileOptions stQuanOpt;
	_set_corr_desc_stats_opts(stDescOpt, stQuanOpt);
	///Kyle 01/05/2009 CORR_OUTPUT_MESSAGE_ABOUT_COLUMNS_MISSING_VALUES
	//return rt_add_desc_stats(outRT, &stDescOpt, &stQuanOpt, pDescStats, pQuantiles, vstrGroup);
	bool bRet = rt_add_desc_stats(outRT, &stDescOpt, &stQuanOpt, pDescStats, pQuantiles, vstrGroup);

	TreeNode trStats = tree_get_node_by_id(outRT, IDST_DESC_STATS_RESULTS, true);
	ReportTable rtStats(trStats);
	if ( trStats && lpsczFooter)
	{
		string strFooter(lpsczFooter);
		TreeNode trFooter = tree_check_get_node(rtStats, "Footer", IDE_FOOTNOTE_BEGIN, TREE_Footnote, "1");
		ASSERT(trFooter);
		trFooter.strVal = strFooter;
	}
	return bRet;
	///End CORR_OUTPUT_MESSAGE_ABOUT_COLUMNS_MISSING_VALUES
}

static void _sign_get_freqs(NPHFreqs stFreqs, int nTies, vector &vFreqs)
{
	vFreqs.SetSize(3);
	vFreqs[0] = stFreqs.LEMd;
	vFreqs[1] = stFreqs.GTMd;
	vFreqs[2] = nTies;
}

static void _nph2_set_footnote(LPCSTR lpsczStat, const int nTail, string& strHYPT, string& strFooter1, string& strFooter2, vector<string>& vstrNPHStatsLabels)
{
	vstrNPHStatsLabels[0] = lpsczStat;
	vstrNPHStatsLabels[1] = _L("Z");
	string strTmp;
	int nHYPT, nConAccept, nConReject;
	switch (nTail)
	{
	///Max 9/26/07 USE_ENUM_TO_CHECK_TAIL
	//case 0:
	case TAILED_TEST_TWO:
	/// END USE_ENUM_TO_CHECK_TAIL
	default:
		strTmp.Format(_L("Prob>|%s|"), lpsczStat);
		nHYPT = FOOTNOTE_NPH2_TWO_TAIL;
		nConAccept = FOOTNOTE_NPH2_CON_DIFF;
		nConReject = FOOTNOTE_NPH2_CON_SAME;
		break;
	///Max 9/26/07 USE_ENUM_TO_CHECK_TAIL
	//case 1:
	case TAILED_TEST_UPPER:
	/// END USE_ENUM_TO_CHECK_TAIL	
		//strTmp.Format("Prob<%s", lpsczStat);
		strTmp.Format(_L("Prob>%s"), lpsczStat);
		nHYPT = FOOTNOTE_NPH2_UPPER_TAIL;
		nConAccept = FOOTNOTE_NPH2_CON_GRT;
		nConReject = FOOTNOTE_NPH2_CON_NOT_GRT;
		break;
	///Max 9/26/07 USE_ENUM_TO_CHECK_TAIL
	//case 2:
	case TAILED_TEST_LOWER:
	/// END USE_ENUM_TO_CHECK_TAIL	
		//strTmp.Format("Prob>%s", lpsczStat);
		strTmp.Format(_L("Prob<%s"), lpsczStat);
		nHYPT = FOOTNOTE_NPH2_LOWER_TAIL;
		nConAccept = FOOTNOTE_NPH2_CON_LES;
		nConReject = FOOTNOTE_NPH2_CON_NOT_LES;
		break;		
	}
	
	vstrNPHStatsLabels[2] = strTmp;

	ocu_load_err_msg_str(nHYPT, &strHYPT);
	ocu_load_err_msg_str(nConAccept, &strFooter1);
	ocu_load_err_msg_str(nConReject, &strFooter2);	
}
//--- Jacky 07/22/10 ORG-102 USER_CAN_SET_SIGNIFICANCE_LEVEL
//bool rt_add_sign_test(ReportBase& outRT, NPHFreqs &stSignFreqs, int nTies, NPHStats &stSignStats, vector<string> &vstrGroup, int nTail)
bool rt_add_sign_test(ReportBase& outRT, NPHFreqs &stSignFreqs, int nTies, NPHStats &stSignStats, vector<string> &vstrGroup, int nTail,double dAlpha)
//--- end USER_CAN_SET_SIGNIFICANCE_LEVEL
{
	if (!outRT)
		return false;
	
	int ii;
	vector vFreqs(1), vFreqTmp;
	string strHYPT, strFooter1, strFooter2;
	vector<string> vstrNPHStatsLabels(3);
	
	_nph2_set_footnote(_L("S"), nTail, strHYPT, strFooter1, strFooter2, vstrNPHStatsLabels);
		
	///***  Frequencis
	ReportTable rtFreqs = outRT.CreateTable("Freqs", _L("Frequencies"), IDST_NPH_SCORES_RESULT+10);
		
	vector<string> vFreqLabels(1);
	vFreqLabels[0] = _L("N");

	vector<string> vRowLabel(3);
	vRowLabel[0] = _L("Positive Differences");
	vRowLabel[1] = _L("Negative Differences");
	vRowLabel[2] = _L("Ties");
	
 	vector<string> vstrColTagName;
	string strColTagName = NPH_FERQ;
	strColTagName.GetTokens(vstrColTagName, '|');
	
	_sign_get_freqs(stSignFreqs, nTies, vFreqTmp);
	for (ii = 0; ii < 3; ii++)
	{
		vFreqs[0] = vFreqTmp[ii]; 
		string strRow = "Freq" + ftoa(ii+1);
		rtFreqs.AddRow(strRow, vFreqs, vstrGroup[1]+"-"+vstrGroup[0],  vFreqLabels, vstrColTagName, make_one_set_ID(IDST_NPH_SCORES_RESULT+10, ii), vRowLabel[ii]);
		///Sophy 3/30/2009 QA80-13352 SUPPORT_SPECIFY_COLUMN_DESIGNATIONS_IN_REPORT_TABLES
		TreeNode trRow = rtFreqs.GetNode(strRow);
		if ( trRow )
			tree_set_attribute_to_all_nodes(trRow, STR_COL_DESIGNATION_ATTRIB, (string)OKDATAOBJ_DESIGNATION_Y);
		///end SUPPORT_SPECIFY_COLUMN_DESIGNATIONS_IN_REPORT_TABLES

	}
		
	/// *** Test Statistics
	vstrNPHStatsLabels[0] = _L("S");
	//--- Jacky 07/22/10 ORG-102 USER_CAN_SET_SIGNIFICANCE_LEVEL
	//rt_add_nph_stats(outRT, stSignStats, vstrGroup, strFooter1, strFooter2, strHYPT, vstrNPHStatsLabels, true, NULL);
	rt_add_nph_stats(outRT, stSignStats, vstrGroup, strFooter1, strFooter2, strHYPT, vstrNPHStatsLabels, true, NULL, dAlpha);
	//--- end USER_CAN_SET_SIGNIFICANCE_LEVEL
	return true;
}
//--- Jacky 07/22/10 ORG-102 USER_CAN_SET_SIGNIFICANCE_LEVEL
//bool rt_add_signed_rank(ReportBase& outRT, NPHRanks *pWilcRanks, NPHStats &stWilcStats,  vector<string> &vstrGroup, int nTail)
bool rt_add_signed_rank(ReportBase& outRT, NPHRanks *pWilcRanks, NPHStats &stWilcStats,  vector<string> &vstrGroup, int nTail,double dAlpha)
//--- end USER_CAN_SET_SIGNIFICANCE_LEVEL
{
	if (!outRT)
		return false;
	
	vector vRanks;
	string strHYPT, strFooter1, strFooter2;
	vector<string> vstrNPHStatsLabels(3);
	_nph2_set_footnote(_L("W"), nTail, strHYPT, strFooter1, strFooter2, vstrNPHStatsLabels);	
			
	///***  Ranks
	if (pWilcRanks)
	{
		ReportTable rtRanks = outRT.CreateTable("Ranks", _L("Ranks"), IDST_NPH_SCORES_RESULT);
			
		vector<string> vRankLabels(3);
		vRankLabels[0] = _L("N");
		vRankLabels[1] = _L("Mean Rank");
		vRankLabels[2] = _L("Sum Rank");
	
	 	vector<string> vstrColTagName;
		string strColTagName = NPH_RANK;
		strColTagName.GetTokens(vstrColTagName, '|');
	
		vector<string> vRowLabel(2);
		vRowLabel[0] = _L("Positive Ranks");
		vRowLabel[1] = _L("Negative Ranks");
		for (int ii = 0; ii < 2; ii++)
		{
			_get_ranks(pWilcRanks, ii, vRanks);
			string strRow = "R" + ftoa(ii+1);
			rtRanks.AddRow(strRow, vRanks, vstrGroup[1]+"-"+vstrGroup[0], vRankLabels, vstrColTagName, make_one_set_ID(IDST_NPH_SCORES_RESULT, ii), vRowLabel[ii]);	
			///Sophy 3/30/2009 QA80-13352 SUPPORT_SPECIFY_COLUMN_DESIGNATIONS_IN_REPORT_TABLES
			TreeNode trRow = rtRanks.GetNode(strRow);
			if ( trRow )
				tree_set_attribute_to_all_nodes(trRow, STR_COL_DESIGNATION_ATTRIB, (string)OKDATAOBJ_DESIGNATION_Y);
			///end SUPPORT_SPECIFY_COLUMN_DESIGNATIONS_IN_REPORT_TABLES
		}
	}
	
	/// *** Test Statistics
	//--- Jacky 07/22/10 ORG-102 USER_CAN_SET_SIGNIFICANCE_LEVEL
	rt_add_nph_stats(outRT, stWilcStats, vstrGroup, strFooter1, strFooter2, strHYPT, vstrNPHStatsLabels,true,NULL,dAlpha);
	//--- end USER_CAN_SET_SIGNIFICANCE_LEVEL
	return true;

}
//--- Jacky 07/22/10 ORG-102 USER_CAN_SET_SIGNIFICANCE_LEVEL
//bool rt_add_ks_2_sample(ReportBase& outRT, const vector& vFreqs, NPHStats& stKSStats, const vector<string> &vstrGroup, const int nTail)
bool rt_add_ks_2_sample(ReportBase& outRT, const vector& vFreqs, NPHStats& stKSStats, const vector<string> &vstrGroup, const int nTail,double dAlpha)
//--- end USER_CAN_SET_SIGNIFICANCE_LEVEL
{
	if (!outRT)
		return false;	
		
	///***  Frequencis
	ReportTable rtFreqs = outRT.CreateTable("Freqs", _L("Frequencies"), IDST_NPH_SCORES_RESULT+10);
		
	vector<string> vFreqLabels(1);
	vFreqLabels[0] = _L("N");
	
 	vector<string> vstrColTagName;
	string strColTagName = NPH_FERQ;
	strColTagName.GetTokens(vstrColTagName, '|');

	vector vFreqTmp(1);	
	
	for (int ii = 0; ii < 2; ii++)
	{
		vFreqTmp[0] = vFreqs[ii];  
		string strRow = "Freq" + ftoa(ii+1);		
		rtFreqs.AddRow(strRow, vFreqTmp, vstrGroup[ii], vFreqLabels, vstrColTagName, make_one_set_ID(IDST_NPH_SCORES_RESULT+10, ii));		
		///Sophy 3/30/2009 QA80-13352 SUPPORT_SPECIFY_COLUMN_DESIGNATIONS_IN_REPORT_TABLES
		TreeNode trRow = rtFreqs.GetNode(strRow);
		if ( trRow )
			tree_set_attribute_to_all_nodes(trRow, STR_COL_DESIGNATION_ATTRIB, (string)OKDATAOBJ_DESIGNATION_Y);
		///end SUPPORT_SPECIFY_COLUMN_DESIGNATIONS_IN_REPORT_TABLES
	}
		
	/// *** Test Statistics
	string strHYPT, strFooter1, strFooter2;
	vector<string> vstrNPHStatsLabels(3);	
	_nph2_set_footnote(_L("D"), nTail, strHYPT, strFooter1, strFooter2, vstrNPHStatsLabels);
	
	///Echo 4/29/08 QA70-11268 V8.0851 KS2_ADD_EXACT_P_LB
	if (max(vFreqs[0],vFreqs[1]) <= KS2_EXACT_CON1 && (vFreqs[0]* vFreqs[1]) <= KS2_EXACT_CON2)
		vstrNPHStatsLabels[2].Insert(0, "Exact ");
	///end KS2_ADD_EXACT_P_LB
	//--- Jacky 07/22/10 ORG-102 USER_CAN_SET_SIGNIFICANCE_LEVEL
	//rt_add_nph_stats(outRT, stKSStats, vstrGroup, strFooter1, strFooter2, strHYPT, vstrNPHStatsLabels);
	rt_add_nph_stats(outRT, stKSStats, vstrGroup, strFooter1, strFooter2, strHYPT, vstrNPHStatsLabels,true,NULL,dAlpha);
	//--- end USER_CAN_SET_SIGNIFICANCE_LEVEL
	return true;	
}

//--- Jacky 07/22/10 ORG-102 USER_CAN_SET_SIGNIFICANCE_LEVEL
////bool rt_add_mann_whitney(ReportBase& outRT, NPHRanks *pMannRanks, NPHStats& stMannStats, const vector<string> &vstrGroup, const int nTail)///Echo 3/17/08 QA70-11268 V8.0825 MW_ADD_EXACT_P
//bool rt_add_mann_whitney(ReportBase& outRT, NPHRanks *pMannRanks, NPHStats& stMannStats, const vector<string> &vstrGroup, const int nTail, const bool bExact)
bool rt_add_mann_whitney(ReportBase& outRT, NPHRanks *pMannRanks, NPHStats& stMannStats, const vector<string> &vstrGroup, const int nTail,double dAlpha, const bool bExact)
//--- end USER_CAN_SET_SIGNIFICANCE_LEVEL
{
	if (!outRT)
		return false;
	
	///***  Ranks
	rt_add_nph_ranks(outRT, pMannRanks, vstrGroup);
	
	/// *** Test Statistics
	string strHYPT, strFooter1, strFooter2, strTemp;
	vector<string> vstrNPHStatsLabels(3);	
	_nph2_set_footnote(_L("U"), nTail, strHYPT, strFooter1, strFooter2, vstrNPHStatsLabels);
	///Echo 3/17/08 QA70-11268 V8.0825 MW_ADD_EXACT_P
	if (bExact)
		vstrNPHStatsLabels[2].Insert(0, "Exact ");
	///end MW_ADD_EXACT_P
	//--- Jacky 07/22/10 ORG-102 USER_CAN_SET_SIGNIFICANCE_LEVEL
	//rt_add_nph_stats(outRT, stMannStats, vstrGroup, strFooter1, strFooter2, strHYPT, vstrNPHStatsLabels);
	rt_add_nph_stats(outRT, stMannStats, vstrGroup, strFooter1, strFooter2, strHYPT, vstrNPHStatsLabels,true,NULL,dAlpha);
	//--- end USER_CAN_SET_SIGNIFICANCE_LEVEL
	return true;
	
}


static string _ht_get_long_name(const string strPlotType, LPCSTR lpsczGroup)
{
	string str;
	str.Format("(%s)", lpsczGroup);
	str = strPlotType + str;
	
	return str;
	
}

#define		VERSION_BEFORE_HISTOGRAM_BOX_GRAPH_ORDERS(_rXFVer)			(0. < (_rXFVer) && (_rXFVer) < 2.)

static bool _hypo_test_graph(GraphPage& gp, const ReportData& rd, const int nIndex, LPCSTR lpsczGroup, const int iPlotType)
{
	XFExeContext	*pxfexectxt = Project.GetCurrentXFExeCtxt();
	/// ML 1/9/2008 QA70-10917 MAKE_XFVERSION_USED_WHEN_XFOP_WAS_RUN_LAST_TIME_AVAILABLE_TO_ORIGINC
	double			rXFVersionLastTime = pxfexectxt->GetXFVersionLastTime();
	/// end MAKE_XFVERSION_USED_WHEN_XFOP_WAS_RUN_LAST_TIME_AVAILABLE_TO_ORIGINC
	///Echo 1/12/08 QA70-10917 NEW_MATHNISM_SET_PLOTID
	int				nPlotIDGet;
	int				nPlotIDSet = HYPO_PLOT_BEGIN + iPlotType + nIndex * 2;		// new
	if ( VERSION_BEFORE_HISTOGRAM_BOX_GRAPH_ORDERS(rXFVersionLastTime) )
	{
		int nGroup = rd.FirstNode.GetNodeCount();
		nPlotIDGet = HYPO_PLOT_BEGIN+iPlotType*nGroup + nIndex;
	}
	else
		nPlotIDGet = nPlotIDSet;
	//int nGroup = rd.FirstNode.GetNodeCount();
	//int nPlotID = HYPO_PLOT_BEGIN+iPlotType*nGroup + nIndex;
	///END NEW_MATHNISM_SET_PLOTID
	gp = pxfexectxt->GetGraph(nPlotIDGet);
	vector<string> vstrPlotType;
	int iPlot = _plot_type(iPlotType,vstrPlotType);
	GraphLayer gl;
	if ( !gp )
	{
		gp.Create(vstrPlotType[0], CREATE_HIDDEN);
		
		string			strInputDesc;
		if ( pxfexectxt->GetArgDescription(strInputDesc, "r") )
		{
			gp.SetLongName(_ht_get_long_name(vstrPlotType[1], lpsczGroup), false);
			gp.TitleShow = WIN_TITLE_SHOW_LABEL;
		}
		int nYID = IDST_FIT_Y + nIndex;
		
		gl = gp.Layers(0);
		
		DataRange drPlot;
		int nn = rd.GetDataRange(drPlot, REPORT_TABLE, nYID, &nYID);
		gl.AddPlot(drPlot, iPlot);
			
		GraphObject	goLegend = gl.GraphObjects("Legend");
		string strTmp;
		strTmp.Format("\l(1) %s", lpsczGroup);
		goLegend.Text = strTmp;	
		
	}else
	{
		gl = gp.Layers(0);
	}
	
	gl.Rescale();
		
	pxfexectxt->SetGraph(gp, nPlotIDSet);
	
	return true;
}

bool hypo_test_rd_plotting(const ReportData& rd, const vector<string>& vstrLabel, const int iPlotType, ReportTree& rtPlot)
{
	rtPlot.ID = IDST_XF_RT_PLOT;
	int nGroups = vstrLabel.GetSize();
	ReportTable grt = rtPlot.CreateTable("Graph", _L("Plots"), IDST_RESULT_GRAPHS, 1, 1);

	bool bHistogram, bBox;
	switch ( iPlotType ) 
	{
	default:
		bHistogram = false;
		bBox = false;
	case HYPO_TEST_HISTOGRAM:
		bHistogram = true;
		break;
	case HYPO_TEST_BOX:
		bBox = true;
		break;
	case HYPO_TEST_HISTOGRAM + HYPO_TEST_BOX:
		bHistogram = true;
		bBox = true;
		break;
	}
	
	for (int ii = 0; ii < nGroups; ii++)
	{
		int iPosition = -1;
		if (bHistogram)
		{
			iPosition++;
			GraphPage gp;
			if (!_hypo_test_graph(gp, rd, ii, vstrLabel[ii], HYPO_TEST_HISTOGRAM))
				return false;
			if ( gp )
			{
				/// YuI 09/20/07 QA70-10397 SHOULD_ALLOW_SETREPORTTREE_TO_MOVE_EMBEDDED_GRAPH_TO_DIFFERENT_LOCATION
				//	grt.SetCell(ii, iPosition, gp);
				grt.SetCell(ii, iPosition, gp, EMBEDGRAPH_MOVE_IF_ALREADY_EMBEDDED);
				/// end SHOULD_ALLOW_SETREPORTTREE_TO_MOVE_EMBEDDED_GRAPH_TO_DIFFERENT_LOCATION
				grt.SetCell(-1, iPosition, _L("Histogram"));
			}
		}
		if (bBox)
		{
			iPosition++;
			GraphPage gp;
			if (!_hypo_test_graph(gp, rd, ii, vstrLabel[ii], HYPO_TEST_BOX))
				return false;
			if ( gp )
			{
				/// YuI 09/20/07 QA70-10397 SHOULD_ALLOW_SETREPORTTREE_TO_MOVE_EMBEDDED_GRAPH_TO_DIFFERENT_LOCATION
				//	grt.SetCell(ii, iPosition, gp);
				grt.SetCell(ii, iPosition, gp, EMBEDGRAPH_MOVE_IF_ALREADY_EMBEDDED);
				/// end SHOULD_ALLOW_SETREPORTTREE_TO_MOVE_EMBEDDED_GRAPH_TO_DIFFERENT_LOCATION
				grt.SetCell(-1, iPosition, _L("Box Plot"));
			}
			
		}
		grt.SetCell(ii, -1, vstrLabel[ii]);
			
	}

	return true;	
	
}

static int _plot_type(int iPlotType,vector<string>& vstrPlotType)
{
	vstrPlotType.SetSize(2);
	if(iPlotType==1)
	{
		vstrPlotType[0]="Hist";
		vstrPlotType[1]="Histogram";
		return IDM_PLOT_HISTOGRAM_TYPE;
	}
	else
	{
		vstrPlotType[0]="Box";
		vstrPlotType[1]="Box Chart";
		return IDM_PLOT_BOX;
	}
}


///Alex 08/08/06 merge the ttest update reportdata
bool ttest_update_report_data(ReportData& outData, vector& vData,vector& vLevels,vector<string>& vstrLabel)
{
	int nSize = vData.GetSize();
	if(nSize<1)
		return false;
	if(vstrLabel.GetSize()<1)
		return false;
	outData.ID = IDST_RESULT_CURVES;
	ReportTable rtPlots;
	vector vCumulLevels;
	vCumulLevels.SetSize(vLevels.GetSize());
	ocmath_d_cumulative_sum(vLevels, 0, vLevels.GetSize(), vCumulLevels);
	vCumulLevels.InsertAt(0, 0);
	rtPlots = outData.CreateTable("ttest", " ", REPORT_TABLE);
	for (int ii = 0; ii < vstrLabel.GetSize(); ii++)
	{
		vector vY;
		vData.GetSubVector(vY, (int)vCumulLevels[ii], (int)vCumulLevels[ii+1]-1);
		string strTagName = "Y" + ftoa(ii);
		int nID = IDST_FIT_Y + ii;
		rtPlots.AddColumn(vY, strTagName, nID, vstrLabel[ii], OKDATAOBJ_DESIGNATION_Y);	
	}
	return true;
	
}

bool one_data_update_report_data(ReportData& outData, const vector& vData, LPCSTR lpsczLabel, const int nIndex)
{

	TreeNode trPlot= tree_get_node_by_id(outData, REPORT_TABLE, true);
	ReportTable rtPlot(trPlot);
	if ( !trPlot )
		rtPlot = outData.CreateTable("ttest", " ", REPORT_TABLE);

	string strTagName = "Y" + ftoa(nIndex);
	rtPlot.AddColumn(vData, strTagName, IDST_FIT_Y+nIndex , lpsczLabel, OKDATAOBJ_DESIGNATION_Y);
	
	return true;		
}

bool one_data_add_plot(ReportTable& rtPlot, const ReportData& rd, LPCSTR lpsczLabel, const int iPlotType, const int iPosition, const int nIndex )
{
	if (!rtPlot)
		return false;
	
	vector<string> vstrPlotType;
	int iPlot = _plot_type(iPlotType,vstrPlotType);
	
	GraphPage gp;
	gp.Create(vstrPlotType[0], CREATE_HIDDEN);
	
	gp.SetLongName(_ht_get_long_name(vstrPlotType[1], lpsczLabel), false);
	gp.TitleShow = WIN_TITLE_SHOW_LABEL;
	
	int nYID = IDST_FIT_Y+nIndex;
	DataRange drPlot;
	int nn = rd.GetDataRange(drPlot, REPORT_TABLE, nYID, &nYID);
	
	GraphLayer gl = gp.Layers(0);
	if (0 != gl.AddPlot(drPlot, iPlot))
		return error_report("fail to create plot");	
		
	gl.Rescale();
	
	if ( gp )
	{
		/// YuI 09/20/07 QA70-10397 SHOULD_ALLOW_SETREPORTTREE_TO_MOVE_EMBEDDED_GRAPH_TO_DIFFERENT_LOCATION
		//	rtPlot.SetCell(iPosition, nIndex, gp);
		rtPlot.SetCell(iPosition, nIndex, gp, EMBEDGRAPH_MOVE_IF_ALREADY_EMBEDDED);
		/// end SHOULD_ALLOW_SETREPORTTREE_TO_MOVE_EMBEDDED_GRAPH_TO_DIFFERENT_LOCATION
	}
	
	rtPlot.SetCell(-1, iPosition,lpsczLabel);
	
	return true;
	
}


static void _get_pss(const double dAlpha, const double dIn, const double dOut, vector& vPSSRes)
{
	vPSSRes.SetSize(3);
	vPSSRes[0] = dAlpha;
	vPSSRes[1] = dIn;
	vPSSRes[2] = dOut;
}

#define IDST_PSS_RESULTS	0x11100010
bool rt_add_pss_res(ReportTree& outRT, const int nCalcType, const double dAlpha, const vector& vSampleSize, const vector& vPower, const string strFootNote)
{
	if (!outRT)
		return false;

	//------ Folger 11/08/07 CATEGORY_NEEDED_WHEN_LOCALIZE
	//report_tree_create(outRT, _L("Power and Sample Size"));
	//string strName =  (nCalcType == CAL_POWER) ? _L("Power(s) for Hypothetical Sample Size(s)") :  _L("Sample Size(s) for Hypothetical Power(s)");
	report_tree_create(outRT, _LC("Power and Sample Size", STR_CAT_STATS));
	string strName =  (nCalcType == CAL_POWER) ? _LC("Power(s) for Hypothetical Sample Size(s)", STR_CAT_STATS) :  _LC("Sample Size(s) for Hypothetical Power(s)", STR_CAT_STATS);
	//------ End CATEGORY_NEEDED_WHEN_LOCALIZE
	ReportTable rtPSS = outRT.CreateTable("PSS", strName, IDST_PSS_RESULTS);
		
	vector<string> vPSSLabels(3);
	//------ Folger 11/08/07 CATEGORY_NEEDED_WHEN_LOCALIZE
	//string strIn = (nCalcType == CAL_POWER) ? _L("Sample Size") : _L("Power");
	//string strOut = (nCalcType == CAL_SAMPLE_SIZE) ? _L("Sample Size") : _L("Power");
	string strIn = (nCalcType == CAL_POWER) ? _L("Sample Size") : STR_POWER;
	string strOut = (nCalcType == CAL_SAMPLE_SIZE) ? _L("Sample Size") : STR_POWER;
	//------ End CATEGORY_NEEDED_WHEN_LOCALIZE
	vPSSLabels[0] = _L("Alpha");
	vPSSLabels[1] = strIn;
	vPSSLabels[2] = strOut;

 	vector<string> vstrColTagName(3);
	string strTagIn = (nCalcType == CAL_POWER) ? "SS" : "Power";	//TagName need no localization
	string strTagOut = (nCalcType == CAL_SAMPLE_SIZE) ? "SS" : "Power";	//TagName need no localization
	vstrColTagName[0] = "Alpha";	//TagName need no localization
	vstrColTagName[1] = strTagIn;
	vstrColTagName[2] = strTagOut;

 	
	
	vector vPSSRes;
	for (int ii = 0; ii < vPower.GetSize(); ii++)
	{
		double dIn = (nCalcType == CAL_POWER) ? vSampleSize[ii] : vPower[ii];
		double dOut = (nCalcType == CAL_SAMPLE_SIZE) ? vSampleSize[ii] : vPower[ii];
		_get_pss(dAlpha, dIn, dOut, vPSSRes);
		///Nicole 07/05/2007 v8.0655 REMOVE_SPACE_FOR_LOCATION_STRING
		//rtPSS.AddRow(_L(""), vPSSRes, _L(" "), vPSSLabels, vstrColTagName, make_one_set_ID(IDST_PSS_RESULTS, ii));		
		rtPSS.AddRow("", vPSSRes, " ", vPSSLabels, vstrColTagName, make_one_set_ID(IDST_PSS_RESULTS, ii));		
		///end REMOVE_SPACE_FOR_LOCATION_STRING
		
		///Sophy 3/30/2009 QA80-13352 SUPPORT_SPECIFY_COLUMN_DESIGNATIONS_IN_REPORT_TABLES
		string strRow = "R" + (ii + 1);
		TreeNode trRow = rtPSS.GetNode(strRow);
		if ( trRow )
			tree_set_attribute_to_all_nodes(trRow, STR_COL_DESIGNATION_ATTRIB, (string)OKDATAOBJ_DESIGNATION_Y);
		///end SUPPORT_SPECIFY_COLUMN_DESIGNATIONS_IN_REPORT_TABLES

	}
	
	TreeNode trFooter = tree_check_get_node(rtPSS, "Footer", IDE_FOOTNOTE_BEGIN, TREE_Footnote, "1"); // just need the TREE_Footnote attribute, value does not matter, so 1 is good
	trFooter.strVal = strFootNote;		
	
	
	return true;
}

string pss_get_err_str(const double dLowestPow)
{
	double dErr = round(dLowestPow, LOW_POW_PRE);
	string strErr;
	//------ Folger 11/08/07 CATEGORY_NEEDED_WHEN_LOCALIZE
	//strErr.Format(_L("\nError: Error Setting! Sample size can not be computed if power value is less than %g"), dErr);
	strErr.Format(_LC("\nError: Error Setting! Sample size can not be computed if power value is less than %g", STR_CAT_STATS), dErr);
	//------ End CATEGORY_NEEDED_WHEN_LOCALIZE
	return strErr;
}


bool sa_add_note_time_ls_0(ReportTree& rtOut, const vector& vTime)
{
	if (!rtOut)
		return false;
	
	double dMin, dMax;
	vTime.GetMinMax(dMin, dMax);
	if ( dMin < 0 )
	{
		add_note(rtOut, TIME_LS_0);
		return false;
	}
	
	return true;
}

string get_column_name(DataRange& drInput, string strRangeName, int index)
{	
	string 		strColName;		
	Worksheet 	wks;
	int			r1, c1, r2, c2;
	///Arvin 04/29/07 v8.0610 GET_WRONG_COLUMN_NAME_WHEN_DATARANGE_HAS_MULTI_SUBRANG_WITH_SAME_RANGE_NAME
	//drInput.GetRange(strRangeName, r1, c1, r2, c2, wks);
	//Column 		col(wks, c1+index);
	vector<int> vnColIndex;
	for(int ii = 0; ii < drInput.GetNumRanges(); ii++)
	{
		string strRange;
		Worksheet wksTemp;
		drInput.GetRange(ii, r1, c1, r2, c2, wksTemp, strRange);
		if(wksTemp.IsValid())
		{
			///Kyle 11/05/2008 HANDLE_WHOLE_WORKSHEET_SELECTED
			if(c2==-1)
				c2 = wksTemp.GetNumCols()-1;
			///End HANDLE_WHOLE_WORKSHEET_SELECTED
			wks = wksTemp;
			if(!strRange.CompareNoCase(strRangeName))
			{
				for(int jj = c1; jj <= c2; jj++)
					vnColIndex.Add(jj);
			}
		}
	}
	if(index < 0 || index >= vnColIndex.GetSize())
		return "";

	Column  col(wks, vnColIndex[index]);
	///end GET_WRONG_COLUMN_NAME_WHEN_DATARANGE_HAS_MULTI_SUBRANG_WITH_SAME_RANGE_NAME
	if(col)
	{
		strColName = col.GetLongName();
		if(strColName.IsEmpty())
			strColName = col.GetName();
		///------ Folger 12/26/08 QA80-12642-P3 v8.0991 CONSISTENT_SHOW_LN_WITH_DOUBLE_QUOTES_IN_REPORT_SHEET
		else
		{
			string str = strColName;
			strColName.Format("\"%s\"", str);
		}
		///------ End CONSISTENT_SHOW_LN_WITH_DOUBLE_QUOTES_IN_REPORT_SHEET
	}
	return strColName;
}

bool 	get_fit_data_label(DataRange& drInput, string& strIndep, string& strDep, bool bFixIntercept, int nData)
{	
	strDep = get_column_name(drInput, "Y");
	
	if(!bFixIntercept && 0 == nData)
		strIndep = _LE("Intercept");
	else
		strIndep = get_column_name(drInput, "X", nData-1);
	
	return true;
}
	
	
/// Iris 8/16/06 NEED_SPECIAL_ROW_COL_HEADER_FOR_MATRIX_TABLE
bool	tree_result_table_add_matrix(TreeNode& trTable, const matrix& mat, const vector<string>& vsColHeaders, const vector<string>& vsRowHeaders, bool bClearOld)
{
	if( vsColHeaders && vsColHeaders.GetSize() != mat.GetNumCols() )
		return false;
	if( vsRowHeaders && vsRowHeaders.GetSize() != mat.GetNumRows() )
		return false;
	
	vector<string> 		vsCols, vsRows;
	if( vsColHeaders )
	{
		vsCols = vsColHeaders;
	}
	else
	{
		str_data_list(vsCols, mat.GetNumCols());
	}
	
	if( vsRowHeaders )
	{
		vsRows = vsRowHeaders;
	}
	else
	{
		str_data_list(vsRows, mat.GetNumRows());
	}
	
	if(trTable.GetNodeCount() > 0 && bClearOld)
		trTable.RemoveChildrenWithPrefix("col");

	int nTableID = trTable.ID;
	for( int nCol=0; nCol<vsCols.GetSize(); nCol++ )
	{
		int			nColID = make_one_set_ID(nTableID, nCol + 1);
		//TreeNode 	trCol = tree_check_get_node(trTable, "col" + nCol, nColID, STR_LABEL_ATTRIB, _L(vsCols[nCol]));
		TreeNode 	trCol = tree_check_get_node(trTable, "col" + nCol, nColID, STR_LABEL_ATTRIB, vsCols[nCol]); /// Hong 11/07/07 v.8.0742 FIX_ERROR_LOCALIZED
		
		for( int nRow=0; nRow<vsRows.GetSize(); nRow++ )
		{
			int 		nRowID = nTableID + nRow + 1;
			//TreeNode 	trRow = tree_check_get_node(trCol, "row" + nRow, nRowID, STR_LABEL_ATTRIB, _L(vsRows[nRow]));
			TreeNode 	trRow = tree_check_get_node(trCol, "row" + nRow, nRowID, STR_LABEL_ATTRIB, vsRows[nRow]); /// Hong 11/07/07 v.8.0742 FIX_ERROR_LOCALIZED
			trRow.dVal = mat[nRow][nCol];
		}
		///Sophy 3/30/2009 QA80-13352 SUPPORT_SPECIFY_COLUMN_DESIGNATIONS_IN_REPORT_TABLES
		tree_set_attribute_to_all_nodes(trCol, STR_COL_DESIGNATION_ATTRIB, (string)OKDATAOBJ_DESIGNATION_Y);
		///end SUPPORT_SPECIFY_COLUMN_DESIGNATIONS_IN_REPORT_TABLES
	}
	return true;
}
///end NEED_SPECIAL_ROW_COL_HEADER_FOR_MATRIX_TABLE

/// YuI 11/25/06 BIN_WKS_AUTOUPDATE
bool	rd_init_from_stats_tree(ReportTable& rtTable, TreeNode& trStats)
{
	vector vCenters;
	vector vCounts;
	vector vCumulativeSum;
	vector vCumulativeProbability;
	
	tree_stats_get_set_counts(trStats, vCounts);
	
	double dBinMin = NANUM;
	double dBinMax = NANUM;
	double dBinSize = NANUM;
	tree_stats_get_set_bin_info(trStats, dBinMin, dBinMax, dBinSize);  
	
	int nBinCount = vCounts.GetSize();
	vCenters.SetSize(nBinCount);
	vCumulativeSum.SetSize(nBinCount);
	vCumulativeProbability.SetSize(nBinCount);
	for( int ii = 0; ii < nBinCount; ii++ )
	{
		vCenters[ii] = dBinMin + (ii + 0.5) * dBinSize;
		if( 0 == ii )
			vCumulativeSum[ii] = (NANUM == vCounts[ii]) ? 0 : vCounts[ii];
		else
			vCumulativeSum[ii] = (NANUM == vCounts[ii]) ? vCumulativeSum[ii - 1] : vCumulativeSum[ii - 1] + vCounts[ii];
	}
	
	int nCumulativeSum = vCumulativeSum[nBinCount - 1];
	for( ii = 0; ii < nBinCount; ii++ )
	{
		vCumulativeProbability[ii] = (0 == nCumulativeSum ) ? NANUM : (vCumulativeSum[ii] / (double) nCumulativeSum) * 100;
	}
	
	int nTableID = rtTable.ID;
	rtTable.AddColumn(vCenters, "BinCenters", nTableID + 1, _L("Bin Centers"), OKDATAOBJ_DESIGNATION_X);
	rtTable.AddColumn(vCounts, "Counts", nTableID + 2, _L("Counts"), OKDATAOBJ_DESIGNATION_Y);	
	rtTable.AddColumn(vCumulativeSum, "CumulativeSum", nTableID + 3, _L("Cumulative Sum"), OKDATAOBJ_DESIGNATION_Y);	
	rtTable.AddColumn(vCumulativeProbability, "CumulativeProbability", nTableID + 4, _L("Cumulative Probability"), OKDATAOBJ_DESIGNATION_Y);	
	
	return true;
}
/// end BIN_WKS_AUTOUPDATE

//
///Echo 1/18/06 FIT_COMP
static string _get_input_data_str(TreeNode& trGUI)
{
	vector<string> vsReportTree = {"X", "Y", "ED"};
	
	TreeNode trInput = tree_get_node_by_tagname(trGUI, "InputData", true);
	string strInput;
	if(trInput.IsValid())
	{
		for(int ii = 0; ii < vsReportTree.GetSize(); ii++)
		{
			string strRange = "--";
			TreeNode trRange = tree_get_node_by_tagname(trInput, vsReportTree[ii], true);
			if(trRange.IsValid())
				strRange = trRange.strVal;
			strInput += strRange + ",";
		}
		strInput.TrimRight(',');
	}
	
	return strInput;

}
/*
static bool _get_input_data_str(TreeNode& trGUI1, TreeNode& trGUI2, string& strInput1, string& strInput2)
{
	vector<string> vsReportTree = {"X", "Y", "ED"};
	
	for(int ii = 0; ii < 2; ii++)
	{
		TreeNode* tr = 0 == ii? &trGUI1 : &trGUI2;
		
		TreeNode trInput = tree_get_node_by_tagname(*tr, "InputData", true);
		string strInput;
		if(trInput.IsValid())
		{
			for(int ii = 0; ii < vsReportTree.GetSize(); ii++)
			{
				string strRange = "--";
				TreeNode trRange = tree_get_node_by_tagname(trInput, vsReportTree[ii], true);
				if(trRange.IsValid())
					strRange = trRange.strVal;
				strInput += strRange + ",";
			}
			strInput.TrimRight(',');
		}
		if(0 == ii)
			strInput1 = strInput;
		else
			strInput2 = strInput;
		
	}
	return true;
}
*/
static string _fitcmp_get_info(const TreeNode& tr, LPCSTR lpsczInfo)
{
	string strInfo;
	TreeNode trEquation = tree_get_node_by_tagname(tr, lpsczInfo, true);	
	if(trEquation.IsValid())
		return trEquation.strVal;
	
	return "";
	
}

///Iris 12/25/2009 QA81-14890-S3 SET_TABLE_DEFAULT_CLOSE
void set_table_open(TreeNode& trTable, bool bOpen)
{
	int nTable;
	if( trTable.GetAttribute(TREE_Table, nTable) && !bOpen )
	{
		nTable &= ~GETNBRANCH_OPEN;	
	}
	
	if( bOpen )
		nTable |= GETNBRANCH_OPEN;
	
	trTable.SetAttribute(TREE_Table, nTable);	
}
///End SET_TABLE_DEFAULT_CLOSE

///Echo 10/8/07 v8.0718 FIT_COM_NEW_DESCRP
bool fitcmp_add_descrp(ReportTree& outRT, TreeNode& trRes1, TreeNode& trRes2, TreeNode& trGUI1, TreeNode&trGUI2, bool bSameModel, vector<string>& vstrFitReport)
{
	if (!outRT)
		return false;
	
	int ID = FITCMP_DESC;
	ReportTable rtDescpt = outRT.CreateTable("Description", _L("Description"), ID++);
	set_table_open(rtDescpt, true); ///Iris 12/25/2009 QA81-14890-S3 SET_TABLE_DEFAULT_CLOSE
	vector<string> vstrDMHeader(2);
	vstrDMHeader[0] = bSameModel ?  _L("Data1") : _L("Model1");
	vstrDMHeader[1] = bSameModel ?  _L("Data2") : _L("Model2");
	string strDMRowTag = bSameModel ?  "Model" : "Data";
	///------ Folger 10/18/2010 ORG-1178 USE_MODEL_ONE_TWO_INSTEAD_OF_FUNCTION_NAME_FOR_TESTING_IN_FIT_COMAPRE_MODELS
	//string strDMRowLabel = bSameModel ?  _L("Input Model") : _L("Input Data");
	string strDMRowLabel = _L("Input Data");
	///------ End USE_MODEL_ONE_TWO_INSTEAD_OF_FUNCTION_NAME_FOR_TESTING_IN_FIT_COMAPRE_MODELS
			
	vector<string> vstrDMRow(2);
	vstrDMRow[0] = _get_input_data_str(trGUI1);
	vstrDMRow[1] = _get_input_data_str(trGUI2);
	rtDescpt.AddRow(strDMRowTag, vstrDMRow, strDMRowLabel, vstrDMHeader, vstrDMHeader, ID++);	
	
	//Fit Report
	rtDescpt.AddRow("Report", vstrFitReport, _L("Fit Report"), vstrDMHeader, vstrDMHeader, ID++); 		
	
	
	//Equation
	vector<string> vstrEquation(2);
	vstrEquation[0] = _fitcmp_get_info(trRes1, "Equation");
	vstrEquation[1] = _fitcmp_get_info(trRes2, "Equation");
	rtDescpt.AddRow("Equation", vstrEquation, _L("Equation"), vstrDMHeader, vstrDMHeader, ID++); 		
	
	//Function
	vector<string> vstrFunction(2);
	vstrFunction[0] = _fitcmp_get_info(trRes1, "Model");
	vstrFunction[1] = _fitcmp_get_info(trRes2, "Model");
	rtDescpt.AddRow("Function", vstrFunction, _L("Function"), vstrDMHeader, vstrDMHeader, ID++); 

	double dSSR1, dSSR2, DF1, DF2, dN1, dN2;
	fitcmp_get_stats_value(trRes1, trRes2, &dSSR1, &dSSR2, &DF1, &DF2, &dN1, &dN2);
	
	//Number of Points
	vector<string> vstrPts(2);
	vstrPts[0] = ftoa(dN1);
	vstrPts[1] = ftoa(dN2);
	rtDescpt.AddRow("Pts", vstrPts, _L("Number of Points"), vstrDMHeader, vstrDMHeader, ID++); 
	
	//Number of Params
	vector<string> vstrParams(2);
	vstrParams[0] = ftoa(dN1 - DF1);
	vstrParams[1] = ftoa(dN2 - DF2);
	rtDescpt.AddRow("Params", vstrParams, _L("Number of Parameters"), vstrDMHeader, vstrDMHeader, ID++); 
	
/*
	
	if(bSameModel)
	{
		//Input Model 		
		ReportTable rtModel = outRT.CreateTable("Model", _L("Input Model"), ID++);
		rtModel.AddRow("Function", _L("Function"), _fitcmp_get_info(trRes1, "Model"), ID++);
		rtModel.AddRow("Equation", _L("Equation"), _fitcmp_get_info(trRes1, "Equation"), ID++);
		
		//Input Data
		ReportTable rtData = outRT.CreateTable("Data", _L("Input Data"), ID++);
		//ReportTable rtData1 = rtDescSprt1.CreateTable("Data1", _L("Input Data"), ID++);
		rtData.AddRow("InputData1", _L("Input Data"), _get_input_data_str(trGUI1), ID++);
		rtData.AddRow("InputData2", _L("Input Data"), _get_input_data_str(trGUI2), ID++);
		
	}else
	{
		//Input Data
		ReportTable rtData = outRT.CreateTable("Data", _L("Input Data"), ID++);
		rtData.AddRow("InputData", _L("Input Data"), _get_input_data_str(trGUI1), ID++);
		
		//Model
		//ReportTable rtModel1 = outRT.CreateTable("Model", _L("Input Model"), ID++);
		ReportTable rtModel = outRT.CreateTable("Model", _L("Input Model"), ID++);
		vector<string> vstrModelHeader(2);
		vstrModelHeader[0] = _L("Model1");
		vstrModelHeader[1] = _L("Model2");
		
		//Equation
		vector<string> vstrEquation(2);
		vstrEquation[0] = _fitcmp_get_info(trRes1, "Equation");
		vstrEquation[1] = _fitcmp_get_info(trRes2, "Equation");
		rtModel.AddRow(_L("Equation"), vstrEquation, _L("Equation"), vstrModelHeader, vstrModelHeader, ID++); 		
		
		//Function
		vector<string> vstrFunction(2);
		vstrFunction[0] = _fitcmp_get_info(trRes1, "Model");
		vstrFunction[1] = _fitcmp_get_info(trRes2, "Model");
		rtModel.AddRow(_L("Function"), vstrFunction, _L("Function"), vstrModelHeader, vstrModelHeader, ID++); 

		double dSSR1, dSSR2, DF1, DF2, dN1, dN2;
		fitcmp_get_stats_value(trRes1, trRes2, &dSSR1, &dSSR2, &DF1, &DF2, &dN1, &dN2);
		
		//Number of Points
		vector<string> vstrPts(2);
		vstrPts[0] = ftoa(dN1);
		vstrPts[1] = ftoa(dN2);
		rtModel.AddRow(_L("Pts"), vstrPts, _L("Number of Points"), vstrModelHeader, vstrModelHeader, ID++); 
		
		//Number of Params
		vector<string> vstrParams(2);
		vstrParams[0] = ftoa(DF1);
		vstrParams[1] = ftoa(DF2);
		rtModel.AddRow(_L("Params"), vstrParams, _L("Number of Parameters"), vstrModelHeader, vstrModelHeader, ID++); 
		
	}
	*/
	return true;
}
///end FIT_COM_NEW_DESCRP

static void _get_ftest(vector& vFtest, const double dSSR1, const double dSSR2, const double DF1, const double DF2)
{
	vFtest.SetSize(4);
	///------ Folger 05/20/09 QA80-13639 FIT_COMPARE_MODEL_RESULTS_ARE_FILPPED_WHEN_DOF_OF_2ND_MODEL_IS_LARGER
	//vFtest[0] = ((dSSR1 - dSSR2)/dSSR2)/((DF1-DF2)/DF2);
	bool b2ndValueIsLarger = DF2 > DF1;
	vFtest[0] = ((dSSR1 - dSSR2)/(b2ndValueIsLarger ? dSSR1 : dSSR2))/((DF1-DF2)/(b2ndValueIsLarger ? DF1 : DF2));
	///------ End FIT_COMPARE_MODEL_RESULTS_ARE_FILPPED_WHEN_DOF_OF_2ND_MODEL_IS_LARGER
	vFtest[1] = fabs(DF1-DF2);
	vFtest[2] = min(DF1, DF2);
	vFtest[3] = 1 - fcdf(vFtest[0], vFtest[1], vFtest[2]);	
}

///Iris 12/25/2009 QA81-14890-S2 REPLACE_MODEL1_MODEL2_TO_REAL_FUNCTION_NAME
//void fitcmp_add_ftest(ReportTree& outRT, const double dSSR1, const double dSSR2, const double DF1, const double DF2, bool bSameModel)
void fitcmp_add_ftest(ReportTree& outRT, const double dSSR1, const double dSSR2, const double DF1, const double DF2, bool bSameModel, LPCSTR lpcszModel1, LPCSTR lpcszModel2, string* pstrCmpConclusion)
///End REPLACE_MODEL1_MODEL2_TO_REAL_FUNCTION_NAME
{
	int ID = FITCMP_FTEST;
	ReportTable rtFtest = outRT.CreateTable("Ftest", _L("F-test"), ID);  
	set_table_open(rtFtest); ///Iris 12/25/2009 QA81-14890-S3 SET_TABLE_DEFAULT_CLOSE
	vector<string> vFTestLabels(4), vFtestTagName(4);
	vFTestLabels[0] = _L("F");
	vFTestLabels[1] = _L("Numer.DF");
	vFTestLabels[2] = _L("Denom.DF");	
	vFTestLabels[3] = _L("Prob > F");
	string strTagName = F_TEST_STATS;
	strTagName.GetTokens(vFtestTagName, '|');
	vFtestTagName.InsertAt(0, _L("F"));
	
	vector vFtest;
	_get_ftest(vFtest, dSSR1, dSSR2, DF1, DF2);
	
	rtFtest.AddRow("FTest", vFtest, " ", vFTestLabels, vFtestTagName, ID++); 
	
	string strConclusion, strDifferent, strTmp;
	string strCmpConclusion; /// Iris 12/25/2009 QA81-14890-S1 ADD_PREFERED_MODEL_TABLE
	int nConclusion;
	if (vFtest[3] == NANUM)
	{
		nConclusion = FOOTNOTE_NO_CONCLUSION;
		ocu_load_err_msg_str(XF_FIT_CMP_NO_CONCLUSION, &strCmpConclusion); /// Iris 12/25/2009 QA81-14890-S1 ADD_PREFERED_MODEL_TABLE
	}
	else
	{
		if (bSameModel)
		{
			nConclusion = (vFtest[3] < 0.05) ? FOOTNOTE_FITCMP_DATASET_F : FOOTNOTE_FITCMP_DATASET_F_NEGATIVE;
		}else
		{
			if (is_equal(DF1,DF2))
			{
				nConclusion = FOOTNOTE_FITCMP_NESTED;
				ocu_load_err_msg_str(XF_FIT_CMP_NO_CONCLUSION, &strCmpConclusion); /// Iris 12/25/2009 QA81-14890-S1 ADD_PREFERED_MODEL_TABLE
			}
			else	
			{
				///------ Folger 05/20/09 QA80-13639 FIT_COMPARE_MODEL_RESULTS_ARE_FILPPED_WHEN_DOF_OF_2ND_MODEL_IS_LARGER
				//strTmp = (vFtest[3] < 0.05) ? _L("Model 2") : _L("Model 1");
				bool	bPreferSmallerDOF = vFtest[3] < 0.05;
				///Iris 12/25/2009 QA81-14890-S2 REPLACE_MODEL1_MODEL2_TO_REAL_FUNCTION_NAME
				/*
				if ( DF1 > DF2 )
					strTmp = bPreferSmallerDOF ? _L("Model 2") : _L("Model 1");
				else
					strTmp = bPreferSmallerDOF ? _L("Model 1") : _L("Model 2");
				*/
				if ( DF1 > DF2 )
					strTmp = bPreferSmallerDOF ? lpcszModel2 : lpcszModel1;
				else
					strTmp = bPreferSmallerDOF ? lpcszModel1 : lpcszModel2;
				///End REPLACE_MODEL1_MODEL2_TO_REAL_FUNCTION_NAME
				strCmpConclusion = strTmp;  /// Iris 12/25/2009 QA81-14890-S1 ADD_PREFERED_MODEL_TABLE
				///------ End FIT_COMPARE_MODEL_RESULTS_ARE_FILPPED_WHEN_DOF_OF_2ND_MODEL_IS_LARGER
					
				nConclusion = FOOTNOTE_FITCMP_MODEL_F;
			}
		}
	}
	ocu_load_err_msg_str(nConclusion, &strConclusion);
	if (!bSameModel)
		strConclusion.Format(strConclusion, strTmp);
	
	TreeNode trFooter = tree_check_get_node(rtFtest, "Footer", IDE_FOOTNOTE_BEGIN, TREE_Footnote, "1"); // just need the TREE_Footnote attribute, value does not matter, so 1 is good
	trFooter.strVal = strConclusion;
	
	/// Iris 12/25/2009 QA81-14890-S1 ADD_PREFERED_MODEL_TABLE
	if(pstrCmpConclusion)
		*pstrCmpConclusion = strCmpConclusion;
	///End ADD_PREFERED_MODEL_TABLE
}

///Iris 12/25/2009 QA81-14890-S2 REPLACE_MODEL1_MODEL2_TO_REAL_FUNCTION_NAME
//void fitcmp_add_fit_params(ReportTree& outRT, TreeNode& trRes1, TreeNode& trRes2, bool bSameModel)
void fitcmp_add_fit_params(ReportTree& outRT, TreeNode& trRes1, TreeNode& trRes2, bool bSameModel, LPCSTR lpcszModel1, LPCSTR lpcszModel2)
///End REPLACE_MODEL1_MODEL2_TO_REAL_FUNCTION_NAME
{
	int ID = FITCMP_FIT_PARAMS;
	ReportTable rtParams = outRT.CreateTable("Params", _L("Fit Parameters"), ID);
	set_table_open(rtParams, false); ///Iris 12/25/2009 QA81-14890-S3 SET_TABLE_DEFAULT_CLOSE
	
	TreeNode tr = tree_get_node_by_tagname(trRes1, "Parameters", true);
	TreeNode trParam1 = rtParams.AddNode("Parameter1", ID++);
	trParam1.Replace(tr.Clone(), true, true);
	trParam1.ID = ID++;
	string strLabel1, strLabel2;
	///Iris 12/25/2009 QA81-14890-S2 REPLACE_MODEL1_MODEL2_TO_REAL_FUNCTION_NAME
	//strLabel1 =  (bSameModel) ? _L("Fit Parameters(Data1)") : _L("Fit Parameters(Model1)");
	strLabel1 =  (bSameModel) ? _L("Fit Parameters(Data1)") : _L("Fit Parameters") + "(" + lpcszModel1 + ")";
	///End REPLACE_MODEL1_MODEL2_TO_REAL_FUNCTION_NAME
	trParam1.SetAttribute(STR_LABEL_ATTRIB, strLabel1);
	tr = tree_get_node_by_tagname(trRes2, "Parameters", true);
	TreeNode trParam2 = rtParams.AddNode("Parameter2", ID++);
	trParam2.Replace(tr.Clone(), true, true);
	trParam2.ID = ID++;
	///Iris 12/25/2009 QA81-14890-S2 REPLACE_MODEL1_MODEL2_TO_REAL_FUNCTION_NAME
	//strLabel2 =  (bSameModel) ? _L("Fit Parameters(Data2)") : _L("Fit Parameters(Model2)");
	strLabel2 =  (bSameModel) ? _L("Fit Parameters(Data2)") : _L("Fit Parameters") +  "(" + lpcszModel2 + ")";
	///End REPLACE_MODEL1_MODEL2_TO_REAL_FUNCTION_NAME
	trParam2.SetAttribute(STR_LABEL_ATTRIB, strLabel2);
		
}

///Iris 12/25/2009 QA81-14890-S2 REPLACE_MODEL1_MODEL2_TO_REAL_FUNCTION_NAME
//void fitcmp_add_fit_stats(ReportTree& outRT, TreeNode& trRes1, TreeNode& trRes2, bool bSameModel)
void fitcmp_add_fit_stats(ReportTree& outRT, TreeNode& trRes1, TreeNode& trRes2, bool bSameModel, LPCSTR lpcszModel1, LPCSTR lpcszModel2)
///End REPLACE_MODEL1_MODEL2_TO_REAL_FUNCTION_NAME
{

	int ID = FITCMP_FIT_STATS;
	ReportTable rtStats = outRT.CreateTable("FitStats", _L("Fit Statistics"), ID);  
	set_table_open(rtStats, false); ///Iris 12/25/2009 QA81-14890-S3 SET_TABLE_DEFAULT_CLOSE
	
	TreeNode tr = tree_get_node_by_tagname(trRes1, "RegStats", true);
	TreeNode trStats1 = rtStats.AddNode("FitStats1", ID++);
	trStats1.Replace(tr.Clone(), true, true);
	trStats1.ID = ID++;
	string strLabel1, strLabel2;
	///Iris 12/25/2009 QA81-14890-S2 REPLACE_MODEL1_MODEL2_TO_REAL_FUNCTION_NAME
	//strLabel1 =  (bSameModel) ? _L("Fit Statistics(Data1)") : _L("Fit Statistics(Model1)");
	strLabel1 =  (bSameModel) ? _L("Fit Statistics(Data1)") : _L("Fit Statistics") +  "(" + lpcszModel1 + ")";
	///End REPLACE_MODEL1_MODEL2_TO_REAL_FUNCTION_NAME
	trStats1.SetAttribute(STR_LABEL_ATTRIB, strLabel1);
	tr = tree_get_node_by_tagname(trRes2, "RegStats", true);
	TreeNode trStats2 = rtStats.AddNode("FitStats2", ID++);
	trStats2.Replace(tr.Clone(), true, true);
	trStats2.ID = ID++;
	///Iris 12/25/2009 QA81-14890-S2 REPLACE_MODEL1_MODEL2_TO_REAL_FUNCTION_NAME
	//strLabel2 =  (bSameModel) ? _L("Fit Statistics(Data2)") : _L("Fit Statistics(Model2)");
	strLabel2 =  (bSameModel) ? _L("Fit Statistics(Data2)") : _L("Fit Statistics") +  "(" + lpcszModel2 + ")";
	///End REPLACE_MODEL1_MODEL2_TO_REAL_FUNCTION_NAME
	trStats2.SetAttribute(STR_LABEL_ATTRIB, strLabel2);
}

bool fitcmp_check_stats(TreeNode& tr)
{
	TreeNode trTemp;
	get_regstats_tr(tr, trTemp);
	
	if (!trTemp.DOF)
		return false;
	if (!trTemp.SSR)
		return false;
	if (!trTemp.N)
		return false;
	
	return true;
	
}

bool get_regstats_tr(const TreeNode& trRes, TreeNode& tr)
{
	if (!trRes)
		return false;
		
	TreeNode trRegStats = tree_get_node_by_tagname(trRes, "RegStats", true);
	///Echo 08/5/20 QA70-10975 v8.0867 FITCMP_RUNTIME_ERROR
	if (!trRegStats)
		return false;
	///end FITCMP_RUNTIME_ERROR
	
	///Echo 11/1/07 NOT_COMPARE_STR
	tr = (trRegStats.GetNodeCount() <= 2) ? trRegStats.FirstNode : trRegStats.LastNode.PrevNode;	
	if (!tr)
		return false;
	/*
	TreeNode trNotes = tree_get_node_by_tagname(trRes, "DataMode", true);
	string strDataMode;
	if (trNotes.IsValid())
		strDataMode = trNotes.strVal;
	tr = strDataMode.Compare("Global Fit") ? trRegStats.FirstNode : trRegStats.LastNode.PrevNode;	
	if (!tr)
		return false;
	*/
	///END NOT_COMPARE_STR
	
	return true;
	
}

void fitcmp_get_stats_value(TreeNode& trRes1, TreeNode& trRes2, double* dSSR1, double* dSSR2, double* DF1, double* DF2, double* dN1, double* dN2)
{
	///------ Folger 05/20/09 QA80-13639 FIT_COMPARE_MODEL_RESULTS_ARE_FILPPED_WHEN_DOF_OF_2ND_MODEL_IS_LARGER
	////Model with larger DF should be Model 1
	//TreeNode tr1, tr2;
	//get_regstats_tr(trRes1, tr1);
	//get_regstats_tr(trRes2, tr2);
	////TreeNode tr = tree_get_node_by_tagname(trRes1, "RegStats", true);
	////TreeNode tr1 = tr.C1;
	////tr = tree_get_node_by_tagname(trRes2, "RegStats", true);
	////TreeNode tr2 = tr.C1;
	//
	//
	//if (tr1.DOF)	*DF1 = tr1.DOF.dVal;
	//if (tr2.DOF)	*DF2 = tr2.DOF.dVal;
	//if (*DF2 > *DF1)
	//{
		//TreeNode trTmp;
		//trTmp = trRes1.Clone();	
		//trRes1 = trRes2.Clone();		
		//trRes2 = trTmp.Clone();				
		//
		//trTmp = tr1.Clone();
		//tr1 = tr2.Clone();
		//tr2 = trTmp.Clone();
		//
		//double dTmp = *DF1;
		//*DF1 = *DF2;
		//*DF2 = dTmp;
	//}
	//
	//if (tr1.SSR)	*dSSR1 = tr1.SSR.dVal;
	//if (tr2.SSR)	*dSSR2 = tr2.SSR.dVal;	
		//
	//if (tr1.N)	*dN1 = tr1.N.dVal;
	//if (tr2.N)	*dN2 = tr2.N.dVal;
	
	TreeNode tr1, tr2;
	get_regstats_tr(trRes1, tr1);
	get_regstats_tr(trRes2, tr2);
	if (tr1.DOF)	*DF1 = tr1.DOF.dVal;
	if (tr2.DOF)	*DF2 = tr2.DOF.dVal;
	
	if (tr1.SSR)	*dSSR1 = tr1.SSR.dVal;
	if (tr2.SSR)	*dSSR2 = tr2.SSR.dVal;	
		
	if (tr1.N)	*dN1 = tr1.N.dVal;
	if (tr2.N)	*dN2 = tr2.N.dVal;
	///------ End FIT_COMPARE_MODEL_RESULTS_ARE_FILPPED_WHEN_DOF_OF_2ND_MODEL_IS_LARGER
}

///------ Folger 10/09/2010 ORG-1228-P1 FIT_COMPARE_MODEL_EMPTY_FUNCTION_NAME_FOR_LINEAR_AND_POLYNOMIAL
//string fitcmp_get_model(TreeNode& trRes1)
string fitcmp_get_model(TreeNode& trRes1, TreeNode& trGUI)
///------ End FIT_COMPARE_MODEL_EMPTY_FUNCTION_NAME_FOR_LINEAR_AND_POLYNOMIAL
{
	TreeNode trModel = trRes1.Notes.Model;
	///------ Folger 10/09/2010 ORG-1228-P1 FIT_COMPARE_MODEL_EMPTY_FUNCTION_NAME_FOR_LINEAR_AND_POLYNOMIAL
	//ASSERT(trModel);
	///------ End FIT_COMPARE_MODEL_EMPTY_FUNCTION_NAME_FOR_LINEAR_AND_POLYNOMIAL
	if( trModel && !trModel.IsEmpty() )
		return trModel.strVal;
	
	///------ Folger 10/09/2010 ORG-1228-P1 FIT_COMPARE_MODEL_EMPTY_FUNCTION_NAME_FOR_LINEAR_AND_POLYNOMIAL
	string	strClassName;
	if ( trGUI.GetAttribute(STR_CLASS_NAME, strClassName) )
	{
		if ( strClassName.Compare(STR_FITTEROPERATION_CLASS_FITLINEAR) == 0 )
		{
			strClassName = _L("Linear");
		}
		else if ( strClassName.Compare(STR_FITTEROPERATION_CLASS_FITPOLYNOMIAL) == 0 )
		{
			TreeNode	trOrder = tree_get_node_by_tagname(trGUI, "Order", true);
			if ( trOrder )
			{
				strClassName.Format("%s %s=%d", _L("Polynomial"), _L("Order"), trOrder.nVal);
			}
			else
			{
				O_A_FAIL;
			}
		}
		return strClassName;
	}
	///------ End FIT_COMPARE_MODEL_EMPTY_FUNCTION_NAME_FOR_LINEAR_AND_POLYNOMIAL
	return "";		
}

bool get_multi_data_col_label(const DataRange& drInput, LPCSTR lpsczRangeName, vector<string>& vstrColLabels)
{
	if (!drInput)
		return false;
	
	DWORD dwRules = DRR_NO_WEIGHTS;
	int nNumData = drInput.GetNumData(dwRules);
	for (int jj = 0; jj < nNumData; jj++)
	{
		string strColLabel = get_column_name(drInput, lpsczRangeName, jj);
		if (!lstrcmp(strColLabel, ""))
			break;
		vstrColLabels.Add(strColLabel);
		
	}
	
		
	return true;
}




static int 	_get_rt_id(int nIndex)
{
	return ELLIPSE_REPORT_TABLE + nIndex;
}

static int _get_curve_id(int ii, int jj, int nLevels)
{
	return IDST_FIT_X + (ii+nLevels) * (jj) * 6;
}

static string _get_ellipse_label(int ii, int jj, const string strDesign, bool bLabel)
{
	string strLabel;
	if (bLabel)
		strLabel.Format("Ellipse%s(%d,%d)",strDesign, ii+1, jj+1);
	else
		strLabel.Format("Ellipse%s%d%d",strDesign, ii+1, jj+1);
	return strLabel;
}

static string _get_fit_label(int ii, int jj, const string strDesign, bool bLabel)
{
	string strLabel;
	if (bLabel)
		strLabel.Format("Fit%s(%d,%d)",strDesign, ii+1, jj+1);
	else
		strLabel.Format("Fit%s%d%d",strDesign, ii+1, jj+1);
	return strLabel;
}

static int _trim_pairwise(vector& vX, vector& vY)
{
	int nX = vX.GetSize();
	int nY = vY.GetSize();
	if (nX <= 0 || nY <= 0)
		return false;
	
	matrix mTemp;
	mTemp.SetSize(max(nX, nY), 2);
	mTemp.SetColumn(vX, 0);
	mTemp.SetColumn(vY, 1);
	
	mTemp.RemoveEmptyRows(false);
	int nRows = mTemp.GetNumRows();
	int nCols = mTemp.GetNumCols();
	if (nRows == 0 || nCols == 0)
		return false;
	
	mTemp.GetColumn(vX, 0);
	mTemp.GetColumn(vY, 1);
	
	return true;
	
}

static string _input_dataset_description(DataRange dr)
{
	return range_get_col_name(dr, 0) + " X " + range_get_col_name(dr, 1);
}

bool scatter_matrix_update_report_data(const matrix& mData, const vector<string> vstrGrpLabel, const double dConfLevel, const bool bEllipse, const bool bFit,ReportData& outData, matrix& mFitStats)
{
	if(!outData)
		return false;

	int nRows = mData.GetNumRows();
	int nLevels = mData.GetNumCols();
	
	double dAlpha = 1 - dConfLevel/100;
	outData.ID = IDST_RESULT_CURVES;
	ReportTable rtCurves;
	string strTableName;
	vector<string> vsColTags;
	vsColTags.SetSize(nLevels);
	for(int kk = 0; kk < nLevels; kk++)
		vsColTags[kk] = "C" + (kk+1);
	
	if (bFit && mFitStats) mFitStats.SetSize(nLevels, nLevels);
	//----
	for (int ii = 0; ii < nLevels; ii++)
	{
		vector vX, vY;
		mData.GetColumn(vX, ii);
		rtCurves = outData.CreateTable("ScatterMatrix"+ftoa(ii), _L("Scatter Matrix"), _get_rt_id(ii));
		rtCurves.AddColumn(vX, vsColTags[ii],_get_curve_id(ii,0,nLevels), vstrGrpLabel[ii], OKDATAOBJ_DESIGNATION_X);
		for (int jj = 0; jj < nLevels; jj++)
		{
			if ( jj!=ii )
			{
				mData.GetColumn(vY, jj);
				rtCurves.AddColumn(vY, vsColTags[jj], _get_curve_id(ii,jj,nLevels)+1, vstrGrpLabel[jj], OKDATAOBJ_DESIGNATION_Y);
				
				int nSize = (_trim_pairwise(vX, vY)) ? vX.GetSize(): 0;
				
				if (bEllipse)
				{
					vector vW, vEllipseX(ELLIPSE_SIZE), vEllipseY(ELLIPSE_SIZE); 
					vW.SetSize(vX.GetSize());
					vW = 1;
					ocmath_ellipse(vX, vY, vW, vX.GetSize(), dAlpha, ELLIPSE_SIZE, vEllipseX, vEllipseY, 0);
					string strEllipseX = _get_ellipse_label(ii,jj, "X", true);
					string strEllipseY = _get_ellipse_label(ii,jj, "Y", true);
					rtCurves.AddColumn(vEllipseX, _get_ellipse_label(ii,jj, "X", false), _get_curve_id(ii,jj,nLevels) + 2, strEllipseX, OKDATAOBJ_DESIGNATION_X);
					rtCurves.AddColumn(vEllipseY, _get_ellipse_label(ii,jj, "Y", false), _get_curve_id(ii,jj,nLevels) + 3, strEllipseY, OKDATAOBJ_DESIGNATION_Y);
					
				}
				if (bFit)
				{
					vector vFitX;
					vector vFitY;
					if (0 < nSize)
					{	
						RegStats rs;
						vector vCoeff;
						if (!fitlinear(vX, vY, vCoeff, NULL, &rs))
						{
							if (mFitStats) mFitStats[ii][jj] = NANUM;
							continue;
						}
						double aa = vCoeff[0];
						double bb = vCoeff[1];
						if (mFitStats) mFitStats[ii][jj] = rs.AdjRSq;
						
						double minX, maxX;
						vX.GetMinMax(minX, maxX);
						vFitX.Data(minX, maxX, (maxX - minX) / ELLIPSE_SIZE);
						vFitY = aa + vFitX * bb;
					}else
					{
						vFitX.SetSize(ELLIPSE_SIZE);
						vFitY.SetSize(ELLIPSE_SIZE);
						vFitX = NANUM;
						vFitY = NANUM;
						mFitStats[ii][jj] = NANUM;
					}
					
					rtCurves.AddColumn(vFitX, _get_fit_label(ii,jj, "X", false), _get_curve_id(ii,jj,nLevels) + 4, _get_fit_label(ii,jj, "X", true), OKDATAOBJ_DESIGNATION_X);
					rtCurves.AddColumn(vFitY, _get_fit_label(ii,jj, "Y", false), _get_curve_id(ii,jj,nLevels) + 5, _get_fit_label(ii,jj, "Y", false),OKDATAOBJ_DESIGNATION_Y);
					
				}
					
			}
			
		}
		
	}	
	
	return true;
}

/// ML 9/25/2007 QA70-10336 MUST_REMOVE_REDUNDANT_DATAPLOTS_IN_SCATTERPLOTMATRIX

// Returns true if dataplot needs to be added, otherwise, false.
static	bool	_spm_check_one_plot(DataRange &drPlot, ReportData& rd, int jjX, int ii, int jj, int nxOffset, int nyOffset, int nLevels, GraphLayer &gl, vector<int> &vnPlotsToRemove)
{
	int			nXID = _get_curve_id(ii, jjX, nLevels) + nxOffset;
	int			nYID = _get_curve_id(ii, jj, nLevels) + nyOffset;
	
	vector<int> vnPlotIndices;
	bool		bRet = false;
	if ( 0 != rd.GetDataRange(drPlot, _get_rt_id(ii), nXID, &nYID) && !check_has_plotted_in_graph(drPlot, gl, vnPlotIndices) )
		bRet = true;
	else
	{
		// vnPlotsToRemove conatins the indices of all the dataplots which need to be removed. We need to remove from this array all those that have been found
		// in vnPlotIndices (probably just one):
		int			num = vnPlotIndices.GetSize();
		for (int nplot = 0; nplot < num; nplot++)
		{
			int		index = vnPlotIndices[nplot];
			int		nCountToRemove = vnPlotsToRemove.GetSize();
			if (nCountToRemove <= 0)
				break;
			for (int nrem = 0; nrem < vnPlotsToRemove.GetSize(); nrem++)
			{
				if (vnPlotsToRemove[nrem] == index)
				{
					vnPlotsToRemove.RemoveAt(nrem);
					--nrem;
				}
			}
		}
	}
	
	return bRet;
}

// Returns the index of the added plot.
///Kyle 05/15/2009 FIX_COLOR_CHANGE_WHEN_RECAL_WHILE_THE_COLOR_SETTING_FROM_TEMPLATE
//static	int	_spm_add_one_plot(DataRange &drPlot, int nPlotType, LPCSTR lpcszLabelFmt, uint dwCntrl, GraphLayer &gl, string &str)
static	int	_spm_add_one_plot(DataRange &drPlot, int nPlotType, LPCSTR lpcszLabelFmt, uint dwCntrl, GraphLayer &gl, string &str, int nColor = -1)
///End FIX_COLOR_CHANGE_WHEN_RECAL_WHILE_THE_COLOR_SETTING_FROM_TEMPLATE
{
	///------ Folger 09/27/2010 ORG-1151-P1 SAVE_AS_ANALYSIS_TEMPLATE_FAILED_TO_CLEAN_GRAPHS_EMEBEDED_IN_WKS
	check_make_full_row_range(drPlot);
	///------ End SAVE_AS_ANALYSIS_TEMPLATE_FAILED_TO_CLEAN_GRAPHS_EMEBEDED_IN_WKS
	int		nRet = gl.AddPlot(drPlot, nPlotType, dwCntrl);
	string	strInData =  _input_dataset_description(drPlot);
	str.Format(lpcszLabelFmt, strInData);
	
	///Kyle 05/15/2009 FIX_COLOR_CHANGE_WHEN_RECAL_WHILE_THE_COLOR_SETTING_FROM_TEMPLATE
	// because the original color setting is from template, so when recalculate, it will remove the redundant plots and the color setting will lose
	if(nColor>=0)
	{
		DataPlot dp = gl.DataPlots(nRet);
		if(dp)
			dp.SetColor(nColor);
	}
	///End FIX_COLOR_CHANGE_WHEN_RECAL_WHILE_THE_COLOR_SETTING_FROM_TEMPLATE
	
	return nRet;
}
/// end MUST_REMOVE_REDUNDANT_DATAPLOTS_IN_SCATTERPLOTMATRIX

static bool _scatter_ellipse_graph(int ii, int jj, int nLevels, GraphPage &gp, uint nGraphCntrl, ReportData& rd, matrix& mFitStats)
{
	if ( !gp )
	{
		gp.Create("plotmatrix", CREATE_HIDDEN);	
	}
		
	GraphLayer	gl = gp.Layers(0);
	
	/// ML 9/25/2007 QA70-10336 MUST_REMOVE_REDUNDANT_DATAPLOTS_IN_SCATTERPLOTMATRIX
	//int nXID, nYID;
	//DataPlot dp;
	//DataRange drPlot;
	//int nPlot = 0;
	//string str, strInData;
	string	str;
	
	vector<int>	vnPlotsToRemove;
	int			nplot = 0;
	// Fill the array vnPlotsToRemove with the indices of the existing dataplots: 0, 1, 2,...
	// The dataplots that remain in vnPlotsToRemove after calling _spm_check_one_plot() will have to be removed (which is what 10336 is all about) 
	foreach (DataPlot dp in gl.DataPlots)
	{
		vnPlotsToRemove.Add(nplot);
		nplot++;
	}
	/// end MUST_REMOVE_REDUNDANT_DATAPLOTS_IN_SCATTERPLOTMATRIX
	uint	dwCntrl = GAP_GROUP_PLOTS | GAP_ALLOW_DUPLICATE_COL;
	/// ML 9/25/2007 QA70-10336 MUST_REMOVE_REDUNDANT_DATAPLOTS_IN_SCATTERPLOTMATRIX
	/*
	vector<int> 	vnPlotIndices;
	if ((nGraphCntrl&PLOT_MATTRIX_SCATTER))
	{
		nXID = _get_curve_id(ii,0,nLevels);
		nYID = _get_curve_id(ii,jj,nLevels) + 1;
				
		if ( 0 != rd.GetDataRange(drPlot, _get_rt_id(ii), nXID, &nYID) && !check_has_plotted_in_graph(drPlot, gl, vnPlotIndices))
		{
			gl.AddPlot(drPlot, IDM_PLOT_SCATTER, dwCntrl);
			
			dp = gl.DataPlots(0);
			
			strInData =  _input_dataset_description(drPlot);
			str.Format(_L("Scatter Plot of %s"),strInData);
		}
	}
	int nPlots = gl.DataPlots.Count();
	*/
	////////////////////	
	DataRange		drPlotDataScatter, drPlotEllipse, drPlotFit;
	bool			bAddDataScatterPlot = false, bAddEllipsePlot = false, bAddFitPlot = false;
	if (nGraphCntrl & PLOT_MATTRIX_SCATTER)
		bAddDataScatterPlot = _spm_check_one_plot(drPlotDataScatter, rd, 0, ii, jj, 0, 1, nLevels, gl, vnPlotsToRemove);
	/// end MUST_REMOVE_REDUNDANT_DATAPLOTS_IN_SCATTERPLOTMATRIX
	GraphObject	goLegend= gl.GraphObjects("Rsq");
	/// ML 9/25/2007 QA70-10336 MUST_REMOVE_REDUNDANT_DATAPLOTS_IN_SCATTERPLOTMATRIX
	/*
	if ((nGraphCntrl&PLOT_MATTRIX_ELLIPSE))
	{
		nXID = _get_curve_id(ii,jj,nLevels) + 2;
		nYID = _get_curve_id(ii,jj,nLevels) + 3;
		if (0 != rd.GetDataRange(drPlot, _get_rt_id(ii), nXID, &nYID) && !check_has_plotted_in_graph(drPlot, gl, vnPlotIndices))
		{
			nPlot++;
			int nTmp = gl.AddPlot(drPlot, IDM_PLOT_LINE, dwCntrl);
	
			dp = gl.DataPlots(nPlot);
			
			strInData =  _input_dataset_description(drPlot);
			str.Format(_L("Confidence ellipse: %s"), strInData);			
		}
	}
	*/
	
	if ( nGraphCntrl & PLOT_MATTRIX_ELLIPSE )
		bAddEllipsePlot = _spm_check_one_plot(drPlotEllipse, rd, jj, ii, jj, 2, 3, nLevels, gl, vnPlotsToRemove);
	/// end MUST_REMOVE_REDUNDANT_DATAPLOTS_IN_SCATTERPLOTMATRIX

	/// ML 9/25/2007 QA70-10336 MUST_REMOVE_REDUNDANT_DATAPLOTS_IN_SCATTERPLOTMATRIX
	/*
	if ((nGraphCntrl&PLOT_MATTRIX_FIT))
	{
		nXID = _get_curve_id(ii,jj,nLevels) + 4;
		nYID = _get_curve_id(ii,jj,nLevels) + 5;
		if (0 != rd.GetDataRange(drPlot, _get_rt_id(ii), nXID, &nYID) && !check_has_plotted_in_graph(drPlot, gl, vnPlotIndices))
		{
			nPlot++;
			int nTmp1 = gl.AddPlot(drPlot, IDM_PLOT_LINE, dwCntrl);
					
			dp = gl.DataPlots(nPlot);
			
			strInData =  _input_dataset_description(drPlot);
			str.Format(_L("Scatter Plot of: %s"), strInData);
			string strLegend;
			
			if (mFitStats[ii][jj] != NANUM)
				strLegend.Format(_L("Adj R^2=%.2f"), mFitStats[ii][jj]);
			goLegend.Text = strLegend;
	
		}
	}
	*/
	if ((nGraphCntrl & PLOT_MATTRIX_FIT))
	{
		bAddFitPlot = _spm_check_one_plot(drPlotFit, rd, jj, ii, jj, 4, 5, nLevels, gl, vnPlotsToRemove);
		
		string strLegend;
		
		if (mFitStats[ii][jj] != NANUM)
		{
			//strLegend.Format(_L("Adj R^2=%.2f"), mFitStats[ii][jj]);
			string		strNum = ftoa(mFitStats[ii][jj], "*");
			strLegend = "Adj R^2=";
			strLegend += strNum;
		}
		if (goLegend)
			goLegend.Text = strLegend;
	}
	/// end MUST_REMOVE_REDUNDANT_DATAPLOTS_IN_SCATTERPLOTMATRIX

	/// ML 9/25/2007 QA70-10336 MUST_REMOVE_REDUNDANT_DATAPLOTS_IN_SCATTERPLOTMATRIX
	// Remove all dataplots whose indices are in vnPlotsToRemove:
	int			nCountToRemove = vnPlotsToRemove.GetSize();
	for (int iplot = nCountToRemove - 1; iplot >= 0; iplot--)
	{
		int			index = vnPlotsToRemove[iplot];
		gl.RemovePlot(index);
	}
	
	// Now add all needed dataplots
	if ( bAddDataScatterPlot )
		///Kyle 05/15/2009 FIX_COLOR_CHANGE_WHEN_RECAL_WHILE_THE_COLOR_SETTING_FROM_TEMPLATE
		//_spm_add_one_plot(drPlotDataScatter, IDM_PLOT_SCATTER, _L("Scatter Plot of %s"), dwCntrl, gl, str);
		_spm_add_one_plot(drPlotDataScatter, IDM_PLOT_SCATTER, _L("Scatter Plot of %s"), dwCntrl, gl, str, SYSCOLOR_BLUE);
		///End FIX_COLOR_CHANGE_WHEN_RECAL_WHILE_THE_COLOR_SETTING_FROM_TEMPLATE
	
	if ( bAddEllipsePlot )
		///Kyle 05/15/2009 FIX_COLOR_CHANGE_WHEN_RECAL_WHILE_THE_COLOR_SETTING_FROM_TEMPLATE
		//_spm_add_one_plot(drPlotEllipse, IDM_PLOT_LINE, _L("Confidence ellipse: %s"), dwCntrl, gl, str);
		_spm_add_one_plot(drPlotEllipse, IDM_PLOT_LINE, _L("Confidence ellipse: %s"), dwCntrl, gl, str, SYSCOLOR_RED);
		///End FIX_COLOR_CHANGE_WHEN_RECAL_WHILE_THE_COLOR_SETTING_FROM_TEMPLATE
	
	if ( bAddFitPlot )
		///Kyle 05/15/2009 FIX_COLOR_CHANGE_WHEN_RECAL_WHILE_THE_COLOR_SETTING_FROM_TEMPLATE
		//_spm_add_one_plot(drPlotFit, IDM_PLOT_LINE, _L("Fit of: %s"), dwCntrl, gl, str);
		_spm_add_one_plot(drPlotFit, IDM_PLOT_LINE, _L("Fit of: %s"), dwCntrl, gl, str, SYSCOLOR_RED);
		///End FIX_COLOR_CHANGE_WHEN_RECAL_WHILE_THE_COLOR_SETTING_FROM_TEMPLATE
	/// end MUST_REMOVE_REDUNDANT_DATAPLOTS_IN_SCATTERPLOTMATRIX
	
	if (!(nGraphCntrl&PLOT_MATTRIX_FIT)&& goLegend)	
		goLegend.Text = " ";
	
	gp.SetLongName(str, false);
	gl.Rescale();	
		
	return TRUE;
	
	
}

bool _ellipse_plotting(ReportData& rd, GraphPage& gp, int ii, int jj, int nLevels, matrix& mFitStats, const uint nGraphCntrl)
{
	XFExeContext	*pxfexectxt = Project.GetCurrentXFExeCtxt();
	int nIndex = ii*nLevels + jj;
	gp = pxfexectxt->GetGraph(nIndex);
	
	if ( !_scatter_ellipse_graph(ii, jj, nLevels, gp, nGraphCntrl, rd, mFitStats) )
		return false;
	
	pxfexectxt->SetGraph(gp, nIndex);
	return true;
		
}

bool plotmatrix_rd_plotting(ReportTree& rt, const ReportData& rd, const int nLevels, const matrix& mFitStats, const uint nGraphCntrl, const vector<string>& vstrFactors)
{
	if (!rt || !rd)
		return false;
	
	ReportTable grt = rt.CreateTable("Graphs", _L("Scatter Matrix"), IDST_RESULT_GRAPHS, 1, 1);	
	for(int ii = 0; ii < nLevels; ii++)
	{
		for (int jj =0; jj < nLevels; jj++)
		{
			if ( ii!=jj )		
			{
				GraphPage gp;
				int nPlotID = _get_curve_id(ii,jj,nLevels);
				_ellipse_plotting(rd, gp, ii, jj, nLevels, mFitStats, nGraphCntrl);
				/// YuI 09/20/07 QA70-10397 SHOULD_ALLOW_SETREPORTTREE_TO_MOVE_EMBEDDED_GRAPH_TO_DIFFERENT_LOCATION
				//	grt.SetCell(jj, ii, gp, EMBEDGRAPH_HIDE_AXES);	
				grt.SetCell(jj, ii, gp, EMBEDGRAPH_HIDE_AXES | EMBEDGRAPH_MOVE_IF_ALREADY_EMBEDDED);	
				/// end SHOULD_ALLOW_SETREPORTTREE_TO_MOVE_EMBEDDED_GRAPH_TO_DIFFERENT_LOCATION
			}
	
		}
		/////Set Label of column and row
		grt.SetCell(-1, ii, vstrFactors[ii]);
		grt.SetCell(ii, -1, vstrFactors[ii]);
		
	}
	
	return true;
}


///------ Folger 04/22/09 QA80-13420 PARETOCHART_XF_BASED_PLOTTING
/// Iris move to report_utils.h
/*
#define FREQ_REPORT_TABLE	0x00000010
enum _DISC_FREQS_RES_ID
{
	_DISC_FREQS_DATA	= 0x00010010,
	_DISC_FREQS_FREQS,
	_DISC_FREQS_PERC,
	_DISC_FREQS_CUMUL_PERC,
	
};
*/

///Kyle 07/09/2009 QA80-13902-S1 FREQUENCY_SUPPORT_FRACTION_AND_PERCENT
//static bool _freqs_update_report_data(ReportData& outData, const vector<string>& vstrData, const vector* pvFreqs, const vector* pvPerc, const vector* pvCulmulPerc, LPCSTR lpsczLabel, bool bSetDataColAsText = false)
///Kyle 11/02/2009 QA80-13902 DISCRETE_FREQUENCY_COPY_SOURCE_COLUMN_FORMAT
//static bool _freqs_update_report_data(ReportData& outData, const vector<string>& vstrData, const vector* pvFreqs, const vector* pvPerc, const vector* pvCulmulPerc, LPCSTR lpsczLabel, int nDataColType = -1)
// if the output column format is not set( nDataColType == -1), nSrcColUID will be used
static bool _freqs_update_report_data(ReportData& outData, const vector<string>& vstrData, const vector* pvFreqs, const vector* pvPerc, const vector* pvCulmulPerc, LPCSTR lpsczLabel, int nDataColType = -1, int nSrcColUID = 0)
///End DISCRETE_FREQUENCY_COPY_SOURCE_COLUMN_FORMAT
///End FREQUENCY_SUPPORT_FRACTION_AND_PERCENT
{
	if (!outData)
		return false;
	
	//string strFreqCounts = "Frequency Counts of " + _L(lpsczLabel);	
	int jj = outData.GetNodeCount()+1;
	ReportTable rtFreqs = outData.CreateTable("FreqCount"+ftoa(jj),  lpsczLabel, FREQ_REPORT_TABLE);
	rtFreqs.AddColumn(vstrData, "Data"+ftoa(jj),_DISC_FREQS_DATA+jj, _L("Data"), OKDATAOBJ_DESIGNATION_X);
	///Kyle 07/09/2009 QA80-13902-S1 FREQUENCY_SUPPORT_FRACTION_AND_PERCENT
	//if ( bSetDataColAsText )
	//	rtFreqs.FirstNode.SetAttribute(STR_COL_FORMAT_ATTRIB, OKCOLTYPE_TEXT);
	if ( nDataColType >= 0 )
	{
		///Kyle 07/09/2009 QA80-13902-P1 DISCRETE_FREQUENCY_SET_DATA_AS_CATEGORICAL_AUTOMATICALLY
		//rtFreqs.FirstNode.SetAttribute(STR_COL_FORMAT_ATTRIB, nDataColType);
		if(nDataColType == OKCOLTYPE_CATEGORICAL)		// a special column type
		{
			rtFreqs.FirstNode.SetAttribute(STR_COL_CATEGORICAL_ATTRIB, CMT_ORDINAL); // default use CMT_ORDINAL
		}
		else
		{
			rtFreqs.FirstNode.SetAttribute(STR_COL_FORMAT_ATTRIB, nDataColType);
		}
		///End DISCRETE_FREQUENCY_SET_DATA_AS_CATEGORICAL_AUTOMATICALLY
	}
	///Kyle 11/02/2009 QA80-13902 DISCRETE_FREQUENCY_COPY_SOURCE_COLUMN_FORMAT
	else if(nSrcColUID != 0)			// 0 ==>OUID_UNKNOWN
	{
		DWORD dwCntrl = SRC_COL_PROPERTY_FORMAT;
		TreeNode trColumn = rtFreqs.FirstNode;
		okutil_source_column_property(&trColumn, &nSrcColUID, &dwCntrl, false);
	}
	///End DISCRETE_FREQUENCY_COPY_SOURCE_COLUMN_FORMAT
	//End FREQUENCY_SUPPORT_FRACTION_AND_PERCENT
	///Echo QA70-12013 v8.0921  LABEL_NOT_CONSISTENT_WITH_FREQ_COUNT
	/*
	if (pvFreqs)	rtFreqs.AddColumn(*pvFreqs, "Frequencies"+ftoa(jj),_DISC_FREQS_FREQS+jj, _L("Frequencies"), OKDATAOBJ_DESIGNATION_Y);
	if (pvPerc)	rtFreqs.AddColumn(*pvPerc, "Percent"+ftoa(jj),_DISC_FREQS_PERC+jj, _L("Percent"), OKDATAOBJ_DESIGNATION_Y);
	if (pvCulmulPerc)	rtFreqs.AddColumn(*pvCulmulPerc, "CumulPerc"+ftoa(jj),_DISC_FREQS_CUMUL_PERC+jj, _L("Cumulative Percent"), OKDATAOBJ_DESIGNATION_Y);
	*/
	if (pvFreqs)	rtFreqs.AddColumn(*pvFreqs, "Count"+ftoa(jj),_DISC_FREQS_FREQS+jj, _L("Count"), OKDATAOBJ_DESIGNATION_Y);
	if (pvPerc)	rtFreqs.AddColumn(*pvPerc, "RelatFreq"+ftoa(jj),_DISC_FREQS_PERC+jj, _L("Relative Frequency"), OKDATAOBJ_DESIGNATION_Y);
	if (pvCulmulPerc)	rtFreqs.AddColumn(*pvCulmulPerc, "CumulFreq"+ftoa(jj),_DISC_FREQS_CUMUL_PERC+jj, _L("Cumulative Frequency"), OKDATAOBJ_DESIGNATION_Y);
	///end LABEL_NOT_CONSISTENT_WITH_FREQ_COUNT
	
	return true;
	
}

struct DiscFreqOptions
{
	bool 	bSensitive;
	bool	bSortFreq;
};

static bool _range_get_discrete_frequencies(const DataRange& irng, int ii, const DiscFreqOptions& stOptions, vector<string>& vstrDiscData, vector& vFreq, vector* pvCumulFreqs = NULL, vector* pvPerc = NULL, vector* pvCumulPerc = NULL, vector* pvInputData = NULL)
{
	int nSize = 0, nFreqs;
	
	vector<string> vstrData;
	DWORD dwRules = DRR_NO_WEIGHTS|DRR_GET_MISSING;
	DWORD dwPlotID;
	irng.GetData(dwRules, ii, &dwPlotID, NULL, &vstrData);
	nSize = vstrData.GetSize();
	if (nSize == 0)
		return false;
	
	DWORD dwCtrl = DF_TRIM_LEFT_RIGHT_SPACE;
	if(stOptions.bSensitive)
		dwCtrl |= DF_CASE_SENSITIVE;

	vector vData;
	vFreq.SetSize(nSize);
	if (0 != dr_get_col_percent_text(irng, ii))
	{
		///Arvin 06/22/07 ADD_CASE_SPACE_SENSITIVE
		//if (!sensitive)
		//	_vec_no_case(vstrData);
		//ocu_discrete_frequencies(&vstrData, &vstrDiscData, vFreq, &nFreqs); 
		ocu_discrete_frequencies(&vstrData, &vstrDiscData, vFreq, &nFreqs, dwCtrl); 
		///end ADD_CASE_SPACE_SENSITIVE
		if(NULL != pvInputData)
			convert_str_vector_to_num_vector(vstrData, vData);
	}else
	{
		vector vDiscData(nSize);
		irng.GetData(dwRules, ii, &dwPlotID, NULL, &vData);
		vData.Trim();
		int nMissing = nSize - vData.GetSize();
		if (nMissing != nSize)
		{
			ocmath_discrete_frequencies(vData, vData.GetSize(), vDiscData, vFreq, &nFreqs);
			vDiscData.Trim();
			convert_double_vector_to_string_vector(vDiscData, vstrDiscData, nFreqs);
		}
		
		//if missing values
		if (nMissing > 0)
		{
			nFreqs++;
			vstrDiscData.InsertAt(0, "--");
			vFreq.InsertAt(0, nMissing);
		}
		
	}
	vFreq.SetSize(nFreqs);
	///Kyle 11/24/2008 SORT_DEGRESSIVELY_BY_FREQ_COUNT
	if( stOptions.bSortFreq )
	{
		vector<uint> vnIndices;
		vFreq.Sort(SORT_DESCENDING, true, vnIndices);
		vstrDiscData.Reorder( vnIndices );
	}
	///End SORT_DEGRESSIVELY_BY_FREQ_COUNT

	if( NULL != pvCumulFreqs || NULL != pvPerc || NULL != pvCumulPerc )
	{
		vector vCumulFreqs, vPerc, vCumulPerc;
		vCumulFreqs.SetSize(nFreqs);
		ocmath_d_cumulative_sum(vFreq, 0, vFreq.GetSize(), vCumulFreqs);
		
		vPerc = vFreq / nSize;
		vCumulPerc = vCumulFreqs / nSize;
		
		if( NULL != pvCumulFreqs) *pvCumulFreqs = vCumulFreqs;
		if( NULL != pvPerc) *pvPerc = vPerc;
		if( NULL != pvCumulPerc) *pvCumulPerc = vCumulPerc;
	}
	
	if( NULL != pvInputData )
		*pvInputData = vData;
	
	return true;
}

///Kyle 07/09/2009 QA80-13902-S1 FREQUENCY_SUPPORT_FRACTION_AND_PERCENT
//int		discrite_frequency_update_report_data(ReportData& rd, const Range& irng, int freq, int perc, int cumul, int sensitive, bool bParetoCht/* = false*/)
int		discrete_frequency_update_report_data(ReportData& rd, const Range& irng, int freq, int perc, int cumul, int sensitive, int nDataColType/* = -1*/)
///End FREQUENCY_SUPPORT_FRACTION_AND_PERCENT
{
	/// Iris 7/08/2009 PLOT_PROB_XF, centrlize code for plot_prob xfunction
	/*
	vector<string> vstrData;
	DWORD dwRules = DRR_NO_WEIGHTS|DRR_GET_MISSING;
	DWORD dwPlotID;
	*/
	DWORD dwRules = DRR_NO_WEIGHTS|DRR_GET_MISSING;
	///end PLOT_PROB_XF
	
	int nErrCode = check_1_data(irng, true, true);
	if (CER_NO_ERROR != nErrCode)
	{
		return nErrCode;
	}
	
	int nNumRanges = irng.GetNumData(dwRules);	
	/// Iris 7/08/2009 PLOT_PROB_XF
	/*
	///Arvin 06/22/07 ADD_CASE_SPACE_SENSITIVE
	DWORD dwCtrl = DF_TRIM_LEFT_RIGHT_SPACE;
	if(sensitive)
		dwCtrl |= DF_CASE_SENSITIVE;
	///end ADD_CASE_SPACE_SENSITIVE
	*/
	///end PLOT_PROB_XF
	for (int ii = 0; ii < nNumRanges; ii++)
	{
		/// Iris 7/08/2009 PLOT_PROB_XF, centrlize code for plot_prob xfunction
		/*
		int nSize = 0, nFreqs;
		vector vFreq, vCumulFreqs, vPerc, vCumulPerc;
		vector<string> vstrDiscData;
		string strLabel = range_get_col_name(irng, ii);		
		irng.GetData(dwRules, ii, &dwPlotID, NULL, &vstrData);
		nSize = vstrData.GetSize();
		if (nSize == 0)
			break;
	
		vFreq.SetSize(nSize);
		if (0 != dr_get_col_percent_text(irng, ii))
		{
			///Arvin 06/22/07 ADD_CASE_SPACE_SENSITIVE
			//if (!sensitive)
			//	_vec_no_case(vstrData);
			//ocu_discrete_frequencies(&vstrData, &vstrDiscData, vFreq, &nFreqs); 
			ocu_discrete_frequencies(&vstrData, &vstrDiscData, vFreq, &nFreqs, dwCtrl); 
			///end ADD_CASE_SPACE_SENSITIVE
		}else
		{
			vector vData, vDiscData(nSize);
			irng.GetData(dwRules, ii, &dwPlotID, NULL, &vData);
			vData.Trim();
			int nMissing = nSize - vData.GetSize();
			if (nMissing != nSize)
			{
				ocmath_discrete_frequencies(vData, vData.GetSize(), vDiscData, vFreq, &nFreqs);
				vDiscData.Trim();
				convert_double_vector_to_string_vector(vDiscData, vstrDiscData, nFreqs);
			}
			
			//if missing values
			if (nMissing > 0)
			{
				nFreqs++;
				vstrDiscData.InsertAt(0, "--");
				vFreq.InsertAt(0, nMissing);
			}
			
		}
		vFreq.SetSize(nFreqs);
		///Kyle 11/24/2008 SORT_DEGRESSIVELY_BY_FREQ_COUNT
		vector<uint> vnIndices;
		vFreq.Sort(SORT_DESCENDING, true, vnIndices);
		vstrDiscData.Reorder( vnIndices );
		///End SORT_DEGRESSIVELY_BY_FREQ_COUNT
	
		vCumulFreqs.SetSize(nFreqs);
		ocmath_d_cumulative_sum(vFreq, 0, vFreq.GetSize(), vCumulFreqs);
		vPerc = vFreq / nSize;
		vCumulPerc = vCumulFreqs / nSize;
		*/
		string 	strLabel = range_get_col_name(irng, ii);	
		
		vector<string> 	vstrDiscData;
		vector 	vFreq, vCumulFreqs, vPerc, vCumulPerc;
		
		DiscFreqOptions stOptions;
		stOptions.bSensitive = sensitive;
		stOptions.bSortFreq = true;
		if( !_range_get_discrete_frequencies(irng, ii, stOptions, vstrDiscData, vFreq, &vCumulFreqs, &vPerc, &vCumulPerc) )
			break;
		///end PLOT_PROB_XF
		///Kyle 07/09/2009 QA80-13902-S1 FREQUENCY_SUPPORT_FRACTION_AND_PERCENT
		//if ( bParetoCht )
		//	vCumulPerc *= 100;
		if( FREQUENCY_IN_PERCENT ==  perc )
			vPerc *= 100;
		if ( FREQUENCY_IN_PERCENT ==  cumul)
			vCumulPerc *= 100;
		///End FREQUENCY_SUPPORT_FRACTION_AND_PERCENT
		
		vector* pvFreqs = NULL;
		vector* pvPerc = NULL;
		vector* pvCulmulPerc = NULL;
		
		if (freq )	pvFreqs = &vFreq;
		if (perc )	pvPerc = &vPerc;
		if (cumul )	pvCulmulPerc = &vCumulPerc;

		///Kyle 07/09/2009 QA80-13902-S1 FREQUENCY_SUPPORT_FRACTION_AND_PERCENT
		//_freqs_update_report_data(rd, vstrDiscData, pvFreqs, pvPerc, pvCulmulPerc, strLabel, bParetoCht ? true : false);
		///Kyle 11/02/2009 QA80-13902 DISCRETE_FREQUENCY_COPY_SOURCE_COLUMN_FORMAT
		//_freqs_update_report_data(rd, vstrDiscData, pvFreqs, pvPerc, pvCulmulPerc, strLabel, nDataColType);
		int nSrcColUID = 0;
		Column col;
		if( range_get_col(irng, ii, col) && col )
			nSrcColUID = col.GetUID(true);
		_freqs_update_report_data(rd, vstrDiscData, pvFreqs, pvPerc, pvCulmulPerc, strLabel, nDataColType, nSrcColUID);
		///End DISCRETE_FREQUENCY_COPY_SOURCE_COLUMN_FORMAT
		///End FREQUENCY_SUPPORT_FRACTION_AND_PERCENT
		
	}
	
	return 0;
}
///------ End PARETOCHART_XF_BASED_PLOTTING

/// Iris 7/08/2009 PLOT_PROB_XF
#define PROB_REPORT_TABLE	0x00000010
enum
{
	_COL_PROB_X_ID	= 0x00010010,
	_COL_PROB_Y_ID,
	_COL_REF_X_ID,
	_COL_REF_Y_ID,

};

static bool _prob_plotting_get_discrete_frequencies_and_basic_stats(const Range& irng, vector& vDiscData, vector& vCumulPerc, double& dMean, double& dSD)
{
	DiscFreqOptions stOptions;
	stOptions.bSensitive = true;
	stOptions.bSortFreq = false;
	
	vector 			vInputData, vFreq;
	vector<string> 	vsDiscData;
	if( _range_get_discrete_frequencies(irng, 0, stOptions, vsDiscData, vFreq, NULL, NULL, &vCumulPerc, &vInputData) )
	{
		convert_str_vector_to_num_vector(vsDiscData, vDiscData);
		
		if( STATS_NO_ERROR == ocmath_basic_summary_stats(vInputData.GetSize(), vInputData, NULL, &dMean, &dSD) )
		{		
			return true;
		}
	}
	return false;	
}

static bool _get_probability_plotting_data(const Range& irng, vector& vObserved, vector& vExpected)
{
	double 	dMean, dSD;
	vector 	vInputData, vDiscData, vCumulPerc;
	if( _prob_plotting_get_discrete_frequencies_and_basic_stats(irng, vDiscData, vCumulPerc, dMean, dSD) )
	{		
		vExpected = (vDiscData - dMean) / dSD;
		
		for(int ii = 0; ii < vExpected.GetSize(); ii++)
		{
			vExpected[ii] = normcdf( vExpected[ii] );
		}
		vObserved = vCumulPerc;
		return true;
	}	
	
	return false;	
}


static bool _get_quantile_plotting_data(const Range& irng, vector& vObserved, vector& vExpected)
{
	double 	dMean, dSD;
	vector 	vInputData, vDiscData, vCumulPerc;
	if( _prob_plotting_get_discrete_frequencies_and_basic_stats(irng, vDiscData, vCumulPerc, dMean, dSD) )
	{
		// x data
		vObserved = vDiscData;
		
		// y data
		vExpected.SetSize(vCumulPerc.GetSize());
		for(int ii = 0; ii < vCumulPerc.GetSize(); ii++)
		{
			vExpected[ii] = norminv(vCumulPerc[ii]);
		}
		
		vExpected = vExpected * dSD + dMean;		
		return true;
	}
	return false;
}

bool probability_plot_report_data(ReportData& rd, const Range& irng, int nOption/* = PLOT_PROB_PP*/)
{
	int nErrCode = check_1_data(irng);
	if (CER_NO_ERROR != nErrCode)
	{
		return false;
	}	

	bool	bRet;
	vector	vX, vProb;
	vector 	vRefX,  vRefY;
	if( PLOT_PROB_PP == nOption )
	{
		vRefX.SetSize(2);
		vRefX[0] = 0;
		vRefX[1] = 1;
		vRefY = vRefX;
		
		bRet = _get_probability_plotting_data(irng, vX, vProb);
	}
	else
	{
		bRet = _get_quantile_plotting_data(irng, vX, vProb);
		
		/// Iris 8/11/2009 FIX_QQ_PLOT_REFERENCE_LINE_NOT_SAME_AS_SPSS
		// cannot use hard code to specify the range of reference line, need to get range from result Y data to generate the data of 45 degreen reference line
		/*
		vRefX.SetSize(vX.GetSize());		
		for(int nn = 0; nn < vX.GetSize(); nn++)
		{
			vRefX[nn] = rnd();
		}
		vRefX = vRefX * 60 + 120;
		vRefY = vRefX;		
		*/
		double min, max, inc;
		vProb.GetMinMax(min, max);		
		RoundLimits(&min, &max, &inc, vProb.GetSize());
		vRefY.Data(min, max, inc);
		vRefX = vRefY;
		///end FIX_QQ_PLOT_REFERENCE_LINE_NOT_SAME_AS_SPSS
	}
	
	if( !bRet )
		return false;
	
	ReportTable rt = rd.CreateTable("normal", _L("Normal"), PROB_REPORT_TABLE);	
	
	rt.AddColumn(vX, "X", _COL_PROB_X_ID, PLOT_PROB_PP? _L("Observed Percent") : _L("Observed Value"), OKDATAOBJ_DESIGNATION_X);	
	rt.AddColumn(vProb, "Prob", _COL_PROB_Y_ID, PLOT_PROB_PP? _L("Expected Percent") : _L("Expected Normal Value"), OKDATAOBJ_DESIGNATION_Y);	
	
	rt.AddColumn(vRefX, "RefX", _COL_REF_X_ID, _L("X"), OKDATAOBJ_DESIGNATION_X);	
	rt.AddColumn(vRefY, "RefY", _COL_REF_Y_ID, _L("Reference Line"), OKDATAOBJ_DESIGNATION_Y);		
	
	return true;
}
///end PLOT_PROB_XF

/// Iris 6/25/2009 QA80-13289-S1 CENTRLIZE_CODE_FOR_WIND_ROSE_PLOT
//*************The following code moved from TwoDBinning XFunction to centralize for plot_windrose XFunction*************
#define TWO_D_BINNING_SUBTOTAL_TABLE  	0x00000020
#define TWO_D_BINNING_SUBTOTAL_X		0x00020010
#define TWO_D_BINNING_SUBTOTAL_Y		0x00020011
#define TWO_D_BINNING_CALM				0x00020012 ///---Sim 09-11-2009 QA81-14287 WIND_ROSE_NEED_INCLUDE_SEPARATE_BIN_FOR_MIN

enum{
	order_ascend,
	order_descend,
};

enum{
	bin_center,
	bin_end,
};

enum{
	step_by_inc,
	step_by_interval
};

static string _get_long_name_for_method(int stats)
{
	string strComments;
	switch(stats)
	{
	case two_d_stats_min:
		strComments = _L("Minimum");
		break;
	case two_d_stats_max:
		strComments = _L("Maximum");
		break;
	case two_d_stats_mean:
		strComments = _L("Mean");
		break;
	case two_d_stats_median:
		strComments = _L("Median");
		break;
	case two_d_stats_sum:
		strComments = _L("Sum");
		break;
	case two_d_stats_count:
		strComments = _L("Count");
		break;
	case two_d_stats_freq:
		strComments = _L("Percent Frequency");
		break;
	}
	return strComments;
}

///Kyle 06/30/2010 ORG-209 EXPAND_2D_BINNING_TO_SUPPORT_ADDITIONAL_Y_COLUMN
//static void _2d_binning_update_report_data(	const vector& vxBinEndsOrCenters, const string& strXLongName, 
//												const vector& vyBenEndsOrCenters, const string& strUserParamName,
//												const vector<string>& vsCommentLabels, int nMethod,
//												const matrix& mdResult, const matrix<uint>& mnResult,
/////---Sim 09-11-2009 QA81-14287 WIND_ROSE_NEED_INCLUDE_SEPARATE_BIN_FOR_MIN
//												//ReportData& outData)
//												ReportData& outData,
//												double *pdCalm = NULL)
/////---END QA81-14287 WIND_ROSE_NEED_INCLUDE_SEPARATE_BIN_FOR_MIN
static void _2d_binning_update_report_data(	const vector& vxBinEndsOrCenters, const string& strXLongName, 
												const vector& vyBenEndsOrCenters, const string& strUserParamName,
												const vector<string>& vsCommentLabels, int nMethod,
												const matrix& mdResult,
												ReportData& outData,
												double *pdCalm = NULL)
///End EXPAND_2D_BINNING_TO_SUPPORT_ADDITIONAL_Y_COLUMN
{
	if(!outData)
		return;
	
	outData.SetAttribute(STR_REPORT_TREE_ALWAYS_UPDATE_COLUMN_LABELS_ATTRIB, 1);		///Kyle 04/19/2010 FORCE_TO_UPDATE_REPORT_COLUMN_LABELS

	ReportTable rtTwoDBinning = outData.CreateTable("TwoDBin1", "", TWO_D_BINNING_REPORT_TABLE, -1, 1);
	
	string strXColumnName = "A";
	TreeNode trX = rtTwoDBinning.AddColumn(vxBinEndsOrCenters, strXColumnName, TWO_D_BINNING_X, strXLongName, OKDATAOBJ_DESIGNATION_X);
	trX.SetAttribute(STR_USER_PARAM_ATTRIB_PREFIX, strUserParamName + "|");		// set name of suer parameter
	
	///Kyle 06/30/2010 ORG-209 EXPAND_2D_BINNING_TO_SUPPORT_ADDITIONAL_Y_COLUMN
	//int nYCol;
	//if(nMethod != two_d_stats_count)
	//	nYCol = mdResult.GetNumRows();
	//else
	//	nYCol = mnResult.GetNumRows();
	int nYCol = mdResult.GetNumRows();
	///End EXPAND_2D_BINNING_TO_SUPPORT_ADDITIONAL_Y_COLUMN

	///---Sim 09-11-2009 QA81-14287 WIND_ROSE_NEED_INCLUDE_SEPARATE_BIN_FOR_MIN
	if ( pdCalm )
		*pdCalm = 0;
	///---END QA81-14287 WIND_ROSE_NEED_INCLUDE_SEPARATE_BIN_FOR_MIN
	
	string strMethod = _get_long_name_for_method(nMethod);
	for(int ii = 0; ii < nYCol; ii ++)
	{
		vector vdData;
		///Kyle 06/30/2010 ORG-209 EXPAND_2D_BINNING_TO_SUPPORT_ADDITIONAL_Y_COLUMN
		//if(nMethod != two_d_stats_count)
		//	mdResult.GetRow(vdData, ii);
		//else
		//	mnResult.GetRow(vdData, ii);
		mdResult.GetRow(vdData, ii);
		///End EXPAND_2D_BINNING_TO_SUPPORT_ADDITIONAL_Y_COLUMN

		///---Sim 09-11-2009 QA81-14287 WIND_ROSE_NEED_INCLUDE_SEPARATE_BIN_FOR_MIN
		if ( pdCalm && ii < 2 )
		{
			double dSum;
			vdData.Sum(dSum);
			*pdCalm += dSum;
			continue;
		}
		///---END QA81-14287 WIND_ROSE_NEED_INCLUDE_SEPARATE_BIN_FOR_MIN
		
		string strYColumnName = "";//"TwoDBinning" + (ii>0 ? (string)ii : "");, use default: A,B,...
		TreeNode tr = rtTwoDBinning.AddColumn(vdData, strYColumnName, TWO_D_BINNING_Y_BEGIN + ii, strMethod, OKDATAOBJ_DESIGNATION_Y);
		tr.SetAttribute(STR_COMMENT_ATTRIB, vsCommentLabels[ii]);
		tr.SetAttribute(STR_USER_PARAM_ATTRIB_PREFIX, ftoa(vyBenEndsOrCenters[ii], "*"));
	}
}

///Kyle 03/28/2009 NEW_TABLE_FOR_SUB_TOTAL_COUNT
///---Sim 09-11-2009 QA81-14287 WIND_ROSE_NEED_INCLUDE_SEPARATE_BIN_FOR_MIN
//static void _2d_binning_update_subtotal_count(const vector<string>& vsCommentLabels, matrix& mdResult, matrix<uint>& mnResult, int nMethod, ReportData& outData, const string& strXLongName)
///Kyle 06/30/2010 ORG-209 EXPAND_2D_BINNING_TO_SUPPORT_ADDITIONAL_Y_COLUMN
//static void _2d_binning_update_subtotal_count(const vector<string>& vsCommentLabels, matrix& mdResult, matrix<uint>& mnResult, int nMethod, ReportData& outData, const string& strXLongName, double *pdCalm = NULL)
static void _2d_binning_update_subtotal_count(const vector<string>& vsCommentLabels, matrix& mdResult, int nMethod, ReportData& outData, const string& strXLongName, double *pdCalm = NULL)
///End EXPAND_2D_BINNING_TO_SUPPORT_ADDITIONAL_Y_COLUMN
///---END QA81-14287 WIND_ROSE_NEED_INCLUDE_SEPARATE_BIN_FOR_MIN
{
	if(!outData)
		return;
	
	ReportTable rtTwoDBinning = outData.CreateTable("TwoDBin1", "", TWO_D_BINNING_SUBTOTAL_TABLE, -1, 1);
	
	///Kyle 07/17/2009 USE_ENUM_COLUMN_NAME_SINCE_IT_WILL_BE_CUT_OFF_IF_THE_BOOK_NAME_IS_TOO_LONG
	// if the column is cut off, the names of the x column and the y column is the same
	// so just use enum names and put the info(like "subtotal of count") into longname of the y column
	//string 	strXColumnName = "SubTotalX",
			//strYColumnName = "SubTotalY",
			//strMethod = _get_long_name_for_method(nMethod);
	string 	strXColumnName = "",
			strYColumnName = "",
			strYLongName = _L("Subtotal of") + " " + _get_long_name_for_method(nMethod);
	///End USE_ENUM_COLUMN_NAME_SINCE_IT_WILL_BE_CUT_OFF_IF_THE_BOOK_NAME_IS_TOO_LONG
	///---Sim 09-11-2009 QA81-14287 WIND_ROSE_NEED_INCLUDE_SEPARATE_BIN_FOR_MIN
	//rtTwoDBinning.AddColumn(vsCommentLabels, strXColumnName, TWO_D_BINNING_SUBTOTAL_X, strXLongName, OKDATAOBJ_DESIGNATION_X);
	///---END QA81-14287 WIND_ROSE_NEED_INCLUDE_SEPARATE_BIN_FOR_MIN

	vector vTotal;
	///Kyle 06/30/2010 ORG-209 EXPAND_2D_BINNING_TO_SUPPORT_ADDITIONAL_Y_COLUMN
	//if(nMethod != two_d_stats_count)
	//{
	//	mdResult.Transpose();
	//	mdResult.SumColumns(vTotal);
	//	mdResult.Transpose();
	//}
	//else
	//{
	//	mnResult.Transpose();
	//	mnResult.SumColumns(vTotal);
	//	mnResult.Transpose();
	//}
	mdResult.Transpose();
	mdResult.SumColumns(vTotal);
	mdResult.Transpose();
	///End EXPAND_2D_BINNING_TO_SUPPORT_ADDITIONAL_Y_COLUMN
	if(nMethod == two_d_stats_sum)		// should skip some NANUM to get the sum
	{
		for(int ii=vTotal.GetSize()-1; ii>=0; ii--)
		{
			if(is_missing_value(vTotal[ii]))
			{
				vector vRow;
				mdResult.GetRow(vRow, ii);
				vRow.Trim();
				if(vRow.GetSize() > 0)
				{
					double dSum;
					vRow.Sum(dSum);
					vTotal[ii] = dSum;
				}
			}
		}
	}

	///---Sim 09-11-2009 QA81-14287 WIND_ROSE_NEED_INCLUDE_SEPARATE_BIN_FOR_MIN
	if ( pdCalm )
	{
		vsCommentLabels.RemoveAt(0, 2);
		vTotal.RemoveAt(0, 2);
	}
	
	rtTwoDBinning.AddColumn(vsCommentLabels, strXColumnName, TWO_D_BINNING_SUBTOTAL_X, strXLongName, OKDATAOBJ_DESIGNATION_X);
	///---END QA81-14287 WIND_ROSE_NEED_INCLUDE_SEPARATE_BIN_FOR_MIN
	///Kyle 07/17/2009 USE_ENUM_COLUMN_NAME_SINCE_IT_WILL_BE_CUT_OFF_IF_THE_BOOK_NAME_IS_TOO_LONG
	//rtTwoDBinning.AddColumn(vTotal, strYColumnName, TWO_D_BINNING_SUBTOTAL_Y, strMethod, OKDATAOBJ_DESIGNATION_Y);
	rtTwoDBinning.AddColumn(vTotal, strYColumnName, TWO_D_BINNING_SUBTOTAL_Y, strYLongName, OKDATAOBJ_DESIGNATION_Y);
	///End USE_ENUM_COLUMN_NAME_SINCE_IT_WILL_BE_CUT_OFF_IF_THE_BOOK_NAME_IS_TOO_LONG
}
///End NEW_TABLE_FOR_SUB_TOTAL_COUNT
///---Sim 09-11-2009 QA81-14287 WIND_ROSE_NEED_INCLUDE_SEPARATE_BIN_FOR_MIN
static void _2d_binning_update_calm(ReportData& outData, double dCalm)
{
	if(!outData)
		return;
	
	ReportTable rtTwoDBinning = outData.CreateTable("TwoDBin1", "", TWO_D_BINNING_SUBTOTAL_TABLE, -1, 1);
	
	vector vv;
	vv.Add(dCalm);
	
	string 	strColumnName = "", strLongName = _L("Calm");
	rtTwoDBinning.AddColumn(vv, strColumnName, TWO_D_BINNING_CALM, strLongName, OKDATAOBJ_DESIGNATION_Y);
}
///---END QA81-14287 WIND_ROSE_NEED_INCLUDE_SEPARATE_BIN_FOR_MIN

static int	_get_include_outliers_type(int nIncMin, int nIncMax, int& iStart, int& iEnd)
{
	if(nIncMin && nIncMax)
	{
		iStart	= 1;
		iEnd	= 1;
		return FAB_INCLUDE_BOTH_OUTLIER_BIN;
	}
	else
	{
		if(nIncMin)
		{	
			iStart	= 1;
			iEnd	= 0;
			return FAB_INCLUDE_LESS_DMIN_BIN;
		}
		else if(nIncMax)
		{
			iStart	= 0;
			iEnd	= 1;
			return FAB_INCLUDE_MORE_DMAX_BIN;
		}
		else
		{		
			iStart	= 0;
			iEnd	= 0;
			return FAB_NOT_INCLUDE_OUTLIERS;
		}
	}

}

/// Hong 09/09/09 QA90-14287 2DBINNING_SUPPORT_HANDLE_MIN_MAX
//static void _get_2d_binning_options(BinningOption& stOption, int& nSize, int& nIncMin, int& nIncMax, int bin, double min, double max, double inc, int periodical, double period, int outleft, int outright)  
static void _get_2d_binning_options(BinningOption& stOption, int& nSize, int& nIncMin, int& nIncMax, int bin, double min, double max, double inc, int periodical, double period, int outleft, int outright, int includeMin = 0, int includeMax = 0)
/// end 2DBINNING_SUPPORT_HANDLE_MIN_MAX
{
	/// Iris 6/25/2009 QA80-13289-S1 CENTRLIZE_CODE_FOR_WIND_ROSE_PLOT
	// min, max here already be convert by bin_center or bin_end
	//stOption.dMax = max + (bin == bin_center ? inc / 2 : 0);
	//stOption.dMin = min - (bin == bin_center ? inc / 2 : 0);
	/// Iris 8/05/2009 FIX_MISS_ONE_BIN_IN_TWODBINNING
	//stOption.dMax = max;
	//stOption.dMin = min;
	stOption.dMax = max + (bin == bin_center ? inc / 2 : 0);
	stOption.dMin = min - (bin == bin_center ? inc / 2 : 0);
	///end FIX_MISS_ONE_BIN_IN_TWODBINNING
	///end CENTRLIZE_CODE_FOR_WIND_ROSE_PLOT
	stOption.dInc = inc;	
	
	nIncMin = outleft && !periodical;
	nIncMax = outright;	
	int iStart, iEnd;
	stOption.wIncludeOutliers = _get_include_outliers_type(nIncMin, nIncMax, iStart, iEnd);
	nSize = (int)( (stOption.dMax - stOption.dMin) / stOption.dInc + 0.5) + iStart + iEnd;
	/// Hong 09/09/09 QA90-14287 2DBINNING_SUPPORT_HANDLE_MIN_MAX
	int	iMin, iMax;
	stOption.wIncludeMinMax = _get_include_outliers_type(includeMin, includeMax, iMin, iMax);
	nSize += iMin + iMax;
	/// end 2DBINNING_SUPPORT_HANDLE_MIN_MAX
	stOption.dPeriod = periodical ? period : -1;		
}

///Kyle 06/30/2010 ORG-209 EXPAND_2D_BINNING_TO_SUPPORT_ADDITIONAL_Y_COLUMN
/*
static bool _calc_2d_binning(matrix<uint>& mnResult, matrix<double>& mdResult, const BinningOption& stOptionX, const BinningOption& stOptionY, 
const vector& vX, const vector& vY, int iSizeX, int iSizeY, int xorder, int yorder, int stats)
{
	if(stats == two_d_stats_count)
	{
		mnResult.SetSize(iSizeY, iSizeX);
		
		BinningResult	stResult;
		stResult.iMatSize = iSizeX * iSizeY;
		stResult.pMatrix = mnResult;
		int nSize = vY.GetSize();
		int nRet = ocmath_2d_binning(nSize, vX, vY, &stResult, &stOptionX, &stOptionY);
		if (nRet != OE_NOERROR)
		{
			XF_THROW_EX(CER_UNKNOWN_ERROR_EX, nRet);
		}
		///Kyle 03/26/2009 ADD_OPTION_TO_OUTPUT_RESULT_ASC_OR_DES
		if(xorder)
		{
			mnResult.Transpose();
			vector<uint> vnIndices;
			vnIndices.Data(mnResult.GetNumRows()-1, 0, -1);
			mnResult.ReorderRowWise(vnIndices);
			mnResult.Transpose();
		}
		if(yorder)
		{
			vector<uint> vnIndices;
			vnIndices.Data(mnResult.GetNumRows()-1, 0, -1);
			mnResult.ReorderRowWise(vnIndices);
		}
		///End ADD_OPTION_TO_OUTPUT_RESULT_ASC_OR_DES
	}
	else
	{
		int nStats;
		switch(stats)
		{
		case two_d_stats_min:
			nStats = OCMATH_2D_BINNING_MIN;
			break;
		case two_d_stats_max:
			nStats = OCMATH_2D_BINNING_MAX;
			break;
		case two_d_stats_mean:
			nStats = OCMATH_2D_BINNING_MEAN;
			break;
		case two_d_stats_median:
			nStats = OCMATH_2D_BINNING_MEDIAN;
			break;
		case two_d_stats_sum:
			nStats = OCMATH_2D_BINNING_SUM;
			break;
		case two_d_stats_freq:
			nStats = OCMATH_2D_BINNING_PERCENTAGES;
			break;
		}
		
		mdResult.SetSize(iSizeY, iSizeX);
		
		BinningStatsResult	stResult;
		stResult.iMatSize = iSizeX * iSizeY;
		stResult.pMatrix = mdResult;
		int nSize = vY.GetSize();
		int nRet = ocmath_2d_binning_stats(nSize, vX, vY, &stResult, nStats, &stOptionX, &stOptionY);
		if (nRet != OE_NOERROR)
		{
			//XF_THROW_EX(CER_UNKNOWN_ERROR_EX, nRet);
			return nRet;
		}
		
		///Kyle 03/26/2009 ADD_OPTION_TO_OUTPUT_RESULT_ASC_OR_DES
		if(xorder)
		{
			mdResult.Transpose();
			vector<uint> vnIndices;
			vnIndices.Data(mdResult.GetNumRows()-1, 0, -1);
			mdResult.ReorderRowWise(vnIndices);
			mdResult.Transpose();
		}
		if(yorder)
		{
			vector<uint> vnIndices;
			vnIndices.Data(mdResult.GetNumRows()-1, 0, -1);
			mdResult.ReorderRowWise(vnIndices);
		}
		///End ADD_OPTION_TO_OUTPUT_RESULT_ASC_OR_DES
	}
	return 0; //no error
}
*/
static int _calc_2d_binning(	matrix<double>& mdResult, double& dMinX, double& dMaxX, double& dMinY, double& dMaxY,				// output
								const BinningOption& stOptionX, const BinningOption& stOptionY,
								const vector& vX, const vector& vY, const vector& vZ, int iSizeX, int iSizeY, int xorder, int yorder, int stats)
{
	bool bIsZNeeded = true;
	int nStats;
	switch(stats)
	{
	case two_d_stats_min:
		nStats = OCMATH_2D_BINNING_MIN;
		break;
	case two_d_stats_max:
		nStats = OCMATH_2D_BINNING_MAX;
		break;
	case two_d_stats_mean:
		nStats = OCMATH_2D_BINNING_MEAN;
		break;
	case two_d_stats_median:
		nStats = OCMATH_2D_BINNING_MEDIAN;
		break;
	case two_d_stats_sum:
		nStats = OCMATH_2D_BINNING_SUM;
		break;
	case two_d_stats_count:
		nStats = OCMATH_2D_BINNING_COUNT;
		bIsZNeeded = false;
		break;
	case two_d_stats_freq:
		nStats = OCMATH_2D_BINNING_PERCENTAGES;
		bIsZNeeded = false;
		break;
	default:
		ASSERT(0);
		return -1;
	}
	int nSize = vX.GetSize();
	if( vY.GetSize() != nSize )
		return -1;
	if( bIsZNeeded && ( !vZ || vZ.GetSize()!=nSize) )
		return -1;

	mdResult.SetSize(iSizeY, iSizeX);

	BinningStatsResult stResult;
	stResult.iMatSize = iSizeX * iSizeY;
	stResult.pMatrix = mdResult;

	int nRet = ocmath_2d_binning_ex(nSize, vX, vY, bIsZNeeded ? vZ : (double*)0, &stResult, nStats, &stOptionX, &stOptionY);
	if (nRet != OE_NOERROR)
		return nRet;
	
	ASSERT(stResult.iSizeX == iSizeX && stResult.iSizeY == iSizeY);
	dMinX = stResult.dMinX;
	dMinY = stResult.dMinY;
	dMaxX = stResult.dMaxX;
	dMaxY = stResult.dMaxY;

	if(xorder)
	{
		mdResult.Transpose();
		vector<uint> vnIndices;
		vnIndices.Data(mdResult.GetNumRows()-1, 0, -1);
		mdResult.ReorderRowWise(vnIndices);
		mdResult.Transpose();
	}
	if(yorder)
	{
		vector<uint> vnIndices;
		vnIndices.Data(mdResult.GetNumRows()-1, 0, -1);
		mdResult.ReorderRowWise(vnIndices);
	}

	return 0; //no error
}
///End EXPAND_2D_BINNING_TO_SUPPORT_ADDITIONAL_Y_COLUMN


///Kyle 03/18/2009 QA80-13251 BETTER_FORMAT_FOR_ftoa_TO_CONSTRUCT_BIN_ENDS
// put here for now, one problem
// if inc is much less than min, ftoa(vv[ii]) will get some string no diff
static		int		_calc_num_significant_digits(const vector& vv)
{
	int		nSignDigit = 0;
	for ( int ii = vv.GetSize()-1; ii >= 0; --ii )
	{
		string	str = ftoa(vv[ii], "*");
		int		nPos = str.ReverseFind('E');
		if ( nPos > 0 )
			str = str.Left(nPos);
		if ( (nPos = str.Find('.') ) < 0 )
			continue;

		str = str.Mid(nPos + 1);
		if ( str.GetLength() > nSignDigit )
			nSignDigit = str.GetLength();
	}

	return nSignDigit;
}
///End BETTER_FORMAT_FOR_ftoa_TO_CONSTRUCT_BIN_ENDS

///Kyle 06/30/2010 ORG-209-P1 FIX_WRONG_OUT_RIGHT_BIN_ON_SEPARATE_COUNT_MAX_CHECKED
//static void _get_bin_ends_comments_label(double dMin, double dMax, double dInc, int nOrder, bool bOutLeft, bool bOutRight, vector<string>& vsLabels)
static void _get_bin_ends_comments_label(double dMin, double dMax, double dInc, int nOrder, bool bOutLeft, bool bOutRight, vector<string>& vsLabels, bool bSeparateCountMax)
///End FIX_WRONG_OUT_RIGHT_BIN_ON_SEPARATE_COUNT_MAX_CHECKED
{
	int nDecimalPlaces = log(dInc);
	nDecimalPlaces = nDecimalPlaces >= 0 ? 5 : (- nDecimalPlaces + 5);

	vector vBinEnds;
	vBinEnds.Data(nOrder==0?dMin:dMax, nOrder==0?dMax:dMin, nOrder==0?dInc:-dInc);
	vBinEnds = round(vBinEnds, nDecimalPlaces);

	int nSignDigit = _calc_num_significant_digits(vBinEnds);
	string strFormat = nSignDigit == 0 ? "*" : ("." + nSignDigit);
	vector<string> vsBinEnds;
	vsBinEnds.SetSize(vBinEnds.GetSize());
	for(int ii=vBinEnds.GetSize()-1; ii>=0; ii--)
		vsBinEnds[ii] = ftoa(vBinEnds[ii], strFormat);
	
	int nSize = vsBinEnds.GetSize()-1+bOutLeft+bOutRight;
	vsLabels.SetSize(nSize);
	
	for(ii=vsLabels.GetSize()-1; ii>=0; ii--)
	{
		string strComments;
		if(bOutLeft && (ii==0&&!nOrder || ii==nSize-1&&nOrder))
		{
			if(nOrder)
				strComments.Format("< %s", vsBinEnds[vsBinEnds.GetSize()-1]);
			else
				strComments.Format("< %s", vsBinEnds[0]);
		}
		else if(bOutRight && (ii==nSize-1&&!nOrder || ii==0&&nOrder))
		{
			///Kyle 06/30/2010 ORG-209-P1 FIX_WRONG_OUT_RIGHT_BIN_ON_SEPARATE_COUNT_MAX_CHECKED
			/*
			if(nOrder)
				strComments.Format(">= %s", vsBinEnds[0]);
			else
				strComments.Format(">= %s", vsBinEnds[vsBinEnds.GetSize()-1]);
			*/
			string strFmt = bSeparateCountMax ? "> %s" : ">= %s";
			if(nOrder)
				strComments.Format(strFmt, vsBinEnds[0]);
			else
				strComments.Format(strFmt, vsBinEnds[vsBinEnds.GetSize()-1]);
			///End FIX_WRONG_OUT_RIGHT_BIN_ON_SEPARATE_COUNT_MAX_CHECKED
		}
		else
		{
			int nIndex;
			if(nOrder)
			{
				nIndex = bOutRight ? ii-1 : ii;
				strComments.Format("%s - %s", vsBinEnds[nIndex + 1], vsBinEnds[nIndex]);
			}
			else
			{
				nIndex = bOutLeft ? ii-1 : ii;
				strComments.Format("%s - %s", vsBinEnds[nIndex], vsBinEnds[nIndex + 1]);
			}
		}
		vsLabels[ii] = strComments;
	}

}
/// Hong 09/09/09 QA90-14287 2DBINNING_SUPPORT_HANDLE_MIN_MAX
//void report_2d_binning(ReportData& rd, const XYRange& iy, 
//						int xbin, double xmin, double xmax, int xstepby, double xinc, double xintervals, int xperiodical, double xperiod, int xoutleft, int xoutright, int xorder,
//						int ybin, double ymin, double ymax, int ystepby, double yinc, double yintervals, int yperiodical, double yperiod, int youtleft, int youtright, int yorder, 
//						int stats, int subcount, MatrixObject& mo/*= NULL*/, int nOrientation/* = wind_rose_orientation_invalid*/)			
///Kyle 06/30/2010 ORG-209 EXPAND_2D_BINNING_TO_SUPPORT_ADDITIONAL_Y_COLUMN
//void report_2d_binning(ReportData& rd, const XYRange& iy, 
//						int xbin, double xmin, double xmax, int xstepby, double xinc, double xintervals, int xperiodical, double xperiod, int xoutleft, int xoutright, int xorder,
//						int ybin, double ymin, double ymax, int ystepby, double yinc, double yintervals, int yperiodical, double yperiod, int youtleft, int youtright, int yorder, 
//						int stats, int subcount, MatrixObject& mo/*= NULL*/, int nOrientation/* = wind_rose_orientation_invalid*/, int xincludemin, int xincludemax, int yincludemin, int yincludemax) //0
void report_2d_binning(ReportData& rd, const XYRange& iy, const vector& vZ,
						int xbin, double xmin, double xmax, int xstepby, double xinc, double xintervals, int xperiodical, double xperiod, int xoutleft, int xoutright, int xorder,
						int ybin, double ymin, double ymax, int ystepby, double yinc, double yintervals, int yperiodical, double yperiod, int youtleft, int youtright, int yorder, 
						int stats, int subcount, MatrixObject& mo/*= NULL*/, int nOrientation/* = wind_rose_orientation_invalid*/, int xincludemin, int xincludemax, int yincludemin, int yincludemax) //0
///End EXPAND_2D_BINNING_TO_SUPPORT_ADDITIONAL_Y_COLUMN
/// end 2DBINNING_SUPPORT_HANDLE_MIN_MAX
									
{

	BinningOption   stOptionX, stOptionY;
	int	iSizeX, nIncMinX, nIncMaxX;
	int iSizeY, nIncMinY, nIncMaxY;
	/// Hong 09/09/09 QA90-14287 2DBINNING_SUPPORT_HANDLE_MIN_MAX
	//_get_2d_binning_options(stOptionX, iSizeX, nIncMinX, nIncMaxX, xbin, xmin, xmax, xinc, xperiodical, xperiod, xoutleft, xoutright);
	//_get_2d_binning_options(stOptionY, iSizeY, nIncMinY, nIncMaxY, ybin, ymin, ymax, yinc, yperiodical, yperiod, youtleft, youtright);	
	_get_2d_binning_options(stOptionX, iSizeX, nIncMinX, nIncMaxX, xbin, xmin, xmax, xinc, xperiodical, xperiod, xoutleft, xoutright, xincludemin, xincludemax);
	_get_2d_binning_options(stOptionY, iSizeY, nIncMinY, nIncMaxY, ybin, ymin, ymax, yinc, yperiodical, yperiod, youtleft, youtright, yincludemin, yincludemax);
	/// end 2DBINNING_SUPPORT_HANDLE_MIN_MAX
	
	vector vX, vY;
	bool bRet = iy.GetData(vY, vX);
	ASSERT( bRet );
	
	///Kyle 06/30/2010 ORG-209 EXPAND_2D_BINNING_TO_SUPPORT_ADDITIONAL_Y_COLUMN
	if( vX.GetSize() != vY.GetSize() || !vX.GetSize() )
	{
		ASSERT(0);
		return;
	}

	if( stats!=two_d_stats_count && stats!=two_d_stats_freq &&		// require vZ
		(!vZ || vZ.GetSize() != vX.GetSize()) )
	{
		ASSERT(0);
		return;
	}
	///End EXPAND_2D_BINNING_TO_SUPPORT_ADDITIONAL_Y_COLUMN
	
	/// Iris 6/26/2009 QA80-13289-S1 CODES_FOR_WINDROSE_PLOT_XF
	if( wind_rose_orientation_from == nOrientation )
	{
		vX += 180;
	}
	///end CODES_FOR_WINDROSE_PLOT_XF

	///---Sim 09-11-2009 QA81-14287 WIND_ROSE_NEED_INCLUDE_SEPARATE_BIN_FOR_MIN
	double dCalm;
	double *pdCalm = NULL;
	if ( (nOrientation > wind_rose_orientation_invalid) && youtleft && yincludemin )
		pdCalm = &dCalm;
	///---END QA81-14287 WIND_ROSE_NEED_INCLUDE_SEPARATE_BIN_FOR_MIN
	
	///Kyle 06/30/2010 ORG-209 EXPAND_2D_BINNING_TO_SUPPORT_ADDITIONAL_Y_COLUMN
	//matrix mdResult;
	//matrix<uint> mnResult;
	//_calc_2d_binning(mnResult, mdResult, stOptionX, stOptionY, vX, vY, iSizeX, iSizeY, xorder, yorder, stats);
	matrix mdResult;
	double dOutMinX, dOutMinY, dOutMaxX, dOutMaxY;
	_calc_2d_binning(mdResult, dOutMinX, dOutMaxX, dOutMinY, dOutMaxY, stOptionX, stOptionY, vX, vY, vZ, iSizeX, iSizeY, xorder, yorder, stats);

	if( xbin == bin_center )
	{
		ASSERT( is_equal(dOutMinX + xinc/2.0, xmin) );
		xmax = dOutMaxX - xinc/2.0;
	}
	else
	{
		ASSERT( is_equal(dOutMinX, xmin) );
		xmax = dOutMaxX;
	}
	if( ybin == bin_center )
	{
		ASSERT( is_equal(dOutMinY + yinc/2.0, ymin) );
		ymax = dOutMaxY - yinc/2.0;
	}
	else
	{
		ASSERT( is_equal(dOutMinY, ymin) );
		ymax = dOutMaxY;
	}
	///End EXPAND_2D_BINNING_TO_SUPPORT_ADDITIONAL_Y_COLUMN

	/// Hong 09/09/09 QA90-14287 2DBINNING_SUPPORT_HANDLE_MIN_MAX
	int			iSizeXExcludeMinMax = iSizeX - (xincludemin + xincludemax);
	int			iSizeYExcludeMinMax = iSizeY - (yincludemin + yincludemax);
	/// end 2DBINNING_SUPPORT_HANDLE_MIN_MAX
	double dMinX, dMaxX, dMinY, dMaxY;
	if(xbin == bin_center)
	{
		dMinX = xmin - (nIncMinX ? xinc : 0);
	}
	else
	{
		dMinX = xmin + (nIncMinX ? 0 : xinc);
	}
	/// Hong 09/09/09 QA90-14287 2DBINNING_SUPPORT_HANDLE_MIN_MAX
	//dMaxX = dMinX + (iSizeX - 1) * xinc;
	dMaxX = dMinX + (iSizeXExcludeMinMax - 1) * xinc;
	/// end 2DBINNING_SUPPORT_HANDLE_MIN_MAX
	
	if(ybin == bin_center)
	{
		dMinY = ymin - (nIncMinY ? yinc : 0);
	}
	else
	{
		dMinY = ymin + (nIncMinY ? 0 : yinc);
	}
	/// Hong 09/09/09 QA90-14287 2DBINNING_SUPPORT_HANDLE_MIN_MAX
	//dMaxY = dMinY + (iSizeY - 1) * yinc;
	dMaxY = dMinY + (iSizeYExcludeMinMax - 1) * yinc;
	/// end 2DBINNING_SUPPORT_HANDLE_MIN_MAX
	
	vector vxBinEndsOrCenters, vyBenEndsOrCenters;
	string strXLongName, strUserParamName;
	vector<string> vsCommentLabels;
	
	vxBinEndsOrCenters.Data(xorder ? dMaxX :dMinX, xorder ? dMinX : dMaxX, xorder ? -xinc : xinc);
	vyBenEndsOrCenters.Data(yorder ? dMaxY :dMinY, yorder ? dMinY : dMaxY, yorder ? -yinc : yinc);
	/// Hong 09/09/09 QA90-14287 2DBINNING_SUPPORT_HANDLE_MIN_MAX
	int			nIndexXMin = nIncMinX ? 1 : 0, nIndexXMax = nIncMaxX ? (iSizeX - 1) - 1: iSizeX - 1;
	int			nIndexYMin = nIncMinY ? 1 : 0, nIndexYMax = nIncMaxY ? (iSizeY - 1) - 1: iSizeY - 1;
	if ( xincludemin )
		vxBinEndsOrCenters.InsertAt(nIndexXMin, xmin);
	if ( xincludemax )
		vxBinEndsOrCenters.InsertAt(nIndexXMax, xmax);
	if ( yincludemin )
		vyBenEndsOrCenters.InsertAt(nIndexYMin, ymin);
	if ( yincludemax )
		vyBenEndsOrCenters.InsertAt(nIndexYMax, ymax);
	/// end 2DBINNING_SUPPORT_HANDLE_MIN_MAX
	
	//strXLongName.Format(_L("Bin %s of %s"), xbin_center == xbin ? _L("Centers") : _L("Ends"), get_xy_range_string(iy, "X"));
	string strInputXName = get_xy_range_string(iy, "X");
	if(strInputXName.IsEmpty())
		strXLongName.Format(_L("Bin %s of X"), bin_center == xbin ? _L("Centers") : _L("Ends"));
	else
		strXLongName.Format(_L("Bin %s of %s"), bin_center == xbin ? _L("Centers") : _L("Ends"), get_xy_range_string(iy, "X"));
	strUserParamName.Format(_L("Bin %s of %s"), bin_center == ybin ? _L("Centers") : _L("Ends"), get_input_data_range_string(iy));
	
	double dYBeg = ymin - (ybin == bin_center ? yinc / 2 : 0);
	///Kyle 05/15/2009 QA80-13521 ONLY_ONE_OUTLIERS_IS_NEED_WHEN_PERIODICAL_CHECKED
	//_get_bin_ends_comments_label(dYBeg, dYBeg + (iSizeY - youtleft - youtright) * yinc, yinc, yorder, youtleft, youtright, vsCommentLabels);
	/// Hong 09/09/09 QA90-14287 2DBINNING_SUPPORT_HANDLE_MIN_MAX
	//_get_bin_ends_comments_label(dYBeg, dYBeg + (iSizeY - nIncMinY - nIncMaxY) * yinc, yinc, yorder, nIncMinY, nIncMaxY, vsCommentLabels);
	///Kyle 06/30/2010 ORG-209-P1 FIX_WRONG_OUT_RIGHT_BIN_ON_SEPARATE_COUNT_MAX_CHECKED
	//_get_bin_ends_comments_label(dYBeg, dYBeg + (iSizeYExcludeMinMax - nIncMinY - nIncMaxY) * yinc, yinc, yorder, nIncMinY, nIncMaxY, vsCommentLabels);
	_get_bin_ends_comments_label(dYBeg, dYBeg + (iSizeYExcludeMinMax - nIncMinY - nIncMaxY) * yinc, yinc, yorder, nIncMinY, nIncMaxY, vsCommentLabels, yincludemax);
	///End FIX_WRONG_OUT_RIGHT_BIN_ON_SEPARATE_COUNT_MAX_CHECKED
	char		szTemp[MAXLINE];
	if ( yincludemin )
	{
		DoubleToStr(ymin, szTemp, MAXLINE, "*");
		vsCommentLabels.InsertAt(nIndexYMin, szTemp);
	}
	if ( yincludemax )
	{
		DoubleToStr(ymax, szTemp, MAXLINE, "*");
		vsCommentLabels.InsertAt(nIndexYMax, szTemp);
	}
	/// end 2DBINNING_SUPPORT_HANDLE_MIN_MAX
	///End ONLY_ONE_OUTLIERS_IS_NEED_WHEN_PERIODICAL_CHECKED
	
	///Kyle 06/30/2010 ORG-209 EXPAND_2D_BINNING_TO_SUPPORT_ADDITIONAL_Y_COLUMN
	//_2d_binning_update_report_data(	vxBinEndsOrCenters, strXLongName,
	//									vyBenEndsOrCenters, strUserParamName,
	//									vsCommentLabels, stats,
	//									mdResult, mnResult,
	/////---Sim 09-11-2009 QA81-14287 WIND_ROSE_NEED_INCLUDE_SEPARATE_BIN_FOR_MIN
	//									//rd);
	//									rd,
	//									pdCalm);
	/////---END QA81-14287 WIND_ROSE_NEED_INCLUDE_SEPARATE_BIN_FOR_MIN
	_2d_binning_update_report_data(	vxBinEndsOrCenters, strXLongName,
										vyBenEndsOrCenters, strUserParamName,
										vsCommentLabels, stats,
										mdResult,
										rd,
										pdCalm);
	///End EXPAND_2D_BINNING_TO_SUPPORT_ADDITIONAL_Y_COLUMN
	
	if(mo)
	{
		mo.SetNumRows(iSizeY);
		mo.SetNumCols(iSizeX);	
		matrixbase& mat = mo.GetDataObject();
		///Kyle 06/30/2010 ORG-209 EXPAND_2D_BINNING_TO_SUPPORT_ADDITIONAL_Y_COLUMN
		//if(stats == two_d_stats_count)
		//	mat = mnResult;
		//else
		//	mat = mdResult;
		mat = mdResult;
		///End EXPAND_2D_BINNING_TO_SUPPORT_ADDITIONAL_Y_COLUMN
		
		///Kyle 03/26/2009 ADD_OPTION_TO_OUTPUT_RESULT_ASC_OR_DES
		//om.SetXY(dMinX, dMinY, dMaxX, dMaxY);
		mo.SetXY(xorder ? dMaxX : dMinX, yorder ? dMaxY : dMinY, xorder ? dMinX : dMaxX, yorder ? dMinY : dMaxY);
		///End ADD_OPTION_TO_OUTPUT_RESULT_ASC_OR_DES
	}
	
	///Kyle 03/28/2009 NEW_TABLE_FOR_SUB_TOTAL_COUNT
	if(subcount && (stats==two_d_stats_sum || stats==two_d_stats_count || stats==two_d_stats_freq) )
	{
		string strXLongName;
		strXLongName.Format(_L("Bins of %s"), get_input_data_range_string(iy));
		///---Sim 09-11-2009 QA81-14287 WIND_ROSE_NEED_INCLUDE_SEPARATE_BIN_FOR_MIN
		//_2d_binning_update_subtotal_count(vsCommentLabels, mdResult, mnResult, stats, rd, strXLongName);
		///Kyle 06/30/2010 ORG-209 EXPAND_2D_BINNING_TO_SUPPORT_ADDITIONAL_Y_COLUMN
		//_2d_binning_update_subtotal_count(vsCommentLabels, mdResult, mnResult, stats, rd, strXLongName, pdCalm);
		_2d_binning_update_subtotal_count(vsCommentLabels, mdResult, stats, rd, strXLongName, pdCalm);
		///End EXPAND_2D_BINNING_TO_SUPPORT_ADDITIONAL_Y_COLUMN
		///---END QA81-14287 WIND_ROSE_NEED_INCLUDE_SEPARATE_BIN_FOR_MIN
	}
	///End NEW_TABLE_FOR_SUB_TOTAL_COUNT
	
	///---Sim 09-11-2009 QA81-14287 WIND_ROSE_NEED_INCLUDE_SEPARATE_BIN_FOR_MIN
	if ( pdCalm )
	{
		_2d_binning_update_calm(rd, *pdCalm);
	}
	///---END QA81-14287 WIND_ROSE_NEED_INCLUDE_SEPARATE_BIN_FOR_MIN
}


/// Max 6/2/08 v8.0875b RUN_WITH_FLYOUT_THEME_REQUIRE_SPECIFY_AUTO_VARIABLES_IN_BEFORE_EXECUTE
void init_two_binning_tree_show(TreeNode& trGetN)
{
	_update_initial_val_x_y(trGetN);

	///Kyle 03/12/2009 QA80-13251 ADD_OPTION_TO_SPECIFY_BIN_BY_CENTER_OR_END
	//freq_update_inc(trGetN.xmin.dVal, trGetN.xmax.dVal, trGetN.xstepby.nVal, trGetN.xoutleft.nVal, trGetN.xoutright.nVal, trGetN.xinc, trGetN.xintervals);
	//freq_update_inc(trGetN.ymin.dVal, trGetN.ymax.dVal, trGetN.ystepby.nVal, trGetN.youtleft.nVal, trGetN.youtright.nVal, trGetN.yinc, trGetN.yintervals);
	/// Iris 6/26/2009 QA80-13289-S1 CODES_FOR_WINDROSE_PLOT_XF
	//freq_update_inc(trGetN.xmin.dVal, trGetN.xmax.dVal, trGetN.xstepby.nVal, trGetN.xoutleft.nVal, trGetN.xoutright.nVal, trGetN.xinc, trGetN.xintervals, trGetN.xbin.nVal == bin_center);
	//freq_update_inc(trGetN.ymin.dVal, trGetN.ymax.dVal, trGetN.ystepby.nVal, trGetN.youtleft.nVal, trGetN.youtright.nVal, trGetN.yinc, trGetN.yintervals, trGetN.ybin.nVal == bin_center);
	int xstepby = trGetN.xstepby? trGetN.xstepby.nVal : step_by_inc;
	int xoutleft = trGetN.xoutleft? trGetN.xoutleft.nVal : 0;
	int xoutright = trGetN.xoutright? trGetN.xoutright.nVal : 1;
	/// Iris 7/23/2009 REMOVE_YBIN_CONTROL_FROM_PLOT_WINDROSE
	//bool bBinCenter = trGetN.xbin? trGetN.xbin.nVal == bin_center : false;
	bool bXBinCenter = trGetN.xbin? trGetN.xbin.nVal == bin_center : false;
	bool bYBinCenter = trGetN.ybin? trGetN.ybin.nVal == bin_center : false;
	///end REMOVE_YBIN_CONTROL_FROM_PLOT_WINDROSE
	int ystepby = trGetN.ystepby? trGetN.ystepby.nVal : step_by_inc;
	int youtleft = trGetN.youtleft? trGetN.youtleft.nVal : 0;
	int youtright = trGetN.youtright? trGetN.youtright.nVal : 1;
	if( trGetN.xmin.Show && trGetN.xmax.Show )
	{
		/// Iris 7/23/2009 REMOVE_YBIN_CONTROL_FROM_PLOT_WINDROSE
		//freq_update_inc(trGetN.xmin.dVal, trGetN.xmax.dVal, xstepby, xoutleft, xoutright, trGetN.xinc, trGetN.xintervals, bBinCenter);
		freq_update_inc(trGetN.xmin.dVal, trGetN.xmax.dVal, xstepby, xoutleft, xoutright, trGetN.xinc, trGetN.xintervals, bXBinCenter);
		///end REMOVE_YBIN_CONTROL_FROM_PLOT_WINDROSE
	}	
	/// Iris 7/23/2009 REMOVE_YBIN_CONTROL_FROM_PLOT_WINDROSE
	//freq_update_inc(trGetN.ymin.dVal, trGetN.ymax.dVal, ystepby, youtleft, youtright, trGetN.yinc, trGetN.yintervals, trGetN.ybin.nVal == bin_center);
	freq_update_inc(trGetN.ymin.dVal, trGetN.ymax.dVal, ystepby, youtleft, youtright, trGetN.yinc, trGetN.yintervals, bYBinCenter);
	///end REMOVE_YBIN_CONTROL_FROM_PLOT_WINDROSE
	///end CODES_FOR_WINDROSE_PLOT_XF
	///End ADD_OPTION_TO_SPECIFY_BIN_BY_CENTER_OR_END
	
	///Kyle 03/12/2009 QA80-13251 ADD_OPTION_TO_SPECIFY_BIN_BY_CENTER_OR_END
	_update_min_max_labels(trGetN);
	///End ADD_OPTION_TO_SPECIFY_BIN_BY_CENTER_OR_END
	
	///Kyle 05/11/2009 QA80-13521 SUPPORT_PERIODICAL_BINS
	_update_period(trGetN);
	///End SUPPORT_PERIODICAL_BINS
}

static void _update_initial_val_x_y(TreeNode& trGetN)
{
 	TreeNode trTemp = trGetN.iy;
	if( trTemp )
	{
		XYRange rgXY;
		okxf_resolve_tree_construct_range(&trTemp, &rgXY);
		if( rgXY )
		{
			vector vX;
			vector vY;
			rgXY.GetData(vY, vX);
			if (0 != vX.GetSize() || 0 != vY.GetSize())
			{
				///Kyle 03/12/2009 QA80-13251 ADD_OPTION_TO_SPECIFY_BIN_BY_CENTER_OR_END
				//set_round_limits(vX, trGetN.xmin, trGetN.xmax, trGetN.xinc, trGetN.xintervals, trGetN.xstepby.nVal);
				//set_round_limits(vY, trGetN.ymin, trGetN.ymax, trGetN.yinc, trGetN.yintervals, trGetN.ystepby.nVal);
				/// Max 3/12/09 v8.0953c_new QA70-13251 RENAME_VAR_coordinate_TO_bin
				//set_round_limits(vX, trGetN.xmin, trGetN.xmax, trGetN.xinc, trGetN.xintervals, trGetN.xstepby.nVal, trGetN.coordinate.nVal == _2D_BINNING_COORDINATE_BIN_CENTER);
				//set_round_limits(vY, trGetN.ymin, trGetN.ymax, trGetN.yinc, trGetN.yintervals, trGetN.ystepby.nVal, trGetN.coordinate.nVal == _2D_BINNING_COORDINATE_BIN_CENTER);
				if( trGetN.xmin.Show )/// Iris 6/26/2009 QA80-13289-S1 CODES_FOR_WINDROSE_PLOT_XF
					set_round_limits(vX, trGetN.xmin, trGetN.xmax, trGetN.xinc, trGetN.xintervals, trGetN.xstepby.nVal, trGetN.xbin.nVal == bin_center);
				///end CODES_FOR_WINDROSE_PLOT_XF
				/// Iris 7/23/2009 REMOVE_YBIN_CONTROL_FROM_PLOT_WINDROSE				
				//set_round_limits(vY, trGetN.ymin, trGetN.ymax, trGetN.yinc, trGetN.yintervals, trGetN.ystepby.nVal, trGetN.ybin.nVal == bin_center);
				set_round_limits(vY, trGetN.ymin, trGetN.ymax, trGetN.yinc, trGetN.yintervals, trGetN.ystepby.nVal, trGetN.ybin ? trGetN.ybin.nVal == bin_center : false);
				///end REMOVE_YBIN_CONTROL_FROM_PLOT_WINDROSE
				/// END RENAME_VAR_coordinate_TO_bin
				///End ADD_OPTION_TO_SPECIFY_BIN_BY_CENTER_OR_END	
			}
		}
	}	
}

///Kyle 03/12/2009 QA80-13251 ADD_OPTION_TO_SPECIFY_BIN_BY_CENTER_OR_END
static void _update_min_max_labels(TreeNode& trGetN)
{
	string strMinLabel, strMaxLabel;
	
	/// Max 3/12/09 v8.0953c_new QA70-13251 RENAME_VAR_coordinate_TO_bin
	// if(trGetN.coordinate.nVal == _2D_BINNING_COORDINATE_BIN_CENTER)	// bin center
	if(trGetN.xbin && trGetN.xbin.nVal == bin_center)
	/// ---
	{
		strMinLabel = _L("Minimum Bin Center");
		strMaxLabel = _L("Maximum Bin Center");
	}
	else						// bin end
	{
		strMinLabel = _L("Minimum Bin Beginning");
		strMaxLabel = _L("Maximum Bin End");
	}
	trGetN.xmin.SetAttribute(STR_LABEL_ATTRIB, strMinLabel);
	trGetN.xmax.SetAttribute(STR_LABEL_ATTRIB, strMaxLabel);

	/// Iris 7/23/2009 REMOVE_YBIN_CONTROL_FROM_PLOT_WINDROSE
	/*
	if(trGetN.ybin && trGetN.ybin.nVal == bin_center)
	{
		strMinLabel = _L("Minimum Bin Center");
		strMaxLabel = _L("Maximum Bin Center");
	}
	else						// bin end
	{
		strMinLabel = _L("Minimum Bin Beginning");
		strMaxLabel = _L("Maximum Bin End");
	}
	trGetN.ymin.SetAttribute(STR_LABEL_ATTRIB, strMinLabel);
	trGetN.ymax.SetAttribute(STR_LABEL_ATTRIB, strMaxLabel);
	*/
	if( trGetN.ybin )
	{
		if( trGetN.ybin.nVal == bin_center )
		{
			strMinLabel = _L("Minimum Bin Center");
			strMaxLabel = _L("Maximum Bin Center");
		}
		else
		{
			strMinLabel = _L("Minimum Bin Beginning");
			strMaxLabel = _L("Maximum Bin End");
		}
		trGetN.ymin.SetAttribute(STR_LABEL_ATTRIB, strMinLabel);
		trGetN.ymax.SetAttribute(STR_LABEL_ATTRIB, strMaxLabel);
	}
	//end REMOVE_YBIN_CONTROL_FROM_PLOT_WINDROSE
}
///End ADD_OPTION_TO_SPECIFY_BIN_BY_CENTER_OR_END

static void _update_period(TreeNode& trGetN)
{
	if(trGetN.xperiodical && trGetN.xperiodical.nVal)
	{
		TreeNode trPeriod = trGetN.xperiod;
		if( trPeriod && 1 == octree_get_auto_support(&trPeriod) )
		{
			double dMin, dMax;
			dMin = trGetN.xmin.dVal - (trGetN.xbin.nVal == bin_center ? trGetN.xinc.dVal / 2.0 : 0);
			dMax = trGetN.xmax.dVal + (trGetN.xbin.nVal == bin_center ? trGetN.xinc.dVal / 2.0 : 0);
			///Kyle 07/10/2009 QA80-13521-P1 SHOULD_SKIP_OR_EXTEND_THE_LAST_BIN_BEFORE_CHECKING_PERIODICAL
			//trPeriod.dVal = _get_auto_period(dMin, dMax);
			trPeriod.dVal = _get_auto_period(dMin, dMax, trGetN.xinc.dVal);
			///End SHOULD_SKIP_OR_EXTEND_THE_LAST_BIN_BEFORE_CHECKING_PERIODICAL
		}
	}
	if(trGetN.yperiodical && trGetN.yperiodical.nVal)
	{
		TreeNode trPeriod = trGetN.yperiod;
		if( trPeriod && 1 == octree_get_auto_support(&trPeriod) )
		{
			double dMin, dMax;
			dMin = trGetN.ymin.dVal - (trGetN.ybin.nVal == bin_center ? trGetN.yinc.dVal / 2.0 : 0);
			dMax = trGetN.ymax.dVal + (trGetN.ybin.nVal == bin_center ? trGetN.yinc.dVal / 2.0 : 0);
			///Kyle 07/10/2009 QA80-13521-P1 SHOULD_SKIP_OR_EXTEND_THE_LAST_BIN_BEFORE_CHECKING_PERIODICAL
			//trPeriod.dVal = _get_auto_period(dMin, dMax);
			trPeriod.dVal = _get_auto_period(dMin, dMax, trGetN.yinc.dVal);
			///End SHOULD_SKIP_OR_EXTEND_THE_LAST_BIN_BEFORE_CHECKING_PERIODICAL
		}
	}
}

///Kyle 07/10/2009 QA80-13521-P1 SHOULD_SKIP_OR_EXTEND_THE_LAST_BIN_BEFORE_CHECKING_PERIODICAL
//static double _get_auto_period(double dMin, double dMax)
static double _get_auto_period(double dMin, double dMax, double dInc)
///End SHOULD_SKIP_OR_EXTEND_THE_LAST_BIN_BEFORE_CHECKING_PERIODICAL
{
	///Kyle 05/15/2009 QA80-13521 ONLY_ONE_OUTLIERS_IS_NEED_WHEN_PERIODICAL_CHECKED
	//// max(|dMin|, |dMax|, dMax-dMin)
	//if(dMin >= dMax)
		//return NANUM;
	//double dPeriod = max(dMax - dMin, abs(dMin));
	//dPeriod = max(dPeriod, abs(dMax));
	//return dPeriod;
	if(dMin < dMax)
	{
		///Kyle 07/10/2009 QA80-13521-P1 SHOULD_SKIP_OR_EXTEND_THE_LAST_BIN_BEFORE_CHECKING_PERIODICAL
		//return dMax-dMin;
		ASSERT(dInc > 0.0);
		int nSize = nint( (dMax - dMin)/dInc );
		return dInc * nSize;
		///End SHOULD_SKIP_OR_EXTEND_THE_LAST_BIN_BEFORE_CHECKING_PERIODICAL
	}
	return NANUM;
	///End ONLY_ONE_OUTLIERS_IS_NEED_WHEN_PERIODICAL_CHECKED
}

///end CENTRLIZE_CODE_FOR_WIND_ROSE_PLOT

#if  _OC_VER >= 0x0820

#define EXTRACTED_TABLE_COL_LABEL_PREFIX 	_L("Principal")
#define	LOADING_PLOT_DATA_LABEL_PREFIX		_L("Component")

enum {
	PCA_REPORT_GRAPH_SCREE_PLOT,
	PCA_REPORT_GRAPH_LOADING_PLOT,
	PCA_REPORT_GRAPH_SCORE_PLOT
};
	
//static int _get_psc_plot_data_table_id(int nGraphIndex, int index)
//{
	//switch(nGraphIndex)
	//{
	//case PCA_REPORT_GRAPH_SCREE_PLOT:
		//return PSA_TABLE_SCREE_PLOT_DATA;
			//
	//case PCA_REPORT_GRAPH_LOADING_PLOT:
		//return PSA_TABLE_LOADING_PLOT_DATA + index;
		//
	//}
//}

static int _get_pca_scree_plot_data_table_id()
{
	return PSA_TABLE_SCREE_PLOT_DATA;
}

static int _get_pca_scree_plot_data_one_col_id(char nColType)
{
	int nOffset = 'X' == nColType? 1 : 2;
	return _get_pca_scree_plot_data_table_id() + nOffset;
}

static int _get_pca_loading_plot_data_table_id()
{
	return PSA_TABLE_LOADING_PLOT_DATA;
}

static int _get_pca_loading_plot_data_one_col_id(int index, char nColType)
{
	const int nNumCols = 5; // X, Y, L
	int nOffset = 0;
	switch(nColType)
	{
	case 'x': // X1
		nOffset = 1;
		break;
	case 'y': // Y 1
		nOffset = 2;
		break;
	case 'X': // X 2
		nOffset = 3;
		break;
	case 'Y': // Y 2
		nOffset = 4;
		break;		
	case 'L': //Label
		nOffset = 5;
		break;
	}	
	return _get_pca_loading_plot_data_table_id() + nNumCols * index + nOffset;
}

static int _get_score_table_id()
{
	return PSA_TABLE_SCORES;
}

static int _get_score_table_column_id(char chColType, int nYIndex = -1)
{
#define MAX_NUM_Y	99
	switch(chColType)
	{
	case 'X':
		return _get_score_table_id() + 1;		
		
	case 'Y':
		ASSERT( nYIndex>=0 );
		return _get_score_table_column_id('X') + nYIndex + 1;
		
	}
	ASSERT(false);
	return -1;
}

//static int _get_combination_num(int nNumComponents)
//{
	//return nNumComponents * (nNumComponents -1 ) / 2;
//}

static string _pca_get_col_name(int index)
{
	return "Col" + (index + 1);
}

void output_pca_plot_data(ReportData& rdplot, const vector<string>& vsDataLongNames, const matrix& mPCAStats, const matrix& mLoadings, const ResultOptions& stOptions)
{
	int nColIndex = 0;
	
	// Eigenvalues data
	vector vecIndex, vecEigen;
	mPCAStats.GetColumn(vecEigen, EIGENVALUES_EIGEN_VALUES);
	vecIndex.Data(1, vecEigen.GetSize(), 1);
	
	ReportTable rtScreePlot = rdplot.CreateTable("ScreePlotData", _L("Eigenvalue"), _get_pca_scree_plot_data_table_id());
	rtScreePlot.AddColumn(vecIndex, _pca_get_col_name(nColIndex++), _get_pca_scree_plot_data_one_col_id('X'), "Principal Component Number", OKDATAOBJ_DESIGNATION_X);
	rtScreePlot.AddColumn(vecEigen, _pca_get_col_name(nColIndex++), _get_pca_scree_plot_data_one_col_id('Y'), "Eigenvalues", OKDATAOBJ_DESIGNATION_Y);
	
	// Loading Plot Data, temp, use the first two columns
	ReportTable rtLoadingPlot = rdplot.CreateTable("LoadingPlotData", _L("Loading Plot"), _get_pca_loading_plot_data_table_id());
	int count = 0;
	nColIndex = 0;
	ASSERT( stOptions.nComponentPlotRangeBegin < stOptions.nComponentPlotRangeEnd );
	for(int ii = stOptions.nComponentPlotRangeBegin-1; ii < stOptions.nComponentPlotRangeEnd; ii++)
	{
		for(int jj = stOptions.nComponentPlotRangeBegin; jj < stOptions.nComponentPlotRangeEnd; jj++)
		{
			if( stOptions.nSelComponentPlotType == COMPONENT_PLOT_METHOD_SPECIFY_BY_TWO )
			{
				if( ii != stOptions.nComponentPlotRangeBegin-1 || jj != stOptions.nComponentPlotRangeEnd-1 )
					continue;
			}
			else
			{			
				if( ii >= jj )
					continue;	
			}
			
			vector vecEigenVec1, vecEigenVec2;
			mLoadings.GetColumn(vecEigenVec1, ii);
			mLoadings.GetColumn(vecEigenVec2, jj);
			
			vector vx1, vy1, vx2, vy2;
			vector<string> vsDataLabels;
			for(int nn = 0; nn < vecEigenVec1.GetSize(); nn++)
			{
				vx1.Add(0);
				vy1.Add(0);
				vx2.Add(vecEigenVec1[nn]);
				vy2.Add(vecEigenVec2[nn]);
				
				if( nn < vsDataLongNames.GetSize() )
					vsDataLabels.Add(vsDataLongNames[nn]);		
			}
			
			rtLoadingPlot.AddColumn(vx1, _pca_get_col_name(nColIndex++), _get_pca_loading_plot_data_one_col_id(count, 'x'), LOADING_PLOT_DATA_LABEL_PREFIX + " 1", OKDATAOBJ_DESIGNATION_X);
			rtLoadingPlot.AddColumn(vy1, _pca_get_col_name(nColIndex++), _get_pca_loading_plot_data_one_col_id(count, 'y'), LOADING_PLOT_DATA_LABEL_PREFIX + " 2", OKDATAOBJ_DESIGNATION_Y);
			rtLoadingPlot.AddColumn(vx2, _pca_get_col_name(nColIndex++), _get_pca_loading_plot_data_one_col_id(count, 'X'), LOADING_PLOT_DATA_LABEL_PREFIX + " 3", OKDATAOBJ_DESIGNATION_X);
			rtLoadingPlot.AddColumn(vy2, _pca_get_col_name(nColIndex++), _get_pca_loading_plot_data_one_col_id(count, 'Y'), LOADING_PLOT_DATA_LABEL_PREFIX + " 4", OKDATAOBJ_DESIGNATION_Y);
			rtLoadingPlot.AddColumn(vsDataLabels, _pca_get_col_name(nColIndex++), _get_pca_loading_plot_data_one_col_id(count, 'L'), "", OKDATAOBJ_DESIGNATION_L);			
			count++;
		}
	}
}

static void _add_pca_plottings(ReportTree& rt, ReportData& rdPlot, ReportData& rdScoreData, const ResultOptions& stOptions)
{
	// Scree Plot
	_add_pca_scree_plotting(rt, rdPlot);
	
	_add_pca_loading_plottings(rt, rdPlot, rdScoreData, stOptions);
	
	_add_pca_scores_plotting(rt, rdPlot, rdScoreData, stOptions);
	
	_add_pca_biplotting(rt, rdPlot, rdScoreData, stOptions);
}

static void _add_pca_scree_plotting(ReportTree& rt, ReportData& rdPlot)
{
	XFExeContext* 	pxfexectxt = Project.GetCurrentXFExeCtxt();	
	int 			nPlotID = PSA_TABLE_SCREE_PLOT;
	GraphPage 		gp = pxfexectxt->GetGraph(nPlotID);	
	if( !gp )
	{
		gp.Create("Line", CREATE_HIDDEN);
		gp.SetLongName("Scree Plot");
		gp.TitleShow = WIN_TITLE_SHOW_LABEL;
	}	
	GraphLayer 	gl = gp.Layers(0);
	
	DataRange 	drScree;
	int 		nYID = _get_pca_scree_plot_data_one_col_id('Y');
	int 		nPlot;
	if (0 != rdPlot.GetDataRange(drScree, _get_pca_scree_plot_data_table_id(), _get_pca_scree_plot_data_one_col_id('X'), &nYID))
	{
		vector<int> 	vnPlotIndices;
		if( !check_has_plotted_in_graph(drScree, gl, vnPlotIndices) )
		{
			nPlot = gl.AddPlot(drScree, IDM_PLOT_LINESYMB);
			
			// remove legend
			if( gl.GraphObjects(GO_LEGEND_NAME).IsValid() )
				gl.RemoveGraphObject(GO_LEGEND_NAME);
			
			// set plot color
			DataPlot dp = gl.DataPlots(nPlot);
			if( dp )
			{
				Tree tr;
				tr.Root.Line.Color.nVal = SYSCOLOR_RED;
				tr.Root.Symbol.FillColor.nVal = SYSCOLOR_BLUE;
				tr.Root.Symbol.EdgeColor.nVal = SYSCOLOR_BLUE;
				if( 0 == dp.UpdateThemeIDs(tr.Root) )
				{
					dp.ApplyFormat(tr, true, true);
				}
			}	
		}	
	}
	gl.Rescale();
	
	pxfexectxt->SetGraph(gp, nPlotID);
	
	ReportTable 	rtScree = rt.CreateTable("ScreePlot", _L("Scree Plot"), PSA_TABLE_SCREE_PLOT);
	rtScree.SetCell(0, 0, gp, EMBEDGRAPH_MOVE_IF_ALREADY_EMBEDDED);

}

static void _add_one_pca_loading_plotting(ReportData& rdPlot, GraphLayer& gl, int index)
{
	DataRange 	drXY1, drXY2;
	int			nTableID = _get_pca_loading_plot_data_table_id();
	int 		nX1ID = _get_pca_loading_plot_data_one_col_id(index, 'x');
	int 		nY1ID = _get_pca_loading_plot_data_one_col_id(index, 'y');
	int 		nX2ID = _get_pca_loading_plot_data_one_col_id(index, 'X');			
	int 		nY2ID = _get_pca_loading_plot_data_one_col_id(index, 'Y');
	DataPlot	dpLine;
	if (0 != rdPlot.GetDataRange(drXY1, nTableID, nX1ID, &nY1ID)
		&& 0 != rdPlot.GetDataRange(drXY2, nTableID, nX2ID, &nY2ID) )
	{			
		vector<int> 	vnPlotIndices;
		if( !check_has_plotted_in_graph(drXY1, gl, vnPlotIndices) && !check_has_plotted_in_graph(drXY2, gl, vnPlotIndices) )
		{					
			DataRange drXYXY;					
			Worksheet wks;
			int	c1, c2;		
			
			// X1
			drXY1.GetRange(wks, c1, c2, 0);					
			drXYXY.Add(wks, c1, "X");
			
			// Y1
			drXY1.GetRange(wks, c1, c2, 1);						
			drXYXY.Add(wks, c1, "Y");
			drXYXY.Add();
			
			// X2
			drXY2.GetRange(wks, c1, c2, 0);	
			drXYXY.Add(wks, c1, "X2");
			
			drXY2.GetRange(wks, c1, c2, 1);						
			drXYXY.Add(wks, c1, "Y2");
			
			int nPlot = gl.AddPlot(drXYXY, IDM_PLOT_FLOWVECTOR);
			if( nPlot >= 0 )
			{	
				dpLine = gl.DataPlots(nPlot);
				
				// get Label column and attach label to plot
				Column colLabel(wks, c1+1);						
				ASSERT(colLabel);
				if( colLabel )
				{							
					Curve crv(wks, c1-1, c1);
					gl.AddLabelPlot(crv, colLabel);
				}						
			}
			
			/*** Set Format in Graph Template, so comment out the following codes****/
			//// remove legend
			//if( gl.GraphObjects(GO_LEGEND_NAME).IsValid() )
				//gl.RemoveGraphObject(GO_LEGEND_NAME);
			//
			//// set line plot color to blue
			//if( dpLine )
			//{
				//Tree tr;
				//tr.Root.Line.Color.nVal = SYSCOLOR_BLUE;
				//if( 0 == dpLine.UpdateThemeIDs(tr.Root) )
				//{
					//dpLine.ApplyFormat(tr, true, true);
				//}
			//}	
			//
			//// add X = 0 and Y = 0 line
			//Tree tr;
			//tr = gl.GetFormat();
			//tr.Root.Axes.X.Additional.ZeroLine.nVal = 1;
			//tr.Root.Axes.X.Additional.OppositeLine.nVal = 1;		
			//tr.Root.Axes.Y.Additional.ZeroLine.nVal = 1;
			//tr.Root.Axes.Y.Additional.OppositeLine.nVal = 1;		
			//if( 0 == gl.UpdateThemeIDs(tr.Root) )
			//{
				//gl.ApplyFormat(tr, true, true);
			//}						
		}		
	}
	gl.Rescale();	
}

static void _add_one_pca_scores_plotting(ReportData& rdScoreData, GraphLayer& gl, int ii, int jj)
{
	DataRange dr1, dr2;
	int nTableID = _get_score_table_id();
	int nColX = _get_score_table_column_id('X');
	int nColY1 = _get_score_table_column_id('Y', ii);
	int nColY2 = _get_score_table_column_id('Y', jj);
	if( 0 != rdScoreData.GetDataRange(dr1, nTableID, nColX, &nColY1) 
		&& 0 != rdScoreData.GetDataRange(dr2, nTableID, nColX, &nColY2) )
	{			
		DataRange drXY;					
		Worksheet wks;
		int	c1, c2;		
		int nColLabelIndex;
		
		// X - index
		dr1.GetRange(wks, c1, c2, 0);
		nColLabelIndex = c1 + 1;
		
		// Y1
		dr1.GetRange(wks, c1, c2, 1);					
		drXY.Add(wks, c1, "X");
		
		// Y2
		dr2.GetRange(wks, c1, c2, 1);						
		drXY.Add(wks, c1, "Y");
			
		vector<int> 	vnPlotIndices;
		if( !check_has_plotted_in_graph(drXY, gl, vnPlotIndices) )
		{	
			// add scatter plot
			int nPlot = gl.AddPlot(drXY, IDM_PLOT_SCATTER);	
			DataPlot dpScatter = gl.DataPlots(nPlot);
			
			// change scatter to red color
			Tree tr;
			tr.Root.Symbol.Size.nVal = 5;
			tr.Root.Symbol.FillColor.nVal = SYSCOLOR_RED;
			tr.Root.Symbol.EdgeColor.nVal = SYSCOLOR_RED;
			if( 0 == dpScatter.UpdateThemeIDs(tr.Root) )
			{
				dpScatter.ApplyFormat(tr, true, true);
			}
			
			// add opposite line and x=0/y=0 line
			tr.Reset();					
			tr.Root.Axes.X.Additional.ZeroLine.nVal = 1;
			tr.Root.Axes.X.Additional.OppositeLine.nVal = 1;		
			tr.Root.Axes.Y.Additional.ZeroLine.nVal = 1;
			tr.Root.Axes.Y.Additional.OppositeLine.nVal = 1;
			if( 0 == gl.UpdateThemeIDs(tr.Root) )
			{
				gl.ApplyFormat(tr, true, true);
			}	
			
			// remove legend
			if( gl.GraphObjects(GO_LEGEND_NAME).IsValid() )
				gl.RemoveGraphObject(GO_LEGEND_NAME);				

		}
	}		
	gl.Rescale();
			
}

static void _add_pca_combine_plottings(ReportTree& rt, ReportData& rdPlot, ReportData& rdScores, const ResultOptions& stOptions, LPCSTR lpcszTableName, LPCSTR lpcszTableLabel,
									int nTableID, LPCSTR lpcszGraphTemplate, LPCSTR lpcszGraphLongName, bool bScoresPlot, bool bLoadingPlot)
{
	ReportTable 	rtGraph = rt.CreateTable(lpcszTableName, lpcszTableLabel, nTableID);
	
	int count = 0;
	ASSERT( stOptions.nComponentPlotRangeBegin < stOptions.nComponentPlotRangeEnd );
	for(int ii = stOptions.nComponentPlotRangeBegin-1; ii < stOptions.nComponentPlotRangeEnd; ii++)
	{
		for(int jj = stOptions.nComponentPlotRangeBegin; jj < stOptions.nComponentPlotRangeEnd; jj++)
		{
			if( stOptions.nSelComponentPlotType == COMPONENT_PLOT_METHOD_SPECIFY_BY_TWO )
			{
				if( ii != stOptions.nComponentPlotRangeBegin-1 || jj != stOptions.nComponentPlotRangeEnd-1 )
					continue;
			}
			else
			{			
				if( ii >= jj )
					continue;	
			}
			
			XFExeContext* 	pxfexectxt = Project.GetCurrentXFExeCtxt();	
			int 			nPlotID = nTableID + count;
			GraphPage 		gp = pxfexectxt->GetGraph(nPlotID);	
			if( !gp )
			{
				gp.Create(lpcszGraphTemplate, CREATE_HIDDEN);
				gp.SetLongName(lpcszGraphLongName + " " + (count+1));
				gp.TitleShow = WIN_TITLE_SHOW_LABEL;
			}		
			GraphLayer 	gl = gp.Layers(0);
			
			if( bScoresPlot )
				_add_one_pca_scores_plotting(rdScores, gl, ii, jj);
			
			if( bLoadingPlot )
				_add_one_pca_loading_plotting(rdPlot, gl, count);
			
			pxfexectxt->SetGraph(gp, nPlotID);				
			rtGraph.SetCell(count, 0, gp, EMBEDGRAPH_MOVE_IF_ALREADY_EMBEDDED);
			count++;			
		}	
	}			
}


static void _add_pca_loading_plottings(ReportTree& rt, ReportData& rdPlot, ReportData& rdScores, const ResultOptions& stOptions)
{
	_add_pca_combine_plottings(rt, rdPlot, rdScores, stOptions, "LoadingPlot", _L("Loading Plot"), PSA_TABLE_LOADING_PLOT, "vectxyxy", "Loading Plot", false, true);
}

static void _add_pca_scores_plotting(ReportTree& rt, ReportData& rdPlot, ReportData& rdScores, const ResultOptions& stOptions)
{	
	_add_pca_combine_plottings(rt, rdPlot, rdScores, stOptions, "ScorePlot", _L("Scores Plot"), PSA_TABLE_SCORE_PLOT, "Origin", "Scores Plot", true, false);

}

static void _add_pca_biplotting(ReportTree& rt, ReportData& rdPlot, ReportData& rdScores, const ResultOptions& stOptions)
{
	_add_pca_combine_plottings(rt, rdPlot, rdScores, stOptions, "BiPlot", _L("BiPlot"), PSA_TABLE_BIPLOT, "vectxyxy", "BiPlot", true, true);	
}



void output_pca_report_table(ReportTree& rt, ReportData& rdPlot, ReportData& rdScoreData, const vector<string>& vsDataLongNames, int nNumObsers, int nNumVars, int nNumComponents,
					const ResultOptions& stOptions, const matrix& mStats, const matrix& mCorr, const matrix& mPCAStats, const matrix& mLoadings)
{	
	//////////////////////////////////////////////////////////////////
	// 	Notes
	//////////////////////////////////////////////////////////////////
	report_tree_create(rt, _L("Principal Component Analysis"));

	//////////////////////////////////////////////////////////////////
	// 	Descriptive Statistics
	//////////////////////////////////////////////////////////////////
	if( mStats.GetNumCols() > 0 && (stOptions.bMean || stOptions.bStd) )
	{
		int ID = PSA_TABLE_STATS;
		ReportTable rtDesc = rt.CreateTable("Description", _L("Descriptive Statistics"), ID++);
		
		vector<string> vsColLabels;
		if( stOptions.bMean )
			vsColLabels.Add(_L("Mean"));
		if( stOptions.bStd )
			vsColLabels.Add(_L("Std"));	
		for(int nn = 0; nn < mStats.GetNumRows(); nn++)
		{
			vector vec;
			mStats.GetRow(vec, nn);		
			rtDesc.AddRow("Row"+(nn+1), vec, vsDataLongNames[nn], vsColLabels, NULL, ID++);
		}
		
		string strMoreInfo;
		strMoreInfo.Format("The Number of Observations is %d.\nThe Number of Variables is %d.", nNumObsers, nNumVars );
		TreeNode trFooter = tree_check_get_node(rtDesc, "Footer", IDE_FOOTNOTE_BEGIN, TREE_Footnote, "1");
		trFooter.strVal = strMoreInfo;		
	}
	
	//////////////////////////////////////////////////////////////////
	// 	Corrlation Matrix
	//////////////////////////////////////////////////////////////////
	if( stOptions.bCorr && mCorr.GetNumCols() > 0 )
	{
		int ID = PSA_TABLE_CORR_MATRIX;
		ReportTable rtCorr = rt.CreateTable("CorrMatrix", _L("Correlation Matrix"), ID++);
		for(int nn = 0; nn < mCorr.GetNumRows(); nn++)
		{
			vector vec;
			mCorr.GetRow(vec, nn);		
			rtCorr.AddRow("Row"+(nn+1), vec, vsDataLongNames[nn], vsDataLongNames, NULL, ID++);
		}
	}
	
	//////////////////////////////////////////////////////////////////
	// 	EigenValues
	//////////////////////////////////////////////////////////////////
	if( stOptions.bEigenValues )
	{
		int ID = PSA_TABLE_EIGENVALUES;
		ReportTable rtEigenvalues = rt.CreateTable("Eigenvalues", _L("Eigenvalues of the Correlation Matrix"), ID++);
		
		vector<string> vsColLabels;
		vsColLabels.Add(_L("Eigenvalue"));
		vsColLabels.Add(_L("Proportion"));
		vsColLabels.Add(_L("Cumulative"));
		if( PCA_MATRIX_TYPE_COV == stOptions.nMatrixType )
		{
			vsColLabels.Add(_L("Chisq"));
			vsColLabels.Add(_L("Degrees of Freedom"));
			vsColLabels.Add(_L("Significance Level")); 
		}
		
		for(int nn = 0; nn < mPCAStats.GetNumRows(); nn++)
		{	
			vector vec;
			mPCAStats.GetRow(vec, nn);
			if( vec.GetSize() > vsColLabels.GetSize() )
				vec.SetSize( vsColLabels.GetSize() );
			rtEigenvalues.AddRow("Row"+(nn+1), vec, (string)(nn+1), vsColLabels, NULL, ID++);
		}		
	}
	
	//////////////////////////////////////////////////////////////////
	// 	EigenVectors
	//////////////////////////////////////////////////////////////////
	if( stOptions.bEigenVectors )
	{
		int ID = PSA_TABLE_EIGENVECTORS;
		ReportTable rtEigenvectors = rt.CreateTable("Eigenvectors", _L("Extracted Eigenvectors"), ID++);
		
		vector<string> vsColLabels;
		for(int nn = 0; nn < nNumComponents; nn++)
		{
			vsColLabels.Add(EXTRACTED_TABLE_COL_LABEL_PREFIX + (nn+1));
		}
		
		for(nn = 0; nn < mLoadings.GetNumRows(); nn++)
		{
			vector vec;
			mLoadings.GetRow(vec, nn);
			vec.SetSize(nNumComponents);
			
			rtEigenvectors.AddRow("Row"+(nn+1), vec, vsDataLongNames[nn], vsColLabels, NULL, ID++);	
		}
	}	
	
	//////////////////////////////////////////////////////////////////
	// 	Plots
	//////////////////////////////////////////////////////////////////
	_add_pca_plottings(rt, rdPlot, rdScoreData, stOptions);
}



void output_pca_report_data(ReportData& rd, const matrix& mScores, int nNumComponents)
{
	if( !rd )
		return;
	
	ReportTable rtScores = rd.CreateTable("Scores", _L("Scores Table"), _get_score_table_id());
	
	for(int nn = 0; nn < nNumComponents; nn++)
	{
		vector vec;
		mScores.GetColumn(vec, nn);		
		if( 0 == nn )
		{
			vector vecIndecs;
			vecIndecs.Data(1, vec.GetSize(), 1);
			rtScores.AddColumn(vecIndecs, "ColX", _get_score_table_column_id('X'), EXTRACTED_TABLE_COL_LABEL_PREFIX + (nn+1), OKDATAOBJ_DESIGNATION_X);
			//rtScores.AddColumn(vsObserNames, "ColLabel", _get_score_table_column_id('L'), "Obser Name", OKDATAOBJ_DESIGNATION_L);
		}
		rtScores.AddColumn(vec, "ColY"+(nn+1), _get_score_table_column_id('Y', nn), EXTRACTED_TABLE_COL_LABEL_PREFIX + (nn+1), OKDATAOBJ_DESIGNATION_Y);
	}	
}
#endif //_OC_VER

BOOL	plot_pareto_chart(GraphLayer& gl, DataRange& dr, TreeNode& trGetN, BOOL bFromAutoUpdate)
{	
	/// Iris 1/19/2010 FIX_PARETO_PLOT_NOT_GOOD_SCALE_AFTER_AUTO_UPDATE
	/*
	if ( bFromAutoUpdate )
		return TRUE;
	*/
	///End FIX_PARETO_PLOT_NOT_GOOD_SCALE_AFTER_AUTO_UPDATE
	
	if ( !gl )
		return FALSE;	
	GraphPage gp = gl.GetPage();
	
	Worksheet	wks;
	int			c1, c2;
	dr.GetRange(wks, c1, c2, 1);
	if ( !wks )
	{
		ASSERT(false);
		return FALSE;
	}
	
	Dataset		dsCount(wks, c1 + 1);
	Curve		curCount(dsCount.GetName());
	gl = gp.Layers(0);
	if( !bFromAutoUpdate ) /// Iris 1/19/2010 FIX_PARETO_PLOT_NOT_GOOD_SCALE_AFTER_AUTO_UPDATE
		gl.AddPlot(curCount); 
	gl.Rescale();
	
	/// Iris 1/25/2010 PARETO_CHAR_ADD_LABEL_PLOT
	//Dataset		dsCumFreq(wks, c1 + 2);
	int 		nCumFreqColIndex = c1 + 2;
	Dataset		dsCumFreq(wks, nCumFreqColIndex);
	///End PARETO_CHAR_ADD_LABEL_PLOT
	Curve		curCumFreq(dsCumFreq.GetName());
	GraphLayer	gl2 = gp.Layers(1);
	if ( !gl2 )
	{
		ASSERT(false);
		return FALSE;
	}
	if( !bFromAutoUpdate ) /// Iris 1/19/2010 FIX_PARETO_PLOT_NOT_GOOD_SCALE_AFTER_AUTO_UPDATE
	{
		gl2.AddPlot(curCumFreq);

		/// Iris 1/25/2010 PARETO_CHAR_ADD_LABEL_PLOT
		XYRange drLabel;
		drLabel.Add(wks, c1, "X");
		drLabel.Add(wks, nCumFreqColIndex, "Y");
		int nLabelPlot = gl2.AddPlot(drLabel, IDM_PLOT_TEXT);
		
		DataPlot dpLabel = gl2.DataPlots(nLabelPlot);
		if( dpLabel )
		{
			int nLabelType = LABEL_Y_VAL_GUI;
			dpLabel.LabTalk(STR_PLOT_DATA_LABEL_TYPE, &nLabelType, true);
			
			///Iris 1/28/2010 SET_PARETO_CHAR_LABEL_SIZE_AND_OFFSET
			string strPath;
			strPath.Format("%sOriginC\\OriginLab\\graph_utils.c", GetAppPath(TRUE));

			Function fn = Project.FindFunction("rotate_offset_resize_label_plot", strPath);
			ROTATE_OFFSET_RESIZE_LABEL_PLOT_FUNC_POINTER pfn = fn;
			if(pfn)
			{
				pfn(dpLabel, 0, 70, -100, 24);
			}
			///End SET_PARETO_CHAR_LABEL_SIZE_AND_OFFSET
		}
		///End PARETO_CHAR_ADD_LABEL_PLOT

	}
	//gl2.Rescale(); /// Iris 1/25/2010 FIX_YAXIS_INC_OF_LAYER2_CHANGE_TO_50 the inc of Y axis default is 20, after rescale, changed to 50, 50 is not good. 
	
	if ( dsCount.GetSize() > 0 && dsCumFreq.GetSize() > 0 )
	{
		const	double		rGL2To = 110.0;
		gl.Y.From = 0.0;
		gl.Y.To = rGL2To * dsCount[0] / dsCumFreq[0];
		gl2.Y.From = 0.0;
		gl2.Y.To = rGL2To;
	}
	
	return TRUE;
}
////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////       Temporary Test Routines          /////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////
