// EPOS-- Semaphore Test Program

#include <utility/ostream.h>
#include <thread.h>
#include <semaphore.h>
#include <alarm.h>
#include <display.h>

__USING_SYS

const int iterations = 10;
const int thinking_time = 100000;
const int eating_time = 500000;

Semaphore sem_display;

Thread * phil[5];
Semaphore * chopstick[5];

OStream cout;

int philosopher(int n, int l, int c)
{

    int first = (n < 4)? n : 0;
    int second = (n < 4)? n + 1 : 4;

    for(int i = iterations; i > 0; i--) {

	sem_display.p();
	Display::position(l, c);
 	cout << "thinking";
	sem_display.v();

	Delay thinking(thinking_time);

	chopstick[first]->p();   // get first chopstick
	chopstick[second]->p();   // get second chopstick

	sem_display.p();
	Display::position(l, c);
	cout << " eating ";
	sem_display.v();

	Delay eating(eating_time);

	chopstick[first]->v();   // release first chopstick
	chopstick[second]->v();   // release second chopstick
    }

    sem_display.p();
    Display::position(l, c);
    cout << "  done  ";
    sem_display.v();

    return(iterations);
}

int main()
{
    sem_display.p();
    Display::clear();
    cout << "The Philosopher's Dinner:\n";
	
    for(int i = 0; i < 5; i++)
	chopstick[i] = new Semaphore;

    unsigned long sleep_time = iterations * (eating_time + thinking_time);

    Thread::Criterion c0 = Thread::Criterion(sleep_time * 11, sleep_time * 2);
    Thread::Criterion c1 = Thread::Criterion(sleep_time * 11, sleep_time * 2);
    Thread::Criterion c2 = Thread::Criterion(sleep_time * 11, sleep_time * 2);
    Thread::Criterion c3 = Thread::Criterion(sleep_time * 11, sleep_time * 2);
    Thread::Criterion c4 = Thread::Criterion(sleep_time * 11, sleep_time * 2);

    phil[0] = new Thread(&philosopher, 0,  5, 32, Thread::READY, c0);
    phil[1] = new Thread(&philosopher, 1, 10, 44, Thread::READY, c1);
    phil[2] = new Thread(&philosopher, 2, 16, 39, Thread::READY, c2);
    phil[3] = new Thread(&philosopher, 3, 16, 24, Thread::READY, c3);
    phil[4] = new Thread(&philosopher, 4, 10, 20, Thread::READY, c4);

    cout << "Philosophers are alife and hungry!\n";
	
    cout << "The dinner is served ...\n";
    Display::position(7, 44);
    cout << '/';
    Display::position(13, 44);
    cout << '\\';
    Display::position(16, 35);
    cout << '|';
    Display::position(13, 27);
    cout << '/';
    Display::position(7, 27);
    cout << '\\';
    sem_display.v();


    for(int i = 0; i < 5; i++) {
	int ret = phil[i]->join();
	sem_display.p();
	Display::position(20 + i, 0);
	cout << "Philosopher " << i << " ate " << ret << " times \n";
	sem_display.v();
    }

    for(int i = 0; i < 5; i++)
	delete chopstick[i];
    for(int i = 0; i < 5; i++)
	delete phil[i];

    cout << "The end!\n";

    return 0;
}