#include <origin.h>
#include <GetNBox.h>
#include <xfutils.h>
enum{
	c1_master,
	c1_red,
	c1_green,
	c1_blue,
};
enum{
	c2_master,
	c2_red,
	c2_green,
	c2_blue,
};
enum{
	func_and,
	func_or,
	func_xor,
	func_add,
	func_sub12,
	func_sub21,
	func_mul,
	func_div12,
	func_div21,
	func_avg,
	func_min,
	func_max,
	func_abs,
};


#include <GetNBox.h>
#include <image_utils.h>
#define MATRIX_PAGE_REFERENCE "Reference"

enum{
	IMGB_ORIGINAL = 0,
	IMGB_INTERSECT,

};

static BOOL _check_input_arg(TreeNode& trGetN, string& strErrMsg, pBITMAPHANDLE* ppimgc, pBITMAPHANDLE* ppimgi)
{
	string strimg1=trGetN.img2.strVal;
	string strimg2=trGetN.img1.strVal;

	Image imgc;
	okxf_resolve_string_get_origin_object(strimg1, &imgc);
	Image imgi;
	okxf_resolve_string_get_origin_object(strimg2, &imgi);

	if(!imgi.IsValid())
	{
		trGetN.img1.Reset(true);
		strErrMsg = XFERR_INVALID_IMAGE_TO_BLEND;
		return false;
	}
	
	if(!imgc.IsValid())
	{
		trGetN.img2.Reset(true);
		strErrMsg = XFERR_INVALID_IMAGE_TO_BLEND;
		return false;
	}
	
	*ppimgc = imgc.GetLBmp();
	*ppimgi = imgi.GetLBmp();
	return true;
}

//Sandy 2007-5-5 support offset 
//static int _combine_image(BITMAPHANDLE* pDstLBmp,BITMAPHANDLE* pSrcLBmp, UINT uMType,
				 //UINT uChannel1,  UINT uChannel2)
static int _combine_image(BITMAPHANDLE* pDstLBmp,BITMAPHANDLE* pSrcLBmp, UINT uMType,
				 UINT uChannel1,  UINT uChannel2, int x, int y, int nOption)
{

	vector<int> vnFlags = {	CB_OP_AND,CB_OP_OR,CB_OP_XOR	,CB_OP_ADD,
						   CB_OP_SUBSRC,CB_OP_SUBDST,CB_OP_MUL,CB_OP_DIVSRC,
						   CB_OP_DIVDST,CB_OP_AVG,CB_OP_MIN,CB_OP_MAX, CB_OP_ABSDIF};
						   
	vector<int> vnSrcChannel = {CB_SRC_MASTER,CB_SRC_RED,CB_SRC_GREEN,CB_SRC_BLUE};
	vector<int> vnDstChannel = {CB_DST_MASTER,CB_DST_RED,CB_DST_GREEN,CB_DST_BLUE};
	vector<int> vnResChannel = {CB_RES_MASTER,CB_RES_RED,CB_RES_GREEN,CB_RES_BLUE};
	
	if(uMType < 0 || uMType >= vnFlags.GetSize())
		return INTOPTN_OUT_OF_RANGE;
	
	if(uChannel1 < 0 || uChannel1 >= vnSrcChannel.GetSize())
		return INTOPTN_OUT_OF_RANGE;
	
	if(uChannel2 < 0 || uChannel2 >= vnDstChannel.GetSize())
		return INTOPTN_OUT_OF_RANGE;
	
	UINT uFlag =vnFlags[uMType]|vnSrcChannel[uChannel1]|vnDstChannel[uChannel2]|vnResChannel[uChannel1];
 
	//Sandy 2007-5-5 support offset 
	//int nXDst, nYDst, nXSize, nYSize,nXSrc, nYSrc;
	//nXDst=nYDst=nXSrc=nYSrc=0;
	//nXSize=pDstLBmp->Width;
	//nYSize=pDstLBmp->Height;
	//return  L_CombineBitmapExt(pDstLBmp,nXDst, nYDst, nXSize, nYSize,pSrcLBmp, nXSrc, nYSrc, uFlag);
	
	int nXSize, nYSize;
	nXSize=pSrcLBmp->Width;
	nYSize=pSrcLBmp->Height;
	int nRet = L_CombineBitmapExt(pDstLBmp,x, y, nXSize, nYSize,pSrcLBmp, 0, 0, uFlag);
	if(SUCCESS != nRet)
		return nRet;
	
	if(nOption == IMGB_INTERSECT)
	{
		//-------CPY 5/4/07 PROPER_CROPPING_IN_RESULT
		//return L_TrimBitmap(pDstLBmp, x, y, nXSize-x, nYSize-y);
		RECT rSrc = {0}, rDest = {0};
		rSrc.right = pSrcLBmp->Width, rSrc.bottom = pSrcLBmp->Height;
		rDest.right =pDstLBmp->Width,rDest.bottom = pDstLBmp->Height;
		OffsetRect(&rSrc, x, y);
		RECT rResult;
		if(!IntersectRect(&rResult, &rSrc, &rDest))
			return -1;
		int nCropWidth = RECT_WIDTH(rResult);
		int nCropHeight = RECT_HEIGHT(rResult);

		return L_TrimBitmap(pDstLBmp, rResult.left, rResult.top, nCropWidth, nCropHeight);
		//------- end PROPER_CROPPING_IN_RESULT
	}	
	
	return SUCCESS;
	//end
    					
}

