#include <origin.h>
#include <GetNBox.h>
#include <xfutils.h>
enum{
	operator_add,
	operator_sub,
	operator_div,
	operator_mul,
	operator_pow,
};
enum{
	operand_constant,
	operand_data,
};
#include <o8dlg.h>
#include <event_utils.h>

//--- Iris 1/04/2010 QA81-14877-S1 PERMIT_MISSING_AND_MASKED_DATA
//--- Iris 1/04/2010 QA81-14877-S2 DIFF_ERR_MSG_FOR_NONE_REFER_DATA
//--- Iris 1/04/2010 QA81-14877-S4 ALLOW_INPUT_DATA_HAS_DIFF_SIZE_WITH_REFER_DATA
///------ Folger 10/20/2010 ORG-1286-P1 MORE_TOOLS_FAILED_TO_COPY_SAMPLING_INTERVAL_FROM_INPUT

//put your own support static functions here

static void _mathtool_operation(const vector& vInput, int nOper, int nUseConstant, double dConstant, const vector& vRange, vector& vOutput)
{ 
	//--- Iris 1/04/2010 QA81-14877-S4 ALLOW_INPUT_DATA_HAS_DIFF_SIZE_WITH_REFER_DATA
	if( 0 == nUseConstant && vInput.GetSize() != vRange.GetSize())
	{
		vRange.SetSize(vInput.GetSize());		
	}
	//---
	
 	switch(nOper)
	{
	case operator_add:
 		if(nUseConstant)
			vOutput = vInput + dConstant; 
		else
 			vOutput = vInput + vRange;
		break;
	case operator_sub:
		if(nUseConstant)
			vOutput = vInput - dConstant;
		else
			vOutput = vInput - vRange;
		break;
	case operator_div:
		if(nUseConstant)
		{
			if(is_equal(0,dConstant))
			{
				XF_THROW(XFERR_DIVIDED_BY_ZERO);
			}
			vOutput = vInput / dConstant;		
		}
		else
		{
			vOutput = vInput / vRange;
		}
		break;
	case operator_mul:
		if(nUseConstant)
			vOutput = vInput * dConstant;
		else
			vOutput = vInput * vRange;
		break;
	case operator_pow:
		vOutput = vInput;
		if(nUseConstant)
			vOutput = pow(vInput,dConstant);
		else
			vOutput = pow(vInput, vRange);
		break;

	}
}

static	void	_set_output_range_comments(vector& ox, int nOperand, const vector& ix1, const vector& ix2, double dConstant, int nOperator)
{
	DataRange drXOutput;
	drXOutput = ox.GetSourceDataRange();
	
	if ( drXOutput )
	{
		DataRange drX1, drX2;
		drX1 = ix1.GetSourceDataRange();
		if ( nOperand == operand_data && ix2 )
			drX2 = ix2.GetSourceDataRange();
		
		vector<string>		vsOperators = {
			"Add",
			"Subtracted by",
			"Divided by",
			"Multiply",
			"Powered by"
		};
		
		string		strOperand = nOperand == operand_data ? get_input_data_range_string(drX2) : ftoa(dConstant);
			
		string	strComments;
		strComments.Format("%s %s on %s", vsOperators[nOperator], strOperand, get_input_data_range_string(drX1));
		ox.SetOutputComment(strComments);
	}
}

