//
// Modifications History
//
//$ LB (13/06/2002)  : changed ObjBitmap management, according to the new ObjBitmap structure
//
//$LB (20/12/2002) : 16bits to 24bits
//




#include "Macro.h"
#include "CObjectBitmap.h"
#include "CObjMessageMove.h"			//pour la classe CObjMessageMove et les directions prédéfinies
#include "CObjMessageHideAndSHow.h"
#include "../x/Objstr.h"
#include "utils.h"
#include "container.h"
#include "colors.h"

extern int OBJNODE;
extern mmachine mm;

#define ALPHA	0

CObjectBitmap::CObjectBitmap(container * cont,Layer *layer,int fatx,int faty,int x_inbitmap,int y_inbitmap,int w,int h,int bmpwidth, int bmpheight, int flags,int contflags, int transp):CObjectBase(cont,layer,fatx,faty,w,h,flags,contflags,transp)
{
//***********************************
#if DEBUG_LIB2D
MMechostr (0, "\nCObjectBitmap::CObjectBitmap");
#endif
//***********************************

	BMPx_inbitmap=x_inbitmap;
	BMPy_inbitmap=y_inbitmap;
	BMPheight = bmpheight;
	BMPwidth = bmpwidth;

//***********************************
#if DEBUG_LIB2D
MMechostr (0, "\nCObjectBitmap::CObjectBitmap end");
#endif
//***********************************

}




CObjectBitmap::~CObjectBitmap()
{
	0;
}



int CObjectBitmap::IsMouseOnObject(int x,int y, int p_tab)
{
	int colorpix;
	unsigned char r, g, b;
	int idx;

//***********************************
#if DEBUG_LIB2D
MMechostr (0, "\nCObjectBitmap::IsMouseOnObject");
#endif
//***********************************

	PtrObjBitmap bmp=GET_PTR_OBJ_BITMAP(GET_BMP(MTOP(MMfetch(mm,p_tab,ALPHA))));
	if ( bmp == NULL )
		return false;
	// on determine si il est dans la zone non transparente ou non
	idx = (BMPx_inbitmap+x-ObjX) * bmp->BytesPP  +  (BMPy_inbitmap+y-ObjY) * bmp->BPL;
	b = bmp->bits[ idx   ];
	g = bmp->bits[ idx+1 ];
	r = bmp->bits[ idx+2 ];
	colorpix = _COLOR_BGR_TO_I (b, g, r);


//***********************************
#if DEBUG_LIB2D
MMechostr (0, "\nCObjectBitmap::IsMouseOnObject end");
#endif
//***********************************

	return ((ObjTransparency==-1)||(colorpix!=ObjTransparency));
}





int CObjectBitmap::CursorMove(int x,int y,int keyFlags, int p_tab,int redrawobject)
{
	int k,tmp_res,mask;

//***********************************
#if DEBUG_LIB2D
MMechostr (0, "\nCObjectBitmap::CursorMove");
#endif
//***********************************

	k=OBJbeginreflex(mm,OBJNODE,(int)this,RFLOBJNODE_CURSORMOVE);
	if (k>0) return 1; 
	if (k==0)
	{
			mask=keyFlags&(MK_CONTROL|MK_LBUTTON|MK_MBUTTON|MK_RBUTTON|MK_SHIFT);
			CHECK(MMpush(mm,ITOM(x)));
			CHECK(MMpush(mm,ITOM(y)));
			CHECK(MMpush(mm,ITOM(mask)));
			return OBJcallreflex(mm,3);
	}

//***********************************
#if DEBUG_LIB2D
MMechostr (0, "\nCObjectBitmap::CursorMove end");
#endif
//***********************************

	return 0;
}

int CObjectBitmap::CursorMoveIn(int x,int y,int keyFlags, int p_tab,int redrawobject)
{
	return 0;
}

int CObjectBitmap::CursorMoveInWithBtnPushed(int x,int y,int keyFlags, int p_tab,int redrawobject)
{
	return 0;
}

int CObjectBitmap::CursorMoveOut(int x,int y,int keyFlags, int p_tab,int redrawobject)
{
	return 0;
}

int CObjectBitmap::CursorMoveOutWithBtnPushed(int x,int y,int keyFlags, int p_tab,int redrawobject)
{
	return 0;
}

