/**
 * Die Klasse Philosopher repr�sentiert einen Philosophen.
 */
class Philosopher extends Thread {
  /**
   * Konstanten f�r die m�glichen Zust�nde
   */
  public final static int THINKING = 1;
  public final static int HUNGRY   = 2;
  public final static int EATING   = 3;

  Table table; // der Tisch
  Canteen canteen; // der Besteckkasten
  int leftFork, rightFork; // die linke und rechte Gabel
  int id; // die eigene ID

  /**
   * Konstruktor: initialisiert alle Attribute und startet
   * den Thread
   */
  public Philosopher (int id, int left, int right, Table tbl, Canteen can) {
    this.id = id;
    this.leftFork = left;
    this.rightFork = right;
    this.table = tbl;
    this.canteen = can;
    start ();
  }

  /**
   * Hauptschleife des Philosophen
   */
  public void run () {
    // Anfangszustand: Nachdenken
    table.setPhilosophersState (id, THINKING);
    
    while (true) {
      // der Besteckkasten ist gesch�tzt !
      synchronized (canteen) {
        // Warten, bis beide Gabeln verf�gbar sind
        while (! canteen.isAvailable (leftFork) || 
              !canteen.isAvailable (rightFork)) {
          // Gabeln sind belegt: Zustand ist Hungrig
          table.setPhilosophersState (id, HUNGRY);
          // wir m�ssen warten
          try {
            canteen.wait ();
          }
          catch (InterruptedException exc) {
          }
        }
        // beide Gabeln aufnehmen
        canteen.takeFork (leftFork);
        canteen.takeFork (rightFork);
      }
      // jetzt k�nnen wir eine Weile essen
      table.setPhilosophersState (id, EATING);

      try {
        sleep ((int) (Math.random () * 3000.0));
      }
      catch (InterruptedException exc) {
      }

      // Besteckkasten ist wieder gesch�tzt
      synchronized (canteen) {
        // Gabeln niederlegen
        canteen.putFork (leftFork);
        canteen.putFork (rightFork);
        // alle wartenden Philosophen aufwecken
        canteen.notifyAll ();
      }

      // wieder eine Weile nachdenken
      table.setPhilosophersState (id, THINKING);
      try {
        sleep ((int) (Math.random () * 5000.0));
      }
      catch (InterruptedException exc) {
      }
    }
  }
}