/*------------------------------------------------------------------------------*
* File Name: ROCCurve.c		 													*
* Creation: Kevin 08/17/05														*
* Purpose: OriginC Source C file												*
* Copyright (c) OriginLab Corp.	2003-2007										*
* All Rights Reserved															*
* 																				*
* Modification Log:																*
* Alex 03/14/06 FIX_VECTOR_CANNOT_GET_NUMBER
* Alex 03/14/06 MAKE_ROCCURVE_TABLE_NAME_STANDARD
* Alex 03/20/06 GET_FIRST_STATEVALUE
*	ML 1/4/2007 EXTRACTING_FACTOR_VALUES_ROC									*
*	Echo 2/12/07 ADD_ERROR_REPORT												*
*	Cheney 2007-5-21 NEED_UPDATE_ERROR_CHECKING_OF_REPORT_TABLE_FOR_OPERATION_BASED_TOOLS
*	ML 6/5/2007 QA70-9869 SPECIAL_GUI_TREE_UPDATE_BEFORE_RERUNNING				*
*	ML 6/6/2007 QA70-9869 MUST_COPY_STATEVALUE_VALE_BECAUSE_tree_copy_values_by_id_CANNOT
*	Cheney 2007-6-7 SHOULD_CHECK_EVENT_ID_IN_EVENT_FUNC							* 
*	Arvin 07/20/07 REMOVE_REFERENCE_LINE_DATA_WHILE_CHANGE_PARAM				*
*	Arvin 07/25/07 v8.0667 WRONG_INPUT_DATA_TABLE_FOR_MULTI_DATA_AND_FACTORS	*
*	Arvin 07/26/07 v8.0668 NOT_SUPPORT_MULTI_COLUMNS_STATE						*
*	Arvin 08/22/07 SHOULD_NOT_RESET_DEFAULT_VALUE_AFTER_CHANGE_PARAM_WITH_SAME_INPUT_DATA
*	Arvin 09/07/07 SHOULD_CHECK_AVAILABLE										*
*	Arvin 09/26/07 ADD_SUMMARY_TABLE_FOR_MULTI_DATA_COLUMNS						*
*   Iris 3/26/2008 v8.0832 ROC_RESULT_DATA_COL_NEED_MORE_LABEL					*
*	Folger 05/22/08 QA80-11574 SUPPORT_GET_ALL_OPERATION_OUTPUT_SHEET_NAME_WITH_GLOBAL_STRING_VARIABLES
*	Kyle 09/24/08 SET_NO_NEED_TO_LOCALIZE										*
*	Sophy 10/17/2008 QA80-12000 SHOULD_UPDATE_MASKED_AND_MISSING_DATA_STATS_ON_RECALCULATE
*	Folger 12/26/08 QA80-12642-P3 v8.0991 CONSISTENT_SHOW_LN_WITH_DOUBLE_QUOTES_IN_REPORT_SHEET
*	Sophy 3/30/2009 QA80-13352 SUPPORT_SPECIFY_COLUMN_DESIGNATIONS_IN_REPORT_TABLES
*	Sim 04-02-2009 QA80-13403 ADD_INDIVIDUAL_OP_VERSION_FOR_CONVERT_GUI_TREE	*
*	Kyle 06/05/2009 QA70-13733 RADIX_POINT_SHOULD_BE_COMMA_IN_GOS				*
*   Iris 10/28/2009 QA81-14546 CHANGE_GUI_REPORT_TABLE_LABEL					*
*-------------------------------------------------------------------------------*/

//////////////////////////////////////////////////////////////////////////////////
// Included header files
//////////////////////////////////////////////////////////////////////////////////

// System includes

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

#ifdef _FOR_SMART_LOADING_ONLY
#include "wksOperation.h"
#include "analysis_utils.h"
#include <stats_utils.h>
#include "stats_guis.h"
#include "stats_operations.h"
#include "nlsf_utils.h" /// Iris 7/08/2008 CLEAN_DUP_CALC_AVE_DATA_CODE_IN_NLSF_PREVIEW_AND_OP
#include "graph_utils.h" //---- Iris 11/19/2008 v8.0975 QA80-12591-P2 FIX_APPARENT_FIT_ON_GRAPH_CUSTOM_RANGE_GET_INCORRECT_X
#endif

#include <xfutils.h>  ///Echo 2/12/07 ADD_ERROR_REPORT
#include "StatsOpCommon.h"
#include "StatsOpBase.h"

#define ROC_CURVES_NAME "ROC Curve1"   
///Arvin 12/05/06 ROCCURVE_SHOULD_HAVE_SPECIAL_DATA_LABEL
#define	ROC_INFO_DATA							"Data"
#define	ROC_INFO_STATE							"State"
///-----

enum
{
	GRAPH_ROC_CURVE = 0,
	
	GRAPH_ROC_MAX_NODE
};

#define		IDST_ROC_COORDINATE_REF_LINE				0x00202300
#define		ROC_THRESHOLD_METHOD_USER_DEFINE			2
///Echo 2/12/07 ADD_ERROR_REPORT
static int roc_event1(TreeNode& tr, int nRow, int nEvent, DWORD& dwEnables, LPCSTR lpcszNodeName, WndContainer& getNCountainer, string& strAux, string& strErrMsg)
{
	DECLARE_BUTTON_ENABLES   //support more buttons enable/disable
	
	
				
	///Sophy 6/10/2008 FIX_REPORT_BOOK_NAME_EMPTY_NO_DATA_SELECTED_OPEN_DIALOG
	_on_input_data_change( tr, nRow, 0 , NULL, 0, 0, getNCountainer );
	///end FIX_REPORT_BOOK_NAME_EMPTY_NO_DATA_SELECTED_OPEN_DIALOG

	///Cheney 2007-6-7 SHOULD_CHECK_EVENT_ID_IN_EVENT_FUNC	
	///Cheney 2007-7-6 SHOULD_CHECK_ERR_WHEN_THEME_CHANGE_ALSO
	//if(GETNE_ON_VALUE_CHANGE == nEvent  || GETNE_ON_INIT == nEvent)
	if(GETNE_ON_VALUE_CHANGE == nEvent  || GETNE_ON_INIT == nEvent || GETNE_ON_THEME == nEvent)
	///end SHOULD_CHECK_ERR_WHEN_THEME_CHANGE_ALSO
	///end SHOULD_CHECK_EVENT_ID_IN_EVENT_FUNC
	{
		DataRange drData;
		drData.Create();
		drData.SetTree(tr.InputData);
		int nErr = check_data_in_group(drData);
		switch (nErr)
		{
		case CER_NOT_INDEX_DATA:
			nErr = CER_NOT_ROC_DATA;
			break;
		case CER_GROUP_NUM_LS_2:
			nErr = CER_NO_ERROR;
			break;
		default:
			break;
			
		}
		///Arvin 07/26/07 v8.0668 NOT_SUPPORT_MULTI_COLUMNS_STATE
		if(nErr == CER_NO_ERROR)
		{
			int r1, r2, c1, c2;
			Datasheet ds;
			drData.GetRange(1, r1, c1, r2, c2, ds);//state range
			if( c1 >= 0 && c2 > c1)
				nErr = CER_COL_NUM_NOT_ONE_EX;
		}
		///end 	NOT_SUPPORT_MULTI_COLUMNS_STATE
		
		/// Iris 06/05/2008 FIX_ALLOW_SPACE_IN_STATE_VALUE
		//if (nErr == CER_NO_ERROR && tr.CompControl.StateValue.strVal == "")
		string		strStateValue = tr.CompControl.StateValue.strVal;
		strStateValue.TrimLeft();
		strStateValue.TrimRight();
		if (nErr == CER_NO_ERROR && strStateValue.IsEmpty() )
		///end FIX_ALLOW_SPACE_IN_STATE_VALUE
		{
			nErr = CER_NO_STATE_VAL;
		}
		
		/// Iris 06/05/2008 FIX_ALLOW_SPACE_IN_STATE_VALUE
		if (nErr == CER_NO_ERROR && !strStateValue.IsEmpty() )
		{
			string	strList;
			if( tr.CompControl.StateValue.GetAttribute(STR_COMBO_ATTRIB, strList) && !strList.IsEmpty() )
			{
				for(int ii = 0; nErr == CER_NO_ERROR && ii < strStateValue.GetNumTokens(); ii++)
				{
					if( strList.Find(strStateValue.GetToken(ii)) < 0 )
						nErr = CER_ILLEGAL_STATE_VALUE;
				}
			}
		}
		///end FIX_ALLOW_SPACE_IN_STATE_VALUE
		
		if (nErr == CER_NO_ERROR && !check_delimiter_space(tr.CompControl.Thresholds.strVal) && tr.CompControl.ThresholdMethod.nVal == ROC_THRESHOLD_METHOD_USER_DEFINE)
		{
			nErr = CER_INVALID_THRESHOLD;
		}
		if (nErr == CER_NO_ERROR && !check_conf_level(tr.CompControl.StdError.ConfLevel.dVal) && tr.CompControl.StdError.ConfLevel.Show)
		{
			nErr = CER_INVALID_CONF_LEV;
		}
		///Sophy 4/11/2008 CHECK_REPORT_DATA_BOOK_NAME_DIFFERENT
		string strRet = "";
		if( CER_NO_ERROR == nErr )
		{
			nErr = check_report_book_curve_book( tr, strRet );
		}
		///end CHECK_REPORT_DATA_BOOK_NAME_DIFFERENT
		if (nErr != CER_NO_ERROR)
		{
			bOKEnable = false;
			///Arvin 07/26/07 v8.0668 NOT_SUPPORT_MULTI_COLUMNS_STATE
			//strErrMsg = nErr;
			if(nErr == CER_COL_NUM_NOT_ONE_EX)
			{
				string strErr;
				ocu_load_msg_str(nErr, &strErr, _L("for State"));
				strErrMsg = strErr;
			}
			///Sophy 4/14/2008 ADD_OUTPUT_ERR_STRING
			else if( !strRet.IsEmpty() )
			{
				strErrMsg = nErr;
				strErrMsg += ":" + strRet;  
			}
			///end ADD_OUTPUT_ERR_STRING
			else
				strErrMsg = nErr;
			///end NOT_SUPPORT_MULTI_COLUMNS_STATE	
		}
	}
	return true;

}
///end ADD_ERROR_REPORT