int CObjectBitmap::CursorMoveOutsideWithBtnPushed(int x,int y,int keyFlags, int p_tab,int redrawobject)
{
	return 0;
}

int CObjectBitmap::ClickIn(int x,int y,int btn,int keyFlags, int p_tab,int redrawobject)
{
	int k,tmp_res,mask;

//***********************************
#if DEBUG_LIB2D
MMechostr (0, "\nCObjectBitmap::ClickIn");
#endif
//***********************************

	k=OBJbeginreflex(mm,OBJNODE,(int)this,RFLOBJNODE_CLICK);
	if (k>0) return 1; 
	if (k==0)
	{
			mask=keyFlags&(MK_CONTROL|MK_LBUTTON|MK_MBUTTON|MK_RBUTTON|MK_SHIFT);
			CHECK(MMpush(mm,ITOM(x)));
			CHECK(MMpush(mm,ITOM(y)));
			CHECK(MMpush(mm,ITOM(btn)));
			CHECK(MMpush(mm,ITOM(mask)));
			return OBJcallreflex(mm,4);
	}

//***********************************
#if DEBUG_LIB2D
MMechostr (0, "\nCObjectBitmap::ClickIn end");
#endif
//***********************************

	return 0;
}




int CObjectBitmap::UnClickIn(int x,int y,int btn,int keyFlags, int p_tab,int redrawobject)
{
	int k,tmp_res,mask;

//***********************************
#if DEBUG_LIB2D
MMechostr (0, "\nCObjectBitmap::UnClickIn");
#endif
//***********************************

	k=OBJbeginreflex(mm,OBJNODE,(int)this,RFLOBJNODE_UNCLICK);
	if (k>0) return 1; 
	if (k==0)
	{
			mask=keyFlags&(MK_CONTROL|MK_LBUTTON|MK_MBUTTON|MK_RBUTTON|MK_SHIFT);
			CHECK(MMpush(mm,ITOM(x)));
			CHECK(MMpush(mm,ITOM(y)));
			CHECK(MMpush(mm,ITOM(btn)));
			CHECK(MMpush(mm,ITOM(mask)));
			return OBJcallreflex(mm,4);
	}
	return 0;
}
	
int CObjectBitmap::ClickOut(int x,int y,int btn,int keyFlags, int p_tab,int redrawobject)
{
	
	return 0;
}

int CObjectBitmap::UnClickOut(int x,int y,int btn,int keyFlags, int p_tab,int redrawobject)
{
	return 0;
}

int CObjectBitmap::DblClickIn(int x,int y,int btn,int keyFlags, int p_tab,int redrawobject)
{
	int k,tmp_res,mask;

//***********************************
#if DEBUG_LIB2D
MMechostr (0, "\nCObjectBitmap::DblClickIn");
#endif
//***********************************

	k=OBJbeginreflex(mm,OBJNODE,(int)this,RFLOBJNODE_DBLCLICK);
	if (k>0) return 1; 
	if (k==0)
	{
			mask=keyFlags&(MK_CONTROL|MK_LBUTTON|MK_MBUTTON|MK_RBUTTON|MK_SHIFT);
			CHECK(MMpush(mm,ITOM(x)));
			CHECK(MMpush(mm,ITOM(y)));
			CHECK(MMpush(mm,ITOM(btn)));
			CHECK(MMpush(mm,ITOM(mask)));
			return OBJcallreflex(mm,4);
	}
	return 0;
}

int CObjectBitmap::MouseWheel(int delta,int x,int y,int keyFlags,int p_tab,int redrawobject)
{
	return 0;
}

int CObjectBitmap::KeyUp(UINT vk,int cRepeat, UINT flags, int p_tab)
{
	return 0;
}

int CObjectBitmap::KeyDown(UINT vk,int keysys,int cRepeat, UINT flags, int p_tab)
{
	return 0;
}

int CObjectBitmap::SetFocus(int reset,int p_tab,int redraw)
{
	return 0;
}

int CObjectBitmap::KillFocus(int p_tab,int redraw)
{
	return 0;
}


int CObjectBitmap::Timer( int timerID )
{
	return 0;
}

