#include <sys/time.h>

#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include "condvar.h"

CondVar::CondVar()
{
	pthread_condattr_t attr;
	pthread_condattr_init(&attr);
	pthread_cond_init(&cond, &attr);
	autolock = 1;
	signalhistory = 0;
}

CondVar::~CondVar()
{
	signalhistory = 7;
	signal();
	pthread_cond_destroy(&cond);
}
	
int CondVar::wait()
{
#ifdef DEBUG
	printf("Waiting for condvar: %p\n", &cond);
	fprintf(stderr,"Waiting for condvar: %p\n", &cond);
#endif
	if (autolock) cond_mutex.lock();
	pthread_cond_wait(&cond, &cond_mutex.mutex);
	if (autolock) cond_mutex.unlock();

#ifdef DEBUG
	printf("Condvar reached: %p\n", &cond);
	fprintf(stderr, "Condvar reached: %p\n", &cond);
#endif

	return(0);
}

int CondVar::signal()
{
#ifdef DEBUG
	printf("Signalling condvar: %p\n", &cond);
	fprintf(stderr, "Signalling condvar: %p\n", &cond);
#endif	

	cond_mutex.lock();
	signalhistory = 3;
	pthread_cond_signal(&cond);
	cond_mutex.unlock();
	return 0;
}

int CondVar::broadcast()
{
#ifdef DEBUG
	printf("Broadcasting condvar: %p\n", &cond);
	fprintf(stderr,"Broadcasting condvar: %p\n", &cond);
#endif	
	cond_mutex.lock();
	signalhistory = 3;
	pthread_cond_broadcast(&cond);
	cond_mutex.unlock();
	return 0;
}

int CondVar::wait_first_signal()
{
#ifdef DEBUG
	printf("Waiting for first signal: %p\n", &cond);
	fprintf(stderr,"Waiting for first signal: %p\n", &cond);
#endif	
	cond_mutex.lock();
	if (! (signalhistory & 1))
		pthread_cond_wait(&cond, &cond_mutex.mutex);	
	signalhistory = 1;  // only bit0 remains, bit 1 is cleared
	cond_mutex.unlock();
}

int CondVar::wait_one_signal()
{
#ifdef DEBUG
	printf("Waiting for first signal: %p\n", &cond);
	fprintf(stderr,"Waiting for first signal: %p\n", &cond);
#endif	
	cond_mutex.lock();
	if (!(signalhistory & 2))
		pthread_cond_wait(&cond, &cond_mutex.mutex);	
	signalhistory = 1;  // only bit0 remains, bit 1 is cleared
	cond_mutex.unlock();
}

int CondVar::wait_one_signal_timeout(int timeoutsec, int timeoutnsec)
{
#ifdef DEBUG
	printf("Waiting for first signal: %p\n", &cond);
	fprintf(stderr,"Waiting for first signal: %p\n", &cond);
#endif	
	cond_mutex.lock();
	
	if (!(signalhistory & 2))
	{
		
		 struct timespec   ts;
		struct timeval    tp;

		gettimeofday(&tp, NULL);

		ts.tv_sec  = tp.tv_sec + timeoutsec;
		ts.tv_nsec = tp.tv_usec * 1000 + timeoutnsec;

		pthread_cond_timedwait(&cond, &cond_mutex.mutex, &ts);	
		
	}
	signalhistory = 1;  // only bit0 remains, bit 1 is cleared
	cond_mutex.unlock();
}

int CondVar::set_signalhistory(int number) 
{
	signalhistory = number;
}

int CondVar::set_autolock_onwait(int al) 
{
	autolock = al;
}