///Sophy 6/10/2008 FIX_REPORT_BOOK_NAME_EMPTY_NO_DATA_SELECTED_OPEN_DIALOG
static bool _on_input_data_change(TreeNode& tr, int nRow, int nCol, TreeNode& trNode, DWORD nEventInfo, int nCntrlType, WndContainer& getNContainer)
{
	OutputGUIManagerBase* pOutputManager = get_output_GUI_manager_pointer(tr);
	if(pOutputManager)
		pOutputManager->UpdateOutputOnDataChange(tr);
	
	return true;
}
///end FIX_REPORT_BOOK_NAME_EMPTY_NO_DATA_SELECTED_OPEN_DIALOG

class OC_REGISTERED ROCCurve : public StatsOpBase
{
protected:
	BOOL Construct(TreeNode& trOperation, int nOption = 0)
	{
		if( WksReportOperation::Construct(trOperation, nOption) )
		{			
			TreeNode trOut = trOperation.Calculation; // Calculation node should have already been prepared in base class

			TreeNode	trGUI = ConstructAddGUI(trOperation);
			ConstructROCCurveGUITree(trGUI, nOption); 
			
			///Arvin 06/06/07 SHOULD_SET_DATAID_FOR_THIS_NODE_FOR_RECALCULATE
			//Theme should not remember this node as Echo said
			TreeNode trStateValue = trGUI.CompControl.StateValue;
			if(trStateValue)
				trStateValue.SetAttribute(STR_XVARIABLE_THEME_APPLICABILITY_ATTRIB, XVTA_DO_NOT_APPLY_VALUE);
			///end SHOULD_SET_DATAID_FOR_THIS_NODE_FOR_RECALCULATE
			
			DWORD dwOptions = REPORT_PLOT_ALL_PLOTS_IN_ONE_GRAPH;
			ConstructAddReportCommon(trOperation, dwOptions, IDST_OUTPUT_RESULTS_OPTIONS, true);
			
			FilterStatsGUI(trOperation);    ///Jim 01/17/06 v8.0358 CREATE_PLOTS_BRANCH_IN_MAIN_NODES
			hidePlotBranch(trOperation);
			
			/// Iris 5/30/2008 CENTRALIZE_SET_RESULT_CURVE_BRANCH_NAME_CODES
			//trGUI.Output.Data.SetAttribute(STR_LABEL_ATTRIB, STR_OUTPUT_ROC_RESULT_CURVE_TABLES);
			///end CENTRALIZE_SET_RESULT_CURVE_BRANCH_NAME_CODES

			Operation::ConstructAddCommonBottom(trGUI);		
			return TRUE;
		}
		return FALSE;
	}
	
	/// Iris 5/30/2008 CENTRALIZE_SET_RESULT_CURVE_BRANCH_NAME_CODES
	//virtual 
	string  GetResultCurveGUIName(TreeNode& trGUI)
	{
		return STR_OUTPUT_ROC_RESULT_CURVE_TABLES;
	}	
	///end CENTRALIZE_SET_RESULT_CURVE_BRANCH_NAME_CODES
	
	//virtual
	bool OnInputDataSelectionChange(TreeNode& trOperation)
	{
		/// Iris 05/08/2007 v8.0613 RANGE_BRANCH_DEFAULT_STATUS_SHOULD_BE_OPEN
		// .Range1 is not existed when runned in Construct, so put the codes here
		TreeNode 	trRange = trOperation.GUI.InputData.Range1;
		int			nTemp;
		if(trRange && !trRange.GetAttribute(STR_ATTRIB_BRANCH, nTemp))
		{
			trRange.SetAttribute(STR_ATTRIB_BRANCH, GETNBRANCH_OPEN);
		}
		///end RANGE_BRANCH_DEFAULT_STATUS_SHOULD_BE_OPEN

		TreeNode	trData = trOperation.GUI.InputData.Range1.X; //X: Data	
		TreeNode	trState = trOperation.GUI.InputData.Range1.F; //F: State	
		if(trData.IsValid())
		{
			GETN_SET_EVENT_EX_HANDLER(trData, roc_update_states_value_by_on_data_change);
		}
		if(trState.IsValid())
		{
			GETN_SET_EVENT_EX_HANDLER(trState, roc_update_states_value_by_on_data_change);
		}
		
		return true;
	}

	
	//virtual
	int ConstructGraphNumber()
	{
		return 1;
	}
	
	//to set the name of X & Y Axis Title 
	string GetGraphTemplate(int nGraphIndex = 0)
	{
		if(GRAPH_ROC_CURVE == nGraphIndex)
			return "ReportROC";
		return "";
	}
	
	//virtual
	string 	GetResultBookName(TreeNode& trGUI) { return E_STR_ROC_REPORT_TABLE_BOOK_SHORT_NAME; } /// Iris 3/21/2008 v8.0829 QA80-10934 ADD_EDITBOX_TO_SPECIFICATION_BOOK_SHEET_NAME
	
	//virtual
	/*int GetPictureNum(TreeNode& trOp, int nTotalNumData, int nGraphIndex)	//Kevin should be modified
	{
		return 1;      
	}*/

	//virtual
	/// Iris 3/21/2008 v8.0829 QA80-10934 ADD_EDITBOX_TO_SPECIFICATION_BOOK_SHEET_NAME, want GUI tree as input in DescStats::GetResultSheetName
	//string 			GetResultSheetName()
	string 			GetResultSheetName(TreeNode& trGUI)
	///end ADD_EDITBOX_TO_SPECIFICATION_BOOK_SHEET_NAME
	{
		return STR_ROC_REPORT_TABLE_SHEET_NAME;
	}
	
	string GetResultCurveBookName(TreeNode& trOperation, int nDataIndex = 0, int nOption = -1, bool bSeparateSheetForDataset = false)
	{
		return "Coordinates";
	}
	
	/// Iris 4/11/2008 SET_BOTH_LONG_NAME_AND_SHORT_NAME_FOR_REPORT_BOOK
	//virtual
	string GetResultCurveBookShortName(TreeNode& trOperation, int nIndex = 0, int nOption = -1)
	{
		return E_STR_ROC_BOOK_SHORT_NAME;
	}
	///end SET_BOTH_LONG_NAME_AND_SHORT_NAME_FOR_REPORT_BOOK

	//virtual
	string GetGraphName(int nIndex, bool bLongName = false)
	{
		if(!bLongName)
			return "ROCCurve";
		return "";
	}

	//virtual
/*	string GetAnalysisName(int nOption)
	{
		string str = "ROCCurve ";
		return str;
	}
	*/
	//virtual
	bool GetCustomGraphTypeName(string& strName, int nIndex)
	{
		strName = ROC_CURVES_NAME;
		return true;
	}
	
	// virtual 
	// fisher 11/16/2007 ADD_MAP_ID_TO_CHM
	int GetHelpID()
	{
		return IDD_XF_Roccurve;
	}
	
