#include "mrevent.h"
#include <sys/time.h>
#include <limits.h>
static pthread_mutex_t mtxLock = PTHREAD_MUTEX_INITIALIZER;

void mrevent_init(struct mrevent *ev, int nSignalled)
{
	ev->triggered = nSignalled;
	pthread_mutex_init(&ev->mutex, 0);
	pthread_cond_init(&ev->cond, 0);
}
void mrevent_trigger(struct mrevent *ev)
{
	pthread_mutex_lock(&ev->mutex);
	ev->triggered = 1;
	pthread_cond_signal(&ev->cond);
	pthread_mutex_unlock(&ev->mutex);
}
void mrevent_trigger_code(struct mrevent *ev, int nCode)
{
	pthread_mutex_lock(&ev->mutex);	
	if (nCode == 0 || nCode == INT_MIN)
		nCode = 1;
	ev->triggered = nCode;
	pthread_cond_signal(&ev->cond);
	pthread_mutex_unlock(&ev->mutex);
}
void mrevent_reset(struct mrevent *ev)
{
	pthread_mutex_lock(&ev->mutex);
	ev->triggered = 0;
	pthread_mutex_unlock(&ev->mutex);
}
int mrevent_wait(struct mrevent *ev)
{
	int nRes;
	pthread_mutex_lock(&mtxLock);
	nRes = ev->triggered;
	if (nRes == INT_MIN)
	{
		pthread_mutex_unlock(&mtxLock);
		return 0;
	}
	pthread_mutex_unlock(&mtxLock);
	pthread_mutex_lock(&ev->mutex);
	while (ev->triggered == 0)
		pthread_cond_wait(&ev->cond, &ev->mutex);
	nRes = ev->triggered;
	if (nRes == INT_MIN)
		nRes = 0;
	pthread_mutex_unlock(&ev->mutex);
	return nRes;
}
int mrevent_timedwait(struct mrevent *ev, int nMilliseconds)
{
	int nRes;
	pthread_mutex_lock(&mtxLock);
	nRes = ev->triggered;
	if (nRes == INT_MIN)
	{
		pthread_mutex_unlock(&mtxLock);
		return 0;
	}
	pthread_mutex_unlock(&mtxLock);
	pthread_mutex_lock(&ev->mutex);
	while (ev->triggered == 0)
	{
		struct timeval now;//, adjst, res;
		struct timespec ts;
		gettimeofday(&now, 0);
		//adjst.tv_sec = nMilliseconds / 1000;
		//adjst.tv_usec = (nMilliseconds % 1000) * 1000;
		//timeradd(&now, &adjst, &res);
		//ts.tv_sec = res.tv_sec;
		//ts.tv_nsec = res.tv_usec * 1000;
		
		ts.tv_sec = now.tv_sec + (nMilliseconds / 1000);
		ts.tv_nsec = now.tv_usec + ((nMilliseconds % 1000) * 1000) * 1000;
		
		nRes = pthread_cond_timedwait(&ev->cond, &ev->mutex, &ts);
		if (nRes != 0 || ev->triggered == INT_MIN)
		{
			nRes = 0;
			break;
		}
		else
			nRes = ev->triggered;
	}
	pthread_mutex_unlock(&ev->mutex);
	return nRes;
}

void mrevent_close(struct mrevent *ev)
{
	pthread_mutex_lock(&mtxLock);
	if (ev->triggered == INT_MIN)
	{
		pthread_mutex_unlock(&mtxLock);
		return;
	}
	ev->triggered = INT_MIN;
	pthread_mutex_unlock(&mtxLock);	
	pthread_mutex_lock(&ev->mutex);
	pthread_cond_signal(&ev->cond);
	pthread_mutex_unlock(&ev->mutex);
	pthread_mutex_destroy(&ev->mutex);
	pthread_cond_destroy(&ev->cond);
}
