#include <origin.h>
#include <GetNBox.h>
#include <xfutils.h>
#include <stats_utils.h>
#include <report_utils.h>
#include <event_utils.h>
#include <o8dlg.h>
//put additional include files here

//put your own support static functions here

/*------------------------------------------------------------------------------*
 * Modification Log:															*
 *	ML 12/14/2006 ADD_INPUT_DATA_TABLE_FRIEDMAN									*
 *	Jacky 07/22/10 ORG-102 USER_CAN_SET_SIGNIFICANCE_LEVEL						*
 *------------------------------------------------------------------------------*/


#define FRI_MIN_DATA_SIZE	4
#define	FRI_MIN_BLOCK_TREATMENT	2
#define FRI_MAX_GROUP	100

//XF error definition
//enum
//{
	//ERR_TOO_FEW_DATA = XF_LOCAL_ERR_BEGIN,
	//ERR_TOO_FEW_BLOCK_TREATMENT,
	//ERR_NOT_SAME_SIZE,
	//ERR_NOT_1_DATA_PER_CELL,
//};

static int _friedman_check_indata(Range& rRange, vector& vData, vector& vTreatment, vector& vBlock, vector<string>& vstrGroup)
{
	if ( !rRange )
		return CER_INVALID_RANGE;

	DWORD		dwRules = DRR_RM_ANOVA;
	Worksheet	wksTemp;
	int nn = rRange.GetNumData(dwRules, NULL, &wksTemp, NULL, NULL);
	if (nn == -98 || nn == -97)
	{
		return CER_NOT_1_DATA_PER_CELL;
	}
	if (nn <= 0)
	{
		return CER_NOT_RM_ANOVA_DATA;
	}	
	
	matrix		mData;
	int			nOutcome, numFactorVals;
	nn = rRange.GetDataRMOneWayANOVA(dwRules, nOutcome, numFactorVals, &mData, &vstrGroup);
	switch (nOutcome)
	{
	case RMDATA_ERR_ONE_WAY_MISSING_VALUES_FOUND:
	case RMDATA_ERR_ONE_WAY_GENERAL_ILLEGAL_DATA:
		return CER_NOT_1_DATA_PER_CELL;
		break;
	case RMDATA_ERR_ONE_WAY_MISSING_SUBJECT_DATA:
		return CER_NOT_RM_ANOVA2_DATA;	
	}
	if (nn < 0 )	
	{
		return CER_NOT_RM_ANOVA_DATA;
	}
	if (mData.GetNumRows() < ANOVA2_MIN_FACTOR_SUBJECT || mData.GetNumCols() < ANOVA2_MIN_FACTOR_SUBJECT)
	{
		return CER_TO_FEW_FACTOR;
	}
	
	vector vTemp;
	int nCols = mData.GetNumCols(), nRows = mData.GetNumRows();
	for (int ii = 0; ii < nCols; ii++)
	{
		vTemp.SetSize(nRows);
		vTemp = ii+1;
		vTreatment.Append(vTemp);
		vTemp.Data(1, nRows);
		vBlock.Append(vTemp);
	}
	
	mData.GetAsVector(vData, false);
				
	return CER_NO_ERROR;
	
}


