#ifndef _IMG_BACKGROUND_DATA_H
#define _IMG_BACKGROUND_DATA_H

//#include <ocImgLT.h>
//#include <image_utils.h>
//#include <wks2mat.h>
//#include <Nag_utils.h>
//#include <image_utils.h>
//#include <..\originlab\ImgChannelData.h>

#define ATTACH_TO_SCALE 2
#define MAX_NUM_POINTS 10
#define MIN_NUM_POINTS 3
#define MATRIX_PAGE_BACKGROUND "Background"
#define MATRIX_PAGE_SRCIMG "SourceImg"
#define GO_CNTL_POINT     "CntlPnt"
#define IMGSIB_PREVIEW_DATA "imgSubtractInterpBackground_data"

#define MATRIX_PAGE_BACKGROUND "Background"

enum{
	ANCHOR_SHAPE_ELLI,
	ANCHOR_SHAPE_RECT,
};

int events_from_control_go()
{
	return _events_from_control_go();
}
		
//
//int matrix_subtract_data_matrix(MatrixObject& mo, MatrixObject& mi, bool bIsHiBG)
//{
//
	//Matrix& mato = mo.GetDataObject();
	//Matrix& mati = mi.GetDataObject();
	//
	//int nOperation;
	//if(bIsHiBG)  
	//{
	 	//L_InvertBitmap(pTargetLBmp);
	 	//nOperation = CB_OP_ADD;
	//}
	//else
	//{
		//nOperation = CB_OP_SUBDST;
	//}
//
						   //
	//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(uChannel < 0 || uChannel >= vnSrcChannel.GetSize())
		//return INTOPTN_OUT_OF_RANGE;
	//
	//UINT uFlag =nOperation|vnSrcChannel[uChannel]|vnDstChannel[uChannel]|vnResChannel[uChannel];
 //
	//int nXDst, nYDst, nXSize, nYSize,nXSrc, nYSrc;
	//nXDst=nYDst=nXSrc=nYSrc=0;
	//nXSize=pTargetLBmp->Width;
	//nYSize=pTargetLBmp->Height;
	//
	//int nRet = L_CombineBitmapExt(pTargetLBmp,nXDst, nYDst, nXSize, nYSize,
    					//pSrcLBmp, nXSrc, nYSrc, uFlag);
//
	//if(bIsHiBG)  
	//{
	 	//L_InvertBitmap(pTargetLBmp);
	 	////L_InvertBitmap(pSrcLBmp);
	//}		
					//
	//return nRet;    					
//}

class OCImgInterpBgData: public OCImgROIPreview
{
public:

	OCImgInterpBgData(MatrixObject& mobj,  LPCSTR lpcstrPreviewPage)
			:OCImgROIPreview(mobj,  lpcstrPreviewPage, EXIST_MATRIX){}
			
	~OCImgInterpBgData():~OCImgROIPreview()
	{
		remove_GraphObjects_with_prefix(m_mlParent, GO_CNTL_POINT );
	}


	bool UpdatePreviewData();

	void SetBGBrightness(int nBrightness)
	{
		m_nBrightness = nBrightness;
	}
	
	void SetApplyAutoLevel(bool bAuto = true)
	{
		m_bAutoLevel = bAuto;
	}
	//bool InitAnchors(int npts, int nRadius, int nShape);
	bool InitAnchors(TreeNode& tr);
	bool EditAnchors(int npts,  int nShape, TreeNode& tr);
	
	bool GetSubtractedResult(MatrixObject& mo);
	
	void SetHiBG(bool bHiBG)
	{
		m_bHiBG = bHiBG;
	}
	
	bool SetupGraphPreview();
	
	bool SaveAnchors(TreeNode& tr)
	{
	
		return save_anchors_to_tree(m_mlParent, tr, GO_CNTL_POINT);
		//tr.Replace(m_trAnchors, true, true, true);
		//
		//
		//if(tr.IsValid())
			//return true;
		//else
			//return false;
	}

	
private:
	//bool changeAnchorsShape(int nShape);	
	bool initAnchor(int nShape, int nX, int nY,int nRadius = 0);
	void trimAnchors(int npts);
	bool getROIBorderXYandZMean(vector& vX, vector& vY, vector& vZ);	

private:
	MatrixLayer m_mlBgPreview;
	MatrixLayer m_mlRsPreview;
	
	MatrixObject m_moBackgroundImg;
	MatrixObject m_moBackgroundData;
	MatrixObject m_moResultImg;

