#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 GLIBC.
 * 22.01.2003 - more stuff: timerTime(), timerResume(), timerRate().
 */
typedef	struct	libv_timer_s
{
	libv_object_t	base;
	vboolean		active;
	u32_t			start_time;
	u32_t			last_time;
	vec_t			rate;
}	libv_timer_t, *libv_timer_p;

#define	LIBV_TIMER_MAGIC	0x44544D52	/* DTMR */
V_LOCAL	char *libv_timer_object = "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;
	self->rate = (vec_t)1e-3; /* seconds per milliseconds */
	self->active = false;
	self->last_time = self->start_time = get_tick_count();
	return self;
}

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

/*
 * Sets timer to active state.
 * Subsequent calls of timerMilliseconds() will return time elapsed
 * _between_ timerStart() and timerMilliseconds().
 */
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();
}

/*
 * Same as above, but subsequent calls of timerMilliseconds()
 * will return time elapsed since latest call to timerStart()
 * minus time between calls to timerStop() and timerResume().
 */
void	V_GLOBAL
timerResume(vhandle_t timer)
{
	u32_t cur_time;
	libv_timer_p self=(libv_timer_p)libvIsHandle(timer,
		"timerResume",libv_timer_object,LIBV_TIMER_MAGIC);
	if(!self)
		return;
	cur_time = get_tick_count();
	self->active=true;
	self->start_time = cur_time - self->last_time;
	self->last_time = cur_time;
}

void	V_GLOBAL
timerRate(vhandle_t timer,vec_t rate)
{
	u32_t gtc;
	vec_t nr;
#ifdef	CHECKED_BUILD
	static char *ptf = "past-to-future";
	static char *ftp = "future-to-past";
#endif	/* CHECKED_BUILD */
	libv_timer_p self=(libv_timer_p)libvIsHandle(timer,
		"timerRate",libv_timer_object,LIBV_TIMER_MAGIC);
	if(!self)
		return;
	nr = (vec_t)1e-3 * rate;
	gtc = get_tick_count();
	if(nr * self->rate < 0)
	{
#ifdef	CHECKED_BUILD
		conlPrintf(LOG_WARNING,
			"timerRate(%g): restarting to adjoin %s with %s time streams.\n",
			rate, (self->rate > 0) ? ptf : ftp, (rate > 0) ? ptf : ftp);
#endif	/* CHECKED_BUILD */
		self->start_time = self->last_time = gtc;
	}
	else
	{
		self->start_time = (u32_t)(gtc - (self->rate / nr) * (gtc - self->start_time));
		self->last_time = gtc;
	}
	self->rate = nr;
}

/*
 * 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 = get_tick_count() - self->start_time;
}

u32_t	V_GLOBAL
timerMilliseconds(vhandle_t timer)
{
	libv_timer_p self=(libv_timer_p)libvIsHandle(timer,
		"timerMilliseconds",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->last_time;
}

/*
 * Returns time (in seconds) since last call to 'timerStart'
 */
vec_t	V_GLOBAL
timerTime(vhandle_t timer)
{
	libv_timer_p self=(libv_timer_p)libvIsHandle(timer,
		"timerTime",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) * self->rate;
	else
		return self->last_time * self->rate;
}

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;
		if(return_time > cur_time)
			delay_execution(return_time - cur_time);
#ifdef	CHECKED_BUILD
		else
			conlPrintf(LOG_ERROR,
				"timerWait(%u): curtime is %d; no time machine to go past :)\n",
				return_time,cur_time);
#endif	/* CHECKED_BUILD */
	}
#ifdef	CHECKED_BUILD
	else
		conlPrintf(LOG_ERROR,
			"timerWait(%u): timer is stopped at time %d\n",
			return_time,self->last_time);
#endif	/* CHECKED_BUILD */
}

/*
 *	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 ? */
	if(!self->active)
		return self->last_time * self->rate;
	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 * self->rate;
}

