#include <origin.h>
#include <GetNBox.h>
#include <xfutils.h>
enum{
	method_specify,
	method_range,
	method_snd,
	method_max,
	method_min,
	method_mean,
	method_median,
	method_sd,
	method_norm,
	method_mode,
	method_sum,
};

//put additional include files here

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

//#define STR_NODE_OPTION "method"
//#define STR_NODE_INPUT  "ix"

#define _NORMALIZE_METHOD_ERROR  0  ///temp solution

/***************************************************************************************
/// Modification Log :
/// Max 11/19/08 QA70-12615 v8.0975b WKS_NORMALIZE_SHOULD_WORK_ON_NON_Y_TYPE_DATA
/// Max 11/20/08 QA70-12615 v8.0975d SHARE_SAME_FUNC_FOR_NORMALIZE_AND_VNORMALIZE
/// Max 11/20/08 QA70-12615 v8.0975d CENTRALIZE_ERR_CHECKING
/// Max 11/20/08 v8.0975d BETTER_OPREATION_OUTPUT_COLUMN_COMMENTS
/// Kyle 01/19/2009 FIX_OK_BUTTON_ENABLED_WHEN_NO_INPUT_DATA
/// Sophy 9/15/2009 IMPROVE_COMMENTS_FOR_NORMALIZE_RESULT_COLUMNS
/// Folger 10/20/2010 ORG-1286-P1 MORE_TOOLS_FAILED_TO_COPY_SAMPLING_INTERVAL_FROM_INPUT
***************************************************************************************/

//put your own support static functions here

/// Max 11/25/08 QA70-12615 v8.0975d SHARE_SAME_FUNC_FOR_NORMALIZE_AND_VNORMALIZE
// no need to use a util func
/*
static void _initial_method_show(TreeNode& trGetN)
{
	switch(trGetN.method.nVal)
	{
	case method_specify:
		trGetN.val.Show = true;
		break;
	default:
		trGetN.val.Show = false;		
	}
}
*/
/// Max 11/20/08 QA70-12615 v8.0975d CENTRALIZE_ERR_CHECKING
static int _check_err_condition(TreeNode& trGetN)
{
	int nErr = CER_NO_ERROR;
	
	nErr = check_input_double_vector(trGetN.ix, 1, true);
	
	if(nErr == CER_NO_ERROR && method_specify == trGetN.method.nVal && trGetN.val.dVal == 0)
		nErr = XFERR_DIVIDED_BY_ZERO;
	
	return nErr;
}
/// ------