	/// Iris 10/28/2009 QA81-14546 CHANGE_GUI_REPORT_TABLE_LABEL
	/*
	/// Iris 4/17/2008 SPECIAL_REPORT_TABLE_NAME_FOR_DIFF_TOOLS
	//virtual	
	string	GetReportTableGUIName(TreeNode& trGUI)
	{
		return STR_OUTPUT_ROC_REPORT_TABLE;
	}
	///end SPECIAL_REPORT_TABLE_NAME_FOR_DIFF_TOOLS
	*/
	///end CHANGE_GUI_REPORT_TABLE_LABEL
	
	//virtual
	DWORD	GetDataRules(const TreeNode& trOperation, bool bIgnoreCombineInfo)
	{
		/// Iris 11/22/06 TRIM_MISSING_FOR_INPUT_DATA
		/*
		//--- Iris 4/24/06 updated according to Marko's mail
		//DWORD	dw =  DRR_NO_FACTORS | DRR_GET_DEPENDENT | DRR_ONE_DEP_MULTIINDEP | DRR_GET_STATS_STATE_LAST_COL;	
		DWORD   dw = DRR_GET_MISSING | DRR_NO_WEIGHTS | DRR_GET_STATS_STATE_LAST_COL ;
		//---
		*/
		DWORD   dw = DRR_NO_WEIGHTS | DRR_GET_STATS_STATE_LAST_COL;
		///end TRIM_MISSING_FOR_INPUT_DATA
		return CheckDataRules(trOperation, dw, bIgnoreCombineInfo);	
	}
	
	//virtual 
	int		GetNumData(TreeNode& trOp, DataRange& dr, TreeNode &trAdditionalData, Worksheet *pwksFirstRange, vector<int> *pvFactorSizes, int *pnNumSubRanges)
	{
		vector<int> vFactorSizes;
		int    nNumDataTakingFactorAsStateIntoAccount = WksReportOperation::GetNumData(trOp, dr, NULL, NULL, &vFactorSizes);
		if (nNumDataTakingFactorAsStateIntoAccount < 1 || 1 != vFactorSizes.GetSize())
		{
			error_report("No data found or too many state columns.");
			return -1;
		}		
		
		// nNumDataTakingFactorAsStateIntoAccount rakes into account factor (state column)
		int    nNumDifferentStates = vFactorSizes[0];  // how many different states
		
		// How many Data columns:
		int    nNumColumns = nNumDataTakingFactorAsStateIntoAccount / nNumDifferentStates;
		
		return nNumColumns;
	}
	
	///Arvin 09/07/07 WRONG_MISSING_AND_MASK_DATA_TABLES_IN_ROC
	/*
	bool IsRocCurve() 
	{ 
		return true;
	}
	
	bool IsNeededData(const TreeNode& trOp, const vector<string>& vstrFactors)
	{
		TreeNode trStateValue = trOp.GUI.CompControl.StateValue;
		if(!trStateValue || vstrFactors.GetSize() < 1)
			return false;
		
		string strStateValue = trStateValue.strVal;
		strStateValue.TrimLeft();
		strStateValue.TrimRight();
		vector<string> vsList;
		str_separate(strStateValue, " ", vsList);
		bool bFind = false;
		for(int ii = 0; ii < vstrFactors.GetSize(); ii++)
		{
			if(vsList.Find(vstrFactors[ii]) < 0)
			{
				bFind = false;
				break;
			}
			else
				bFind = true;
		}
		
		return bFind;		
	}
	
	void GetNeededDataIndices(const TreeNode& trOp, vector<int> vNeededDataIndices)
	{
		vector			vY;
		DWORD			dwPlotUID;
		vector<string>	vstrFactors;
		DWORD			dwRules = GetDataRules(trOp);
		DataRange dr;
		GetInput(dr);
		int nNumData = dr.GetNumData(dwRules);
		
		for (int ii = 0; ii < nNumData; ii++)
		{
			dr.GetData(dwRules, ii, &dwPlotUID, NULL, &vY, NULL, NULL, &vstrFactors);
			if(IsNeededData(trOp, vstrFactors))
				vNeededDataIndices.Add(ii);
		}
	}
	*/
	///end USE_WRONG_DATA_TO_CALC_IF_NOT_FIRST_STAT_VALUE_SELECTED_IN_ROC
	
	///Arvin 12/07/06 ROCCURVE_NEED_MASKED_AND_MISSING_DATA_TABLE
	void UpdateMaskedAndMissingDataTables(TreeNode& trOp, TreeNode&	trAdditionalData, DataRange& dr, vector<int>& vFactorSizes, vector<string> &vstrFactors, int numSubRanges, DWORD dwRules)
	{
		///Arvin 01/22/06 WRONG_DATA_NUMBER
		//int		nNumData = WksReportOperation::GetNumData(trOp, dr, NULL, NULL, &vFactorSizes);//dr.GetNumData(dwRules);
		int		nNumData = WksReportOperation::GetNumData(trOp, dr, NULL, NULL, &vFactorSizes);
		///END WRONG_DATA_NUMBER
		vstrFactors.SetSize(1);
		///Sophy 10/17/2008 QA80-12000 SHOULD_UPDATE_MASKED_AND_MISSING_DATA_STATS_ON_RECALCULATE
		SetHasMissingData( false ); //reset status before detecting missing and masked data
		SetHasMaskedData( false );
		///end SHOULD_UPDATE_MASKED_AND_MISSING_DATA_STATS_ON_RECALCULATE
		for(int ii = 0; ii < nNumData; ii++)
		{
			string		strDataLabel;
			int nFactors = 1;
			if(vFactorSizes.GetSize() > 0)
				nFactors = vFactorSizes[0];
			
			GetEscapedMainDataString(trOp, strDataLabel, ii/nFactors +1, true);
			//dr.GetFactorsValues(dwRules, ii, &vstrFactors);
			vstrFactors[0] = ftoa(ii+1); 
			/// Iris 10/29/2009 QA81-14546 OP_DLG_NEW_STRUCTURE
			//TreeNode tnCreate = trOp.GUI.Output.Create;
			TreeNode tnCreate = OP_GUI_OUTPUT_TABLES_BRANCH(trOp.GUI);
			///end OP_DLG_NEW_STRUCTURE
			if(tnCreate)
			{
				///Sophy 8/12/2008 QA80-12000-S1 DEFAULT_TURN_OFF_REPORT_MISSING_DATA_FOR_STATS_TOOL
				//if(tnCreate.MaskedData /*&& tnCreate.MaskedData.nVal*/)///Arvin 11/08/06 MASKEDDATA_AND_MISSINGDATA_TABLES_SHOULD_ALWAYS_HAVE_ATTRIBUTE
				//	UpdateMaskedOrMissingDataTables(trOp, dr, vstrFactors, ii, nNumData, numSubRanges, dwRules, strDataLabel, false);
				//if(tnCreate.MissingData /*&& tnCreate.MissingData.nVal*/)///Arvin 11/08/06 MASKEDDATA_AND_MISSINGDATA_TABLES_SHOULD_ALWAYS_HAVE_ATTRIBUTE
				//	UpdateMaskedOrMissingDataTables(trOp, dr, vstrFactors, ii, nNumData, numSubRanges, dwRules, strDataLabel, true);
				if(tnCreate.MaskedData )
				{
					bool	bHasMaskedData = false;
					UpdateMaskedOrMissingDataTables(trOp, dr, vstrFactors, ii, nNumData, numSubRanges, dwRules, strDataLabel, false, bHasMaskedData );
					if( bHasMaskedData )
						SetHasMaskedData( true );
				}
				
				if(tnCreate.MissingData )
				{
					bool	bHasMissingData = false;
					UpdateMaskedOrMissingDataTables(trOp, dr, vstrFactors, ii, nNumData, numSubRanges, dwRules, strDataLabel, true, bHasMissingData );
					if( bHasMissingData )
						SetHasMissingData( true );
				}
				
				///end DEFAULT_TURN_OFF_REPORT_MISSING_DATA_FOR_STATS_TOOL
			}	
		}
	}
	///end ROCCURVE_NEED_MASKED_AND_MISSING_DATA_TABLE

