//
// 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 "CObjectRollOver.h"
#include "../x/Objstr.h"
#include "utils.h"
#include "container.h"
#include "colors.h"

#define STATE_OFF_UNDISPLAYED		0	/* undisplay */
#define STATE_OFF					1	/* highlight */
#define STATE_OFF_PUSHED			2	/* pushed    */
#define STATE_OFF_PUSHED_OUT		3	/* pushed out*/

extern int OBJNODE;
extern mmachine mm;

#define ALPHA 0

int CObjectRollOver::GetIndexBitmap()
{
//***********************************
#if DEBUG_LIB2D
MMechostr (0, "\nCObjectRollOver::GetIndexBitmap");
#endif
//***********************************


	if ((ObjFlags&OBJ_DISABLE)&&(ObjFlags&ROL_DISABLE))
		return 3; 
	else
	{
		if (ObjFlags&OBJ_DISABLE)
			return 0;
		else
			switch(ROBstate)
			{
				case STATE_OFF_UNDISPLAYED:
					return 0;
					break;
				case STATE_OFF:
					return 1;
					break;
				case STATE_OFF_PUSHED:
					return 2;
					break;
				case STATE_OFF_PUSHED_OUT:
					return 1;
				break;
			}
	
	}
	return -1;
}





int CObjectRollOver::GetIndexMask()
{
	return ((ObjFlags&ROL_MASK)?((ObjFlags&ROL_DISABLE)?4:3):-1);
}




int CObjectRollOver::DestroyAllLayers()
{
//***********************************
#if DEBUG_LIB2D
MMechostr (0, "\nCObjectRollOver::DestroyAllLayers");
#endif
//***********************************
	
	// un seul layer 
	if (ObjLayer!=NULL)
		delete(ObjLayer);
	ObjLayer=NULL;
	return 0;
}





int CObjectRollOver::ResizeCompLayer(char * desc,int w,int h,int p_tab)
{
	int k,tmp_res;
//***********************************
#if DEBUG_LIB2D
MMechostr (0, "\nCObjectRollOver::ResizeCompLayer");
#endif
//***********************************

	k=OBJbeginreflex(mm,OBJNODE,(int)this,RFLOBJNODE_RESIZE_RESSOURCE);
	if (k==0)
	{
		// execution du reflexe
		CHECK(MMpush(mm,ITOM(w)));
		CHECK(MMpush(mm,ITOM(h)));
		CHECK(OBJcallreflex(mm,2));
		
		/* prevent from destruction of container or object in user callback */
		if (GetObjectBase(mm,FindObjNodeFromHdlSys(mm,(int)this))==NULL) 
			return 0;

		// pile : AlphaBitmap
		int transparency;
		int p_abmp;

		if ((p_abmp=MTOP(MMget(mm,-2)))==NIL)
		{
			// ressource invalide!!
			MMechostr(1,"%s: alphabitmap is nil\n",desc);
			ChangeResource(mm,ALPHA,NIL);		
			return 0;
		}

		// remplacement du layer du rollover dans la structure
		// recuperation de l'alphabitmap utilisateur 
		// et creation du nouveau layer
		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;

		if (bmp!=NULL)
		{
			if (bmp->TailleW==w && bmp->TailleH==h)
				ObjLayer = new Layer(bmp,abmp, transparency );
			else
				MMechostr(1,"%s: not good format for alphabitmap (requested size:%d %d received size:%d %d)\n",desc,w,h,bmp->TailleW,bmp->TailleH);
		}
		else
			ObjLayer = new Layer( w, h, transparency,abmp!= NULL);
		
		// remplacement de la valeur du pointeur de l'alphabitmap
		// dans le tab
		ChangeResource(mm,ALPHA,p_abmp);
		return 0;
	}
	// callback non definie ou invalide et objet doit etre absolument resizé!!
	MMechostr(1,"%s not defined and object need to be resized!!!\n",desc);
	return 1;
}




