/*
 * Copyright (c) 2004-2008 Darron M Broad
 * All rights reserved.
 *
 * Licensed under the terms of the GPL3 license, see file COPYING for details.
 */

#include "conductor.h"

/*
 * Conductor class methods
 */

Conductor::Conductor(void) : Thread()
{
	pthread_mutex_init(&eventqueue_lock, NULL);
	pthread_cond_init(&eventqueue_wakeup, NULL);
}

Conductor::~Conductor(void)
{
	pthread_mutex_destroy(&eventqueue_lock);
	pthread_cond_destroy(&eventqueue_wakeup);
}

/*
 * new event
 */
void
Conductor::newevent(struct event newevent)
{
	struct event event= newevent;
	
	pthread_mutex_lock(&eventqueue_lock);
	eventqueue.push_back(event);
	pthread_cond_signal(&eventqueue_wakeup);
	pthread_mutex_unlock(&eventqueue_lock);
}

/*
 * the thread
 */
int
Conductor::thread(void)
{
	try
	{
		Driver *driver[NUMBEROFDRIVERS];

		for(int i=0; i<NUMBEROFDRIVERS; i++)
		{
			driver[i]= new Driver();
			driver[i]->start(argc, argv);
		}

		Cleaner *cleaner= new Cleaner();
		cleaner->start(argc, argv);

		struct timespec timespec;
		struct event event;
		int index=0, testindex;

		pthread_mutex_lock(&eventqueue_lock);
		while(true)
		{
			/* when idle timedwait allows us to continue pushing the queue */
			timespec.tv_sec =time(NULL) + 2;
			timespec.tv_nsec=0;
			pthread_cond_timedwait(&eventqueue_wakeup, &eventqueue_lock, &timespec);

			/* post event to driver threads */
			testindex= index;
			while( eventqueue.size() > 0 )
			{
				event = eventqueue.back();

				if( driver[index]->newevent(event) == true )
					eventqueue.pop_back();
				
				index= (index + 1) % NUMBEROFDRIVERS;
				if( testindex==index )  /* max of one iteration */
					break;
			}
		}
	}
	catch (const char *exception)
	{
		cout << "Conductor: exception: " << exception << endl;
		exit( EX_SOFTWARE );
	}
	return 0;
}
