#include	"..\Basic\ZooStd.h"
#include	"..\SCOL\ZooSCOL.h"

#define ARG3D_I			0
#define ARG3D_F			1
#define ARG3D_S			2
#define ARG3D_H3d		3
#define ARG3D_HMat3d	4
#define ARG3D_HTx3d		5


// fun [S3d H3d I fun [S3d H3d Arg3D] Arg3D] I
int M3setH3dCB(mmachine m)
{
	int cb		=		MMpull(m);
	int id		= MTOI( MMpull(m) );
	int h3d		= MTOP( MMpull(m) );
	int s3d		= MTOP( MMget(m,0));

	if((s3d==NIL)||(h3d==NIL)||(id==NIL)||(id<0))			{   MMset(m,0,NIL);		return 0;	}

	ZNode	*node = (ZNode*) MMfetch(m,h3d,0);
	if((node==NULL)||(node->type>MSH_TYPE_ID))				{   MMset(m,0,NIL);		return 0;	}
		
	ZScene	*scene = (ZScene*) MMfetch(m,s3d,0);
	if(scene==NULL)											{	MMset(m,0,NIL);		return 0;	}



	int cbtup, cbid;

	int liste	= MTOP( MMfetch(m,h3d,1) ); 
	int prev	= NIL;

	/* Suppression de la callback dont l'identifiant est id */
	if(cb==NIL)
	{
		while(liste!=NIL)
		{
			cbtup	= MTOP( MMfetch(m,liste,0)); 
			cbid	= MTOI( MMfetch(m,cbtup,0));			
			if(cbid==id)
			{
				if(prev==NIL) MMstore(m, h3d, 1, MMfetch(m,liste,1));
				else
				{
					MMstore(m, prev, 1, MMfetch(m,liste,1));
					MMstore(m, h3d, 1, prev);
					
					MMset(m,0,ITOM(0) );

					return 0;
				}
			}
			
			prev	= liste;
			liste	= MTOP( MMfetch(m,liste,1));;
		}
	}

	else
	{
		/* Si il existe déjà une callback on la modifie */
		while(liste!=NIL)
		{
			cbtup	= MTOP( MMfetch(m,liste,0)); 
			cbid	= MTOI( MMfetch(m,cbtup,0));

			if(cbid==id)
			{
				MMstore(m, cbtup, 1, cb);
				
				MMset(m,0,ITOM(0) );
				
				return 0;
			}
			else liste	= MTOP( MMfetch(m,liste,1));		
		}


		/* La callback n'existe pas alors on l'ajoute */
		MMpush(m,cb);
		cbtup = MMmalloc(m, 2, TYPETAB);					if(cbtup==NIL)		return MERRMEM;

		MMstore(m, cbtup, 0, ITOM(id));							// user defined ID for that call-back
		MMstore(m, cbtup, 1, MMpull(m));						// call-back handler

		liste = MTOP( MMfetch(m,h3d,1) ); 
		
		MMpush(m, PTOM(liste));
		MMpush(m, PTOM(cbtup));
		int newlist = MMmalloc(m, 2, TYPETAB);				if(newlist==NIL)	return MERRMEM;
		
		MMstore(m, newlist, 0, MMpull(m));
		MMstore(m, newlist, 1, MMpull(m));

		MMstore(m, h3d, 1, PTOM( newlist ));
	}

	MMset(m,0,ITOM(0) );

	return 0;
}


