#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)
{

	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()
{
	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;
	
	// 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(); 
	
	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)
{
	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)
{
	if (!TTisVisible)
	{
		Disarm();
		Arm(CursorX,CursorY);
	}
}

void CObjToolTip::TimerEnd()
{
	TTtimer=mt_start(TIP_VISIBLE_END,(int)this,CObjToolTipEndCallBack);
}

// Clear The Tip and disarm the tip display mechanism
void CObjToolTip::Disarm()
{
	if (TTtimer!=NO_TIMER)
	{
		mt_del(TTtimer);
		TTtimer=NO_TIMER;
	}
	if (TTisVisible)
	{
		TTisVisible=0;
		ToolTipOff();
	}
}

// Show Tip
int CObjToolTip::ToolTipOn()
{
	int k,tmp_res;
	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;

	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()
{
	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)
{
	*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()
{
	delete(TTDtxt);

	if (TTDlayer!=NULL)
	{
		delete(TTDlayer);
		TTDlayer=NULL;
	}

    Lib2dFontService.delLayerFont(TTDfont);
}

int CObjToolTipDefaut::ToolTipOn()
{
	// 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()
{
	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()
{
	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;
	
	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;

	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;

	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;
	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;
}
