#include <origin.h>
#include <GetNBox.h>
#include <xfutils.h>
enum{
	method_nearest,
	method_bilinear,
	method_bicubic,
	method_spline,
	method_biquad,
};
#include <getnbox.h> //temp
#include <event_utils.h>
//put additional include files here

//put your own support static functions here
///justin 11/01/2006 MOVE_TO_EVENT_UTILS
/* 
static bool _set_value_for_auto_and_unsigned(TreeNode& trParam, double dVal)
{
	if(!trParam)	
		return false;
	int nType = _get_variable_type(trParam);
	if(PDS_AUTO == nType || PDS_UNASSIGNED == nType)
	{
		trParam.dVal = dVal;	
		return true;
	}
}
static bool _set_value_for_auto_and_unsigned(TreeNode& trParam, int nVal)
{
	if(!trParam)	
		return false;
	int nType = _get_variable_type(trParam);
	if(PDS_AUTO == nType || PDS_UNASSIGNED == nType)
	{
		trParam.nVal = nVal;	
		return true;
	}	
}
static int _get_variable_type(TreeNode& trParam)
{
	string strParam = trParam.strVal;
	if(strParam.IsEmpty())	
		return PDS_UNASSIGNED;
	
	return okutil_cvt_str_to_predefined_type(strParam);
}
*/
///end MOVE_TO_EVENT_UTILS
///justin 09/08/2006 REPLACED_WITH_SIMPLE_METHOD
/*
static int _cast_to_double_matrix(MatrixObject& im, matrix& mat)
{
	int nRet = OE_NOERROR;
	switch( im.GetInternalData())
	{
	case FSI_DOUBLE:
		matrix& matD = im.GetDataObject();
		mat = matD;
		break;
	case FSI_REAL:
		matrix<float>& matF = im.GetDataObject();
		nRet = matF.CastToDouble(mat);
		break;
	case FSI_SHORT:
		matrix<short>& matS = im.GetDataObject();
		nRet = matS.CastToDouble(mat);
		break;
	case FSI_LONG:
		matrix<int>& matL = im.GetDataObject();
		nRet = matL.CastToDouble(mat);
		break;
	case FSI_CHAR:
		matrix<char>& matC = im.GetDataObject();
		nRet = matC.CastToDouble(mat);
		break;
	case FSI_BYTE:
		matrix<byte>& matB = im.GetDataObject();
		matB.CastToDouble(mat);
		break;
	case FSI_USHORT:
		matrix<unsigned short>& matUS = im.GetDataObject();
		nRet = matUS.CastToDouble(mat);
		break;
	case FSI_ULONG:
		matrix<unsigned int>& matUL = im.GetDataObject();
		nRet = matUL.CastToDouble(mat);
		break;
	default:
		nRet = CER_INVALID_MAT;
	}
	return nRet;
}
*/
//end REPLACED_WITH_SIMPLE_METHOD

static bool _initial_parameters_without_value(TreeNode& trGetN)
{
	MatrixObject im;
	if(!( okxf_resolve_string_get_origin_object(trGetN.im.strVal, &im) && im.IsValid() && im.HasData(true)) )
	{
		return false;
	}
	
	set_value_for_auto_and_unassigned(trGetN.cols, im.GetNumCols());
	set_value_for_auto_and_unassigned(trGetN.rows, im.GetNumRows());

	double dXMin, dYMin, dXMax, dYMax;
	im.GetXY(dXMin, dYMin, dXMax, dYMax);
	set_value_for_auto_and_unassigned(trGetN.xmin, dXMin);
	set_value_for_auto_and_unassigned(trGetN.ymin, dYMin);
	set_value_for_auto_and_unassigned(trGetN.xmax, dXMax);
	set_value_for_auto_and_unassigned(trGetN.ymax, dYMax);
	return true;
}

static bool _check_input_matrix(int nMethod, MatrixObject& im)
{
	if(!im.IsValid())
		return false;
	
	int nCols, nRows;
	nCols = im.GetNumCols();
	nRows = im.GetNumRows();

	switch(nMethod)
	{
	case method_nearest:
	case method_bilinear:
	case method_bicubic:
		if(min(nCols, nRows) < 2)
		{
			return false;
		}
		break;
	case method_spline:
		if(min(nCols, nRows) < 4)
		{
			return false;
		}
		break;
	case method_biquad:
		if(min(nCols , nRows) < 3)
		{
			return false;
		}
		break;
	
	default:
		return false;
	}
	
	return true;
}