// fun [S3d H3d I Arg3D] Arg3D
int M3execH3dCB(mmachine m)
{
	int arg		=		MMpull(m);
	int id		= MTOI( MMpull(m) );
	int h3d		= MTOP( MMpull(m) );
	int s3d		= MTOP( MMget(m,0));

	if((s3d==NIL)||(h3d==NIL)||(id==NIL))					{   MMset(m,0,NIL);		return 0;	}

	ZNode	*node = (ZNode*) MMfetch(m,h3d,0);
	if((node==NULL)||(node->type>MSH_TYPE_ID))				{   MMset(m,0,NIL);		return 0;	}
		
	ZScene	*scene = (ZScene*) MMfetch(m,s3d,0);
	if(scene==NULL)											{	MMset(m,0,NIL);		return 0;	}

	MMpull(m);

	bool flag = false;

	int cbtup, cbid, cbptr, res=NIL;

	int liste = MTOP( MMfetch(m,h3d,1) ); 

	while(liste!=NIL && !flag)
	{
		cbtup	= MTOP( MMfetch(m,liste,0)); 
		cbid	= MTOI( MMfetch(m,cbtup,0));
		cbptr	=		MMfetch(m,cbtup,1);

		if(cbid==id)
		{
			flag=true;

			MMpush(m, PTOM( s3d ));
			MMpush(m, PTOM( h3d ));
			MMpush(m,		arg );								// user param
			MMpush(m, cbptr);									// callback
	
			if ((res = Minterpreter(m)) < 0)
			  return res;

		}
		else liste	= MTOP( MMfetch(m,liste,1));		
	}

	if (liste == NIL)
	  MMpush(m, NIL);
	return 0;
}


// fun [S3d H3d I] fun [S3d H3d Arg3D] Arg3D
int M3getH3dCB(mmachine m)
{
	#ifdef CB_DEBUG
		_asm{int 3};
	#endif

	int id		= MTOI( MMpull(m) );
	int h3d		= MTOP( MMpull(m) );
	int s3d		= MTOP( MMget(m,0));

	if((s3d==NIL)||(h3d==NIL)||(id==NIL))					{   MMset(m,0,NIL);		return 0;	}

	ZNode	*node = (ZNode*) MMfetch(m,h3d,0);
	if((node==NULL)||(node->type>MSH_TYPE_ID))				{   MMset(m,0,NIL);		return 0;	}
		
	ZScene	*scene = (ZScene*) MMfetch(m,s3d,0);
	if(scene==NULL)											{	MMset(m,0,NIL);		return 0;	}



	int cbtup, cbid;

	int liste = MTOP( MMfetch(m,h3d,1) ); 

	while(liste!=NIL)
	{
		cbtup	= MTOP( MMfetch(m,liste,0)); 
		cbid	= MTOI( MMfetch(m,cbtup,0));

		if(cbid==id)
		{
			MMset(m,0, MMfetch(m,cbtup,1));
			return 0;
		}
		else liste	= MTOP( MMfetch(m,liste,1));		
	}

	MMset(m,0, NIL);
	return 0;
}

// fun [S I Arg3D] Arg3D
int concArg3D_I(mmachine m)
{
	int arg		= MTOP( MMpull(m) );
	int val		= MTOI( MMpull(m) );
	int str		= MTOP( MMget(m,0));

	if(str==NIL)											{   MMset(m,0,NIL);		return 0;	}

	int argtmp = arg;
	int tup, typ, sid;

	while(argtmp!=NIL)
	{
		tup		= MTOP( MMfetch(m,argtmp,0)); 
		typ		= MTOI( MMfetch(m,tup,0));
		if(typ==ARG3D_I)
		{
			sid	= MTOP( MMfetch(m,tup,1));
			if(!strcmp( MMstartstr(m, sid), MMstartstr(m, str) ))
			{
				MMstore(m, tup, 2, ITOM(val));
				MMset(m, 0, PTOM(arg));
				return 0;
			}
		}
		argtmp		= MTOP( MMfetch(m,argtmp,1));		
	}

	MMpush(m, PTOM(str));
	tup = MMmalloc(m, 3, TYPETAB);						if(tup==NIL)		return MERRMEM;
	MMstore(m, tup, 0, ITOM(ARG3D_I));
	MMstore(m, tup, 1, MMpull(m));
	MMstore(m, tup, 2, ITOM(val));

	MMpush(m, PTOM(arg));
	MMpush(m, PTOM(tup));
	int list = MMmalloc(m, 2, TYPETAB);						if(list==NIL)		return MERRMEM;
	MMstore(m, list, 0, MMpull(m));
	MMstore(m, list, 1, MMpull(m));

	MMset(m, 0, PTOM(list));
	return 0;
}



