#include <origin.h>
#include <GetNBox.h>
#include <xfutils.h>
enum{
	type_sum,
	type_max,
	type_min,
};
//put additional include files here
#include <GetNBox.h>
#include <image_utils.h>
//put your own support static functions here
bool copy_filter_to_pointer(L_INT* pFilter, int* pVector, int size)
{
	memcpy(pFilter, pVector, size * sizeof(int));
	return true;
}

static int _user_filter_image(BITMAPHANDLE* pLBmp, matrixbase& flt, int offset, int dv, int option)
{
	if(dv < 1)
		return XFERR_DIVISOR_NOT_VALID;
//	vector<uint> vFlag = {UD_SUM, UD_MAX, UD_MIN};
	//if(option > vFlag.GetSize() || option<0)
		//return false;
	int nxsize, nysize;
	nxsize = flt.GetNumCols();
	nysize = flt.GetNumRows();
	
	
	LPUSERFLT  pFilter; 

	pFilter = (LPUSERFLT)malloc(sizeof(USERFLT) + nxsize * nysize * sizeof(L_INT)); 


	pFilter->uStructSize 	= sizeof(USERFLT); 
	pFilter->ufltWidth 	= nxsize; 
	pFilter->ufltHeight	= nysize; 
	pFilter->ufltCenter.x	= (nxsize%2)?(nxsize/2):(nxsize/2+1); 
	pFilter->ufltCenter.y	= (nysize%2)?(nysize/2):(nysize/2+1); 
	pFilter->ufltDivisor 	= dv; 
	pFilter->nfltOffset 	= offset; 
	pFilter->ufltFlag 	= option ;//vFlag[option]; 
	
	vector<int> vflt;
	flt.GetAsVector(vflt);
	
	
	copy_filter_to_pointer(pFilter->ufltMatrix, vflt, nxsize * nysize);
	

	int nRet = L_UserFilterBitmap(pLBmp, pFilter);
	
	/* Free the filter */
	free(pFilter);
	return nRet;	
}

static bool _check_filter_matix_valid(string strFilter, string& strErrMsg)
{

	MatrixObject moFlt;
	okxf_resolve_string_get_origin_object(strFilter, &moFlt);
	if(!moFlt.IsValid())
	{
		strErrMsg = XFERR_INVALID_USER_FILTER_FOR_IMAGE;
		return false;
	}
	
	if(!moFlt.HasData(false))
	{
		strErrMsg =	XFERR_INVALID_USER_FILTER_FOR_MATRIX;
		return false;
	}
	
	int nCol = moFlt.GetNumCols();
	int nRow = moFlt.GetNumRows();
	if(nCol*nRow>=100)
	{
		strErrMsg = XFERR_FILTER_SIZE_TOO_LARGE;
		return false;
	}
	
	if( nCol < 3 || nRow < 3)
	{
		strErrMsg = XFERR_FILTER_TOO_SMALL;
		return false;
	}
	
	return true;
}


void imgUserfilter(const Image& img, Image& oimg, const MatrixObject& fltm, const int& offset, const int& dv, const int& type)
{
	
	
	
	matrix matFlt = fltm.GetDataObject();
	
	oimg.SetLBmp(img.GetLBmp(), TRUE);
	pBITMAPHANDLE phBmp = oimg.GetLBmp();	
	int nRet = _user_filter_image(phBmp, matFlt, offset, dv, type);	
	
	if(nRet < MAX_ERROR_CODE_FROM_LT)
		XF_THROW_EX(XFERR_LEADTOOLS_FUNCTION_UNKNOWN_ERR, nRet);
	
	if(nRet !=  SUCCESS)
		XF_THROW(nRet);
	
}

//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 imgUserfilter_event1(TreeNode& trGetN, int nRow, int nEventID, DWORD& dwEnables, LPCSTR lpcszNodeName, WndContainer& DynaCntrlContainer, string& strAux, string& strErrMsg)
{
	if( xf_is_extended_event(nEventID) )
		return imgUserfilter_event1_ex(trGetN, nRow, nEventID, dwEnables, lpcszNodeName, DynaCntrlContainer, strAux, strErrMsg);
	DECLARE_BUTTON_ENABLES
	return false;

}