	//int m_nAnchorShape;
	//int m_nAnchorNum;
	int m_nBrightness;
	bool m_bHiBG;
	bool m_bAutoLevel;
	//Tree m_trAnchors;
	
};

bool OCImgInterpBgData::SetupGraphPreview()
{
	
	if(m_gpPreview.IsValid())
		m_gpPreview.Destroy();
	
	
	m_mlBgPreview = m_pTempData.Layers(0);
 	int nNewLayerInd = m_pTempData.AddLayer();
 	m_mlRsPreview = m_pTempData.Layers(1);
 	
 	m_mlBgPreview.SetName("Background");
 	m_mlRsPreview.SetName("After subtracted");
 	m_pTempData.SetShow();
 	m_mlRsPreview.CheckShowActivate();   //Sandy 2008-9-28 add as Howard's suggested 

	
	m_mlBgPreview.SetSize(2, m_nRows , m_nCols);
	m_moBackgroundImg = m_mlBgPreview.MatrixObjects(0);	
	m_moBackgroundData = m_mlBgPreview.MatrixObjects(1);
	
	m_mlRsPreview.SetSize(1, m_nRows , m_nCols);
	m_moResultImg = m_mlRsPreview.MatrixObjects(0);	
	
	m_mlRsPreview.SetViewImage();
	
	
	//MatrixLayer  ml = m_dsTempData;
	//ml.SetSize(3, m_nRows, m_nCols);
	//MatrixObject& moBackground = ml.MatrixObjects(0);
	//MatrixObject& moResult = ml.MatrixObjects(1);
	//
	//page_load(m_gpPreview, "imgSubtractInterpBackgroundPreview");
	//GraphLayer gl1 = m_gpPreview.Layers(0);
	//GraphLayer gl2 = m_gpPreview.Layers(1);
 	//if(-1 == gl1.AddPlot(moBackground, IDM_PLOT_MATRIX_IMAGE))
 	//{
 		//return false;
 	//}
 	//
  	//if(-1 == gl2.AddPlot(moResult, IDM_PLOT_MATRIX_IMAGE))
 	//{
 		//return false;
 	//}	
 	//
 	//gl1.Rescale();
 	//gl2.Rescale();

	return true;	

}
//
//bool OCImgInterpBgData::changeAnchorsShape(int nShape)
//{
	////vector<int> vx(MAX_NUM_POINTS), vy(MAX_NUM_POINTS);
	////int iCount = 0;
	////foreach(GraphObject go in m_mlParent.GraphObjects)
	////{
		////string str = go.GetName();
		////if(0 == strncmp(str, GO_CNTL_POINT, strlen(GO_CNTL_POINT)))
		////{
			////
			////vx[iCount] = go.X;
			////vy[iCount] = go.Y;
			////iCount++;
			////go.Destroy();
		////}
	////}
		////
	////for(int jj = 0; jj<iCount; jj++)
	////{
		////if(!initAnchor(nShape, vx[jj], vy[jj]))
			////return false;
	////}
	////
	//////m_nAnchorShape = nShape;
	//
	//int nObjectType = s_vnObjectType[nShape];
	//update_tree_anchors_object_type(nObjectType, m_trAnchors);
	//
	//remove_GraphObjects_with_prefix(m_mlParent, GO_CNTL_POINT);
	//
	////if(!DrawAnchor(m_trAnchor))
		////return false;
	////return save_anchors_to_tree(m_mlParent,m_trAnchor, GO_ROI_NAME);
	//return InitAnchors(m_trAnchors);	
	////return true;
//
	//
//}

bool OCImgInterpBgData::getROIBorderXYandZMean(vector& vX, vector& vY, vector& vZ)
{
	int npts = 0;
	
	foreach(GraphObject go in m_mlParent.GraphObjects)
	{
		PolylineGraphObject pgo;
		pgo = go;
		
		string str = go.GetName();
		if(0 == strncmp(str, GO_CNTL_POINT, strlen(GO_CNTL_POINT)))
		{
			vector vx, vy, vz;

			pgo.GetPoints(vx, vy);
			m_moIntensity.GetRegionPoints(vx, vy, vz); 
			
			//mean value of vz;
			double dSum;
			vz.Sum(dSum);
			double dMean = dSum/vz.GetSize();
			
			vX[npts] = pgo.X;
			vY[npts] = pgo.Y;
			vZ[npts] = dMean;
			npts ++;
		}	
	}
	
	vX.SetSize(npts); 
	vY.SetSize(npts);
	vZ.SetSize(npts);
	return true;
}	