// fun [S Arg3D] I
int getArg3D_I(mmachine m)
{
	int arg		= MTOP( MMpull(m) );
	int str		= MTOP( MMget(m,0));

	if(str==NIL)											{   MMset(m,0,NIL);		return 0;	}
	
	int tup, typ, sid, val=NIL;
	bool flag = false;

	while(!flag && arg!=NIL)
	{
		tup		= MTOP( MMfetch(m,arg,0)); 
		typ		= MTOI( MMfetch(m,tup,0));
		if(typ==ARG3D_I)
		{
			sid	= MTOP( MMfetch(m,tup,1));
			if(!strcmp( MMstartstr(m, sid), MMstartstr(m, str) ))
			{
				val		= MTOI( MMfetch(m,tup,2));
				flag	= true;
			}
		}
		arg		= MTOP( MMfetch(m,arg,1));		
	}

	MMset(m,0, ITOM(val));

	return 0;
}


// fun [S F Arg3D] Arg3D
int concArg3D_F(mmachine m)
{
	int		arg		= MTOP( MMpull(m) );
	float	val		= MTOF( MMpull(m) );
	int		str		= MTOP( MMget(m,0));

	if(str==NIL)											{   MMset(m,0,NIL);		return 0;	}

	int argtmp = arg;
	int tup, typ, sid;

	while(argtmp!=NIL)
	{
		tup		= MTOP( MMfetch(m,argtmp,0)); 
		typ		= MTOI( MMfetch(m,tup,0));
		if(typ==ARG3D_F)
		{
			sid	= MTOP( MMfetch(m,tup,1));
			if(!strcmp( MMstartstr(m, sid), MMstartstr(m, str) ))
			{
				MMstore(m, tup, 2, FTOM(val));
				MMset(m, 0, PTOM(arg));
				return 0;
			}
		}
		argtmp		= MTOP( MMfetch(m,argtmp,1));		
	}

	MMpush(m, PTOM(str));
	tup = MMmalloc(m, 3, TYPETAB);						if(tup==NIL)		return MERRMEM;
	MMstore(m, tup, 0, ITOM(ARG3D_F));
	MMstore(m, tup, 1, MMpull(m));
	MMstore(m, tup, 2, FTOM(val));

	MMpush(m, PTOM(arg));
	MMpush(m, PTOM(tup));
	int list = MMmalloc(m, 2, TYPETAB);						if(list==NIL)		return MERRMEM;
	MMstore(m, list, 0, MMpull(m));
	MMstore(m, list, 1, MMpull(m));


	MMset(m, 0, PTOM(list));
	return 0;
}



// fun [S Arg3D] F
int getArg3D_F(mmachine m)
{
	int arg		= MTOP( MMpull(m) );
	int str		= MTOP( MMget(m,0));

	if(str==NIL)											{   MMset(m,0,NIL);		return 0;	}
	
	int tup, typ, sid, val=NIL;
	bool flag = false;

	while(!flag && arg!=NIL)
	{
		tup		= MTOP( MMfetch(m,arg,0)); 
		typ		= MTOI( MMfetch(m,tup,0));
		if(typ==ARG3D_F)
		{
			sid	= MTOP( MMfetch(m,tup,1));
			if(!strcmp( MMstartstr(m, sid), MMstartstr(m, str) ))
			{
				val		= MMfetch(m,tup,2);
				flag	= true;
			}
		}
		arg		= MTOP( MMfetch(m,arg,1));		
	}

	MMset(m,0, val);

	return 0;
}