static int _factor_image(BITMAPHANDLE* pLBmp, double dFactor, int uChannel)
{
	vector<int> vnChannel = {CHANNEL_MASTER,CHANNEL_RED,CHANNEL_GREEN,CHANNEL_BLUE};
	
	int nFlag = AML_OP_MUL|vnChannel[uChannel];
	int nFactor = dFactor*100;
	return L_ApplyMathLogicBitmap(pLBmp,nFactor, nFlag);
}

static void destroy_temp_MatrixObject()
{
	MatrixPage mpTemp(MATRIX_PAGE_REFERENCE);
	if(mpTemp.IsValid())
	{
		mpTemp.Destroy();
	}
}

static MatrixObject& create_temp_MatrixObject()
{
	MatrixPage mpTemp(MATRIX_PAGE_REFERENCE);
	if(!mpTemp.IsValid())
	{
		mpTemp.Create("Origin", CREATE_HIDDEN|CREATE_SET_MISSING_IN_MANAGER );
		mpTemp.Rename(MATRIX_PAGE_REFERENCE);
	}	
	
	MatrixLayer ml = mpTemp.Layers(0);
	return ml.MatrixObjects(0);
}

static bool _update_preview(TreeNode& trGetN, BITMAPHANDLE* pPreviewBitmap, string& strErrMsg)
{
	string strimg=trGetN.img2.strVal;
	Image imgRef;
	okxf_resolve_string_get_origin_object(strimg, &imgRef);	
	
	MatrixObject moCopy = create_temp_MatrixObject();
	imgRef.CopyTo(moCopy);
	
	Image imgcpy(moCopy);
		
	
	BITMAPHANDLE* pCpyBmp=imgcpy.GetLBmp();
	
	int nRet;
	///Sandy 2007-9-5 add z offset of image1 as CP suggested
	if(trGetN.z1.nVal != 0)
	{
		int nFlag = AML_OP_ADD|trGetN.c1.nVal;
	
		nRet = L_ApplyMathLogicBitmap(pPreviewBitmap, trGetN.z1.nVal, nFlag);
		if( SUCCESS != nRet)
		{
			//XF_THROW_EX(XFERR_LEADTOOLS_FUNCTION_UNKNOWN_ERR, nRet);
			if(nRet == -13)
			{
				strErrMsg = XFERR_INVALID_ARG;
			}
			else
				strErrMsg = nRet;
			return false;
		}
	}
	///end	
	
	nRet = _factor_image(pPreviewBitmap, trGetN.f1.nVal,  trGetN.c1.nVal);
	if( SUCCESS != nRet)
	{
		if(nRet == -13)
			strErrMsg = XFERR_INVALID_ARG;
		else
			strErrMsg = nRet;
	}
	
	nRet = _factor_image(pCpyBmp, trGetN.f2.nVal,  trGetN.c2.nVal);
	if( SUCCESS != nRet)
	{
		if(nRet == -13)
			strErrMsg = XFERR_INVALID_ARG;
		else
			strErrMsg = nRet;
		return false;
	}
	
	nRet = _combine_image(pPreviewBitmap, pCpyBmp, trGetN.func.nVal, trGetN.c1.nVal, trGetN.c2.nVal, 
			trGetN.x.nVal, trGetN.y.nVal, false);
	if( SUCCESS != nRet)
	{
		if(nRet == -13)
			strErrMsg = XFERR_INVALID_ARG;
		else
			strErrMsg = nRet;
		return false;
	}
	
	return true;
}