void vnormalize(const vector& ix, const TreeNode& datainfo, const int& method, const double& val, vector& ox)
{
	
	if(0 >= ix.GetSize())
	{
		ox.SetSize(0);
		return;
	}
	
	double dSub = 0.0;
	double dFactor = 1.0;
	//double dStart = 0.0;
	int nRet = 0;
	switch(method)
	{
	case method_range:
		double dMin, dMax;
		ix.GetMinMax(dMin, dMax);
		dSub = dMin;
		//dStart = val1;		
		if(dMin == dMax)
			dFactor = 0;
		else
			dFactor = (1.0 - 0) / (dMax - dMin);
		break;
	case method_specify:
		dFactor = (is_equal(0.0, val)) ? NANUM : 1.0 / val;
		break;
	case method_snd:
		double dMean, dSD;
		nRet = ocmath_basic_summary_stats(ix.GetSize(), ix, NULL, &dMean, &dSD);
		dSub = dMean;
		dFactor = (is_equal(0.0, dSD)) ? NANUM : 1.0 / dSD;
		break;
	case method_mean:
		double dMean;
		nRet = ocmath_basic_summary_stats(ix.GetSize(), ix, NULL, &dMean);
		dFactor = (is_equal(0.0, dMean)) ? NANUM : 1.0 / dMean;
		break;
	case method_median:
		int nSize = ix.GetSize();
		/// Max 11/20/08 v8.0975d SORT_BEFORE_CALCULATE_MEDIAN
		//double dMedian = (nSize%2) ? ix[nSize/2] : 0.5* ( ix[nSize/2] + ix[nSize/2-1]);
		vector vSort;
		vSort = ix;
		vSort.Sort();
		double dMedian = (vSort.GetSize() == 1) ? vSort[0] : ((nSize%2) ? vSort[nSize/2] : 0.5* ( vSort[nSize/2] + vSort[nSize/2-1]));
		/// ---
		dFactor = (is_equal(0.0, dMedian)) ? NANUM : 1.0 / dMedian;
		break;
	case method_sd:
		double dSD;
		nRet = ocmath_basic_summary_stats(ix.GetSize(), ix, NULL, NULL, &dSD);
		dFactor = (is_equal(0.0, dSD)) ? NANUM : 1.0 / dSD;		
		break;
	case method_norm:
		double dNorm;
		vector vTmp;
		vTmp = ix * ix;
		vTmp.Sum(dNorm);
		dFactor = (is_equal(0.0, dNorm)) ? NANUM : 1.0 / sqrt(dNorm);
		break;
	case method_mode:
		double dMode;
		nRet = ocmath_opt_summary_stats(ix.GetSize(), ix, 0.95, &dMode); //Here 0.95 doesn't make sense
		dFactor = (is_equal(0.0, dMode)) ? NANUM : 1.0 / dMode;
		break;
	case method_max:
		double dMin, dMax;
		ix.GetMinMax(dMin, dMax);
		dFactor = (is_equal(0.0, dMax)) ? NANUM : 1.0 / dMax;		
		break;
	case method_min:
		double dMin, dMax;
		ix.GetMinMax(dMin, dMax);
		dFactor = (is_equal(0.0, dMin)) ? NANUM : 1.0 / dMin;		
		break;	
	case method_sum:
		double dSum;
		ix.Sum(dSum);
		dFactor = (is_equal(0.0, dSum)) ? NANUM : 1.0 / dSum;		
		break;		
	default:
		XF_THROW(_NORMALIZE_METHOD_ERROR);
		break;
	}
	
	ox = (ix - dSub) * dFactor;  //ox = (ix - dSub) * dFactor + dStart;
	
	/// Max 11/20/08 v8.0975d BETTER_OPREATION_OUTPUT_COLUMN_COMMENTS
	Range rngix, rngox;
	if ( ix )
		rngix = ix.GetSourceDataRange();
	if ( ox )
		rngox = ox.GetSourceDataRange();
	///Sophy 9/15/2009 IMPROVE_COMMENTS_FOR_NORMALIZE_RESULT_COLUMNS
	//string strMethod = normalize_get_method_string(method, val);
	string strComments = normalize_get_method_string(get_input_data_range_string(rngix), method, val);
	///end IMPROVE_COMMENTS_FOR_NORMALIZE_RESULT_COLUMNS
	
	///Sophy 9/15/2009 IMPROVE_COMMENTS_FOR_NORMALIZE_RESULT_COLUMNS
	//string	strComments;
	//strComments.Format("%s of %s", strMethod, get_input_data_range_string(rngix));
	///end IMPROVE_COMMENTS_FOR_NORMALIZE_RESULT_COLUMNS
	///Sophy 4/20/2010 FIX_RUNTIME_ERROR_WHEN_OUTPUT_NOT_A_COLUMN
	//rngox.SetOutputComment(strComments);
	if ( rngox )
		rngox.SetOutputComment(strComments);
	///end FIX_RUNTIME_ERROR_WHEN_OUTPUT_NOT_A_COLUMN
	/// ------
	///------ Folger 10/20/2010 ORG-1286-P1 MORE_TOOLS_FAILED_TO_COPY_SAMPLING_INTERVAL_FROM_INPUT
	xf_copy_vector_sampling_interval(ox, ix, "ox");
	///------ End MORE_TOOLS_FAILED_TO_COPY_SAMPLING_INTERVAL_FROM_INPUT
}