	//virtual
	void UpdateReportingTables(TreeNode &trOperation, int nTotalNumData, int nExeMode)
	{
		WksReportOperation::UpdateReportingTables(trOperation, nTotalNumData, nExeMode);	
	
		//if(!UpdateTableString(trOperation.Calculation.ROC, true, true, atof(GetTableStringMain(true, false, false)) ))
			//error_report("ROC Curve update report table ROC failed");
		
		if( !UpdateTableString(trOperation.Calculation.AreaTable, false, false, atof(GetTableStringMain(false))) )
			error_report("ROC Curve update report table AreaTable failed");
		
		if( !UpdateTableString(trOperation.Calculation.Summary, false, false, atof(GetTableStringMain(false))) )
			error_report("ROC Curve update report table Summary failed");		
 
	}	
	
	//virtual
	uint	GetResultCurveTableID(TreeNode& trOp, int nDataIndex, int nTotalNumData = -1, int nGraphIndex = 0)
	{
		///Arvin 06/01/07 WRONG_TABLE_ID_FOR_DIFFERENT_DATASET
		//return IDST_ROC_CURVE;
		return make_one_set_ID(IDST_ROC_CURVE, nDataIndex+1); 
		///END WRONG_TABLE_ID_FOR_DIFFERENT_DATASET
	}
	
	///Cheney 2007-9-28 MODIFY_TITLE_AS_MAX_SAID
	//virtual
	string	GetDlgDescription(int nOption)
	{
		return _L("Perform Receiver Operating Characteristic (ROC) Curve Analysis");
	}
	///end MODIFY_TITLE_AS_MAX_SAID
	
	//virtual
	int	ReportGetPicureIndexFromDataIndex(int nGraphIndex, int nDataIndex)
	{
		if( 0 == nGraphIndex)
			return 0;

		return -1;
	}

	//virtual
	int ReportGetPlotIndex(int nGraphIndex, int nPictureIndex, int nDataIndex = -1)
	{
		if( 0 == nGraphIndex && 0 == nPictureIndex )
			return 0;
	}
	
	//virtual
	int	ReportGetPlotTypeFromGraphIndex(int nGraphIndex)
	{
		if( GRAPH_ROC_CURVE == nGraphIndex)
			return IDM_PLOT_LINE;		

		return -1;
	}
	
	int GetTotalNumPictureForOneGraphType(TreeNode& trOp, int nGraphIndex = -1)
	{
		return 1;
	}

	
	//virtual
	int GetResultCurvesID() { return IDST_REPORT_CURVE_OPTIONS;}
	
	
	//virtual
	BOOL	CalcOneData(TreeNode& trOp, int index, int nTotalNumData, const vector<int> &vFactorSizes,
		const vector<string> &vstrFactors, vector &vData, vector &vDummy, matrix &mDummy, vector &vWeights, 
		DWORD dwPlotObjUID, int nRowColIndex, const vector<int>& vintRowsInSource = NULL)   
	{
		vector 	vInputData, vState;
		vector<string> vStateValueNames;
		vector	vStateList; //this only is useful when State value all are string, not numeric
		if( !extracteDataStateValues(trOp, index, vInputData, vState, vStateValueNames))
			return false;		

		//get Threshold
		int			nThreshold = getThershold(trOp, vInputData);
		if(nThreshold<0)
			return false;
		
		ROCArea 	sROCArea;
		ROCCuv 		*psROCCuv;	
		psROCCuv = (ROCCuv*)calloc(nThreshold, sizeof(ROCCuv));	//allocate memory for struct ROCCuv
		
		vector		vecList;
		bool		bStateIsNumeric;
		getStateValList(trOp, vStateValueNames, vecList, bStateIsNumeric);
		if( 0 == calcROCCurve(trOp, vInputData, vState, vStateValueNames, vecList, index, vstrFactors, nThreshold, sROCArea, psROCCuv))
		{
			///Arvin 09/26/07 ADD_SUMMARY_TABLE_FOR_MULTI_DATA_COLUMNS
			//updateSummaryTable(trOp, vState, vStateValueNames, vecList, bStateIsNumeric);
			updateSummaryTable(trOp, index, vState, vStateValueNames, vecList, bStateIsNumeric);
			///END ADD_SUMMARY_TABLE_FOR_MULTI_DATA_COLUMNS
			
			//add Area table
			updateAreaUnderCurve(trOp, index, sROCArea);
			
			/// Iris 01/08/2007 v8.0538 REPORT_GRAPHS_ARRANGEMENT
			//if(isPlotRocCurve(trOp) && 0 == index ) //has only one graph cell 
			//	PrepareGraphNodes(trOp, GetNumGraphs(), index, "ROC Curve");
			///end REPORT_GRAPHS_ARRANGEMENT

			//updateCoordinateTable(trOp, index, nThreshold, psROCCuv);
			prepareCurveData(trOp, index, nThreshold, psROCCuv);
		}
		free(psROCCuv);
		psROCCuv = NULL;
		
		if (isPlotReferenceLine(trOp) && index == nTotalNumData-1 ) 
			prepareReferenceLineData(trOp);	

		return true;
	}
	
	///Echo 2/12/07 ADD_ERROR_REPORT
	//virtual 
	PEVENT_GETN GetNewEventFunction()
	{
		return roc_event1;
	}
	///end ADD_ERROR_REPORT

	/// Iris 01/08/2007 v8.0538 REPORT_GRAPHS_ARRANGEMENT
	////virtual
	//int GetReportGraphTableColNum(TreeNode& trOp, int nGraphIndex = 0) 
//
	//{
		//return 1;
	//}
	
	//virtual
	//int GetReportGraphTableRowNum(TreeNode& trOp, int nGraphIndex = 0) 
//
	//{
		//return 1;
	//}	
	/////end REPORT_GRAPHS_ARRANGEMENT
	
	///Arvin 12/05/06 ROCCURVE_SHOULD_HAVE_SPECIAL_DATA_LABEL
	void GetMaskedOrMissingDataLabel(const TreeNode& trOp, LPCSTR &lpcszDataXLabel, LPCSTR &lpcszMainLabel, LPCSTR &lpcszDataYIndepLabel = NULL)
	{
		lpcszDataXLabel = NULL;
		lpcszMainLabel = ROC_INFO_DATA;	
	}
	
	/// Iris 05/08/2007 v8.0613 PROPER_REPORT_SHEET_NAME
	/*
	string	GetResultCurveSheetName(TreeNode& trOperation, int nIndex, int nOption)	
	{
		return "ROCValues";
	}
	*/
	/// Iris 4/11/2008 SET_BOTH_LONG_NAME_AND_SHORT_NAME_FOR_REPORT_BOOK
	/*
	string		GetResultCurveSheetFullName(TreeNode& trOperation, int nIndex, int nOption)	
	{
		return "ROCValues1";		
	}
	*/
	string		GetResultCurveSheetFullName(TreeNode& trOperation, int nIndex, int nOption)	
	{
		return GetResultCurveSheetName(trOperation, nIndex, nOption);		
	}
	string	GetResultCurveSheetName(TreeNode& trOperation, int nIndex = 0, int nOption = -1)	
	{
		///Kyle 09/24/08 SET_NO_NEED_TO_LOCALIZE
		//return _L("ROCValues1");		
		return "ROCValues1";
		///End 
	}
	///end SET_BOTH_LONG_NAME_AND_SHORT_NAME_FOR_REPORT_BOOK
	///end PROPER_REPORT_SHEET_NAME
	
	///Arvin 07/25/07 v8.0667 WRONG_INPUT_DATA_TABLE_FOR_MULTI_DATA_AND_FACTORS
	void UpdateDataSourceInReportingHeader(TreeNode& trOp, vector<string>&vstrFactors, Worksheet& wksInputData, int nIndex, int numSubRanges = 0, DWORD dwRules = 0) ///Arvin 07/19/07 v8.0662 WRONG_INPUT_DATA_TABLE_FOR_ROCCURVE
	{
		if(nIndex != 0)
			return;
		
		string strDataLabel = _L("Data"), strStateLabel = _L("State");
		AddMultiInputDataWithFactorSourceTable(trOp, strDataLabel, strStateLabel, dwRules);	
	}
	///end WRONG_INPUT_DATA_TABLE_FOR_MULTI_DATA_AND_FACTORS
	
	///Arvin 07/20/07 REMOVE_REFERENCE_LINE_DATA_WHILE_CHANGE_PARAM
	void 	CheckRemoveAndDestroyOutput(TreeNode& trOperation)
	{
		if(!isPlotReferenceLine(trOperation))
		{
			TreeNode trGraph = tree_get_node_by_id(trOperation, make_one_set_ID(IDST_ROC_CURVE, 1), true);
			if(trGraph)
			{
				TreeNode trReferenceX = trGraph.ReferenceX;
				if(trReferenceX)
					trReferenceX.Remove();
				
				TreeNode trReferenceY = trGraph.ReferenceY;
				if(trReferenceY)
					trReferenceY.Remove();
			}		
		}
		
		WksReportOperation::CheckRemoveAndDestroyOutput(trOperation);
	}
	///end REMOVE_REFERENCE_LINE_DATA_WHILE_CHANGE_PARAM
	
