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