void friedman(const Range& irng, const double& alpha, ReportTree& rt)
{
	
	vector vData, vBlock, vTreatment;
	vector<string> vstrGroup;
	int nErr = _friedman_check_indata(irng, vData, vTreatment, vBlock, vstrGroup);
	if ( CER_NO_ERROR != nErr )
	{
		if (CER_DATA_TOO_FEW == nErr)
			XF_THROW_EX(CER_DATA_TOO_FEW, FRI_MIN_DATA_SIZE)
		else
			XF_THROW(nErr);
	}
	
	
	DescStatResults pDescStats[FRI_MAX_GROUP];
	QuantileResults pQuantiles[FRI_MAX_GROUP];
	desc_stats_group(vData, vTreatment, pDescStats, pQuantiles);
	LPCSTR lpsczLabel = _L("Friedman ANOVA");
	report_tree_create(rt, lpsczLabel, "irng");
	
	///Echo 1/5/07 MOVE_TO_REPORT_TREE_CREATE
	/*
	/// ML 12/14/2006 ADD_INPUT_DATA_TABLE_FRIEDMAN 
	XFExeContext	*pxfexectxt = Project.GetCurrentXFExeCtxt();
	// Create table and add entries to it for argument "irng":
	pxfexectxt->AddInputToTree(rt, "irng", _L("Input"));
	/// end ADD_INPUT_DATA_TABLE_FRIEDMAN 
	*/
	///END MOVE_TO_REPORT_TREE_CREATE
	
	rt_add_nph_descriptive(rt, pDescStats, pQuantiles, vstrGroup);
	
	NPHSummary FrieSummary[FRI_MAX_GROUP];
	NPHRanks FrieRanks[FRI_MAX_GROUP];
	NPHStats FrieStats;
	int nRet = ocmath_friedman_test(vData, vData.GetSize(), vTreatment, vTreatment.GetSize(), vBlock,vBlock.GetSize(), FrieSummary, FrieRanks, &FrieStats);
	if (nRet != STATS_NO_ERROR)
	{
		XF_THROW_EX(CER_UNKNOWN_ERROR_EX, nRet);
	}
	
	rt_add_nph_ranks(rt, FrieRanks, vstrGroup);
	
	string strHYPT, strFooter1, strFooter2;
	ocu_load_err_msg_str(FOOTNOTE_NPH_K_SAMPLE, &strHYPT);
	ocu_load_err_msg_str(FOOTNOTE_FRIEDMAN_CON_DIFF, &strFooter1);
	ocu_load_err_msg_str(FOOTNOTE_FRIEDMAN_CON_SAME, &strFooter2);
	//--- Jacky 07/22/10 ORG-102 USER_CAN_SET_SIGNIFICANCE_LEVEL
	//rt_add_nph_stats(rt, FrieStats, vstrGroup, strFooter1, strFooter2, strHYPT,NULL);
	rt_add_nph_stats(rt, FrieStats, vstrGroup, strFooter1, strFooter2, strHYPT,NULL,false,NULL,alpha);
	//--- end USER_CAN_SET_SIGNIFICANCE_LEVEL
			
}

//nEventID < 0 on event, like GETNE_ON_INIT, GETNE_ON_OK etc, >0 on change from control
//return 0 to do nothing, return PEVENT_GETN_RET_TO_CLOSE to close dialog
//dwEnables = bOKEnable, bBTN1Enable, bBTN2Enable, bBTN3Enable, , can set to false to disable OK/Apply buttons
//lpcszNodeName = the trGetN TreeNode tag name that generates the event, or is  if GETNE_ON_OK etc
//strAux = optional string for XF Wizard Bar, like DLG_NEED_CHANGE_GRID etc, it will be invalid if from internal node value change event
//strErrMsg = allowing messages to be shown
int friedman_event1(TreeNode& trGetN, int nRow, int nEventID, DWORD& dwEnables, LPCSTR lpcszNodeName, WndContainer& DynaCntrlContainer, string& strAux, string& strErrMsg)
{
	if( xf_is_extended_event(nEventID) )
		return friedman_event1_ex(trGetN, nRow, nEventID, dwEnables, lpcszNodeName, DynaCntrlContainer, strAux, strErrMsg);
	DECLARE_BUTTON_ENABLES
	
	TreeNode trRange = trGetN.irng;
	Range rRange;
	okxf_resolve_tree_construct_range(&trRange, &rRange);
	vector vData, vBlock, vTreatment;
	vector<string> vstrGroup;
	int nErr = _friedman_check_indata(rRange, vData, vTreatment, vBlock, vstrGroup);
	if (CER_NO_ERROR != nErr)
	{
		bOKEnable = false;
		strErrMsg = nErr;
		if (CER_DATA_TOO_FEW == nErr) strErrMsg += ":" + FRI_MIN_DATA_SIZE;
	}
	//DynaCntrlContainer.PostMessage(WM_USER_MSG_ON_DLG, nErr, FRI_MIN_DATA_SIZE);
	
	/*
	if ( GETNE_ON_OK == nEventID && rRange)	
	{
		vector vData, vBlock, vTreatment;
		vector<string> vstrGroup;
		if ( OE_NOERROR != nErr )
		{
			if (CER_DATA_TOO_FEW == nErr)
				DynaCntrlContainer.PostMessage(WM_USER_MSG_BOX, CER_DATA_TOO_FEW, FRI_MIN_DATA_SIZE);
			else
				DynaCntrlContainer.PostMessage(WM_USER_MSG_BOX, nErr);
			bOKEnable = false;		
		}
	}
	*/
	int nErr2 = hyt_check_input(trGetN);
	if (nErr2 != CER_NO_ERROR)
	{
		bOKEnable = false;
		strErrMsg = nErr2;
	}
	return true;	

}