// fun [S H3d Arg3D] Arg3D
int concArg3D_H3d(mmachine m)
{
	int		arg		= MTOP( MMpull(m) );
	int		val		= MTOP( MMpull(m) );
	int		str		= MTOP( MMget(m,0));

	if(str==NIL)											{   MMset(m,0,NIL);		return 0;	}

	int argtmp = arg;
	int tup, typ, sid;

	while(argtmp!=NIL)
	{
		tup		= MTOP( MMfetch(m,argtmp,0)); 
		typ		= MTOI( MMfetch(m,tup,0));
		if(typ==ARG3D_H3d)
		{
			sid	= MTOP( MMfetch(m,tup,1));
			if(!strcmp( MMstartstr(m, sid), MMstartstr(m, str) ))
			{
				MMstore(m, tup, 2, PTOM(val));
				MMset(m, 0, PTOM(arg));
				return 0;
			}
		}
		argtmp		= MTOP( MMfetch(m,argtmp,1));		
	}

	MMpush(m, PTOM(val));
	MMpush(m, PTOM(str));
	tup = MMmalloc(m, 3, TYPETAB);						if(tup==NIL)		return MERRMEM;
	MMstore(m, tup, 0, ITOM(ARG3D_H3d));
	MMstore(m, tup, 1, MMpull(m));
	MMstore(m, tup, 2, MMpull(m));

	MMpush(m, PTOM(arg));
	MMpush(m, PTOM(tup));
	int list = MMmalloc(m, 2, TYPETAB);						if(list==NIL)		return MERRMEM;
	MMstore(m, list, 0, MMpull(m));
	MMstore(m, list, 1, MMpull(m));


	MMset(m, 0, PTOM(list));
	return 0;
}



// fun [S Arg3D] H3d
int getArg3D_H3d(mmachine m)
{
	int arg		= MTOP( MMpull(m) );
	int str		= MTOP( MMget(m,0));

	if(str==NIL)											{   MMset(m,0,NIL);		return 0;	}
	
	int tup, typ, sid, val=NIL;
	bool flag = false;

	while(!flag && arg!=NIL)
	{
		tup		= MTOP( MMfetch(m,arg,0)); 
		typ		= MTOI( MMfetch(m,tup,0));
		if(typ==ARG3D_H3d)
		{
			sid	= MTOP( MMfetch(m,tup,1));
			if(!strcmp( MMstartstr(m, sid), MMstartstr(m, str) ))
			{
				val		= MMfetch(m,tup,2);
				flag	= true;
			}
		}
		arg		= MTOP( MMfetch(m,arg,1));		
	}

	MMset(m,0, val);

	return 0;
}


// fun [S HMat3d Arg3D] Arg3D
int concArg3D_HMat3d(mmachine m)
{
	int		arg		= MTOP( MMpull(m) );
	int		val		= MTOP( MMpull(m) );
	int		str		= MTOP( MMget(m,0));

	if(str==NIL)											{   MMset(m,0,NIL);		return 0;	}

	int argtmp = arg;
	int tup, typ, sid;

	while(argtmp!=NIL)
	{
		tup		= MTOP( MMfetch(m,argtmp,0)); 
		typ		= MTOI( MMfetch(m,tup,0));
		if(typ==ARG3D_HMat3d)
		{
			sid	= MTOP( MMfetch(m,tup,1));
			if(!strcmp( MMstartstr(m, sid), MMstartstr(m, str) ))
			{
				MMstore(m, tup, 2, PTOM(val));
				MMset(m, 0, PTOM(arg));
				return 0;
			}
		}
		argtmp		= MTOP( MMfetch(m,argtmp,1));		
	}

	MMpush(m, PTOM(val));
	MMpush(m, PTOM(str));
	tup = MMmalloc(m, 3, TYPETAB);						if(tup==NIL)		return MERRMEM;
	MMstore(m, tup, 0, ITOM(ARG3D_HMat3d));
	MMstore(m, tup, 1, MMpull(m));
	MMstore(m, tup, 2, MMpull(m));

	MMpush(m, PTOM(arg));
	MMpush(m, PTOM(tup));
	int list = MMmalloc(m, 2, TYPETAB);						if(list==NIL)		return MERRMEM;
	MMstore(m, list, 0, MMpull(m));
	MMstore(m, list, 1, MMpull(m));


	MMset(m, 0, PTOM(list));
	return 0;
}



