#include <../source/TAL/objbase.h>
#include <../source/PAL/dataman.h>
#include <../source/PAL/oshead.h>

#ifdef		__WIN32__

#define		delay_execution(milliseconds)		Sleep(milliseconds)
#define		get_tick_count						GetTickCount

#elif		defined(__UNIX__)	/* !__WIN32__ */

#ifdef		EMULATE_USLEEP
/* nap()'ing support routine for 4.2BSD system call emulations
 * Last edit:   29-Oct-1984    D A Gwyn
 * Returns 0 if ok, else -1 */
int	delay_execution(long milliseconds)
{
	static struct /* `timeval' */
	{
    	long tv_sec;      /* seconds */
        long tv_usec;     /* microsecs */
	}   delay;   /* _select() timeout */
	delay.tv_sec = microseconds / 1000000L;
    delay.tv_usec = microseconds % 1000000L;
	return select(0,(long *)0,(long *)0,(long *)0,&delay);
}
#else		/* !EMULATE_USLEEP */

#define		delay_execution(milliseconds)	usleep(1000*milliseconds)

#endif		/* !EMULATE_USLEEP */

u32_t	V_LOCAL
get_tick_count(void)
{
	struct timezone tz={0,0};
	struct timeval tv;
	gettimeofday((struct timeval*)&tv,&tz);
	return tv.tv_sec * 1000 + tv.tv_usec / 1000;
}

#endif	/* __UNIX__ */

u32_t	V_GLOBAL
timeTickCount()
{
	return get_tick_count();
}

void	V_GLOBAL
timeDelay(u32_t Milliseconds)
{
	delay_execution(Milliseconds);
}

/*
 *	22.09.2001 - rewrote timer code to avoid namespace collisions
 *	with moderate linux kernels (listen: kernels with broken source tree;
 *	i mean it, source tree for MDK-8 + 2.4.3 IS broken !).
 *	Ideology changed too.
 */
typedef	struct	libv_timer_s
{
	libv_object_t	base;
	vboolean		active;
	u32_t			start_time;
	u32_t			last_time;
}	libv_timer_t, *libv_timer_p;

#define	LIBV_TIMER_MAGIC	0x44544D52	/* DTMR */
V_LOCAL	char *libv_timer_object = "dumb timer";

V_LOCAL	u32_t V_CALL
libv_timer_destroy(vhandle_t handle)
{
	libv_timer_p self=(libv_timer_p)handle;
	if(--self->base.ref_count)
		return self->base.ref_count;	/* still references */
	memFreeObject(self);
	return 0;
}

vhandle_t	V_GLOBAL
timerCreate(void)
{
	libv_timer_p self;
	ALLOC_OBJECT(self,libv_timer_t,0,LIBV_TIMER_MAGIC);
	self->base.destroy=libv_timer_destroy;
	timerDiffTime(self);
	return (vhandle_t)self;
}

void	V_GLOBAL
timerDestroy(vhandle_t timer)
{
	libvCloseHandle(timer,"timerDestroy",libv_timer_object,
		LIBV_TIMER_MAGIC);
}

/*
 *	Sets timer to active state.
 */
void	V_GLOBAL
timerStart(vhandle_t timer)
{
	libv_timer_p self=(libv_timer_p)libvIsHandle(timer,
		"timerStart",libv_timer_object,LIBV_TIMER_MAGIC);
	if(!self)
		return;
	self->active=true;
	self->last_time=self->start_time=get_tick_count();
}

/*
 *	Sets timer to passive state: subsequent calls of timerMilliseconds()
 *	will return time of this call.
 */	
void	V_GLOBAL
timerStop(vhandle_t timer)
{
	libv_timer_p self=(libv_timer_p)libvIsHandle(timer,
		"timerStop",libv_timer_object,LIBV_TIMER_MAGIC);
	if(!self)
		return;
	self->active=false;
	self->last_time=self->start_time=get_tick_count();
}

u32_t	V_GLOBAL
timerMilliseconds(vhandle_t timer)
{
	libv_timer_p self=(libv_timer_p)libvIsHandle(timer,
		"timerStop",libv_timer_object,LIBV_TIMER_MAGIC);
	if(!self)
		return 0; /* FIXME: what we can return in this case ? */
	if(self->active)
		return get_tick_count() - self->start_time;
	else
		return self->start_time;
}

void	V_GLOBAL
timerWait(vhandle_t timer,u32_t return_time)
{
	u32_t cur_time;
	libv_timer_p self=(libv_timer_p)libvIsHandle(timer,
		"timerWait",libv_timer_object,LIBV_TIMER_MAGIC);
	if(!self)
		return;
	if(self->active)
		cur_time = get_tick_count() - self->start_time;
	else
		cur_time = self->start_time;
	delay_execution(return_time - cur_time);
}

/*
 *	The most useful routine: returns time since last call in seconds;
 *	correctly handles counter overflow.
 */
vec_t	V_GLOBAL
timerDiffTime(vhandle_t timer)
{
	u32_t cur_time, time_ret;
	libv_timer_p self=(libv_timer_p)libvIsHandle(timer,
		"timerDiffTime",libv_timer_object,LIBV_TIMER_MAGIC);
	if(!self)
		return 0; /* FIXME: what we can return in this case ? */
	cur_time=get_tick_count();
	/* Check for overflow */
	if(cur_time < self->last_time)
	{
		/* counter overflowed; restart timer. */
		self->start_time=self->last_time=cur_time;
		time_ret = 0;
	}
	else
	{
		if(self->active)
			time_ret = 0;
		else
			time_ret = cur_time - self->last_time;
	}
	self->last_time=cur_time;
	return time_ret  * (vec_t)0.001;
}
