//
// 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 "CObjectCheck.h"
#include "../x/Objstr.h"
#include "utils.h"
#include "container.h"
#include "CObjMessageHideAndShow.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


/* Retourne l'index de la colonne de la bitmap à afficher */
int CObjectCheck::GetColumnIndexBitmap()
{
//***********************************
#if DEBUG_LIB2D
MMechostr (0, "\nCObjectCheck::GetColumnIndexBitmap");
#endif
//***********************************

	switch(CBcheck)
	{
	case STATE_UNCHECKED:
		return 0;
		break;
	case STATE_CHECKED:
		return 1;
		break;
	default:
		//undefined
		break;
	}

//***********************************
#if DEBUG_LIB2D
MMechostr (0, "\nCObjectCheck::GetColumnIndexBitmap end");
#endif
//***********************************

	return -1;
}


CObjectCheck::CObjectCheck(container * cont,
						   Layer *layer,
						   int x,int y,int w,int h,
						   int flags,int contflags,int transp)
						   :CObjectRollOver(cont, layer, x,y, w, h, flags, contflags, transp)
{
	CBcheck=STATE_UNCHECKED;
}

CObjectCheck::~CObjectCheck()
{
}


int CObjectCheck::IsMouseOnObject(int x,int y,int p_tab)
{
	int colorpix, idx;
	unsigned char r, g, b;

//***********************************
#if DEBUG_LIB2D
MMechostr (0, "\nCObjectCheck::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+(GetColumnIndexBitmap()*ObjW)) * 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+(GetColumnIndexBitmap()*ObjW)) * 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 CObjectCheck::ClickIn(int x,int y,int btn,int keyFlags, int p_tab,int redrawobject)
{

//***********************************
#if DEBUG_LIB2D
MMechostr (0, "\nCObjectCheck::ClickIn");
#endif
//***********************************

	if (btn==1)
	{
		ROBstate=STATE_OFF_PUSHED;
		if ( redrawobject )
			Redraw();
	}

//***********************************
#if DEBUG_LIB2D
MMechostr (0, "\nCObjectCheck::ClickIn end");
#endif
//***********************************

	return 0;
}

int CObjectCheck::UnClickIn(int x,int y,int btn,int keyFlags, int p_tab,int redrawobject)
{
	int k,tmp_res,mask;

//***********************************
#if DEBUG_LIB2D
MMechostr (0, "\nCObjectCheck::UnClickIn");
#endif
//***********************************

	if (btn==1)
	{
		ROBstate=STATE_OFF;

		// appel du reflexe utilisateur _CBcompCheckClick s'il existe
		k = OBJbeginreflex(mm, OBJNODE, (int)this, RFLOBJNODE_CLICK);
		if (k > 0)
			return 1; 
		if (k == 0)
		{
			if ( redrawobject && IsObjectRepaintBeforeCallback() )
				SetState((CBcheck == STATE_CHECKED)?STATE_UNCHECKED:STATE_CHECKED, 1, 1);
			else
				SetState((CBcheck == STATE_CHECKED)?STATE_UNCHECKED:STATE_CHECKED, 1, 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);
		}
		else if (redrawobject)
			SetState((CBcheck == STATE_CHECKED)?STATE_UNCHECKED:STATE_CHECKED, 1, 1);
		else
			SetState((CBcheck == STATE_CHECKED)?STATE_UNCHECKED:STATE_CHECKED, 1, 0);
	}

//***********************************
#if DEBUG_LIB2D
MMechostr (0, "\nCObjectCheck::UnClickIn end");
#endif
//***********************************

	return 0;
}




int CObjectCheck::SetFocus(int reset,int p_tab,int redraw)
{
	return 0;
}

int CObjectCheck::KillFocus(int p_tab,int redraw)
{
	return 0;
}

int CObjectCheck::GetState()
{
	return this->CBcheck;
}

int CObjectCheck::SetState(int newState, int notifylinks, int redrawobject)
{
	int k, tmp_res;


//***********************************
#if DEBUG_LIB2D
MMechostr (0, "\nCObjectCheck::SetState");
#endif
//***********************************

	//vérifie si le nouvel état n'est pas le même que l'état actuel
	//ou que le nouvel état est bien l'une des deux valeurs authorisées
	if ( (newState != this->CBcheck) &&
		 ((newState == STATE_CHECKED) || (newState == STATE_UNCHECKED)) )
	{
		CObjMessageHideAndShow *msg;
	    //change l'état du CompCheck
		CBcheck = ((newState == STATE_UNCHECKED)?STATE_UNCHECKED:STATE_CHECKED);

		// lien HIDE_AND_SHOW
		if ( notifylinks )
		{
			msg = new CObjMessageHideAndShow( CBcheck == STATE_CHECKED ? SHOW : HIDE, redrawobject );
			this->notify(msg);
			delete msg;
		}

		//gestion du reflexe "état modifié"
		k = OBJbeginreflex(mm, OBJNODE, (int)this, RFLOBJNODE_CHANGE);
		if (k > 0)
			return 1; 
		if (k == 0)
		{
			if (redrawobject && IsObjectRepaintBeforeCallback())
				Redraw();
			CHECK(MMpush(mm, ITOM(this->CBcheck)));
			return OBJcallreflex(mm,1);
		}
		else if ( redrawobject )
			Redraw();
	}

//***********************************
#if DEBUG_LIB2D
MMechostr (0, "\nCObjectCheck::SetState end");
#endif
//***********************************

	return 0;
}




Layer *CObjectCheck::GetLayer(mmachine m,int p_tab)
{

//***********************************
#if DEBUG_LIB2D
MMechostr (0, "\nCObjectCheck::GetLayer");
#endif
//***********************************

	if (ObjLayer==NULL) return NULL;

	//récupere la ligne et la colonne de la portion de bitmap à afficher
	int rowIndex = GetIndexBitmap();
	int columnIndex = GetColumnIndexBitmap();

	// 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( columnIndex*ObjW,
								   rowIndex*ObjH,
								   (columnIndex+1)*ObjW,
								   (rowIndex+1)*ObjH
								 );


//***********************************
#if DEBUG_LIB2D
MMechostr (0, "\nCObjectCheck::GetLayer end");
#endif
//***********************************

	return ObjLayer;
}




Layer *CObjectCheck::GetLayerPart(mmachine m,Rect2D *paintrect,int p_tab)
{

//***********************************
#if DEBUG_LIB2D
MMechostr (0, "\nCObjectCheck::GetLayerPart");
#endif
//***********************************

	if (ObjLayer==NULL) return NULL;

	//récupere la ligne et la colonne de la portion de bitmap à afficher
	int rowIndex = GetIndexBitmap();
	int columnIndex = GetColumnIndexBitmap();

	// 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	(
												columnIndex*ObjW,
												rowIndex*ObjH,
												(columnIndex+1)*ObjW,
												(rowIndex+1)*ObjH
											),
									MoveRectangleByVecteur
											(
												*paintrect,
												Point2D(columnIndex*ObjW, rowIndex*ObjH)
											)
								  );

