/*
 * Philosopher.java
 *
 * The dining philosophers problem solved using synchronization
 *
 * copyright (c) 2000, 2001, 2002, 2010 - Russell C. Bjork
 *
 */

package philosophers;
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 first of the two chopsticks needed to eat
     *  @param secondChopstick the second of the two chopsticks needed to eat
     */
     
    public Philosopher(JLabel label, Chopstick firstChopstick, 
                       Chopstick secondChopstick)
    {
        this.label = label;
        this.firstChopstick = firstChopstick;
        this.secondChopstick = secondChopstick;
        
        this.state = HUNGRY;
        this.dead = false;
    }

    /** Simulate the philosophers' life - eating and thinking ... */
    
    public void run()
    {
        while (! dead)
        {
            switch(state)
            {
                case HUNGRY:
                
                    // Depict hungry state on the screen
                    
                    label.setForeground(Color.red);
                    label.repaint();
                    
                    // Obtain the chopsticks
                    
                    firstChopstick.pickup(this);
                    secondChopstick.pickup(this);
                    
                    // Can now eat
                    
                    state = EATING;
                    break;
                            
                case EATING:
                
                    // Depict eating state on the screen
                    
                    label.setForeground(Color.green);
                    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)
                    { }
                    
                    // Appetite now satisfied
                    
                    state = SATED;
                    break;
                    
                case SATED:
                    
                    // Depict sated state on the screen
                    
                    label.setForeground(Color.yellow);
                    label.repaint();
                    
                    // Put down the chopsticks when through using them
                    
                    firstChopstick.putdown();
                    secondChopstick.putdown();
                    
                    // With hunger sated, can now think
                    
                    state = THINKING;
                    break;
                    
                case THINKING:
                
                    // Depict thinking state on the screen
                    
                    label.setForeground(Color.blue);
                    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)
                    { }
                    
                    // Hunger interrupts thinking - time to eat again
                    
                    state = HUNGRY;
                    break;
            }
        }
            
        // The philosopher is dead - depict this on the screen
        
        label.setForeground(Color.black);
        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 Chopstick firstChopstick;
    private Chopstick secondChopstick;
    
    // Instance variable - the philosopher's current state, possible values
    
    private int state;
    private static final int HUNGRY = 1;
    private static final int EATING = 2;
    private static final int SATED = 3;
    private static final int THINKING = 4;
    
    // 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
}