static int _check_err_condition(TreeNode& trGetN, string* pstrErrMsg = NULL)
{
	string strErrMsg;
	int nErr = CER_NO_ERROR;
	
	//--- Iris 1/04/2010 QA81-14877-S1 PERMIT_MISSING_AND_MASKED_DATA
	//nErr = check_input_double_vector(trGetN.ix1);
	nErr = check_input_double_vector(trGetN.ix1, 1, true);
	//---
	if ( CER_NO_ERROR != nErr )
	{
		strErrMsg = nErr;
	}
	
	if( CER_NO_ERROR == nErr )
	{
		if ( trGetN.operand.nVal == operand_data )
		{
			nErr = check_input_double_vector(trGetN.ix1, 1, true);
			if ( CER_NO_ERROR != nErr )
			{
				strErrMsg = nErr;
			}
			
			nErr = check_input_double_vector(trGetN.ix2, 1, true);
			if ( CER_NO_ERROR != nErr )
			{
				//--- Iris 1/04/2010 QA81-14877-S2 DIFF_ERR_MSG_FOR_NONE_REFER_DATA
				if( CER_FFT_GET_INPUT_FAIL == nErr )
					nErr = CER_GET_REFER_DATA_FAIL;
				//---
				strErrMsg = nErr;
			}
		}
	}
	
	if(CER_NO_ERROR == nErr && trGetN.constant.Show==1 && trGetN.constant.dVal == NANUM)
	{
		nErr = CER_EMPTY_VARIABLE;
		strErrMsg = nErr;
		strErrMsg += ":" + _L("Input Constant number");
	}
	
	if(pstrErrMsg != NULL)
		*pstrErrMsg = strErrMsg;
	return nErr;
}


void vmathtool(const vector& ix1, const int& operator, const int& operand, const vector& ix2, const double& constant, vector& ox, double& xmin, double& xmax, double& xmean)
{
	if( 0 == ix1.GetSize() )
	{
		XF_THROW(CER_NO_DATA);
	}
	
	if (operand == operand_data)
	{
		if( 0 == ix2.GetSize() )
		{
			XF_THROW(CER_NO_DATA);
		}
	}
	
	_mathtool_operation(ix1, operator, (operand_constant == operand), constant, ix2, ox);		
	
	ox.GetMinMax(xmin, xmax);
	ox.Sum(xmean);
	xmean /= ox.GetSize();
	
	_set_output_range_comments(ox, operand, ix1, ix2, constant, operator);
	///------ Folger 10/20/2010 ORG-1286-P1 MORE_TOOLS_FAILED_TO_COPY_SAMPLING_INTERVAL_FROM_INPUT
	xf_copy_vector_sampling_interval(ox, ix1, "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 vmathtool_event1(TreeNode& trGetN, int nRow, int nEventID, DWORD& dwEnables, LPCSTR lpcszNodeName, WndContainer& DynaCntrlContainer, string& strAux, string& strErrMsg)
{
	if( xf_is_extended_event(nEventID) )
		return vmathtool_event1_ex(trGetN, nRow, nEventID, dwEnables, lpcszNodeName, DynaCntrlContainer, strAux, strErrMsg);
	DECLARE_BUTTON_ENABLES
	
	bool bShowRef = false;
	bool bShowConstant = false;	
	switch(trGetN.operand.nVal)
	{
		case operand_data:
			bShowRef = true;
			break;
		case operand_constant:
			bShowConstant = true;
			break;
	}
			
	trGetN.ix2.Show = bShowRef;
	trGetN.constant.Show = bShowConstant;
	
	int nErr = CER_NO_ERROR;
	nErr = _check_err_condition(trGetN, strErrMsg);
	
	if(nErr != CER_NO_ERROR)
	{
		bOKEnable = false;
	}
	return true;

}

int vmathtool_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 vmathtool_before_execute(TreeNode& trGetN, int nGetNDialog, int& nRet, int dwCntrl)
{
	
	if(is_use_origin_chm())
		trGetN.SetAttribute(STR_HELPID_ATTRIB, IDD_XF_vmathtool);	
	
	if ((dwCntrl & LTXF_THEME_USED) && (dwCntrl & LTXF_FROM_GUI_MENU) && nGetNDialog == 0)
	{
		if(_check_err_condition(trGetN) != CER_NO_ERROR)
			nRet = XFEVT_PROCEED_WITH_DLG;		
	}	
	
	if ( -1 == nGetNDialog || 0 == nGetNDialog )
	{
		if ( trGetN.operand.nVal == operand_constant )
		{
			trGetN.ix2.strVal = STR_OPTIONAL;
		}
	}
	
}
//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 vmathtool_event1_ex(TreeNode& trGetN, int nRow, int nEventID, DWORD& dwEnables, LPCSTR lpcszNodeName, WndContainer& DynaCntrlContainer, string& strAux, string& strErrMsg)
{
	return false;
}