//***********************************
#if DEBUG_LIB2D
MMechostr (0, "\nCObjectCheck::GetLayerPart end");
#endif
//***********************************

	return ObjLayer;
}



int CObjectCheck::ResizeLayer(int w,int h,int p_tab)
{

//***********************************
#if DEBUG_LIB2D
MMechostr (0, "\nCObjectCheck::ResizeLayer");
#endif
//***********************************

	int nbre_etat=3;
	// evaluation de la taille du bouton
	if (ObjFlags&ROL_MASK) nbre_etat++;
	if (ObjFlags&ROL_DISABLE) nbre_etat++;
	w=w*2;
	h=h*nbre_etat;


//***********************************
#if DEBUG_LIB2D
MMechostr (0, "\nCObjectCheck::ResizeLayer end");
#endif
//***********************************

	return ResizeCompLayer("_CBcompCheckResizeResource",w,h,p_tab);
}




int CObjectCheck::supports( int type )
{
	return ( type == LINK_HIDE_AND_SHOW );
}

int CObjectCheck::handle( CObjMessage *msg )
{
//***********************************
#if DEBUG_LIB2D
MMechostr (0, "\nCObjectCheck::handle");
#endif
//***********************************

	switch ( msg->GetType() )
	{
	case LINK_HIDE_AND_SHOW:
		SetState( (int)(static_cast <CObjMessageHideAndShow*> (msg))->GetMode() == HIDE ? STATE_UNCHECKED : STATE_CHECKED, 0, msg->GetRedrawObject() );
		break;
	default:
		break;
	}

//***********************************
#if DEBUG_LIB2D
MMechostr (0, "\nCObjectCheck::handle end");
#endif
//***********************************

	return 0;
}