//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 vnormalize_event1(TreeNode& trGetN, int nRow, int nEventID, DWORD& dwEnables, LPCSTR lpcszNodeName, WndContainer& DynaCntrlContainer, string& strAux, string& strErrMsg)
{
	if( xf_is_extended_event(nEventID) )
		return vnormalize_event1_ex(trGetN, nRow, nEventID, dwEnables, lpcszNodeName, DynaCntrlContainer, strAux, strErrMsg);
	DECLARE_BUTTON_ENABLES
	
	/// Max 11/19/08 QA70-12615 v8.0975b WKS_NORMALIZE_SHOULD_WORK_ON_NON_Y_TYPE_DATA
	bool bIsChangingData = lstrcmpi(lpcszNodeName,"ix") == 0? true:false;
	if(GETNE_ON_INIT == nEventID || bIsChangingData)
	{
		vector vx;
		TreeNode trInputX = trGetN.ix;
		///Kyle 01/19/2009 FIX_OK_BUTTON_ENABLED_WHEN_NO_INPUT_DATA
		//if(!okxf_resolve_tree_get_data_into_vector(&trInputX, &vx) )
			//return false;
		//normalize_set_datainfo(vx, trGetN.dataInfo);
		if(okxf_resolve_tree_get_data_into_vector(&trInputX, &vx) )
			normalize_set_datainfo(vx, trGetN.dataInfo);
		///End FIX_OK_BUTTON_ENABLED_WHEN_NO_INPUT_DATA
	}
	/// END WKS_NORMALIZE_SHOULD_WORK_ON_NON_Y_TYPE_DATA	
	
	bool bIsChangingOption = lstrcmpi(lpcszNodeName,"method") == 0? true:false;
	
	if( (0 > nEventID &&  GETNE_ON_OK != nEventID )|| bIsChangingOption)
		//_initial_method_show(trGetN);
		trGetN.val.Show = (trGetN.method.nVal == method_specify) ? true : false;	/// Max 11/25/08 v8.0975d SHARE_SAME_FUNC_FOR_NORMALIZE_AND_VNORMALIZE
	
	int nErr = CER_NO_ERROR;
	
	/// Max 11/20/08 QA70-12615 v8.0975d CENTRALIZE_ERR_CHECKING
	/*
	if( GETNE_ON_INIT == nEventID || lstrcmpi(lpcszNodeName,"ix") == 0 )
		nErr =  check_input_double_vector(trGetN.ix, 1,true);
	
	if(nErr == CER_NO_ERROR && method_specify == trGetN.method.nVal && trGetN.val.dVal == 0)
		nErr = XFERR_DIVIDED_BY_ZERO;
	*/
	nErr = _check_err_condition(trGetN);
	
	if(nErr != CER_NO_ERROR)
	{
		bOKEnable = false;
		strErrMsg = nErr;
	}
	
	return true;
	

}

int vnormalize_make_tree(TreeNode& tr, LPCSTR lpcszVarName)
{
	/// Max 11/25/08 QA70-12615 v8.0975d SHARE_SAME_FUNC_FOR_NORMALIZE_AND_VNORMALIZE
	return normalize_make_datainfo_tree(tr, lpcszVarName);
	/// ---
}
//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 vnormalize_before_execute(TreeNode& trGetN, int nGetNDialog, int& nRet, int dwCntrl)
{
	// ADD_MAP_ID_TO_CHM
	/// Folger, 01/16/09, show vnormalize help in X-Function.chm
	//if(is_use_origin_chm())
		//trGetN.SetAttribute(STR_HELPID_ATTRIB, IDD_XF_vnormalize);
	/// Max 11/20/08 QA70-12615 v8.0975d CENTRALIZE_ERR_CHECKING
	if(0 == nGetNDialog && (dwCntrl&LTXF_THEME_USED) && (dwCntrl&LTXF_FROM_GUI_MENU) && (CER_NO_ERROR != _check_err_condition(trGetN)) )
		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 vnormalize_event1_ex(TreeNode& trGetN, int nRow, int nEventID, DWORD& dwEnables, LPCSTR lpcszNodeName, WndContainer& DynaCntrlContainer, string& strAux, string& strErrMsg)
{
	return false;
}