Layer *CObjectBitmap::GetLayer(mmachine m,int p_tab)
{
//***********************************
#if DEBUG_LIB2D
MMechostr (0, "\nCObjectBitmap::GetLayer");
#endif
//***********************************

	if (ObjLayer==NULL) return NULL;
	
	// m a j des ptr Scol
	ObjLayer->RGBbitmap   = GET_PTR_OBJ_BITMAP(GET_BMP(MTOP(MMfetch(mm,p_tab,ALPHA))));
	ObjLayer->AlphaBitmap = GET_PTR_OBJ_BITMAP(GET_ABMP(MTOP(MMfetch(mm,p_tab,ALPHA))));
	ObjLayer->sourceRect = Rect2D( BMPx_inbitmap, BMPy_inbitmap, BMPx_inbitmap+ObjW, BMPy_inbitmap+ObjH );
	return ObjLayer;
}



Layer *CObjectBitmap::GetLayerPart(mmachine m,Rect2D *paintrect,int p_tab)
{

//***********************************
#if DEBUG_LIB2D
MMechostr (0, "\nCObjectBitmap::GetLayerPart");
#endif
//***********************************

	if (ObjLayer==NULL) return NULL;

	// m a j des ptr Scol
	ObjLayer->RGBbitmap   = GET_PTR_OBJ_BITMAP(GET_BMP(MTOP(MMfetch(mm,p_tab,ALPHA))));
	ObjLayer->AlphaBitmap = GET_PTR_OBJ_BITMAP(GET_ABMP(MTOP(MMfetch(mm,p_tab,ALPHA))));
	// on cherche quelle est la sous-bitmap de l'objet	
	ObjLayer->sourceRect = IntersectionRectangle( Rect2D(BMPx_inbitmap, BMPy_inbitmap, BMPx_inbitmap+ObjW, BMPy_inbitmap+ObjH ),
												  MoveRectangleByVecteur( *paintrect,
																		  Point2D( BMPx_inbitmap, BMPy_inbitmap ) ) );

	return ObjLayer;
}



int CObjectBitmap::DestroyAllLayers()
{
//***********************************
#if DEBUG_LIB2D
MMechostr (0, "\nCObjectBitmap::DestroyAllLayers");
#endif
//***********************************

	// un seul layer
	if (ObjLayer!=NULL)
		delete(ObjLayer);
	ObjLayer=NULL;
	return 0;
}