/***************************************************************************************************/
/*                           LES FONCTIONS SCOL DU CHECK BUTTON                                 */
/***************************************************************************************************/
int _CRcompCheck(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;
	CObjectCheck *new_object;
	CObjectBase *obj_root,*obj_father;
	PtrObjBitmap bmp,abmp;
	container * co;


//***********************************
#if DEBUG_LIB2D
MMechostr (0, "\n_CRcompCheck");
#endif
//***********************************

	// les differents tests de non validité
	if ((MMget(m,6))==NIL)
	{
		MMechostr(MSKTRACE,"_CRcompCheck: channel is nil\n");
		m->pp += 6;
		MMset(m,0,NIL);
		return 0;	
	}
	if ((MMget(m,5))==NIL)
	{
		MMechostr(MSKTRACE,"_CRcompCheck: container is nil\n");
		m->pp += 6;
		MMset(m,0,NIL);
		return 0;
	}
	if ((p_alphabmp=MTOP(MMget(m,0)))==NIL)
	{
		MMechostr(MSKTRACE,"_CRcompCheck: 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,"_CRcompCheck: alphabitmap already destroyed\n");
		m->pp += 6;
		MMset(m,0,NIL);
		return 0;
	}
	
#if DEBUG_OBJNODE
		MMechostr(MSKTRACE,"DEBUG_OBJNODE _CRcompCheck\n");
#endif

	// 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;	


	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/2;		//une colonne pour coché, une autre pour non coché
	h=height/nbre_etat;

	// pile Chn ObjContainer ObjNode AlphaBitmap
	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 );
	
	if ((p_objpere!=NIL)&&(obj_father==NULL))
	{
		MMechostr(MSKTRACE,"_CRcompCheck: object father already destroyed\n");
		m->pp += 3;
		MMset(m,0,NIL);
		return 0;
	}
	else if ((co=RetrievePtrContainer(m,p_container))==NULL)
	{
		MMechostr(MSKTRACE,"_CRcompCheck: container already destroyed\n");
		m->pp += 3;
		MMset(m,0,NIL);
		return 0;
	}
	else if (!co->OwnsObject(obj_father))
	{
		MMechostr(MSKTRACE,"_CRcompCheck: 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 CObjectCheck(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_CRcompCheck end");
#endif
//***********************************

	return 0;
}




int _DScompCheck(mmachine m)
{
	int p;

//***********************************
#if DEBUG_LIB2D
MMechostr (0, "\n_DScompCheck");
#endif
//***********************************

	if ((p=MTOP(MMpull(m)))!=NIL)
	{
		DsNode(m,p);
		return MMpush(m,0);
	}
	else
		return MMpush(m,NIL);
}

int _CONVERTcompCheckToObjNode(mmachine m)
{
	return 0;
}

/* Retourne 0(unchecked), 1(checked) ou nil(CompCheck non trouvé) */
int _GETcompCheckState(mmachine m)
{
	int p_obj;
	int state = NIL;


//***********************************
#if DEBUG_LIB2D
MMechostr (0, "\n_GETcompCheckState");
#endif
//***********************************

	//récupère le pointeur scol sur le CompCheck
	if ((p_obj = MTOP(MMget(m, 0))) != NIL)
	{
		CObjectBase* obj;

		//récupère le pointeur sur l'object CObjectCheck
		if ((obj = GetObjectBase(m, p_obj)) == NULL)
			MMechostr(MSKTRACE, "_GETcompCheckState : Object already destroyed.\n");
		else
			//récupère l'état du CompCheck
			state = (int)(static_cast <CObjectCheck *> (obj))->GetState();
	}

	MMset(m, 0, ITOM(state));
	return 0;
}






/* Retourne 0(état non modifié) 1(état modifié) ou nil(erreur) */
int _SETcompCheckState(mmachine m)
{
	int p_obj, tmp_res;
	int new_state,old_state;

//***********************************
#if DEBUG_LIB2D
MMechostr (0, "\n_SETcompCheckState");
#endif
//***********************************

	//récupère le nouvel état du CompCheck
	if ((old_state = new_state = MTOI(MMpull(m))) == NIL)
	{
		MMechostr(MSKTRACE, "_SETcompCheckState : State is nil.\n");
		MMset(m, 0, NIL);
		return 0;
	}

	//récupère le pointeur scol sur le CompCheck
	if ((p_obj = MTOP(MMget(m, 0))) != NIL)
	{
		CObjectBase* obj;

		//récupère le pointeur sur l'object CObjectCheck
		if ((obj = GetObjectBase(m, p_obj)) == NULL)
			MMechostr(MSKTRACE, "_SETcompCheckState : Object already destroyed.\n");
		else
		{
			//récupère l'état du CompCheck
			old_state = (int)(static_cast <CObjectCheck *> (obj))->GetState();
			//change l'état du CompCheck
			CHECK( (static_cast <CObjectCheck *> (obj))->SetState(new_state, 1, 0) );
		}
	}

	MMset(m, 0, ITOM(old_state != new_state));


//***********************************
#if DEBUG_LIB2D
MMechostr (0, "\n_SETcompCheckState end");
#endif
//***********************************

	return 0;
}


//$BLG: v4.6a6 - _FORCEcompCheckROverDisplay()
//Original source code from _SETcompCheckState()
//fun [CompCheck I] I
//Returns 0 or nil if error
int _FORCEcompCheckROverDisplay(mmachine m)
{
	int p_obj;
	int display;

MMechostr(0, "\n_FORCEcompCheckROverDisplay");
//***********************************
#if DEBUG_LIB2D
MMechostr (0, "\n_FORCEcompCheckROverDisplay");
#endif
//***********************************

	//Retrieves forced display mode
	display = MTOI(MMpull(m));
MMechostr(0,"\n%d",display);
	if (display == NIL)
	{
		MMechostr(MSKTRACE, "\n_FORCEcompCheckROverDisplay : Display mode is nil.");
		MMset(m, 0, NIL);
		return 0;
	}
	if ((display != DISPLAY_NOROVER) && (display != DISPLAY_ROVER))
	{
		MMechostr(MSKTRACE, "\n_FORCEcompCheckROverDisplay : Display mode wrong value.");
		MMset(m, 0, NIL);
		return 0;
	}

	//Retrieves CompCheck pointer
	p_obj = MTOP(MMget(m, 0));
	if (p_obj == NIL)
	{
		MMechostr(MSKTRACE, "\n_FORCEcompCheckROverDisplay : Pointer is nil.");
		MMset(m, 0, NIL);
		return 0;		
	}
	else
	{
		//Retrieves CObjectCheck object pointer
		CObjectBase* obj;
		obj = GetObjectBase(m, p_obj);
		if (obj == NULL)
		{
			MMechostr(MSKTRACE, "\n_FORCEcompCheckROverDisplay : Object already destroyed.");
			MMset(m, 0, NIL);
			return 0;
		}
		else
		{
			//Modifying display
			if (display == DISPLAY_NOROVER)		// NOROVER
				(static_cast <CObjectCheck *> (obj))->ROBstate = STATE_OFF_UNDISPLAYED;
			else															// ROVER
				(static_cast <CObjectCheck *> (obj))->ROBstate = STATE_OFF;
			(static_cast <CObjectCheck *> (obj))->Redraw();
		}
	}

	MMset(m, 0, ITOM(0));


//***********************************
#if DEBUG_LIB2D
MMechostr (0, "\n_FORCEcompCheckROverDisplay");
#endif
//***********************************

	return 0;
}



int _CBcompCheckCursorMoveIn(mmachine m)
{
	return OBJaddreflex(m,OBJNODE,RFLOBJNODE_CURSORMOVEIN);
}

int _CBcompCheckCursorMoveOut(mmachine m)
{
	return OBJaddreflex(m,OBJNODE,RFLOBJNODE_CURSORMOVEOUT);
}

int _CBcompCheckClick(mmachine m)
{
	return OBJaddreflex(m,OBJNODE,RFLOBJNODE_CLICK);
}

int _CBcompCheckStateChanged(mmachine m)
{
	return OBJaddreflex(m,OBJNODE,RFLOBJNODE_CHANGE);
}

int _CBcompCheckResizeResource(mmachine m)
{
	return OBJaddreflex(m,OBJNODE,RFLOBJNODE_RESIZE_RESSOURCE);
}

int _CBcompCheckResize(mmachine m)
{
	return OBJaddreflex(m,OBJNODE,RFLOBJNODE_RESIZE);
}
