#include "Macro.h"
#include "CObjToolTip.h"
#include "container.h"

#define NO_TIMER -1



#ifdef SCOL

extern int (*mt_start)(int per, int param, int (*fun)(int i, int param));
extern int (*mt_del)(int i);
extern int OBJNODE;
extern mmachine mm;

#endif


///////////////////////////////////////////////////////////////////////////////////////////////
//    CLASSE DE BASE POUR LE TOOLTIP
///////////////////////////////////////////////////////////////////////////////////////////////

CObjToolTip::CObjToolTip(CObjectBase *obj, char *txt, int timeout)
{
//MMechostr(0,"CObjToolTip::CObjToolTip\n");
	TTcursorX = TTcursorY = 0;
	TTtimeout = timeout;
	TTtimer = NO_TIMER;
	TTisVisible = 0;
	
	// le texte
	char *temp = (char *)malloc(sizeof(char)*(strlen(txt)+1));
	strcpy(temp, txt);
	TTtexte = ReplaceRnByR(temp);
	free(temp);

	TTobj = obj;
}


CObjToolTip::~CObjToolTip()
{
//MMechostr(0,"CObjToolTip::~CObjToolTip\n");
	Disarm();
	TTobj = NULL;
	if (TTtexte != NULL)
		free(TTtexte);
	if (TTtimer != NO_TIMER)
		mt_del(TTtimer);
}


int CObjToolTipEndCallBack(int timerid, int objtool)
{
	CObjToolTip *obj = (CObjToolTip *)objtool;
//MMechostr(0,"CObjToolTipEndCallBack\n");

	// truc hyper crade!!!!!!! pour desactiver definitivement le tooltip
	obj->GetObject()->Container()->CoActiveToolTipObject = NULL;
	obj->Disarm();

	return 0;
}


int CObjToolTipCallBack( int timerid, int objtool )
{
	CObjToolTip * obj = (CObjToolTip *)objtool;
	Point2D P = obj->GetObject()->Container()->GetCursorPosClient(); 
//MMechostr(0,"CObjToolTipCallBack\n");	

	if ((obj->TTcursorX == P.iptX) && (obj->TTcursorY==P.iptY))
	{
		obj->Disarm();
		obj->TimerEnd();
		obj->TTisVisible = 1;
		return obj->ToolTipOn();
	}
	return 0;
}


// arm the tip display mechanism
void CObjToolTip::Arm(int CursorX, int CursorY)
{
//MMechostr(0,"CObjToolTip::Arm\n");
	TTtimer = mt_start(TTtimeout, (int)this, CObjToolTipCallBack);
	TTcursorX = CursorX;
	TTcursorY = CursorY;
}


// Reset the WakeUp Time, and the current point
void CObjToolTip::Reset(int CursorX, int CursorY)
{
//MMechostr(0,"CObjToolTip::Reset\n");
	if (!TTisVisible)
	{
		Disarm();
		Arm(CursorX, CursorY);
	}
}


void CObjToolTip::TimerEnd()
{
//MMechostr(0,"CObjToolTip::TimerEnd\n");
	TTtimer = mt_start(TIP_VISIBLE_END, (int)this, CObjToolTipEndCallBack);
}


// Clear The Tip and disarm the tip display mechanism
void CObjToolTip::Disarm()
{
//MMechostr(0,"CObjToolTip::Disarm\n");
	if (TTtimer != NO_TIMER)
	{
		mt_del(TTtimer);
		TTtimer = NO_TIMER;
	}
	if (TTisVisible)
	{
		TTisVisible = 0;
		ToolTipOff();
	}
}


