import java.applet.Applet;
import java.util.concurrent.Semaphore;
import java.awt.*;
import java.awt.image.*;
/**
 * PhilosopherApplet.java
 *
 *
 * Created: Fri Oct 14 13:46:06 2005
 *
 * @author <a href="mailto:cpresser@triton-cs.cs.gettysburg.edu">Clif Presser</a>
 * @version 1.0
 */
public class PhilosopherApplet extends Applet implements Runnable{
    public static final int PHILOSOPHER_COUNT = 5;
    Color[] colors = {Color.BLACK, Color.RED, Color.GREEN, Color.YELLOW, 
                      Color.BLUE, Color.ORANGE};

    int[] forks;
    int[] seats;

    Philosopher[] philosophers;
    Semaphore[] mutex;

    Thread thread;

    BufferedImage im = null;

    public PhilosopherApplet() {
        
    } // PhilosopherApplet constructor
    
    public void init(){
        boolean sleep = true;
        String sleepStr = getParameter("SLEEP");
        
        if(sleepStr.equals("NO")){
            sleep = false;
        }

        forks = new int[PHILOSOPHER_COUNT];
        seats = new int[PHILOSOPHER_COUNT];
        philosophers = new Philosopher[PHILOSOPHER_COUNT];
        mutex = new Semaphore[PHILOSOPHER_COUNT];

        for(int i = 0; i < PHILOSOPHER_COUNT; i++){
            forks[i] = -1;
            seats[i] = i;
            philosophers[i] = new Philosopher(this, i, sleep);
            mutex[i] = new Semaphore(1);
        }

        thread = new Thread(this);
        thread.start();
    }

    public void run(){
        //start all of the philosophers
        for(int i = 0; i < PHILOSOPHER_COUNT; i++){
            philosophers[i].start();
        }

        //periodically repaint
        try{
            while(true){
                repaint();
                showStatus("Philosophers got to eat " + Philosopher.getEat() 
                           + " times.");
                thread.sleep(200);
            }
        }
        catch(InterruptedException ie){
        }
    }

    public void getFork(int philId, int forkId) 
        throws InterruptedException{
        mutex[forkId].acquire();
        forks[forkId] = philId;

    }

    public boolean releaseFork(int philId, int forkId){
        if(forks[forkId] == philId){
            forks[forkId] = -1;
            mutex[forkId].release();
            return true;
        }
        else
            return false;

    }

    public void paint(Graphics g){
        int width = getWidth();
        int height = getHeight();
        int w = width;
        int h = height;

        if(w < h)
            h = w;
        else
            w = h;

        if(im == null){
            im = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
        }

        Graphics2D g2d = (Graphics2D)im.getGraphics();

        Color current = g2d.getColor();

        //clear out background
        g2d.setColor(Color.GRAY);
        g2d.fillRect(0, 0, width, height);
        //draw table
        g2d.setColor(Color.BLACK);
        g2d.drawOval(w >> 2, h >> 2, w >> 1, h >> 1);
        
        double angle = 0;
        double angleInc = 2*Math.PI / PHILOSOPHER_COUNT;

        for(int i = 0; i < PHILOSOPHER_COUNT; i++){

            //draw fork
            g2d.setColor(colors[forks[(i + 3) % PHILOSOPHER_COUNT] +1]);
            g2d.drawLine(w >> 1 , 5*(h >> 3), w >> 1, 3*(h >> 2));

            //draw seat
            g2d.setColor(colors[i+1]);
            g2d.fillOval(7*( w >> 4), h >> 3, w >> 3, h >> 3);
            

            //rotate
            g2d.rotate(angleInc, w >> 1, h >> 1);
        }

        //unrotate
        //g2d.rotate(-(PHILOSOPHER_COUNT - 1)*angleInc, w >> 1, h >> 1);

        //write out philosopher strings
        g2d.setColor(Color.BLACK);
        int x = 10;
        int y = h + 5;
        for(int i = 0; i < philosophers.length; i++){
            g2d.setColor(colors[i+1]);
            g2d.drawString(philosophers[i].toString(), x, y);
            //System.out.println(philosophers[i]);
            y += 15;
        }

        //reset color
        g2d.setColor(current);
        g.drawImage(im, 0, 0, this);
    }

    
    public void update(Graphics g){
        //clear the screen, just paint
        paint(g);
    }

    
} // PhilosopherApplet