CObjectRollOver::CObjectRollOver(container * cont,Layer *layer,int x,int y,int w,int h,int flags,int contflags,int transp):CObjectBase(cont,layer,x,y,w,h,flags,contflags,transp)
{
	ROBstate=STATE_OFF_UNDISPLAYED;
	0;
}

CObjectRollOver::~CObjectRollOver()
{
	0;
}


int CObjectRollOver::IsMouseOnObject(int x,int y,int p_tab)
{
	int colorpix, idx;
	unsigned char r, g, b;
	
//***********************************
#if DEBUG_LIB2D
MMechostr (0, "\nCObjectRollOver::IsMouseOnObject");
#endif
//***********************************

	PtrObjBitmap bmp=GET_PTR_OBJ_BITMAP(GET_BMP(MTOP(MMfetch(mm,p_tab,ALPHA))));
	if ( bmp == NULL )
		return false;

	if (ObjFlags&ROL_MASK)
	{
		idx = (x-ObjX) * bmp->BytesPP + (y-ObjY+GetIndexMask()*ObjH) * bmp->BPL;
		b = bmp->bits[ idx   ];
		g = bmp->bits[ idx+1 ];
		r = bmp->bits[ idx+2 ];
		colorpix = _COLOR_BGR_TO_I (b, g, r);
		return (colorpix!=0);
	}
	else
	{
		idx = (x-ObjX) * bmp->BytesPP + (y-ObjY+GetIndexBitmap()*ObjH) * bmp->BPL;
		b = bmp->bits[ idx   ];
		g = bmp->bits[ idx+1 ];
		r = bmp->bits[ idx+2 ];
		colorpix = _COLOR_BGR_TO_I (b, g, r);
		return ((ObjTransparency==NO_TRANSPARENCY)||(colorpix!=ObjTransparency));
	}
}





int CObjectRollOver::CursorMove(int x,int y,int keyFlags, int p_tab,int redrawobject)
{
	return 0;
}




int CObjectRollOver::CursorMoveIn(int x,int y,int keyFlags, int p_tab,int redrawobject)
{
	int k,mask,tmp_res;

//***********************************
#if DEBUG_LIB2D
MMechostr (0, "\nCObjectRollOver::CursorMoveIn");
#endif
//***********************************

	ROBstate=((ROBstate==STATE_OFF)?STATE_OFF_UNDISPLAYED:STATE_OFF);

	// appel du reflexe utilisateur s'il existe
	k=OBJbeginreflex(mm,OBJNODE,(int)this,RFLOBJNODE_CURSORMOVEIN);
	if (k>0) return 1; 
	if (k==0)
	{
		if (redrawobject && IsObjectRepaintBeforeCallback())
			Redraw();
	
		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);
	}
	else if ( redrawobject )
		Redraw();

	return 0;
}





int CObjectRollOver::CursorMoveInWithBtnPushed(int x,int y,int keyFlags, int p_tab,int redrawobject)
{
//***********************************
#if DEBUG_LIB2D
MMechostr (0, "\nCObjectRollOver::CursorMoveInWithBtnPushed");
#endif
//***********************************
	
	if (ROBstate==STATE_OFF_PUSHED_OUT)
	{ /* Make the button Pushed */
		ROBstate=STATE_OFF_PUSHED;
		if (redrawobject) Redraw();
	}
	return 0;
}





int CObjectRollOver::CursorMoveOut(int x,int y,int keyFlags, int p_tab,int redrawobject)
{
	int k,mask,tmp_res;

//***********************************
#if DEBUG_LIB2D
MMechostr (0, "\nCObjectRollOver::CursorMoveOut");
#endif
//***********************************

	ROBstate=STATE_OFF_UNDISPLAYED;

	// appel du reflexe utilisateur s'il existe
	k=OBJbeginreflex(mm,OBJNODE,(int)this,RFLOBJNODE_CURSORMOVEOUT);
	if (k>0) return 1; 
	if (k==0)
	{
		if (redrawobject && IsObjectRepaintBeforeCallback())
			Redraw();

		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);
	}
	else if ( redrawobject )
		Redraw();

	return 0;
}