// Show Tip
int CObjToolTip::ToolTipOn()
{
	int k, tmp_res;
//MMechostr(0,"CObjToolTip::ToolTipOn\n");

	k = OBJbeginreflex(mm, OBJNODE, (int)TTobj, RFLOBJNODE_TOOLTIP_ON);
	if (k > 0) return 1; 
	if (k == 0)
	{
			int p;
			char *p_c;
			char *txt = ReplaceRByN(TTtexte);
			int len = strlen(txt);
		

			if ((p = MMmalloc(mm, STR_SIZE(len), TYPEBUF)) < 0) return p;
			MMstore(mm, p, 0, len);
			p_c = MMstartstr(mm, p);
			memcpy(p_c, txt, len);
			p_c[len] = 0;
			free(txt);
			
			
			Point2D pt = TTobj->Container()->GetCursorPosScreen();
			CHECK(MMpush(mm, PTOM(p)));
			CHECK(MMpush(mm, ITOM(pt.iptX)));
			CHECK(MMpush(mm, ITOM(pt.iptY+GetSystemMetrics(SM_CYCURSOR)/2)));
			
			
			tmp_res = OBJcallreflex(mm, 3);
			
			/* on recupere le pointeur de l'objet et on execute un focus sur le container*/
			if (OBJ_VALIDITY(TTobj) && TTobj->Container()->GetPtrWindow()!=NULL)
				TTobj->Container()->GetPtrWindow()->SetFocus();
			
			return tmp_res;
	}
	return 0;
}


// Destroy Tip
int CObjToolTip::ToolTipOff()
{
	int k, tmp_res;
//MMechostr(0,"CObjToolTip::ToolTipOff\n");

	k = OBJbeginreflex(mm, OBJNODE, (int)TTobj, RFLOBJNODE_TOOLTIP_OFF);
	if (k > 0) return 1; 
	if (k == 0)
	{
		int p;
		char *p_c;
		char *txt = ReplaceRByN(TTtexte);
		int len = strlen(txt);
	
		if ((p = MMmalloc(mm, STR_SIZE(len), TYPEBUF)) < 0) return p;
		MMstore(mm, p, 0, len);
		p_c = MMstartstr(mm, p);
		memcpy(p_c, txt, len);
		p_c[len] = 0;
		free(txt);
		CHECK(MMpush(mm, PTOM(p)));
		return OBJcallreflex(mm, 1);
	}
	return 0;
}


Layer* CObjToolTip::GetLayerToolTip()
{
//MMechostr(0,"CObjToolTip::GetLayerToolTip\n");
	return NULL;
}


///////////////////////////////////////////////////////////////////////////////////////////////
//    CLASSE TOOLTIP PAR DEFAUT
///////////////////////////////////////////////////////////////////////////////////////////////
#define BORDER_SIZE 1
#define BORDER_SPACE 5
#define TT_LEFT (1<<(LAST_OBJ_FLAG+1))


// Constructeur-Destructeur
CObjToolTipDefaut::CObjToolTipDefaut(	CObjectBase *obj,
											char *txt,
											int timeout,
											int textcolor,
											int tipcolor,
											int p_font,
											int *failed
									):CObjToolTip(obj,txt,timeout)
{
//MMechostr(0,"CObjToolTipDefaut::CObjToolTipDefaut\n");
	*failed = 0;

	// couleur du fond
	TTDbackground = tipcolor;

	// font
	TTDfont=Lib2dFontService.getLayerFont(GET_PTR_OBJ_FONT(p_font));
	
	// text
	TTDtxt=new TextMonoFont(	TTtexte,
								TTDfont,
								TTDtextcolor=textcolor,
								0,
								0,
								0,
								1,
								obj->Container()->GetXSize()-2*BORDER_SIZE-2*BORDER_SPACE
							 );

	// hauteur/largeur
	TTDw = TTDtxt->getMaxWidth()+2*BORDER_SIZE+2*BORDER_SPACE;
	
	if ((TTDh = TTDtxt->getHeight()+2*BORDER_SIZE) > obj->Container()->GetYSize()) 
		*failed = 1;
	
	// layer d'affichage
	TTDlayer = NULL;
}


CObjToolTipDefaut::~CObjToolTipDefaut()
{
//MMechostr(0,"CObjToolTipDefaut::~CObjToolTipDefaut\n");
	delete(TTDtxt);

	if (TTDlayer != NULL)
	{
		delete(TTDlayer);
		TTDlayer = NULL;
	}

  Lib2dFontService.delLayerFont(TTDfont);
}