	/// Iris 3/26/2008 v8.0832 ROC_RESULT_DATA_COL_NEED_MORE_LABEL
	//virtual 
	
	//------ Folger 05/22/08 QA80-11574 SUPPORT_GET_ALL_OPERATION_OUTPUT_SHEET_NAME_WITH_GLOBAL_STRING_VARIABLES
	//void AfterDoReport(Datasheet& ds, bool bHierarchy)
	//{
		//WksReportOperation::AfterDoReport(ds, bHierarchy);
	void AfterDoReport(Datasheet& ds, int nOutputOption = OUTPUT_PARTIAL_REGRESSION_CURVES_SHEET)
	{
		WksReportOperation::AfterDoReport(ds, nOutputOption);
	//------		
		switch( ds.GetPage().GetType() )
		{
		case EXIST_WKS:
			Worksheet wks(ds);
			setResultDataColumnLabels(wks);
			break;
		case EXIST_MATRIX:
			break;
		default:
			break;
		}
	}
	///end ROC_RESULT_DATA_COL_NEED_MORE_LABEL
	
private:
	/// Iris 3/26/2008 v8.0832 ROC_RESULT_DATA_COL_NEED_MORE_LABEL
	bool  	setResultDataColumnLabels(Worksheet& wks)
	{
		if(!wks)
			return false;
		
		DataRange dr;
		GetInput(dr);
		
		Tree trOp;
		GetTree(trOp);
		
		int nNumData = GetNumData(trOp, dr);
		vector<string> vsOneXYLabel = {"Sensitivity", "1 - Specificity"};
		vector<string> vsLabels;
		for(int nData = 0; nData < nNumData; nData++)
		{
			vsLabels.Append(vsOneXYLabel);
		}
		
		
		for(int nCol = 0; nCol < vsLabels.GetSize(); nCol++)
		{
			Column col(wks, nCol);
			if(col)
				col.SetComments(vsLabels[nCol]);
		}
		return true;		
	}
	///end ROC_RESULT_DATA_COL_NEED_MORE_LABEL
	
	bool  extracteDataStateValues(const TreeNode& trOp, int index, vector &vData, vector &vStateIndices, vector<string> &vsStateValueNames)
	{		
		TreeNode trInputData = trOp.GUI.InputData;
		DataRange dr;
		dr.Create();
		dr.SetTree(trInputData, false);	
		
		
		DWORD   		dwRules = GetDataRules(trOp);
		vector<int>  	vFactorSizes;
		int    nNumDataTakingFactorAsStateIntoAccount = dr.GetNumData(dwRules, NULL, NULL, &vFactorSizes);
		if (nNumDataTakingFactorAsStateIntoAccount < 1 || 1 != vFactorSizes.GetSize())
		{
			return error_report("No data found or too many state columns.");
		}		
		
		//// nNumDataTakingFactorAsStateIntoAccount rakes into account factor (state column)
		int    nNumDifferentStates = vFactorSizes[0];  // how many different states
		
		vsStateValueNames.SetSize(nNumDifferentStates);
		for (int istateval = 0; istateval < nNumDifferentStates; istateval++)
		{
			vector  vTemp;
			DWORD  	ouidAux = 0;
			vector<string> vFactorValueName;
			int 	ii = index * nNumDifferentStates + istateval;
			int   	nn = dr.GetData(dwRules, ii, &ouidAux, NULL, &vTemp, NULL, NULL, &vFactorValueName);
			if (nn < 0 || 1 != vFactorValueName.GetSize())
			{
				return error_report("Fail to get data");
			}
			///Arvin 09/07/07 SHOULD_CHECK_AVAILABLE
			if(vTemp.GetSize() > 0)
			{
			///end SHOULD_CHECK_AVAILABLE
				vData.Append(vTemp);			
	
				vector vStateIndicesTemp(vTemp.GetSize());
				///Arvin 09/18/07 CALLING_WRONG_FUNCTION
				//vStateIndicesTemp = is_numeric(vFactorValueName[0])? atoi(vFactorValueName[0]) : istateval;  // set all to the same value (index istateval)
				vStateIndicesTemp = is_numeric(vFactorValueName[0])? atof(vFactorValueName[0]) : istateval;  // set all to the same value (index istateval)
				///end CALLING_WRONG_FUNCTION
				vStateIndices.Append(vStateIndicesTemp);
				///Arvin 06/06/07 SHOULD_TRIM_SPACE_FOR_STRING
				//vsStateValueNames[istateval] = vFactorValueName[0];// Get the name of State from Factor Names vector		
				string strFactorValueName = vFactorValueName[0];
				strFactorValueName.TrimLeft();
				strFactorValueName.TrimRight();
				vsStateValueNames[istateval] = strFactorValueName;
				///end SHOULD_TRIM_SPACE_FOR_STRING
			}///Arvin 09/07/07 SHOULD_CHECK_AVAILABLE
		}		
		
		return true;
	}

	//use Roc Curve to replace Plot branch
	void hidePlotBranch(TreeNode &trOp)
	{
#ifndef OP_DLG_TOTALLY_NEW_STRUCTURE
		TreeNode trPlots = trOp.GUI.Plots;
		if(trPlots)
			trPlots.Show = 0;
		TreeNode trPlotSettings = trOp.GUI.Output.PlotSettings;
		if(trPlotSettings)
			trPlotSettings.Show = 0;
	
#else
		for(int nGraphIndex = 0; nGraphIndex < ConstructGraphNumber(); nGraphIndex++)
		{
			TreeNode trGraph = GetGUIGraphNodes(trOp, nGraphIndex);
		}
		TreeNode trPlotSettings = OP_GUI_GRAPH_ARRANGEMENT_NODE(trOp.GUI);
		if(trPlotSettings)
			trPlotSettings.Show = 0;		
#endif //OP_DLG_TOTALLY_NEW_STRUCTURE
	}
	
	void prepareReferenceLineData(TreeNode &trOp)
	{		
		///Arvin 06/20/07 v8.0645 USE_WRONG_NODE_ID
		//TreeNode trGraph = tree_get_node_by_id(trOp, IDST_ROC_CURVE, true);
		TreeNode trGraph = tree_get_node_by_id(trOp, make_one_set_ID(IDST_ROC_CURVE, 1), true);
		///END USE_WRONG_NODE_ID
		vector vecX = {0, 0.5, 1}, vecY = {0, 0.5, 1};

		/// Iris 3/26/2008 v8.0832 ROC_RESULT_DATA_COL_NEED_MORE_LABEL
		//TreeNode	trX = tree_check_get_node(trGraph, "ReferenceX", IDST_ROC_COORDINATE_REF_LINE + 1, STR_LABEL_ATTRIB, _L("Reference X"));
		TreeNode	trX = tree_check_get_node(trGraph, "ReferenceX", IDST_ROC_COORDINATE_REF_LINE + 1, STR_LABEL_ATTRIB, _L("Reference Line"));
		///end ROC_RESULT_DATA_COL_NEED_MORE_LABEL
		trX.dVals = vecX;
		trX.SetAttribute(STR_COL_DESIGNATION_ATTRIB, OKDATAOBJ_DESIGNATION_X);
		
		TreeNode	trY	= tree_check_get_node(trGraph, "ReferenceY", IDST_ROC_COORDINATE_REF_LINE + 2, STR_LABEL_ATTRIB, _L("Reference Line"));
		trY.dVals = vecY;
		trY.SetAttribute(STR_COL_DESIGNATION_ATTRIB, OKDATAOBJ_DESIGNATION_Y);
	}

	int	getThershold(TreeNode& trOp, const vector& vecX)
	{		
		int nThreshold;
		if( STATS_NO_ERROR != ocmath_threshold_list(vecX, vecX.GetSize(), &nThreshold, false))
			return -1;
		
		return nThreshold;
	}
	