// fun [S Arg3D] HMat3d
int getArg3D_HMat3d(mmachine m)
{
	int arg		= MTOP( MMpull(m) );
	int str		= MTOP( MMget(m,0));

	if(str==NIL)											{   MMset(m,0,NIL);		return 0;	}
	
	int tup, typ, sid, val=NIL;
	bool flag = false;

	while(!flag && arg!=NIL)
	{
		tup		= MTOP( MMfetch(m,arg,0)); 
		typ		= MTOI( MMfetch(m,tup,0));
		if(typ==ARG3D_HMat3d)
		{
			sid	= MTOP( MMfetch(m,tup,1));
			if(!strcmp( MMstartstr(m, sid), MMstartstr(m, str) ))
			{
				val		= MMfetch(m,tup,2);
				flag	= true;
			}
		}
		arg		= MTOP( MMfetch(m,arg,1));		
	}

	MMset(m,0, val);

	return 0;
}

// fun [S HTx3d Arg3D] Arg3D
int concArg3D_HTx3d(mmachine m)
{
	int		arg		= MTOP( MMpull(m) );
	int		val		= MTOP( MMpull(m) );
	int		str		= MTOP( MMget(m,0));

	if(str==NIL)											{   MMset(m,0,NIL);		return 0;	}

	int argtmp = arg;
	int tup, typ, sid;

	while(argtmp!=NIL)
	{
		tup		= MTOP( MMfetch(m,argtmp,0)); 
		typ		= MTOI( MMfetch(m,tup,0));
		if(typ==ARG3D_HTx3d)
		{
			sid	= MTOP( MMfetch(m,tup,1));
			if(!strcmp( MMstartstr(m, sid), MMstartstr(m, str) ))
			{
				MMstore(m, tup, 2, PTOM(val));
				MMset(m, 0, PTOM(arg));
				return 0;
			}
		}
		argtmp		= MTOP( MMfetch(m,argtmp,1));		
	}

	MMpush(m, PTOM(val));
	MMpush(m, PTOM(str));
	tup = MMmalloc(m, 3, TYPETAB);						if(tup==NIL)		return MERRMEM;
	MMstore(m, tup, 0, ITOM(ARG3D_HTx3d));
	MMstore(m, tup, 1, MMpull(m));
	MMstore(m, tup, 2, MMpull(m));

	MMpush(m, PTOM(arg));
	MMpush(m, PTOM(tup));
	int list = MMmalloc(m, 2, TYPETAB);						if(list==NIL)		return MERRMEM;
	MMstore(m, list, 0, MMpull(m));
	MMstore(m, list, 1, MMpull(m));


	MMset(m, 0, PTOM(list));
	return 0;
}



// fun [S Arg3D] HTx3d
int getArg3D_HTx3d(mmachine m)
{
	int arg		= MTOP( MMpull(m) );
	int str		= MTOP( MMget(m,0));

	if(str==NIL)											{   MMset(m,0,NIL);		return 0;	}
	
	int tup, typ, sid, val=NIL;
	bool flag = false;

	while(!flag && arg!=NIL)
	{
		tup		= MTOP( MMfetch(m,arg,0)); 
		typ		= MTOI( MMfetch(m,tup,0));
		if(typ==ARG3D_HTx3d)
		{
			sid	= MTOP( MMfetch(m,tup,1));
			if(!strcmp( MMstartstr(m, sid), MMstartstr(m, str) ))
			{
				val		= MMfetch(m,tup,2);
				flag	= true;
			}
		}
		arg		= MTOP( MMfetch(m,arg,1));		
	}

	MMset(m,0, val);

	return 0;
}

#define Nbcb3dPKG	14