bool OCImgInterpBgData::UpdatePreviewData()
{
	vector vX(MAX_NUM_POINTS), vY(MAX_NUM_POINTS), vZ(MAX_NUM_POINTS);
	
	if(!getROIBorderXYandZMean(vX, vY, vZ))
		return false;

	//matrix& matSrc = m_moIntensity.GetDataObject(); 
	matobj_copy(m_moBackgroundData, m_moIntensity);
	matrix& matBackground = m_moBackgroundData.GetDataObject();
	if(0 != compute_surface_from_anchor_points(vX, vY, vZ,  m_nRows , m_nCols, matBackground))
		return false;
	

	//MatrixObject& moImg = ml.MatrixObjects(2);
	//MatrixObject& moImgSrc = ml.MatrixObjects(3);
	//matobj_copy(moResult, moBackground);
	//image_convert_from_data(moResult, moImg, 0, 255, 8);
	
	//add code to decide the color_bits	
	//double dmin = matBackground.GetMin();
	//double dmax = matBackground.GetMax();
	//
	//
	//int nbits = 8;
	//if(dmax > 4095)
		//nbits = 16;
	//else if(dmax > 255)
		//nbits = 12;	

	double dmax, dmin;
	Image img(m_moSrcImage);
	pBITMAPHANDLE pBmp = img.GetLBmp();
	dmax = get_image_data_max_val(pBmp);
	dmin = 0;
	m_moBackgroundImg.SetInternalDataType(FSI_BYTE, OCD_RESET_VIEW);
	int nbits = 8;
	if(dmax > 255)
	{
		m_moBackgroundImg.SetInternalDataType(FSI_SHORT, OCD_RESET_VIEW);
		nbits = 16;
	}

	
	image_convert_from_data(m_moBackgroundData, m_moBackgroundImg, dmin, dmax, nbits);

	GetSubtractedResult(m_moResultImg);
	
	//save_anchors_to_tree(m_mlParent,m_trAnchors, GO_CNTL_POINT);
	//UINT uChannel = 0;
	//matobj_copy(m_moResultImg, m_moBackgroundImg);
	//int nRet = image_subtract_background(m_moResultImg, m_moSrcImage,uChannel,m_bHiBG);
	//if( SUCCESS != nRet)
	//{
		//return false;
	//}

	return true;
	
}



bool OCImgInterpBgData::initAnchor(int nShape, int nX, int nY,int nRadius )
{
	GraphObject go;

	int nr = (nRadius<=0? 10:nRadius);
	if(nShape == ANCHOR_SHAPE_RECT)
	{	
		if( !add_rect(m_mlParent, go, nX-nr, nY-nr, nX+nr, nY+nr, INDEX_COLOR_TRANSPARENT,  ATTACH_TO_SCALE, LN_FREE, false,  false) )
			return false;
	}
	else
	{
		if( !add_ellipse(m_mlParent, go, nX-nr, nY-nr, nX+nr, nY+nr, INDEX_COLOR_TRANSPARENT,  ATTACH_TO_SCALE,  false) )
			return false;			
	}
		
	go.SetName(GO_CNTL_POINT);
	set_go_border_color(go, SYSCOLOR_GREEN);
	set_LT_script(go, "events_from_control_go;" , GRCT_SIZEMOVE);	
		
	return true;
}

bool OCImgInterpBgData::GetSubtractedResult(MatrixObject& mo)
{
	MatrixPage mpTemp;
	mpTemp.Create("Origin", CREATE_HIDDEN | CREATE_SET_MISSING_IN_MANAGER);
	MatrixLayer mlTemp = mpTemp.Layers(0);
	MatrixObject moTemp = mlTemp.MatrixObjects(0);
	
	if(!m_moSrcImage.HasData(false))
	{
		if(m_nBrightness!=0)
		{
			if(SUCCESS != adjust_image_brightness(m_moBackgroundImg, m_nBrightness))
				return false;	
		}


		MatrixObject& mobg = m_mlBgPreview.MatrixObjects(0);
	
		UINT uChannel = 0;
		matobj_copy(moTemp, mobg);
		int nRet = gray_image_subtract_background(moTemp, m_moSrcImage,uChannel,m_bHiBG);
		if( SUCCESS != nRet)
		{
			return false;
		}
	

		if(m_bAutoLevel)
		{
			nRet = auto_level_image(moTemp, 2);//auto intensity
			if( SUCCESS != nRet)
			{
				return false;
			}
		}
	}
	else
	{
		///Sandy 2007-1-15 add consider for data matrix
		m_moBackgroundData.SetInternalData(FSI_DOUBLE);
		m_moSrcImage.SetInternalData(FSI_DOUBLE);
		matobj_copy(moTemp, m_moBackgroundData);
		matrix& matSrc = m_moSrcImage.GetDataObject();
		matrix& matTag = moTemp.GetDataObject();
		
		if(m_bHiBG)
		   matTag = matTag - matSrc ;

		else
		   matTag =  matSrc - matTag;
		return true;
		///end
	}
	
	matobj_copy(mo, moTemp);
	
	moTemp.Destroy();

	return true;
}