void minterp2(const MatrixObject& im, const int& method, const int& cols, const int& rows, const double& xmin, const double& xmax, const double& ymin, const double& ymax, MatrixObject& om)
{
	if( !im.IsValid() || !om.IsValid() )
	{
		XF_THROW(XFERR_INVALID_MATOBJ)
	}
	
	if(!_check_input_matrix(method, im))
	{
		XF_THROW(XFERR_MATRIX_TOO_SMALL);		
	}
	
	//check parameter
	int nRows = im.GetNumRows(); 
	int nCols = im.GetNumCols();
	double dxMin, dyMin, dxMax, dyMax;
	im.GetXY(dxMin, dyMin, dxMax, dyMax);	
	
	double xNwMin = (xmin == NANUM)? dxMin : xmin; 
	double xNwMax = (xmax == NANUM)? dxMax : xmax; 
	double yNwMin = (ymin == NANUM)? dyMin : ymin; 
	double yNwMax = (ymax == NANUM)? dyMax : ymax; 
	//justin 09/04/2006
	//if(xNwMax - xNwMin <= 0 || yNwMax - yNwMin <=0 || cols <2 || rows < 2)
	if( cols < 1 || rows < 1) //if( cols < 2 || rows < 2)
	//end 
	{
		XF_THROW( CER_INVALID_SIZE )
	}
	
	//Matrix& mat = im.GetDataObject();
	matrix mat;
	im.GetDataObject().CastToDouble(mat); //_cast_to_double_matrix(im, mat); ///justin 09/08/2006 REPLACED_WITH_SIMPLE_METHOD
	
	//prepare xy coordinats
	vector vX, vY, vZ, vTmp1, vTmp2;
	if(cols == 1)
	{
		vTmp1.Add(xNwMin);
	}
	else
	{
		vTmp1.Data(xNwMin, xNwMax, (xNwMax - xNwMin)/(cols -1));
	}
	double dyInc =0; 
	if(rows != 1)
	{
		dyInc = (yNwMax - yNwMin)/(rows -1);
	}
	vTmp2.SetSize(cols);
	vTmp2 = yNwMin;
	for(int ii = 0; ii < rows; ii++)
	{
		vX.Append(vTmp1);
		vY.Append(vTmp2);
		vTmp2 += dyInc;
	}
	vZ.SetSize(cols*rows);
	///Sophy 6/25/2010 MEXPAND_ON_MAT_OBJ_CAUSE_OTHER_MATS_FILLED_WITH_ZEROS we do NOT allow matrixobjects with different dimensions on same layer, so it is reasonable to set size on layer level.
	//matrix& matDest = om.GetDataObject();
	//matDest.SetSize(rows, cols);
	MatrixLayer ml;
	om.GetParent(ml);
	ml.SetSize(-1, rows, cols);
	matrix& matDest = om.GetDataObject();
	///end MEXPAND_ON_MAT_OBJ_CAUSE_OTHER_MATS_FILLED_WITH_ZEROS
	
		
	// Fisher QA80-11334 REMOVE_MISSING_VALUE 
	vector vTmpX, vTmpY;
	/// Fisher 06/29/10 ORG-419	MINTERP2_XF_GOT_BAD_MISSING_VALUE_INTERP_RESULTS
	//vTmpX.Data(1.0, nCols, 1.0);
	//vTmpY.Data(1.0, nRows, 1.0);
	get_matrix_xymap(im, vTmpX, vTmpY);
	/// End MINTERP2_XF_GOT_BAD_MISSING_VALUE_INTERP_RESULTS
	int nRet = ocmath_2d_remove_missingvalue(vTmpX, vTmpY, mat, nRows, nCols);
	if(nRet != OE_NOERROR)
	{
		XF_THROW(nRet)
	}
	// END QA80-11334 REMOVE_MISSING_VALUE 
	
	nRet = ocmath_2d_interpolate(cols*rows, vX, vY, vZ, nRows, nCols, mat, dxMin, dxMax, dyMin, dyMax, method);
	if(nRet != OE_NOERROR)
	{
		XF_THROW(nRet)
	}
	//output
	matDest.SetByVector(vZ);
	om.SetXY(xNwMin, yNwMin, xNwMax, yNwMax);
	
}

//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 minterp2_event1(TreeNode& trGetN, int nRow, int nEventID, DWORD& dwEnables, LPCSTR lpcszNodeName, WndContainer& DynaCntrlContainer, string& strAux, string& strErrMsg)
{
	if( xf_is_extended_event(nEventID) )
		return minterp2_event1_ex(trGetN, nRow, nEventID, dwEnables, lpcszNodeName, DynaCntrlContainer, strAux, strErrMsg);
	DECLARE_BUTTON_ENABLES
	
	MatrixObject im;
	if(!( okxf_resolve_string_get_origin_object(trGetN.im.strVal, &im) && im.IsValid() && im.HasData(true)) )
	{
		///Sophy 6/25/2010 ORG-322-P1 BETTER_ERR_MSG_INFORM_CVT_IMAGE_TO_DATA
		//strErrMsg = XFERR_INVALID_MATOBJ;
		if ( !im.IsValid() )
			strErrMsg = XFERR_INVALID_MATOBJ;
		else
			strErrMsg = CER_COLOR_IMAGE_NEED_CVT;
		///end BETTER_ERR_MSG_INFORM_CVT_IMAGE_TO_DATA
		bOKEnable = false;
		return false;
	}
	
	//add checking for matrix size
	if(!_check_input_matrix(trGetN.method.nVal, im))
	{
		strErrMsg = XFERR_MATRIX_TOO_SMALL;
		bOKEnable = false;
		return false;		
	}
		
	if (GETNE_ON_INIT == nEventID || GETNE_ON_THEME == nEventID)  
	{
		_initial_parameters_without_value(trGetN);
	}
	
	return false;
	

}

int minterp2_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 minterp2_before_execute(TreeNode& trGetN, int nGetNDialog, int& nRet, int dwCntrl)
{
	
	if(0 == nGetNDialog || -1 == nGetNDialog)
	{
		_initial_parameters_without_value(trGetN);
	}
	
}
//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 minterp2_event1_ex(TreeNode& trGetN, int nRow, int nEventID, DWORD& dwEnables, LPCSTR lpcszNodeName, WndContainer& DynaCntrlContainer, string& strAux, string& strErrMsg)
{
	return false;
}