int friedman_make_tree(TreeNode& tr, LPCSTR lpcszVarName)
{
	
	return false;
	
}
//nGetNDialog = 0,1,2, corresponding to the XF GetN dropdown, 0 = dialog is not used
//you can change nRet to be one of XFEVT_PROCEED (defualt), XFEVT_ABORT, XFEVT_PROCEED_NO_DLG or XFEVT_PROCEED_WITH_DLG(when nGetNDialog = 0)
//nGetNDialog = -1 when Ok on GetN dialog to allow handler to preocess <auto> etc variables
//dwCntrl is combination of bits
//LTXF_FROM_GUI_MENU, LTXF_FROM_GUI_PROMPT, LTXF_FROM_AUTO_UPDATE, LTXF_FROM_FUNCTION, LTXF_THEME_USED, LTXF_CHANGE_PARAM
void friedman_before_execute(TreeNode& trGetN, int nGetNDialog, int& nRet, int dwCntrl)
{
	
	//------ fisher 11/16/07 ADD_MAP_ID_TO_CHM
	if(is_use_origin_chm())
		trGetN.SetAttribute(STR_HELPID_ATTRIB, IDD_XF_friedman);
	
	if ( (dwCntrl&LTXF_THEME_USED) && nGetNDialog <= 0 )
	{
		TreeNode trRange = trGetN.irng;
		Range rRange;
		okxf_resolve_tree_construct_range(&trRange, &rRange);
		vector vData, vBlock, vTreatment;
		vector<string> vstrGroup;
		int nErr = _friedman_check_indata(rRange, vData, vTreatment, vBlock, vstrGroup);
		if ( CER_NO_ERROR != nErr )
			nRet = XFEVT_PROCEED_WITH_DLG;
	}
	
}
//nEventID < 0 on event, like GETNE_ON_INIT, GETNE_ON_OK etc, >0 on change from control
//return 0 to do nothing, return PEVENT_GETN_RET_TO_CLOSE to close dialog
//dwEnables = bOKEnable, bBTN1Enable, bBTN2Enable, bBTN3Enable, , can set to false to disable OK/Apply buttons
//lpcszNodeName = the trGetN TreeNode tag name that generates the event, or is  if GETNE_ON_OK etc
//strAux = optional string for XF Wizard Bar, like DLG_NEED_CHANGE_GRID etc, it will be invalid if from internal node value change event
//strErrMsg = allowing messages to be shown
int friedman_event1_ex(TreeNode& trGetN, int nRow, int nEventID, DWORD& dwEnables, LPCSTR lpcszNodeName, WndContainer& DynaCntrlContainer, string& strAux, string& strErrMsg)
{
	return false;
}