int imgUserfilter_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 imgUserfilter_before_execute(TreeNode& trGetN, int nGetNDialog, int& nRet, int dwCntrl)
{

}
//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 imgUserfilter_event1_ex(TreeNode& trGetN, int nRow, int nEventID, DWORD& dwEnables, LPCSTR lpcszNodeName, WndContainer& DynaCntrlContainer, string& strAux, string& strErrMsg)
{
	return false;
}


// this is called when the GetNImageBox dialog is open
// bUpdateGrid = false when entering this function
// you need to set bUpdateGrid = true if you need to modify trGetN data and want to see the
// grid updated, for example
// trGetN.angle.nVal = 0; // force rotation to init to 0
// bUpdateGrid = true;
// bOKEnable is default = true, you may add code to check trGetN and decide that the OK button should be disabled, then set this to false
// example: 
// if(0==trGetN.angle.nVal) // no change, no point to click Ok to do nothing
//    bOKEnable = false; 
static void GetNImageBox_OnInit(TreeNode& trGetN, ImageControlBase* pimgCntrl, bool& bUpdateGrid, bool& bOKEnable, string& strErrMsg)
{
	
	bOKEnable = _check_filter_matix_valid(trGetN.fltm.strVal, strErrMsg);
	
	if(bOKEnable)
	{
		MatrixObject moFlt;
		okxf_resolve_string_get_origin_object(trGetN.fltm.strVal, &moFlt);	
		pBITMAPHANDLE pPreviewBitmap;
		pPreviewBitmap=pimgCntrl->GetBitmapHandlePtr();
		int nRet = _user_filter_image(pPreviewBitmap, moFlt.GetDataObject(), trGetN.offset.nVal, trGetN.dv.nVal, trGetN.type.nVal);
		if( SUCCESS != nRet)
		{
			strErrMsg = nRet;
			bOKEnable = false;
		}
	}

	bUpdateGrid = true;
}

// this is called whenever any controls in the grid is modified by the user
// upon entering function
// bUpdatePreview = true;// to update the preview image pPreviewBitmap
// bUpdateGrid = false; // event triggered by grid change, so default no need to update again
// if you want to modify other controls in the grid, then you need to set bUpdateGrid to true
// bOKEnable is default = true, you may add code to check trGetN and decide that the OK button should be disabled, then set this to false
static void GetNImageBox_OnChange(BITMAPHANDLE* pPreviewBitmap, TreeNode& trGetN, TreeNode& trNode, ImageControlBase* pimgCntrl, bool& bUpdatePreview, bool& bUpdateGrid, bool& bOKEnable, string& strErrMsg)
{
	
	if(!(bOKEnable = _check_filter_matix_valid(trGetN.fltm.strVal, strErrMsg)))
		return;

	
	MatrixObject moFlt;
	okxf_resolve_string_get_origin_object(trGetN.fltm.strVal, &moFlt);	
	int nRet = _user_filter_image(pPreviewBitmap, moFlt.GetDataObject(), trGetN.offset.nVal, trGetN.dv.nVal, trGetN.type.nVal);
	if( SUCCESS != nRet)
	{
		strErrMsg = nRet;
		bOKEnable = false;
	}
	else
	{
		bUpdatePreview=true;
	}
	
	bUpdateGrid = true;
}
	
int GetNImageBox_imgUserfilter(TreeNode& trGetN, int nRow, int nCol, TreeNode& trNode, DWORD dwCntrl, int nType, WndContainer& theDlg, ImageControlBase* pimgCntrl)
{
	return xf_GetNImageBox_event_handler(trGetN, nRow, nCol, trNode, dwCntrl, nType, pimgCntrl,
								GetNImageBox_OnInit, GetNImageBox_OnChange);	
}