//////////////////////////////////////////////////////////////////////////////////////////////
///		Definition des noms de fonction SCOL
//////////////////////////////////////////////////////////////////////////////////////////////
char	*cb3dName[Nbcb3dPKG] =
{
	"Arg3D",												// type Arg3D

	"M3setH3dCB",											// M3setH3dCB
	"M3execH3dCB",											// M3execH3dCB
	"M3getH3dCB",											// M3getH3dCB

	"concArg3D_I",											// concArg3D_I
	"getArg3D_I",											// getArg3D_I
	"concArg3D_F",											// concArg3D_F
	"getArg3D_F",											// getArg3D_F
	"concArg3D_H3d",										// concArg3D_H3d
	"getArg3D_H3d",											// getArg3D_H3d
	"concArg3D_HMat3d",										// concArg3D_HMat3d
	"getArg3D_HMat3d",										// getArg3D_HMat3d
	"concArg3D_HTx3d",										// concArg3D_HTx3d
	"getArg3D_HTx3d",										// getArg3D_HTx3d
};


//////////////////////////////////////////////////////////////////////////////////////////////
///		Definition des pointeurs sur fonctions
//////////////////////////////////////////////////////////////////////////////////////////////
int (*cb3dFunc[Nbcb3dPKG])(mmachine m)=
{
	NULL,													// type Arg3D

	M3setH3dCB,												// M3setH3dCB
	M3execH3dCB,											// M3execH3dCB
	M3getH3dCB,												// M3getH3dCB

	concArg3D_I,											// concArg3D_I
	getArg3D_I,												// getArg3D_I
	concArg3D_F,											// concArg3D_F
	getArg3D_F,												// getArg3D_F
	concArg3D_H3d,											// concArg3D_H3d
	getArg3D_H3d,											// getArg3D_H3d
	concArg3D_HMat3d,										// concArg3D_HMat3d
	getArg3D_HMat3d,										// getArg3D_HMat3d
	concArg3D_HTx3d,										// concArg3D_HTx3d
	getArg3D_HTx3d,											// getArg3D_HTx3d
};


//////////////////////////////////////////////////////////////////////////////////////////////
///		Definition du nombre de paramètres
//////////////////////////////////////////////////////////////////////////////////////////////
int cb3dNArg[Nbcb3dPKG]=
{
	TYPTYPE,												// type Arg3D

	4,														// M3setH3dCB
	4,														// M3execH3dCB
	3,														// M3getH3dCB

	3,														// concArg3D_I
	2,														// getArg3D_I
	3,														// concArg3D_F
	2,														// getArg3D_F
	3,														// concArg3D_H3d
	2,														// getArg3D_H3d
	3,														// concArg3D_HMat3d
	2,														// getArg3D_HMat3d
	3,														// concArg3D_HTx3d
	2,														// getArg3D_HTx3d
};



//////////////////////////////////////////////////////////////////////////////////////////////
///		Definition des grammaires fontionnelles
//////////////////////////////////////////////////////////////////////////////////////////////
char* cb3dType[Nbcb3dPKG]=
{
	NULL,													// type CBarg3D


	"fun [S3d H3d I fun [S3d H3d Arg3D] Arg3D] I",			// M3setCallback
	"fun [S3d H3d I Arg3D] Arg3D",							// M3execH3dCB
	"fun [S3d H3d I] fun [S3d H3d Arg3D] Arg3D",			// M3getH3dCB

	"fun [S I Arg3D] Arg3D",								// concArg3D_I
	"fun [S Arg3D] I",										// getArg3D_I
	"fun [S F Arg3D] Arg3D",								// concArg3D_F
	"fun [S Arg3D] F",										// getArg3D_F
	"fun [S H3d Arg3D] Arg3D",								// concArg3D_H3d
	"fun [S Arg3D] H3d",									// getArg3D_H3d
	
	"fun [S HMat3d Arg3D] Arg3D",							// concArg3D_HMat3d
	"fun [S Arg3D] HMat3d",									// getArg3D_HMat3d
	"fun [S HTx3d Arg3D] Arg3D",							// concArg3D_HTx3d
	"fun [S Arg3D] HTx3d",									// getArg3D_HTx3d
};


int SCOLloadCB3D(mmachine m,cbmachine w)
{
	int k;

	k=(PKhardpak(m,"Callback3D",Nbcb3dPKG,cb3dName,cb3dFunc,cb3dNArg,cb3dType));

	return k;
}



int SCOLfreeCB3D()
{
	MMechostr(1,"Release Callback3D ressources\n");

	return 0;
}