int CObjectRollOver::CursorMoveOutWithBtnPushed(int x,int y,int keyFlags, int p_tab,int redrawobject)
{
	int k,mask,tmp_res;

//***********************************
#if DEBUG_LIB2D
MMechostr (0, "\nCObjectRollOver::CursorMoveOutWithBtnPushed");
#endif
//***********************************

	if (ROBstate==STATE_OFF_PUSHED)
		ROBstate=STATE_OFF_PUSHED_OUT;

	// appel du reflexe utilisateur s'il existe
	k=OBJbeginreflex(mm,OBJNODE,(int)this,RFLOBJNODE_CURSORMOVEOUT);
	if (k>0) return 1; 
	if (k==0)
	{
		if (redrawobject && IsObjectRepaintBeforeCallback())
			Redraw();

		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);
	}
	else if ( redrawobject )
		Redraw();

	return 0;
}





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





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

//***********************************
#if DEBUG_LIB2D
MMechostr (0, "\nCObjectRollOver::ClickIn");
#endif
//***********************************	
	
	if (btn==1)
	{

		ROBstate=STATE_OFF_PUSHED;

		// appel du reflexe utilisateur s'il existe
		if (ObjFlags&ROL_CLICK)
		{
			k=OBJbeginreflex(mm,OBJNODE,(int)this,RFLOBJNODE_CLICK);
			if (k>0) return 1; 
			if (k==0)
			{
				if (redrawobject && IsObjectRepaintBeforeCallback())
					Redraw();

				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);
			}
			else if ( redrawobject )
				Redraw();
		} else if ( redrawobject )
			Redraw();
	}
	return 0;
}




	
int CObjectRollOver::UnClickIn(int x,int y,int btn,int keyFlags, int p_tab,int redrawobject)
{
	int k,tmp_res,mask;
//***********************************
#if DEBUG_LIB2D
MMechostr (0, "\nCObjectRollOver::UnClickIn");
#endif
//***********************************

	
	if (btn==1)
	{
		ROBstate=STATE_OFF;

		// appel du reflexe utilisateur s'il existe
		if (!(ObjFlags&ROL_CLICK))
		{
			k=OBJbeginreflex(mm,OBJNODE,(int)this,RFLOBJNODE_CLICK);
			if (k>0) return 1; 
			if (k==0)
			{
				if (redrawobject && IsObjectRepaintBeforeCallback())
					Redraw();

				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);
			}
			else if ( redrawobject )
				Redraw();
		} else if ( redrawobject )
			Redraw();

	}
	return 0;
}




int CObjectRollOver::ClickOut(int x,int y,int btn,int keyFlags, int p_tab,int redrawobject)
{
//***********************************
#if DEBUG_LIB2D
MMechostr (0, "\nCObjectRollOver::ClickOut");
#endif
//***********************************
	
	switch(ROBstate)
	{
		case STATE_OFF:
			Container()->CoHandledObject = NULL;
		case STATE_OFF_PUSHED:
		case STATE_OFF_PUSHED_OUT:
			ROBstate=STATE_OFF_UNDISPLAYED;
			if (redrawobject) Redraw();
			break;
	}
	return 0;
}





int CObjectRollOver::UnClickOut(int x,int y,int btn,int keyFlags, int p_tab,int redrawobject)
{
//***********************************
#if DEBUG_LIB2D
MMechostr (0, "\nCObjectRollOver::UnClickOut");
#endif
//***********************************
	
	ROBstate=STATE_OFF_UNDISPLAYED;
	if (redrawobject) Redraw();
	return 0;
}






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

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

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

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

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

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

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