static void _update_offset_x_y(BITMAPHANDLE* pimgc, BITMAPHANDLE* pPreviewBitmap, TreeNode trGetN)
{
	int nw1, nh1, nw2, nh2;
	if(pimgc)
	{
		nw1 = pimgc->Width;
		nh1 = pimgc->Height;		
	}

	if(pPreviewBitmap)
	{
		nw2 = pPreviewBitmap->Width;
		nh2 = pPreviewBitmap->Height;			
	}
	String strV;
	if(nw1 > 0 && nh1 > 0 && nw2 > 0 && nh2 > 0 )
	{
		strV.Format("%d|%d|%d",-nw1+1,nw2-1,nw1+nw2-2);
		trGetN.x.SetAttribute(STR_COMBO_ATTRIB,strV);
		strV.Format("%d|%d|%d",-nh1+1,nh2-1,nh1+nh2-2);
		trGetN.y.SetAttribute(STR_COMBO_ATTRIB,strV);
	}
	
	//trGetN.x.nVal = 0;
	//trGetN.y.nVal = 0;

}

void imgSimpleMath(const Image& img1, const int& c1, const double& f1, const int& z1, const Image& img2, const int& c2, const double& f2, const int& func, Image& oimg, const int& x, const int& y, const int& crop)
{
	
	
	
	MatrixObject moCopy = create_temp_MatrixObject();
	img2.CopyTo(moCopy);
	
	Image imgcpy(moCopy);
	
	oimg.SetLBmp(img1.GetLBmp(), true);
	
	BITMAPHANDLE* pdstBmp = oimg.GetLBmp();
	BITMAPHANDLE* prefBmp = imgcpy.GetLBmp();
	
	if(!pdstBmp || !prefBmp)
		XF_THROW(XFERR_INVALID_IMAGE_TO_BLEND);	
		
	int nRet;	
	///Sandy 2007-9-5 add z offset of image1 as CP suggested
	if(z1 != 0)
	{
		int nFlag = AML_OP_ADD|c1;
	
		nRet = L_ApplyMathLogicBitmap(pdstBmp, z1, nFlag);
		if( SUCCESS != nRet)
		{
			//XF_THROW_EX(XFERR_LEADTOOLS_FUNCTION_UNKNOWN_ERR, nRet);
			if(nRet == -13)
			{
				XF_THROW(XFERR_INVALID_ARG);
			}
			else
				XF_THROW_EX(XFERR_LEADTOOLS_FUNCTION_UNKNOWN_ERR, nRet);
		}
	}
	///end		
		
	
	nRet = _factor_image(pdstBmp, f1,  c1);
	if( SUCCESS != nRet)
	{
		destroy_temp_MatrixObject();
		//XF_THROW_EX(XFERR_LEADTOOLS_FUNCTION_UNKNOWN_ERR, nRet);
		if(nRet == -13)
		{
			XF_THROW(XFERR_INVALID_ARG);
		}
		else
			XF_THROW_EX(XFERR_LEADTOOLS_FUNCTION_UNKNOWN_ERR, nRet);
	}
	nRet = _factor_image(prefBmp, f2, c2);
	if( SUCCESS != nRet)
	{
		//XF_THROW_EX(XFERR_LEADTOOLS_FUNCTION_UNKNOWN_ERR, nRet);
		if(nRet == -13)
		{
			XF_THROW(XFERR_INVALID_ARG);
		}
		else
			XF_THROW_EX(XFERR_LEADTOOLS_FUNCTION_UNKNOWN_ERR, nRet);
	}
	
	
	
	nRet = 	_combine_image(pdstBmp,prefBmp, func, c1, c2, x, y, crop);
	
	destroy_temp_MatrixObject();
	
	if(nRet < MAX_ERROR_CODE_FROM_LT)
	{
		
		if(nRet == -13)
		{
			XF_THROW(XFERR_INVALID_ARG);
		}
		else
			XF_THROW_EX(XFERR_LEADTOOLS_FUNCTION_UNKNOWN_ERR, nRet);
		//if( -13 == nRet )
			//XF_THROW(XFERR_INVALID_ARG);
		//else
			//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 imgSimpleMath_event1(TreeNode& trGetN, int nRow, int nEventID, DWORD& dwEnables, LPCSTR lpcszNodeName, WndContainer& DynaCntrlContainer, string& strAux, string& strErrMsg)
{
	if( xf_is_extended_event(nEventID) )
		return imgSimpleMath_event1_ex(trGetN, nRow, nEventID, dwEnables, lpcszNodeName, DynaCntrlContainer, strAux, strErrMsg);
	DECLARE_BUTTON_ENABLES
	
	return false;

}

int imgSimpleMath_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 imgSimpleMath_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 imgSimpleMath_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)
{
	//strErrMsg = XFERR_INVALID_IMAGE_TO_COMBINE;
	
	pBITMAPHANDLE pimgc=NULL, pimgi=NULL;
	bOKEnable = _check_input_arg(trGetN, strErrMsg, &pimgc, &pimgi);
	
	//create_temp_MatrixObject();
	pBITMAPHANDLE pPreviewBitmap;
	pPreviewBitmap=pimgCntrl->GetBitmapHandlePtr();
	
	//_update_offset_x_y(pimgc, pPreviewBitmap, trGetN);
	
	if(bOKEnable)
		bOKEnable =	_update_preview(trGetN, pPreviewBitmap, strErrMsg);
	
	if(bOKEnable)
		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)
{
	pBITMAPHANDLE pimgc, pimgi;
	bOKEnable = _check_input_arg(trGetN, strErrMsg, &pimgc, &pimgi);
	if(!bOKEnable)
		return;	
		
		
	//string strimg=trGetN.imgc.strVal;
	////
	//Image imgRef;
	//okxf_resolve_string_get_origin_object(strimg, &imgRef);	
	//
	//if(!imgRef.IsValid())
	//{
		//strErrMsg = XFERR_INVALID_IMAGE_TO_COMBINE;
		//bOKEnable = false;
		//return;
	//}
	
	///Sandy 2007-5-5 add for support optional offset
	//BITMAPHANDLE* pimgRef = imgRef.GetLBmp();



	if(trNode.IsValid())
	{
		if(trNode.tagName == "img2")
		{
			_update_offset_x_y(pimgc, pPreviewBitmap, trGetN);
		}
	}
	//end
	
	bOKEnable =	_update_preview(trGetN, pPreviewBitmap, strErrMsg);

	if(bOKEnable)
		bUpdatePreview=true;

	
}
	
int GetNImageBox_imgSimpleMath(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);	
}