int CObjectBitmap::ResizeLayer(int w,int h,int p_tab)
{
	int k,tmp_res;
//***********************************
#if DEBUG_LIB2D
MMechostr (0, "\nCObjectBitmap::ResizeLayer");
#endif
//***********************************

	k=OBJbeginreflex(mm,OBJNODE,(int)this,RFLOBJNODE_RESIZE_RESSOURCE);
	if (k==0)
	{
		// execution du reflexe de redimensionnemnt du layer
		CHECK(MMpush(mm,ITOM(w)));
		CHECK(MMpush(mm,ITOM(h)));
		CHECK(MMpush(mm,ITOM(BMPx_inbitmap)));
		CHECK(MMpush(mm,ITOM(BMPy_inbitmap)));
		CHECK(MMpush(mm,ITOM(BMPwidth)));
		CHECK(MMpush(mm,ITOM(BMPheight)));
		CHECK(MMpush(mm,ITOM(4)));
		CHECK(MBdeftab(mm));
		CHECK(OBJcallreflex(mm,3));
		
		/* prevent from destruction of container or object in user callback */
		if (GetObjectBase(mm,FindObjNodeFromHdlSys(mm,(int)this))==NULL) 
			return 0;

		// pile : [AlphaBitmap [I I I I]]
		int p_ret,p_param;
		int p_abmp=NIL;
		if ((p_ret=MTOP(MMget(mm,-2)))==NIL)
		{   // valeur de retour nil
			MMechostr(1,"_CBcompBitmapResizeResource: return value is nil\n");
			ChangeResource(mm,ALPHA,NIL);		
			return 0;
		}

		if ((p_abmp=MTOP(MMfetch(mm,p_ret,0)))==NIL)
		{
			MMechostr(1,"_CBcompBitmapResizeResource: alphabitmap is nil\n");
			ChangeResource(mm,ALPHA,NIL);		
			return 0;
		}	
				
		// recuperation de l'alphabitmap utilisateur 
		// et creation du nouveau layer
		int transparency;
		PtrObjBitmap bmp =GET_PTR_OBJ_BITMAP(GET_BMP(p_abmp));
		PtrObjBitmap abmp=GET_PTR_OBJ_BITMAP(GET_ABMP(p_abmp));
		if ((transparency = GET_TRANSP(p_abmp))==NIL) transparency = NO_TRANSPARENCY;

		// mise à jour des parametres du CompBitmap
		p_param=MTOP(MMfetch(mm,p_ret,1));
		if (p_param==NIL || (BMPx_inbitmap=MTOI(MMfetch(mm,p_param,0)))==NIL) BMPx_inbitmap = 0;
		if (p_param==NIL || (BMPy_inbitmap=MTOI(MMfetch(mm,p_param,1)))==NIL) BMPy_inbitmap = 0;
		if (p_param==NIL || (BMPwidth=MTOI(MMfetch(mm,p_param,2)))==NIL) BMPwidth = 0;
		if (p_param==NIL || (BMPheight=MTOI(MMfetch(mm,p_param,3)))==NIL) BMPheight = 0;
		
		int bmpH = 0;
		int bmpW = 0;
		if (bmp!=NULL)
		{
			
			if (abmp!=NULL)
			{
				bmpH = min( bmp->TailleH, abmp->TailleH );
				bmpW = min( bmp->TailleW, abmp->TailleW );
			}
			else
			{
				bmpH = bmp->TailleH;
				bmpW = bmp->TailleW;
			}
		}
		BMPwidth  = min( BMPwidth, bmpW - BMPx_inbitmap );
		BMPheight = min( BMPheight, bmpH - BMPy_inbitmap );
		
		// creation du nouveau layer
		if (bmp!=NULL)
			if (BMPwidth==w && BMPheight==h)
				ObjLayer = new Layer(bmp,abmp, transparency );
			else
				MMechostr(1,"_CBcompBitmapResizeResource: not good format for alphabitmap (requested size:%d %d received size:%d %d)\n",w,h,bmp->TailleW,bmp->TailleH);
		else
			ObjLayer = new Layer( w, h, transparency,abmp!= NULL);
		
		ChangeResource(mm,ALPHA,p_abmp);
		return 0;
	}
	// callback non definie ou invalide et objet doit etre absolument resizé!!
	MMechostr(1,"_CBcompBitmapResizeResource not defined and object need to be resized!!!\n");

//***********************************
#if DEBUG_LIB2D
MMechostr (0, "\nCObjectBitmap::ResizeLayer end");
#endif
//***********************************

	return 1;
}




// pour les liens entre objets
int CObjectBitmap::handle(CObjMessage* msg)
{
	int direction, value, redrawobject;
//***********************************
#if DEBUG_LIB2D
MMechostr (0, "\nCObjectBitmap::handle");
#endif
//***********************************


	switch(msg->GetType())
	{
	case LINK_MOVE:
		//recherche les informations du message
		direction = (int)(static_cast <CObjMessageMove*> (msg))->GetDirection();
		value =		(int)(static_cast <CObjMessageMove*> (msg))->GetOffset();
		redrawobject = msg->GetRedrawObject();

		//traite les informations du message
		if ( direction == DIR_VERTICAL )
			BMPy_inbitmap = min( max( 0, BMPy_inbitmap + value ), BMPheight - ObjH );
		else if ( direction == -DIR_VERTICAL )
			BMPy_inbitmap = min( max( 0, BMPy_inbitmap - value ), BMPheight - ObjH );
		else if ( direction == DIR_HORIZONTAL )
			BMPx_inbitmap = min( max( 0, BMPx_inbitmap + value ), BMPwidth - ObjW );
		else if ( direction == -DIR_HORIZONTAL )
			BMPx_inbitmap = min( max( 0, BMPx_inbitmap - value ), BMPwidth - ObjW );

		if ( redrawobject )
			Redraw();
		break;
	case LINK_HIDE_AND_SHOW:
		if ( (int)(static_cast <CObjMessageHideAndShow*> (msg))->GetMode() == SHOW )
		{
			this->ObjFlags -= this->ObjFlags&OBJ_HIDE;
			this->ObjFlags -= this->ObjFlags&OBJ_DISABLE;
			this->ObjFlags |= OBJ_VISIBLE;
			this->ObjFlags |= OBJ_ENABLE;
		}
		else
		{
			this->ObjFlags |= OBJ_HIDE;
			this->ObjFlags |= OBJ_DISABLE;
			this->ObjFlags -= this->ObjFlags&OBJ_VISIBLE;
			this->ObjFlags -= this->ObjFlags&OBJ_ENABLE;
		}

		if ( msg->GetRedrawObject() )
			this->Container()->Redraw(1);

		break;

	default:
		break;
	}


//***********************************
#if DEBUG_LIB2D
MMechostr (0, "\nCObjectBitmap::handle end");
#endif
//***********************************

	return 0;
}



