#include <pthread.h>
#include <stdio.h>
#include <taskLib.h>	
#include <semaphore.h>
	
                                   
#define     SLEEP_TIME       3     /* maximum amount of time */
#define		NUM_PHILOSOPHERS 5	   /* number of philosophers */

void hungry();
void thinking();
void *philosopher(void*);
void eating(int num);
void orderWine(int num);
void *serviceTask(void *arg);

sem_t* gabel[5];	/* semaphores for all forks */


pthread_t thread[5];		/* threads for all philosophers */
int id[5];					/* id parameter */


int main()
{
	int i;
	
	/************************************************/
	/*initialize 5 semaphores						*/
	/************************************************/

	gabel[0] = sem_open("sem0", O_CREAT, 1, 1);
	gabel[1] = sem_open("sem1", O_CREAT, 1, 1);
	gabel[2] = sem_open("sem2", O_CREAT, 1, 1);
	gabel[3] = sem_open("sem3", O_CREAT, 1, 1);
	gabel[4] = sem_open("sem4", O_CREAT, 1, 1);


	

	/************************************************/
	/*create philosopher threads					*/
	/************************************************/
	for (i=0; i<5; i++) {
		id[i] = i;
		if (0!=pthread_create (&thread[i], NULL, philosopher, &id[i])) /* creation of philosopher thread i */ {
			printf("ERROR: main thread: could not create thread%d\n", i);
			return -1;
		}
		else {
			printf("INFO: main thread: thread%d created\n", i);
		}

	}

	pthread_join(thread[0], NULL);
	pthread_join(thread[1], NULL);
	pthread_join(thread[2], NULL);
	pthread_join(thread[3], NULL);
	pthread_join(thread[4], NULL);
	
	printf("END\n");

	return 0;
}

/**********************************************************************/
/**FUNCTION:  philTask()                                         	 **/
/**                                                                  **/
/**DESCRIPTION:  every philosopher thinks, is hungry, eats and     	 **/
/** 			 orders wine			                             **/
/**********************************************************************/
void *philosopher(void *arg)
{
	int i;
	struct timespec current_time;

	clock_gettime(CLOCK_REALTIME, &current_time); /* current time */
	srand((int)current_time.tv_nsec);

	/**************************************************************/
	/*philosopher (child) thinks, becomes hungry, ...*/
	/**************************************************************/

	for (i=0;i<10;i++)
	{
		thinking(*(int*)arg);
		hungry(*(int*)arg);		
		eating(*(int*)arg);	
	}
	
	return 0;
}

/**********************************************************************/
/**FUNCTION:  hungry()                                               **/
/**                                                                  **/
/**DESCRIPTION:   This function is representative of a philosopher   **/
/** being hungry.                                                    **/
/**********************************************************************/
void hungry(int p_num)
{
	printf("Philosopher %d: I'm hungry!\n",p_num);
}


/**********************************************************************/
/**FUNCTION:   thinking()                                            **/
/**                                                                  **/
/**DESCRIPTION:   This function is representative of a philosopher   **/
/** thinking for a random amount of time.                            **/
/**********************************************************************/
void thinking(int p_num)
{
	printf("Philosopher %d is thinking!\n",p_num);
	taskDelay((rand() % SLEEP_TIME) * 60); /* 1 tick is normally 1/60s */
}


/**********************************************************************/
/**FUNCTION:  eating()                                               **/
/**                                                                  **/
/**DESCRIPTION:   This function is representative of a philosopher   **/
/** eating for a random amount of time.                              **/
/**********************************************************************/
void eating(int p_num)
{

	int lower, higher;
		/*********************/
		/****    TAKE FORKS **/
		/*********************/
		lower = min((p_num + 1) % NUM_PHILOSOPHERS, p_num);
		higher = max((p_num + 1) % NUM_PHILOSOPHERS, p_num);
		printf("*** Philo %d, acquires first %d, then %d, releases them in reverse order\n", p_num, lower, higher);
			
		sem_wait(gabel[lower]);
		taskDelay(SLEEP_TIME * 60);
		sem_wait(gabel[higher]);
			
		printf("Philosopher %d is eating!\n",p_num);
		taskDelay((rand() % SLEEP_TIME) * 60); /* 1 tick is normally 1/60s */
			
		/*********************/
		/****    GIVE FORKS **/
		/*********************/
		sem_post(gabel[higher]);
		sem_post(gabel[lower]);
	

}

