#include <origin.h>
#include <GetNBox.h>
#include <xfutils.h>


#include <GetNBox.h>
#include <image_utils.h>


static int _find_offset_image(BITMAPHANDLE* pDstLBmp,BITMAPHANDLE* pRefLBmp, int nOffsetX, int nOffsetY,int nOpacity)
{

	int nXDst, nYDst, nRefXSize, nRefYSize, nXSrc, nYSrc, nDstXSize, nDstYSize;
	nXDst=nOffsetX;
	nYDst=nOffsetY;
	
	nXSrc=nYSrc=0;
	
	nRefXSize=pRefLBmp->Width;
	nRefYSize=pRefLBmp->Height;
	nDstXSize=pDstLBmp->Width;
	nDstYSize=pDstLBmp->Height;
	
	if(nXDst <= -nDstXSize|| nXDst>= nDstXSize||nYDst<=-nDstYSize||nYDst>=nDstYSize)
		return INTOPTN_OUT_OF_RANGE;
	
	if(nOpacity>255||nOpacity<0)
		return INTOPTN_OUT_OF_RANGE;

	
	return  L_AlphaBlendBitmap(pDstLBmp,nXDst, nYDst, nRefXSize, nRefYSize,
    					pRefLBmp, nXSrc, nYSrc, nOpacity);

}

static int _offset_image(BITMAPHANDLE* pDstLBmp,BITMAPHANDLE* pSrcLBmp, int nOffsetX, int nOffsetY)
{

	UINT uWidth, uHeight;
	
	int nXSize=pSrcLBmp->Width;
	int nYSize=pSrcLBmp->Height;
	
	if(abs(nOffsetX)>nXSize ||abs(nOffsetY)>nYSize)
		return INTOPTN_OUT_OF_RANGE;	

	uWidth=pSrcLBmp->Width-nOffsetX;
	uHeight=pSrcLBmp->Height-nOffsetY;
	
	return   L_COPY_BITMAP_RECT(pDstLBmp, pSrcLBmp,  nOffsetX, nOffsetY, uWidth, uHeight);
}


static bool _chech_images_set_range_of_offset(TreeNode& trGetN, string& strErrMsg)
{
	
	Image imgRef, imgTaget;
	string strimg=trGetN.img.strVal;
	okxf_resolve_string_get_origin_object(strimg, &imgTaget);
	

	if(!imgTaget.IsValid())
	{
		strErrMsg = XFERR_INVALID_IMAGE;
		return false;
	}
		
	strimg=trGetN.imgr.strVal;	
	okxf_resolve_string_get_origin_object(strimg, &imgRef);

	if(!imgRef.IsValid())
	{
		strErrMsg = XFWAR_TO_SELECT_REF_IMG;
		return false;
	}
	

	BITMAPHANDLE* pBmpRef=imgRef.GetLBmp();
	BITMAPHANDLE* pBmpTag=imgTaget.GetLBmp();
	
	String str;
	int nMin = (-pBmpTag->Width+1)/2;
	int nMax = (pBmpTag->Width-1)/2;
    str.Format("%d|%d|%d",nMin,nMax,300);
	trGetN.x.SetAttribute(STR_COMBO_ATTRIB,str);
	
	if(trGetN.x.nVal <nMin || trGetN.x.nVal >nMax)
	{
		strErrMsg = INTOPTN_OUT_OF_RANGE;
		return false;
	}
	
	
	nMin = (-pBmpTag->Height+1)/2;
	nMax = (pBmpTag->Height-1)/2;
	str.Format("%d|%d|%d",nMin ,nMax, 300);
	trGetN.y.SetAttribute(STR_COMBO_ATTRIB,str);
	


	if(trGetN.y.nVal <nMin || trGetN.y.nVal >nMax)
	{
		strErrMsg = INTOPTN_OUT_OF_RANGE;
		return false;
	}
	
	return true;
}

static BITMAPHANDLE* _get_ref_img_from_get(TreeNode trGetN)
{
	if(!trGetN)
		return NULL;
	ASSERT(trGetN.imgr);
	Image imgRef;
	string strimg=trGetN.imgr.strVal;
	if(okxf_resolve_string_get_origin_object(strimg, &imgRef))
		return imgRef.GetLBmp();
	else
		return NULL;
}

void imgOffset(const Image& img, const Image& imgr, const int& x, const int& y, const int& o, Image& oimg)
{
		
	oimg.SetLBmp(img.GetLBmp(), true);
	
	BITMAPHANDLE* pdstBmp = oimg.GetLBmp();
	BITMAPHANDLE* prefBmp = img.GetLBmp();
	
	int nRet = _offset_image(pdstBmp,prefBmp,x,y);
	
	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 imgOffset_event1(TreeNode& trGetN, int nRow, int nEventID, DWORD& dwEnables, LPCSTR lpcszNodeName, WndContainer& DynaCntrlContainer, string& strAux, string& strErrMsg)
{
	if( xf_is_extended_event(nEventID) )
		return imgOffset_event1_ex(trGetN, nRow, nEventID, dwEnables, lpcszNodeName, DynaCntrlContainer, strAux, strErrMsg);
	DECLARE_BUTTON_ENABLES
	return false;

}

int imgOffset_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 imgOffset_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 imgOffset_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 = _chech_images_set_range_of_offset(trGetN, strErrMsg);

	
	//pBITMAPHANDLE pBmp=pimgCntrl->GetBitmapHandlePtr();
	
	//String str;
    //str.Format("%d|%d|%d",-pBmp->Width,pBmp->Width,300);
	//trGetN.x.SetAttribute(STR_COMBO_ATTRIB,str);
	//trGetN.x.nVal=0;
//
	//str.Format("%d|%d|%d",-pBmp->Height,pBmp->Height,300);
	//trGetN.y.SetAttribute(STR_COMBO_ATTRIB,str);
	//trGetN.y.nVal=0;
	
	//trGetN.o.nVal=128;
	
	//strErrMsg = XFWAR_TO_SELECT_REF_IMG;
	if(bOKEnable)
	{
		pBITMAPHANDLE pPreviewBitmap;
		pPreviewBitmap=pimgCntrl->GetBitmapHandlePtr();	
		BITMAPHANDLE* pBmpRef = _get_ref_img_from_get(trGetN);
		int nRet = _find_offset_image( pPreviewBitmap, pBmpRef,  trGetN.x.nVal, trGetN.y.nVal,trGetN.o.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)
{

	bOKEnable = _chech_images_set_range_of_offset(trGetN, strErrMsg);
	
	if(bOKEnable)
	{
		BITMAPHANDLE* pBmpRef = _get_ref_img_from_get(trGetN);
		//Image imgRef;
		//string strimg=trGetN.imgr.strVal;
		//okxf_resolve_string_get_origin_object(strimg, &imgRef);
		//BITMAPHANDLE* pBmpRef=imgRef.GetLBmp();
		
			
		int nRet = _find_offset_image( pPreviewBitmap,pBmpRef,  trGetN.x.nVal, trGetN.y.nVal,trGetN.o.nVal);
		if( SUCCESS != nRet)
		{
			strErrMsg = nRet;
			bUpdatePreview = false;
			bOKEnable = false;
		}		
	}
	

	
	bUpdatePreview=true;
	
	
}
	
int GetNImageBox_imgOffset(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);	
}