int CObjToolTipDefaut::ToolTipOn()
{
//MMechostr(0,"CObjToolTipDefaut::ToolTipOn\n");
	// creation du layer
	TTDlayer = new Layer(TTDw, TTDh, TTDbackground, 0);
	TTDlayer->Transparency = NO_TRANSPARENCY;
	TTDlayer->drawLine(0, 0, TTDw, 0, 1, BORDER_SIZE, TTDtextcolor);
	TTDlayer->drawLine(0, 0, 0, TTDh, 1, BORDER_SIZE, TTDtextcolor);
	TTDlayer->drawLine(TTDw-BORDER_SIZE, 0, TTDw-BORDER_SIZE, TTDh, 1, BORDER_SIZE, TTDtextcolor);
	TTDlayer->drawLine(0, TTDh-BORDER_SIZE, TTDw, TTDh-BORDER_SIZE, 1, BORDER_SIZE, TTDtextcolor);
	
	// on affiche le texte
	int i, y;
	i = y = 0;
	do
	{
		y += TTDtxt->DrawSubString(TTDlayer, BORDER_SPACE+BORDER_SIZE, y, TT_LEFT, i);
		i++;
	}while ((y<TTDh)&&(i<(int)TTDtxt->getNbLines()));
	
	EvalPosition();

	// on redessine la zone occupée par le ToolTip
	(TTobj->Container())->RedrawArea(Rect2D(TTDx, TTDy, TTDx+TTDw, TTDy+TTDh), 1);
	return 0;
}


int CObjToolTipDefaut::ToolTipOff()
{
//MMechostr(0,"CObjToolTipDefaut::ToolTipOff\n");
	if(TTDlayer != NULL)
	{
		delete(TTDlayer);
		TTDlayer = NULL;
	}
	// on redessine la zone occupée par le ToolTip
	(TTobj->Container())->RedrawArea(Rect2D(TTDx, TTDy, TTDx+TTDw, TTDy+TTDh), 1);

	return 0;
}


Layer* CObjToolTipDefaut::GetLayerToolTip()
{
//MMechostr(0,"CObjToolTipDefaut::GetLayerToolTip\n");
	if (TTisVisible)
	{
		TTDlayer->sourceRect = Rect2D(0, 0, TTDw, TTDh);
		TTDlayer->Xdecal = TTDx-TTobj->ObjX;
		TTDlayer->Ydecal = TTDy-TTobj->ObjY;

		return TTDlayer;
	}
	return NULL;
}


void CObjToolTipDefaut::EvalPosition()
{
	int h_mouse = GetSystemMetrics(SM_CYCURSOR);
	int d;
//MMechostr(0,"CObjToolTipDefaut::EvalPosition\n");
	
	TTDx = (TTcursorX>(d=TTobj->Container()->GetXSize()-TTDw))?d:TTcursorX;
	TTDy = (TTcursorY+h_mouse+TTDh>TTobj->Container()->GetYSize())?TTcursorY-TTDh:TTcursorY+h_mouse/2;
}



//////////////////////////////////////////////////////////////////////////////////////////////////////
//  Fonctions Scol
//////////////////////////////////////////////////////////////////////////////////////////////////////

int _CRtoolTip(mmachine m)
{
	int p_obj, tmp_res, p_texte, timeout;
	char *texte;
//MMechostr(0,"_CRtoolTip\n");

	if ((p_obj = MTOP(MMget(m, 6))) == NIL)
	{
		m->pp += 6;
		MMset(m, 0, NIL);
		return 0;
	}
	else if (MMget(m, 1) == NIL)
	{
		MMechostr(MSKTRACE, "_CRtoolTip: function for ToolTipOff is nil\n");
		m->pp += 6;
		MMset(m, 0, NIL);
		return 0;
	}
	else if (MMget(m, 3) == NIL)
	{
		MMechostr(MSKTRACE, "_CRtoolTip: function for ToolTipOn is nil\n");
		m->pp += 6;
		MMset(m, 0, NIL);
		return 0;
	}
	else
	{
		CObjectBase * obj;
		if ((obj = GetObjectBase(m, p_obj)) == NULL)
		{
			MMechostr(MSKTRACE, "_CRtoolTip: ObjNode already destoyed\n");
			m->pp += 6;
			MMset(m, 0, NIL);
			return 0;
		}
		else
		{	// ObjNode valide
			if (obj->ObjToolTip != NULL)
			{
				delete(obj->ObjToolTip);
				obj->ObjToolTip = NULL;
			}

			// on empile l'ObjNode
			CHECK(MMpush(m, MMget(m, 6)));
			INVERT(m, 0, 1);
			INVERT(m, 1, 2);

			// pile : .. ObjNode fonc param
			CHECK(OBJaddreflex(m, OBJNODE,RFLOBJNODE_TOOLTIP_OFF));
			
			INVERT(m, 0, 1);
			INVERT(m, 1, 2);

			// pile : .. ObjNode fonc param
			CHECK(OBJaddreflex(m, OBJNODE,RFLOBJNODE_TOOLTIP_ON));

			MMpull(m);

			if ((p_texte = MTOP(MMpull(m))) == NIL)
			{
				texte = (char *)malloc(sizeof(char)*2);
				strcpy(texte, "");
			}
			else
			{
				int len = MMsizestr(m, p_texte);
				texte = (char *)malloc(sizeof(char)*(len+1));
				memcpy(texte, MMstartstr(m, p_texte), len+1);
			}

			if ((timeout = MTOI(MMpull(m))) == NIL)
				timeout = TOOLTIP_TIMEOUT;

			obj->ObjToolTip = new CObjToolTip(obj, texte, timeout);
			free(texte);
			return 0;
		}
	}
}