int CObjectBitmap::supports( int type )
{
	return ( type == LINK_MOVE || type == LINK_HIDE_AND_SHOW );
}




/***************************************************************************************************/
/*                           LES FONCTIONS SCOL DU BITMAP										   */
/***************************************************************************************************/
int _CRcompBitmap(mmachine m)
{
	int tmp_res;
	int p_alphabmp,flags,contflags;
	int p_coordinates,p_objpere,p_container;
	int transparency,x,y,w,h, bmpW, bmpH;
	int x_inbitmap,y_inbitmap;
	PtrObjBitmap bmp,abmp;
	CObjectBitmap *new_object;
	CObjectBase *obj_root,*obj_father;
	container *co;

//***********************************
#if DEBUG_LIB2D
MMechostr (0, "\n_CRcompBitmap");
#endif
//***********************************


	// les differents tests de non validité
	if ((MMget(m,10))==NIL)
	{
		MMechostr(MSKTRACE,"_CRcompBitmap: channel is nil\n");
		m->pp += 10;
		MMset(m,0,NIL);
		return 0;	
	}
	if ((MMget(m,9))==NIL)
	{
		MMechostr(MSKTRACE,"_CRcompBitmap: container is nil\n");
		m->pp += 10;
		MMset(m,0,NIL);
		return 0;
	}
	if ((p_alphabmp=MTOP(MMget(m,4)))==NIL)
	{
		MMechostr(MSKTRACE,"_CRcompBitmap: alphabitmap is nil\n");
		m->pp += 10;
		MMset(m,0,NIL);
		return 0;
	}
	if (GET_PTR_OBJ_BITMAP(GET_BMP(p_alphabmp))==NULL)
	{
		MMechostr(MSKTRACE,"_CRcompBitmap: alphabitmap already destroyed\n");
		m->pp += 10;
		MMset(m,0,NIL);
		return 0;
	}

#if DEBUG_OBJNODE
		MMechostr(MSKTRACE,"DEBUG_OBJNODE _CRcompBitmap\n");
#endif

	// pile: Chn ObjContainer ObjNode [I I] I I AlphaBitmap I I I I

	if ((h=MTOI(MMpull(m)))==NIL) h = 0;
	if ((w=MTOI(MMpull(m)))==NIL) w = 0;
	if ((y_inbitmap=MTOI(MMpull(m)))==NIL) y_inbitmap = 0;
	if ((x_inbitmap=MTOI(MMpull(m)))==NIL) x_inbitmap = 0;

	// pile: Chn ObjContainer ObjNode [I I] I I AlphaBitmap
	// on inverse l'AlphaBitmap et les coordonnees
	INVERT( m, 0, 3 );

	if ((p_coordinates=MTOP(MMpull(m)))==NIL)
	{
		x=0;
		y=0;
	}
	else
	{
		x=MTOI(MMfetch(m,p_coordinates,0));
		y=MTOI(MMfetch(m,p_coordinates,1));
	}
	if ((contflags=MTOI(MMpull(m)))==NIL) contflags=0;
	if ((flags=MTOI(MMpull(m)))==NIL) flags=OBJ_ENABLE|OBJ_VISIBLE;
	
	// pile: Chn ObjContainer ObjNode AlphaBitmap
	p_alphabmp = MTOP( MMget( m, 0 ) );
	bmp =GET_PTR_OBJ_BITMAP(GET_BMP(p_alphabmp));
	abmp=GET_PTR_OBJ_BITMAP(GET_ABMP(p_alphabmp));

	if ((transparency = GET_TRANSP(p_alphabmp))==NIL) transparency = NO_TRANSPARENCY;
	
	// clip sur la taille reelle du bitmap
	bmpH = 0;
	bmpW = 0;
	if (bmp!= NULL)
	{
		if (abmp!=NULL)
		{
			bmpH = min( bmp->TailleH, abmp->TailleH );
			bmpW = min( bmp->TailleW, abmp->TailleW );
		}
		else
		{
			bmpH = bmp->TailleH;
			bmpW = bmp->TailleW;
		}
	}
	h = min( h, bmpH - y_inbitmap );
	w = min( w, bmpW - x_inbitmap );

	p_objpere=MTOP(MMget(m,1));
	p_container=MTOP(MMget(m,2));
	obj_father=GetObjectBase(m,p_objpere);

	// on inverse p_objpere et channel
	INVERT( m, 1, 3 );
	
	// pile ObjNode ObjContainer Chn AlphaBitmap
	if ((p_objpere!=NIL)&&(obj_father==NULL))
	{
		MMechostr(MSKTRACE,"_CRcompBitmap: object father already destroyed\n");
		m->pp += 3;
		MMset(m,0,NIL);
		return 0;
	}
	else if ((co=RetrievePtrContainer(m,p_container))==NULL)
	{
		MMechostr(MSKTRACE,"_CRcompBitmap: container already destroyed\n");
		m->pp += 3;
		MMset(m,0,NIL);
		return 0;
	}
	else if (!co->OwnsObject(obj_father))
	{
		MMechostr(MSKTRACE,"_CRcompBitmap: father object was not created in this container!\n");
		m->pp += 3;
		MMset(m,0,NIL);
		return 0;
	}
	else
	{
		// evaluation de l'Image
		Layer *layer;
		
		if (bmp!=NULL)
			layer = new Layer(bmp,abmp,transparency);
		else
			layer = new Layer( w, h, transparency, abmp != NULL );

		obj_root=co->Root();
	
		// creation du nouvel objet
		new_object=new CObjectBitmap(co,layer,x,y,x_inbitmap,y_inbitmap,w,h,bmp->TailleW, bmp->TailleH, flags,contflags,transparency);
	
		// ajout de l'objet et creation du nouvel OBJNODE
		CHECK( AddNode(m,obj_root,obj_father,new_object,1) );

		// pile ObjPere Container ObjNode
		tmp_res = MMpull( m );
		MMpull(m);
		MMpull(m);
		CHECK( MMpush( m, tmp_res ) );

#if DEBUG_OBJNODE
	PrintTree(m,0,FindObjNodeFromHdlSys(m,(int)obj_root));
#endif


	}

//***********************************
#if DEBUG_LIB2D
MMechostr (0, "\n_CRcompBitmap end");
#endif
//***********************************

	return 0;
}




