/*
 * Philosopher.java
 *
 * The dining philsopher's problem using message passing
 *
 * copyright (c) 2000, 2001, 2002, 2010 - Russell C. Bjork
 *
 */

package philosophers;

import concurrency.Message;

import javax.swing.JLabel;
import java.awt.Color;

/** Simulation of an individual philosopher */

public class Philosopher extends Thread
{
    /** Constructor
     *
     *  @param label the label representing this philosopher on the screen -
     *   set to be red when the philosopher is waiting for a chopstick, green
     *   while eating, yellow when sated, blue while thinking, and black when
     *   the philosper is dead
     *  @param firstChopstick the number of the first of the two chopsticks
     *         needed to eat
     *  @param secondChopstick the number of the second of the two chopsticks
     *         needed to eat
     */
     
    public Philosopher(JLabel label,
                       int firstChopstick,
                       int secondChopstick)
    {
        this.label = label;
        this.firstChopstick = firstChopstick;
        this.secondChopstick = secondChopstick;
        this.dead = false;
    }

    /** Simulate the philosophers' life - eating and thinking ... */
    
    public void run()
    {
        while (! dead)
        {
                // Depict hungry state on the screen

                label.setForeground(HUNGRY_COLOR);
                label.repaint();

                // Obtain the chopsticks

                new Message("U" + (char) firstChopstick).
                            sendAwaitReply(Coordinator.getInstance());
                new Message("U" + (char) secondChopstick).
                            sendAwaitReply(Coordinator.getInstance());
 
                // Can now eat

                label.setForeground(EATING_COLOR);
                label.repaint();

                // Simulate eating by having the thread sleep for a
                // random time

                try
                {
                    Thread.sleep((int) (AVERAGE_EAT_TIME *
                            (0.5 + Math.random())));
                }
                catch(InterruptedException e)
                { }

                // Put down the chopsticks when through using them

                new Message("D" + (char) firstChopstick).send(Coordinator.getInstance());
                new Message("D" + (char) secondChopstick).send(Coordinator.getInstance());

                // With hunger sated, can now think

                label.setForeground(THINKING_COLOR);
                label.repaint();

                // Simulate thinking by having the thread sleep for a
                // random time

                try
                {
                    Thread.sleep((int) (AVERAGE_THINK_TIME *
                            (0.5 + Math.random())));
                }
                catch(InterruptedException e)
                { }
         }
            
        // The philosopher is dead - depict this on the screen
        
        label.setForeground(DEAD_COLOR);
        label.repaint();
    }
    
    /** Kill this philosopher's thread, ending the philosopher's endless
     *  cycle of eating and thinking
     */
    
    public void kill()
    {
        dead = true;
        interrupt();
    }
    
    /** Accessor for philosopher's name
     *
     *  @return the name of this philosopher
     */
     
    public String name()
    {
        return label.getText();
    }
    
    // Instance variables - information passed to the constructor
    
    private JLabel label;
    private int firstChopstick;
    private int secondChopstick;
    
    // Colors representing the various states
    
    private static final Color HUNGRY_COLOR = Color.RED;
    private static final Color EATING_COLOR = Color.GREEN;
    private static final Color THINKING_COLOR = Color.BLUE;
    private static final Color DEAD_COLOR = Color.BLACK;
    
    // Instance variable - becomes true when the philosopher has been killed
    
    private boolean dead;
    
    // These constants control the amount of time spent eating, thinking. The 
    // actual time will be a random number between 0.5 and 1.5 times average.
    
    private static final int AVERAGE_EAT_TIME = 5000;       // Milliseconds
    private static final int AVERAGE_THINK_TIME = 5000;     // Milliseconds
}