void OCImgInterpBgData::trimAnchors(int npts)
{
	int ii = 0;
	foreach(GraphObject go in m_mlParent.GraphObjects)
	{
		string str = go.GetName();
		if(0 == strncmp(str, GO_CNTL_POINT, strlen(GO_CNTL_POINT)))
		{	
			ii++;
			if(ii > npts)
			{
				go.Destroy();
			}
		}
	}
		
	//m_nAnchorNum = npts;
}

bool OCImgInterpBgData::InitAnchors(TreeNode& trAnchors)//int npts, int nRadius, int nShape)
{
	
	remove_GraphObjects_with_prefix(m_mlParent,GO_CNTL_POINT );
	
	
	if(!trAnchors.IsValid())
		return false;

	if(!read_and_create_anchors_from_tree(m_mlParent, trAnchors, GO_CNTL_POINT))
	{

		int w = m_nCols/4;
		int h = m_nRows/4;
		int r = min(m_nCols, m_nRows)/25 ;
		

		initAnchor(ANCHOR_SHAPE_ELLI, m_nCols - w, h, r);
		initAnchor(ANCHOR_SHAPE_ELLI, w, m_nRows - h, r);
		initAnchor(ANCHOR_SHAPE_ELLI, m_nCols - w, m_nRows - h, r);
		//
		//for(int ii = 4; ii<=npts; ii++)
		//{
			//initAnchor(nShape, w+ii*r, h+ii*r, r);
		//}
		//m_nAnchorNum = 3;
	}
	save_anchors_to_tree(m_mlParent, trAnchors, GO_CNTL_POINT);
	//m_nAnchorNum = trAnchors.Number.nVal;
	foreach(GraphObject go in m_mlParent.GraphObjects)
	{
		string str = go.GetName();
		if(0 == strncmp(str, GO_CNTL_POINT, strlen(GO_CNTL_POINT)))
		{	
			set_go_border_color(go, SYSCOLOR_GREEN);
			set_LT_script(go, "events_from_control_go;" , GRCT_SIZEMOVE);
		}
	}
	


	
	
	

	return true;
}

bool OCImgInterpBgData::EditAnchors(int npts,  int nShape, TreeNode& trAnchors)
{
	if(npts > MAX_NUM_POINTS|| npts<MIN_NUM_POINTS)
		return false;
	
	//changeAnchorsShape(nShape);
	int nObjectType = s_vnObjectType[nShape];
		
	if(update_tree_anchors_object_type(nObjectType, trAnchors))
	{
		remove_GraphObjects_with_prefix(m_mlParent, GO_CNTL_POINT);
		InitAnchors(trAnchors);
	}
	
	if(!trAnchors)
		return false;
	
	int nNum = trAnchors.Number.nVal;
	if(nNum != npts)
	{
		if(nNum > npts)
		{
			trimAnchors(npts);
			
		}
		else			
		{
			int nRadius = min(m_nCols, m_nRows)/25 ;
			for(int ii = nNum+1; ii<=npts; ii++)
			{
				initAnchor(nShape, nRadius+ii*nRadius, nRadius+ii*nRadius, nRadius);
			}			
		}
		
		
	}
	
	save_anchors_to_tree(m_mlParent, trAnchors, GO_CNTL_POINT);
	//m_nAnchorNum = m_trAnchors.Number.nVal;
	//if(nShape != m_nAnchorShape)
	//{
	//
		//if(true == changeAnchorsShape(nShape))
			//m_nAnchorShape = nShape;
		//
	//}
	
	return true;
	
}