package philosophers;

/*
 * Philosopher.java
 *
 * The dining philsopher's problem using semaphores
 *
 * copyright (c) 2000, 2001, 2002, 2010 - Russell C. Bjork
 *
 */
 
import concurrency.BinarySemaphoreWithFIFOQueue;
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,
                       BinarySemaphoreWithFIFOQueue firstChopstick,
                       BinarySemaphoreWithFIFOQueue 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

                firstChopstick.P();
                secondChopstick.P();

                // 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

                firstChopstick.V();
                secondChopstick.V();

                // 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 BinarySemaphoreWithFIFOQueue firstChopstick;
    private BinarySemaphoreWithFIFOQueue 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
}