Layer *CObjectRollOver::GetLayer(mmachine m,int p_tab)
{
//***********************************
#if DEBUG_LIB2D
MMechostr (0, "\nCObjectRollOver::GetLayer");
#endif
//***********************************
	
	if (ObjLayer==NULL) return NULL;

	int indx=GetIndexBitmap();
	// 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( 0, indx*ObjH, ObjW, (indx+1)*ObjH );

	return ObjLayer;
}




Layer *CObjectRollOver::GetLayerPart(mmachine m,Rect2D *paintrect,int p_tab)
{
//***********************************
#if DEBUG_LIB2D
MMechostr (0, "\nCObjectRollOver::GetLayerPart");
#endif
//***********************************
	
	if (ObjLayer==NULL) return NULL;

	int indx=GetIndexBitmap();
	// 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	(
												0,
												indx*ObjH,
												ObjW,
												(indx+1)*ObjH
											),
									MoveRectangleByVecteur
											(
												*paintrect,
												Point2D(0,indx*ObjH)
											)
								  );
	return ObjLayer;
}





int CObjectRollOver::ResizeLayer(int w,int h,int p_tab)
{
//***********************************
#if DEBUG_LIB2D
MMechostr (0, "\nCObjectRollOver::ResizeLayer");
#endif
//***********************************
	
	
	int nbre_etat=3;
	// evaluation de la taille du bouton
	if (ObjFlags&ROL_MASK) nbre_etat++;
	if (ObjFlags&ROL_DISABLE) nbre_etat++;
	h=h*nbre_etat;	
	return ResizeCompLayer("_CBcompRollOverResizeResource",w,h,p_tab);
}






/***************************************************************************************************/
/*                           LES FONCTIONS SCOL DU ROLLOVER BUTTON                                 */
/***************************************************************************************************/
int _CRcompRollOver(mmachine m)
{
	int tmp_res;
	int p_alphabmp,flags,contflags;
	int p_coordinates,p_objpere,p_container;
	int transparency,x,y,w,h, width, height;
	int nbre_etat=3;
	PtrObjBitmap bmp,abmp;
	CObjectRollOver *new_object;
	CObjectBase *obj_root,*obj_father;
	container * co;

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


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

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

	// 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 ObjPere 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;

	width  = bmp->TailleW;
	height = bmp->TailleH;

	// evaluation de la taille du bouton
	if (flags&ROL_MASK) nbre_etat++;
	if (flags&ROL_DISABLE) nbre_etat++;
	w=width;
	h=height/nbre_etat;

	// pile Chn ObjContainer ObjPere AlphaBitmap
	p_objpere=MTOP(MMget(m,1));
	p_container=MTOP(MMget(m,2));
	obj_father=GetObjectBase(m,p_objpere);
	// on inverse ObjPere et Chn
	INVERT( m, 1, 3 );
	
	if ((p_objpere!=NIL)&&(obj_father==NULL))
	{
		MMechostr(MSKTRACE,"_CRcompRollOver: object father already destroyed\n");
		m->pp += 3;
		MMset(m,0,NIL);
		return 0;
	}
	else if ((co=RetrievePtrContainer(m,p_container))==NULL)
	{
		MMechostr(MSKTRACE,"_CRcompRollOver: container already destroyed\n");
		m->pp += 3;
		MMset(m,0,NIL);
		return 0;
	}
	else if (!co->OwnsObject(obj_father))
	{
		MMechostr(MSKTRACE,"_CRcompRollOver: 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 CObjectRollOver(co,layer,x,y,w,h,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_CRcompRollOver end");
#endif
//***********************************


	return 0;
}






int _DScompRollOver(mmachine m)
{
	int p;

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

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





int _CONVERTcompRollOverToObjNode(mmachine m)
{
	return 0;
}

int _CBcompRollOverCursorMoveIn(mmachine m)
{
	return OBJaddreflex(m,OBJNODE,RFLOBJNODE_CURSORMOVEIN);
}

int _CBcompRollOverCursorMoveOut(mmachine m)
{
	return OBJaddreflex(m,OBJNODE,RFLOBJNODE_CURSORMOVEOUT);
}

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

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

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