	int calcROCCurve(TreeNode& trOp, const vector& vecX, const vector& vState, const vector<string> &vStateValueNames, const vector &vecList, int index, vector<string> &vstrFactors, 
			int nThreshold, ROCArea& sROCArea, ROCCuv* psROCCuv)
	{
		//----- Iris 11/01/06 USER_DEFINED_THRESHOD_METHOD_CAUSE_CRASH
		//vector* 	pThres;
		//-----
		
		TreeNode 	trCtrl = trOp.GUI.CompControl;		
		
		int			nThresMethod = trCtrl.ThresholdMethod.nVal;
		double		dConfLevel = trCtrl.StdError.ConfLevel.dVal;
		dConfLevel /= 100;

		vector vecThres;	//----- Iris 11/01/06 USER_DEFINED_THRESHOD_METHOD_CAUSE_CRASH
		if( 2 == nThresMethod )
		{
			//----- Iris 11/01/06 USER_DEFINED_THRESHOD_METHOD_CAUSE_CRASH
			//vector vecThres;
			//pThres = &vecThres;
			//-----
			getUserThreshold(trOp, vecThres);
		}
		
		//----- Iris 11/01/06 USER_DEFINED_THRESHOD_METHOD_CAUSE_CRASH
		//int iRet = stats_roc_curve(vecX, vState, vecList, sROCArea, psROCCuv, nThreshold,  dConfLevel, nThresMethod, pThres);
		int iRet = stats_roc_curve(vecX, vState, vecList, sROCArea, psROCCuv, nThreshold,  dConfLevel, nThresMethod, &vecThres);
		//-----
		///Cheney 2007-5-21 NEED_UPDATE_ERROR_CHECKING_OF_REPORT_TABLE_FOR_OPERATION_BASED_TOOLS
		//return iRet;
		if(iRet)
		{
			string strErr;
			if( ocu_load_err_msg_str(CER_FAILED_GET_ROC_CURVE, &strErr) )
				///Cheney 2007-9-26 USE_ERROR_REPORT_TO_SHOW_OPERATION_ERR
				//okoc_out_msg(strErr);
				error_report(strErr);
				///end USE_ERROR_REPORT_TO_SHOW_OPERATION_ERR
		}
		return STATS_NO_ERROR;
		///end NEED_UPDATE_ERROR_CHECKING_OF_REPORT_TABLE_FOR_OPERATION_BASED_TOOLS
	}
	
	/// ML 6/5/2007 QA70-9869 SPECIAL_GUI_TREE_UPDATE_BEFORE_RERUNNING
	// virtual
	/// YuI 06/06/08 QA70-11619 MORE_CLEAR_WORKSHEET_PROBLEM
	//	void	GUIOnUpdateTreeBeforeRunning(TreeNode &trGUINew, TreeNode &trGUIOriginal)
	///---Sim 04-02-2009 QA80-13403 ADD_INDIVIDUAL_OP_VERSION_FOR_CONVERT_GUI_TREE
	//void	GUIOnUpdateTreeBeforeRunning(TreeNode &trGUINew, TreeNode &trGUIOriginal, TreeNode& trOperation)	
	void	GUIOnUpdateTreeBeforeRunning(const MultipleVersion& mvOld, TreeNode &trGUINew, TreeNode &trGUIOriginal, TreeNode& trOperation)	
	///---END QA80-13403 ADD_INDIVIDUAL_OP_VERSION_FOR_CONVERT_GUI_TREE
	/// end MORE_CLEAR_WORKSHEET_PROBLEM
	{
		/// YuI 06/06/08 QA70-11619 MORE_CLEAR_WORKSHEET_PROBLEM
		//	StatsOpBase::GUIOnUpdateTreeBeforeRunning(trGUINew, trGUIOriginal);
		///---Sim 04-02-2009 QA80-13403 ADD_INDIVIDUAL_OP_VERSION_FOR_CONVERT_GUI_TREE
		//StatsOpBase::GUIOnUpdateTreeBeforeRunning(trGUINew, trGUIOriginal, trOperation);
		StatsOpBase::GUIOnUpdateTreeBeforeRunning(mvOld, trGUINew, trGUIOriginal, trOperation);
		///---END QA80-13403 ADD_INDIVIDUAL_OP_VERSION_FOR_CONVERT_GUI_TREE
		/// end MORE_CLEAR_WORKSHEET_PROBLEM
		TreeNode		trCCNew = trGUINew.CompControl;
		TreeNode		trCCOriginal = trGUIOriginal.CompControl;
		if ( trCCNew.IsValid() && trCCOriginal.IsValid() )
		{
			TreeNode	trSVNew = trCCNew.StateValue;
			TreeNode	trSVOriginal = trCCOriginal.StateValue;
			if ( trSVNew.IsValid() && trSVOriginal.IsValid() )
			{
				octree_node_copy_attribute(&trSVOriginal, &trSVNew, STR_COMBO_ATTRIB);
				/// ML 6/6/2007 QA70-9869 MUST_COPY_STATEVALUE_VALE_BECAUSE_tree_copy_values_by_id_CANNOT
				trSVNew.strVal = trSVOriginal.strVal;
				/// end MUST_COPY_STATEVALUE_VALE_BECAUSE_tree_copy_values_by_id_CANNOT
			}
		}
		
		return;
	}
	/// end SPECIAL_GUI_TREE_UPDATE_BEFORE_RERUNNING


	void updateAreaUnderCurve(TreeNode &trOp, int index, ROCArea &sROCArea)
	{
		int nDataID = IDST_ROC_AREA_VALUE;
		
		TreeNode trAreaTable = tree_check_get_node(trOp.Calculation, "AreaTable", nDataID++, STR_LABEL_ATTRIB, _L("Area Under the Curve"));
		
		string strLabel = GetInputDataColName(trOp, index); //will get column name as lable here later
		TreeNode		trRow = check_add_enumerated_node(trAreaTable, CALCULATION_REPORT_TABLE_COL_PREFIX, index + 1, IDST_TEMP_ONE_SET, STR_LABEL_ATTRIB,_L(strLabel));
		trRow += sROCArea;
		trRow.ID = make_one_set_ID(nDataID++, index);
		
		//show label to replace show tagName
		trRow.Prob.SetAttribute(STR_LABEL_ATTRIB, _L("Asymptotic Prob"));
		trRow.Area.SetAttribute(STR_LABEL_ATTRIB, _L("Area"));		
		
		TreeNode 	trErrConf = trOp.GUI.CompControl.StdError;
		if(trErrConf.Use)
		{
			trRow.SE.SetAttribute(STR_LABEL_ATTRIB, _L("Std. Error"));
			double dConfidence = trOp.GUI.CompControl.StdError.ConfLevel.dVal;
			///Kyle 09/24/08 SET_NO_NEED_TO_LOCALIZE
			//trRow.LCL.SetAttribute(STR_LABEL_ATTRIB, (string)dConfidence + _L("% LCL"));
			//trRow.UCL.SetAttribute(STR_LABEL_ATTRIB, (string)dConfidence + _L("% UCL"));
			///Kyle 06/05/2009 QA70-13733 RADIX_POINT_SHOULD_BE_COMMA_IN_GOS
			//trRow.LCL.SetAttribute(STR_LABEL_ATTRIB, (string)dConfidence + "% LCL");
			//trRow.UCL.SetAttribute(STR_LABEL_ATTRIB, (string)dConfidence + "% UCL");
			trRow.LCL.SetAttribute(STR_LABEL_ATTRIB, ftoa(dConfidence) + "% LCL");
			trRow.UCL.SetAttribute(STR_LABEL_ATTRIB, ftoa(dConfidence) + "% UCL");
			///End RADIX_POINT_SHOULD_BE_COMMA_IN_GOS
			///End SET_NO_NEED_TO_LOCALIZE
		}
		else /// Iris 06/30/06 REMOVE_ERR_CONF_NODE_IF_UNCHECKED
		{
			trRow.SE.Remove();
			trRow.LCL.Remove();
			trRow.UCL.Remove();
		}
		///End REMOVE_ERR_CONF_NODE_IF_UNCHECKED
		///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.SE )
			trRow.SE.SetAttribute(STR_COL_DESIGNATION_ATTRIB, OKDATAOBJ_DESIGNATION_ERROR);
		///end SUPPORT_SPECIFY_COLUMN_DESIGNATIONS_IN_REPORT_TABLES

	}

	
	//void updateCoordinateTable(TreeNode &trOp, int index, int nThreshold, const ROCCuv* psROCCuv)
	//{
		//TreeNode	trRoc = tree_check_get_node(trOp.Calculation, "ROC", IDST_ROC_COORDINATE, STR_LABEL_ATTRIB, "Coordinates of the Curve");
//
		//string strSubTableNode = "Sub" + index;	//why the name is "Sub", not others?	
		//TreeNode trSub = tree_check_get_node(trRoc, strSubTableNode, IDST_ROC_SUB + index, STR_LABEL_ATTRIB, strSubTableNode);
//
//
		//trSub.SetAttribute(STR_ATTRIB_BRANCH, GETNBRANCH_KEEP_SIZE_ON_COLLAPSE);
		//prepareCurveData(trOp, trSub, index, strSubTableNode);
	//}
	
	
	