int _CRtoolTipDefault(mmachine m)
{
	int p_obj, p_font, p_texte;
	int textcolor, bckcolor, timeout;
	char *texte;
//MMechostr(0,"_CRtoolTipDefault\n");

	if ((p_obj = MTOP(MMget(m, 5))) == NIL)
	{
		m->pp += 5;
		MMset(m, 0, NIL);
		return 0;
	}
	else
	{
		CObjectBase * obj;
		if ((obj = GetObjectBase(m, p_obj)) == NULL)
		{
			MMechostr(MSKTRACE, "_CRtoolTipDefault: ObjNode already destoyed\n");
			m->pp += 5;
			MMset(m, 0, NIL);
			return 0;
		}
		else
		{
			// ObjNode valide
			if (obj->ObjToolTip != NULL)
			{
				delete(obj->ObjToolTip);
				obj->ObjToolTip = NULL;
			}

			if ((bckcolor = MTOI(MMpull(m))) == NIL)
#if VERSIONPC
				bckcolor = GetSysColor(COLOR_INFOBK);		
#else
				bckcolor = 255+(255<<8)+(224<<16);
#endif

			//la font
			p_font = MTOP( MMpull( m) );		
		
			// la couleur du texte
			if ((textcolor = MTOI(MMpull(m))) == NIL)
#if VERSIONPC
				textcolor = GetSysColor(COLOR_INFOTEXT);		
#else
				textcolor = 0;
#endif
			// le texte
			if ((p_texte = MTOP(MMpull(m))) == NIL)
			{
				texte = (char *)malloc(sizeof(char)*2);
				strcpy(texte, "");
			}
			else
			{
				int len = MMsizestr(m, p_texte);
				texte = (char *)malloc(sizeof(char)*(len+1));
				memcpy(texte, MMstartstr(m, p_texte), len+1);
			}

			if ((timeout = MTOI(MMpull(m))) == NIL)
				timeout = TOOLTIP_TIMEOUT;
			
			int failed = 1;
			obj->ObjToolTip=new CObjToolTipDefaut(	obj,
													texte,
													timeout,
													textcolor,
													bckcolor,
													p_font,
													&failed
												  );
			if (failed)
			{
				// creation failed: container is not big enough
				MMechostr(MSKTRACE, "_CRtoolTipDefault: Container is not big enough to create ToolTip for this object...\n");
				delete(obj->ObjToolTip);
				obj->ObjToolTip = NULL;
			}

			free(texte);
		}
	}

	return 0;
}


int _DStoolTip(mmachine m)
{
	int p_obj;
//MMechostr(0,"_DStoolTip\n");
	
	if ((p_obj = MTOP(MMget(m,0))) == NIL)
		MMechostr(MSKTRACE, "_DStoolTip: ObjNode is nil\n");
	else
	{
		CObjectBase * obj;
		if ((obj = GetObjectBase(m, p_obj)) == NULL)
		{
			MMechostr(MSKTRACE, "_DStoolTip: ObjNode already destoyed\n");
			MMset(m, 0, NIL);
		}
		else
		{
			delete(obj->ObjToolTip);
			obj->ObjToolTip = NULL;
 		}
 	}
 	return 0;
}