int _DScompBitmap(mmachine m)
{
	int p,tmp_res;

//***********************************
#if DEBUG_LIB2D
MMechostr (0, "\n_DScompBitmap");
#endif
//***********************************


	if ((p=MTOP(MMpull(m)))!=NIL)
	{
		DsNode(m,p);
		CHECK(MMpush(m,MTOI(0)));
	}
	else
		CHECK(MMpush(m,NIL));

//***********************************
#if DEBUG_LIB2D
MMechostr (0, "\n_DScompBitmap end");
#endif
//***********************************

	return 0;
}




int _CONVERTcompBitmapToObjNode(mmachine m)
{
	return 0;
}

int _CBcompBitmapCursorMove(mmachine m)
{
	return OBJaddreflex(m,OBJNODE,RFLOBJNODE_CURSORMOVE);
}

int _CBcompBitmapClick(mmachine m)
{
	return OBJaddreflex(m,OBJNODE,RFLOBJNODE_CLICK);
}

int _CBcompBitmapUnClick(mmachine m)
{
	return OBJaddreflex(m,OBJNODE,RFLOBJNODE_UNCLICK);
}

int _CBcompBitmapDblClick(mmachine m)
{
	return OBJaddreflex(m,OBJNODE,RFLOBJNODE_DBLCLICK);
}

int _CBcompBitmapResizeResource(mmachine m)
{
	return OBJaddreflex(m,OBJNODE,RFLOBJNODE_RESIZE_RESSOURCE);
}

int _CBcompBitmapResize(mmachine m)
{
	return OBJaddreflex(m,OBJNODE,RFLOBJNODE_RESIZE);
}