	void prepareCurveData(TreeNode &trOp, int index, int nThreshold, const ROCCuv* psROCCuv)
	{	
		//TreeNode trGraph = tree_check_get_node(trOp.ResultCurves, "ROCCurve", IDST_ROC_CURVE, TREE_Table, GetTableStringMain(true));
		/// Iris 3/26/2008 v8.0832 ROC_RESULT_DATA_COL_NEED_MORE_LABEL
		//TreeNode trGraph = CheckCreateOneResultCurvesTable(trOp, 0, -1, GRAPH_ROC_CURVE, "Coordinates", IDST_ROC_CURVE, NULL, "Temp");
		/// Iris 3/19/2009 QA8.-13285-P4 REMOVE_ROC_RESULT_DATA_SHEET_EMPTY_PARAMETERS_LABEL
		//TreeNode trGraph = CheckCreateOneResultCurvesTable(trOp, 0, -1, GRAPH_ROC_CURVE, "Coordinates", IDST_ROC_CURVE, " ", " ");
		TreeNode trGraph = CheckCreateOneResultCurvesTable(trOp, 0, -1, GRAPH_ROC_CURVE, "Coordinates", IDST_ROC_CURVE, " ", "");
		///end REMOVE_ROC_RESULT_DATA_SHEET_EMPTY_PARAMETERS_LABEL
		///end ROC_RESULT_DATA_COL_NEED_MORE_LABEL
		
		/// Iris 3/26/2008 v8.0832 ROC_RESULT_DATA_COL_NEED_MORE_LABEL
		//setNodeData(trGraph, "1-Specificity", "X", index, nThreshold, psROCCuv, "Sensitivity");		
		setNodeData(trGraph, GetInputDataColName(trOp, index), "X", index, nThreshold, psROCCuv);	
		///end ROC_RESULT_DATA_COL_NEED_MORE_LABEL
		setNodeData(trGraph, GetInputDataColName(trOp, index), "Y", index, nThreshold, psROCCuv);
	}
	
	void setNodeData(TreeNode &tr, string strLable, string strName, int nIndex, int nThreshold, ROCCuv *psROCCuv)
	{
		vector vecData(nThreshold);
		int nColType;
		
		if( strcmp(strName, "X") == 0 )
		{
			nColType = OKDATAOBJ_DESIGNATION_X;
			for(int ii = 0;ii < nThreshold;ii++)
				vecData[ii] = psROCCuv[ii].TPP;
		}

		if( strcmp(strName, "Y") == 0 )
		{
			nColType = OKDATAOBJ_DESIGNATION_Y;
			for(int ii = 0;ii < nThreshold;ii++)
				vecData[ii] = psROCCuv[ii].FPP;
		}
		
		strName += nIndex;
		int 		nID = getCoordinateSubNodeID(tr);	
		TreeNode 	trData = tree_check_get_node(tr, strName, nID, STR_LABEL_ATTRIB, strLable);
		trData.dVals = vecData;
		trData.SetAttribute(STR_COL_DESIGNATION_ATTRIB, nColType);		
	}
	
	int		getCoordinateSubNodeID(const TreeNode &trTable)
	{
		return IDST_ROC_COORDINATE + trTable.Children.Count();
	}

	// get selected state values from GUI
	void	getStateValList(TreeNode &trOp, const vector<string> &vsStateNames, vector &vecList, bool &bStateIsNumeric)
	{
		TreeNode 		trVecList = trOp.GUI.CompControl.StateValue;
		if(!trVecList)
			return;		
			
		string 		strStateValue = trVecList.strVal;
		vector<string>	vsList;
		strStateValue.TrimLeft();
		strStateValue.TrimRight();		
		str_separate(strStateValue, " ", vsList);
		remove_empty_item(vsList);
		
		vecList.SetSize(vsList.GetSize());
		for(int ii=0; ii<vsList.GetSize(); ii++)
		{			
			if( is_numeric(vsList[ii]) )
			{
				bStateIsNumeric = true;
				///Arvin 09/18/07 CALLING_WRONG_FUNCTION
				//vecList[ii] = atoi(vsList[ii]);
				vecList[ii] = atof(vsList[ii]);
				///END CALLING_WRONG_FUNCTION
			}
			else
			{
				bStateIsNumeric = false;
				int index = vsStateNames.Find(vsList[ii]);
				vecList[ii] = index;
			}
		
		}		
	}
	
	///Arvin 09/26/07 ADD_SUMMARY_TABLE_FOR_MULTI_DATA_COLUMNS
	//void 	updateSummaryTable(TreeNode &trOp, vector &vState, const vector<string> &vsStateNames, const vector & vecList, bool bStateIsNumeric)
	void 	updateSummaryTable(TreeNode &trOp, int index, vector &vState, const vector<string> &vsStateNames, const vector & vecList, bool bStateIsNumeric)
	///end ADD_SUMMARY_TABLE_FOR_MULTI_DATA_COLUMNS
	{		
	    
	    // get the data according to selected state values 
	    vector<string>	vsPositiveNames;
		int 			nNumPositive = 0;
		vector<uint> 	vnIndex, vnTemp;
		for(int ii=0 ;ii < vecList.GetSize(); ii++)
		{
			vState.Find(vnIndex, vecList[ii]);
			nNumPositive += vnIndex.GetSize();
			
			string 	strOnePositive;
			if(bStateIsNumeric)
			{
				///Kyle 10/12/2009 QA80-13733 RADIX_POINT_SHOULD_BE_COMMA_IN_GOS
				//strOnePositive = vecList[ii];
				strOnePositive = ftoa(vecList[ii]);
				///End RADIX_POINT_SHOULD_BE_COMMA_IN_GOS
			}
			else
			{
				strOnePositive = vsStateNames[vecList[ii]];
			}
			
			if( vsPositiveNames.Find(strOnePositive) < 0)	
			{				
				vsPositiveNames.Add(strOnePositive);
			}
		}		
		
		//add table
		TreeNode trTable = tree_check_get_node(trOp.Calculation, "Summary", IDST_ROC_SUMMARY, STR_LABEL_ATTRIB, _L("Case Processing Summary"));
		///Arvin 09/26/07 ADD_SUMMARY_TABLE_FOR_MULTI_DATA_COLUMNS
		//TreeNode trPositive = tree_check_get_node(trTable, "Positive", IDST_ROC_SUMMARY + 1, STR_LABEL_ATTRIB, "Positive");
		//TreeNode trNegative = tree_check_get_node(trTable, "Negative", IDST_ROC_SUMMARY + 2, STR_LABEL_ATTRIB, "Negative");
		string 			strLabel = GetInputDataColName(trOp, index); //will get column name as lable here later
		TreeNode		trRow = check_add_enumerated_node(trTable, CALCULATION_REPORT_TABLE_COL_PREFIX, index + 1, IDST_TEMP_ONE_SET, STR_LABEL_ATTRIB,_L(strLabel));
		trRow.SetAttribute(TREE_Table, GetTableStringMain(false));
		int nID = make_one_set_ID(IDST_ROC_SUMMARY, index);
		trRow.ID = nID;
		TreeNode trPositive = tree_check_get_node(trRow, "Positive", IDST_ROC_SUMMARY + 1, STR_LABEL_ATTRIB, _L("Positive"));
		TreeNode trNegative = tree_check_get_node(trRow, "Negative", IDST_ROC_SUMMARY + 2, STR_LABEL_ATTRIB, _L("Negative"));
		///END ADD_SUMMARY_TABLE_FOR_MULTI_DATA_COLUMNS
		
		TreeNode trTemp1 = tree_check_get_node(trPositive, "State", IDST_ROC_SUMMARY + 3, STR_LABEL_ATTRIB, _L("State"));
		trTemp1.nVal = nNumPositive;
		
		TreeNode trTemp2 = tree_check_get_node(trNegative, "State", IDST_ROC_SUMMARY + 3, STR_LABEL_ATTRIB, _L("State"));	
		trTemp2.nVal = vState.GetSize() - nNumPositive;
	
		// add foot node 
		string		strFootLabel = _L("The positive actual state is") + " ";
		for(ii=0 ;ii < vsPositiveNames.GetSize(); ii++)
		{
			strFootLabel += vsPositiveNames[ii] + " ";
		}
		///Sophy 3/30/2009 QA80-13352 SUPPORT_SPECIFY_COLUMN_DESIGNATIONS_IN_REPORT_TABLES
		tree_set_attribute_to_all_nodes(trPositive, STR_COL_DESIGNATION_ATTRIB, (string)OKDATAOBJ_DESIGNATION_Y);
		tree_set_attribute_to_all_nodes(trNegative, STR_COL_DESIGNATION_ATTRIB, (string)OKDATAOBJ_DESIGNATION_Y);
		///end SUPPORT_SPECIFY_COLUMN_DESIGNATIONS_IN_REPORT_TABLES
		///Arvin 09/26/07 ADD_SUMMARY_TABLE_FOR_MULTI_DATA_COLUMNS
		//TreeNode 	trFooter = tree_check_get_node(trTable, "Footnote", IDE_FOOTNOTE_BEGIN, TREE_Footnote, "1"); // just need the TREE_Footnote attribute, value does not matter, so 1 is good
		TreeNode 	trFooter = tree_check_get_node(trRow, "Footnote", IDE_FOOTNOTE_BEGIN, TREE_Footnote, "1"); // just need the TREE_Footnote attribute, value does not matter, so 1 is good
		///end ADD_SUMMARY_TABLE_FOR_MULTI_DATA_COLUMNS
		trFooter.strVal = strFootLabel;	
	}

	void getUserThreshold(TreeNode &tr, vector &vecThres)
	{
		TreeNode trTemp = tr.GUI.CompControl.Thresholds;
	
		string strThres = trTemp.strVal;
		vector<string> vecStrThres;
		strThres.GetTokens(vecStrThres, ',');
			
		vecThres.SetSize( vecStrThres.GetSize() );
	
		for(int ii = 0;ii < vecStrThres.GetSize(); ii++)
			///Arvin 09/18/07 CALLING_WRONG_FUNCTION
			//vecThres[ii] = atoi(vecStrThres[ii]);
			vecThres[ii] = atof(vecStrThres[ii]);
			///end CALLING_WRONG_FUNCTION
	}
	
	bool SetupPlotDetails(const TreeNode& trOp, GraphLayer& gl, int nFittedPlot, int nNumPlots = 1, int nGraphIndex = 0, int nDataIndex = 0, bool bIsSourceGraph = false, bool bUpdateExistedReportGraph = false)
	{
		if( !bUpdateExistedReportGraph )
		{
			if( !gl )
				return false;	
	
			//Setup Color
			if(GRAPH_ROC_CURVE == nGraphIndex)
			{
				int nIndex = 2;
				foreach(DataPlot dp in gl.DataPlots)
					dp.SetColor(nIndex++ , true);
				
				//set color for reference Line
				if(isPlotReferenceLine(trOp))
				{ 
					dp = gl.DataPlots(gl.DataPlots.Count() - 1);
					dp.SetColor(7, true);		//7: dark yellow
				}
	
				legend_update(gl);
			}
		}

		return true;

	}
	
	bool	isPlotReferenceLine(TreeNode& trOp)
	{
		TreeNode trRefernceLine = trOp.GUI.CompControl.ROCCurve.WithLine;

		if (trRefernceLine.IsValid())
			return	trRefernceLine.nVal;

		return false;
	}

	bool	isPlotRocCurve(TreeNode& trOp)
	{
		TreeNode trRocCurve = trOp.GUI.CompControl.ROCCurve;

		if ( trRocCurve.IsValid() ) 
			return trRocCurve.Use;

		return false;
	}

	string GetInputDataColName(TreeNode &trOp, int nIndex)
	{
		DataRange dr, drData;		
		TreeNode trInputData = trOp.GUI.InputData;
		dr.Create(trInputData, FALSE);

		int 		c1, c2, r1, r2;
		Worksheet 	wks;
		dr.GetRange(0, r1, c1, r2, c2, wks);

		string 		strName;
		int			nCol = nIndex + c1;
		if(nCol <= c2)
		{
			Column 	col(wks, nCol);			
			strName = col.GetLongName();
			if (strName.IsEmpty()) 
				col.GetName(strName);
			///------ Folger 12/26/08 QA80-12642-P3 v8.0991 CONSISTENT_SHOW_LN_WITH_DOUBLE_QUOTES_IN_REPORT_SHEET
			else
			{
				string str = strName;
				strName.Format("\"%s\"", str);
			}
			///------ End CONSISTENT_SHOW_LN_WITH_DOUBLE_QUOTES_IN_REPORT_SHEET
		}
		
		return strName;
	}

};

static bool roc_update_states_value_by_on_data_change(TreeNode& tr, int nRow, int nCol, TreeNode& trNode, DWORD nEventInfo, int nCntrlType, WndContainer& getNContainer)
{
	/// Iris 4/19/06 SUPPORT_READ_CHAR_DATA_FOR_STATE
	//DataRange dr;	
	//vector vecX;

	//bool bRet = ReadDataFromTree(dr, tr, vecX);
	string strStateList, strDefault;
	bool bRet = get_states_from_input_tree(tr, strStateList, strDefault);
	/// End SUPPORT_READ_CHAR_DATA_FOR_STATE

	if(bRet)
	{
		/// Iris 4/19/06 SUPPORT_READ_CHAR_DATA_FOR_STATE
		//string strStateList;
		//vector_to_str_list(vecX, strStateList);
		/// End SUPPORT_READ_CHAR_DATA_FOR_STATE
		strStateList =  "|" + strStateList;
		///Arvin 08/22/07 SHOULD_NOT_RESET_DEFAULT_VALUE_AFTER_CHANGE_PARAM_WITH_SAME_INPUT_DATA
		//tr.CompControl.StateValue.SetAttribute(STR_COMBO_ATTRIB, strStateList);
		//tr.CompControl.StateValue.strVal = strDefault;
		string strOldStateList;
		TreeNode trStateValue = tr.CompControl.StateValue;
		if(trStateValue && trStateValue.GetAttribute(STR_COMBO_ATTRIB, strOldStateList) && (strOldStateList.Compare(strStateList)!=0))
		{
			trStateValue.SetAttribute(STR_COMBO_ATTRIB, strStateList);
			trStateValue.strVal = strDefault;
		}
		///end SHOULD_NOT_RESET_DEFAULT_VALUE_AFTER_CHANGE_PARAM_WITH_SAME_INPUT_DATA
	}

	return true;
}



static bool get_states_from_input_tree(TreeNode &trOp, string& strStateList, string& strDefault)
{
	DataRange dr;
	dr.Create();
	dr.SetTree(trOp.InputData);
	DWORD			dwRules = 0;
	if(!dr || dr.GetNumRanges() <= 0 || dr.GetNumData(dwRules) <= 0)
		return false;
	
	/// ML 1/4/2007 EXTRACTING_FACTOR_VALUES_ROC
	/*
	Worksheet 	wks;
	int			r1, r2, c1, c2;
	dr.GetRange(1, r1, c1, r2, c2, wks); //0: Data; 1: State	
	Dataset dsState(wks, c1);
	if(!dsState)
		return false;

	vector<string> vsData, vsTemp;
	dsState.GetStringArray(vsData);
	char chDelimiter = '|';
	for(int ii=0; ii<vsData.GetSize(); ii++)
	{
		strStateList.GetTokens(vsTemp, chDelimiter);
		if( vsTemp.Find(vsData[ii]) < 0 )
			vsTemp.Add(vsData[ii]);
		strStateList.SetTokens(vsTemp, chDelimiter);
	}
	*/
	char	chDelimiter = '|';
	vector<string>	vsTemp;
	int				numData = dr.GetNumData(dwRules);
	for (int ii = 0; ii < numData; ii++)
	{
		vector<string>	fctValues;
		if ( 1 == dr.GetFactorsValues(dwRules, ii, &fctValues) )	// must be 1 for ROC?
		{
			///Sophy 8/13/2008 NEVER_DISPLAY_MISSING_VALUE_IN_STATE_VALUE_COMBOLIST or may cause runtime error in Roc with missing value as data
			//if( vsTemp.Find(fctValues[0]) < 0 )
			if( vsTemp.Find(fctValues[0]) < 0 && fctValues[0].Compare("--") != 0 )
			///end NEVER_DISPLAY_MISSING_VALUE_IN_STATE_VALUE_COMBOLIST
				vsTemp.Add(fctValues[0]);
		}
	}
	strStateList.SetTokens(vsTemp, chDelimiter);
	/// end EXTRACTING_FACTOR_VALUES_ROC
	
	/// Iris 04/04/2007 STATE_VALUE_SHOULD_BE_EMPTY_FOR_INIT_TIME, by Echo
	//if(vsTemp.GetSize()>0)
	//	strDefault = vsTemp[0];
	strDefault = "";
	///end STATE_VALUE_SHOULD_BE_EMPTY_FOR_INIT_TIME

	return true;
}
