/* 
java jode 
this is an applet that demonstraits the dining philosophers problem


this is the prebeta version
*/

import java.awt.Graphics; 
import java.awt.*;
import java.net.*;
import java.io.InputStream;

public class DiningPhil extends java.applet.Applet implements Runnable 
  {
    String audio;
    Image bullet;
    Image phil[] = new Image[5];
    Image oldphil[] = new Image[5];
    Image thinkingphil[][] = new Image[5][4];
    Image hungryphil[][] = new Image[5][4];
    Image eatingphil[][] = new Image[5][4];
    Image background;
    int slide1=185,slide2=185,slide3=185,oldslide1,oldslide2,oldslide3;
    boolean slide1click=false, slide2click=false, slide3click=false;
    sticksPB Sticks[] = new sticksPB[5];
    int thishand[] = new int[5];
    int thathand[] = new int[5];
    Thread au=null;
    Thread bu=null;
    Thread cu=null;
    Thread du=null;
    Thread eu=null;
    Thread fu=null;
    int ticketnumber=0;

    float EatChance=.25f;
    float ThinkChance=.75f;
    int speed=80;

    final int xoffset =-80 ,yoffset=-100;
    final int buttonx=xoffset+80+73, buttony=yoffset+138+398, buttonspace=90;
    final int slide1y=yoffset+138+433, slide2y=yoffset+138+463, slide3y=yoffset+138+493;
    final int slidexl=xoffset+80+60,slidexr=xoffset+80+430;

    public void init() 
      {
	audio="eat";

	oldslide1=slide1;
	oldslide2=slide2;
	oldslide3=slide3;

	Sticks[0]=new sticksPB();
	Sticks[1]=new sticksPB();
	Sticks[2]=new sticksPB();
	Sticks[3]=new sticksPB();
	Sticks[4]=new sticksPB();

	Sticks[0].returnStick(7);
	Sticks[1].returnStick(3);
	Sticks[2].returnStick(3);
	Sticks[3].returnStick(3);
	Sticks[4].returnStick(3);


	au=new Thread(this);
	bu=new Thread(this);
	cu=new Thread(this);
	du=new Thread(this);
	eu=new Thread(this);
	fu=new Thread(this);
/*	System.out.println("we think, therefore we are");
*/
	au.start();
	bu.start();
	cu.start();
	du.start();
	eu.start();
	fu.start();



	stop();
	initializeImages();
      }

    public void start()
      {
/*	System.out.println("we live");
*/
	au.resume();
	bu.resume();
	cu.resume();
	du.resume();
	eu.resume();
	fu.resume();
      }

    public void stop()
      {
/*	System.out.println("help, they're comming to stop us");
*/
	au.suspend();
	bu.suspend();
	cu.suspend();
	du.suspend();
	eu.suspend();
	fu.suspend();
      }
    public void destroy()
      {
/*	System.out.println("help, they're comming to killing us!");
*/
	au.stop();
	bu.stop();
	cu.stop();
	du.stop();
	eu.stop();
	fu.stop();

/* wake up threads so they can die */

	au.resume();
	bu.resume();
	cu.resume();
	du.resume();
	eu.resume();
	fu.resume();

	Sticks[0].returnStick(3);
	Sticks[1].returnStick(3);
	Sticks[2].returnStick(3);
	Sticks[3].returnStick(3);
	Sticks[4].returnStick(3);

      }

    Graphics offg;
    Image offimg;

    public void paint(Graphics g)
      {
	  if (background == null) {
	      return;
	  }

	  Dimension d = size();
/*only draw things that might have changed */
	  if (offimg == null) {
	      offimg = createImage(d.width, d.height);
	      offg = offimg.getGraphics();
	  }
	  
	  offg.setColor(getBackground());
	  offg.fillRect(0, 0, d.width, d.height);
	  offg.setColor(Color.black);

	    offg.drawImage(background,xoffset+80,yoffset+138, this);
	    offg.drawImage(bullet, buttonx, buttony, this);
	    offg.drawImage(bullet, buttonx+buttonspace, buttony, this);
	    offg.drawImage(bullet, buttonx+buttonspace*2, buttony, this);
	    offg.drawImage(bullet, buttonx+buttonspace*3, buttony, this);
	    offg.drawString("Speed",xoffset+80,slide1y+12);
	    offg.drawString("Think",xoffset+80,slide2y+12);
	    offg.drawString("Talk ",xoffset+80,slide3y+12);
	    offg.drawLine(slidexl,slide1y+8,slidexr,slide1y+8);
	    offg.drawLine(slidexl,slide2y+8,slidexr,slide2y+8);
	    offg.drawLine(slidexl,slide3y+8,slidexr,slide3y+8);

	offg.drawImage(phil[0],xoffset+216,yoffset+181, this);
	offg.drawImage(phil[1],xoffset+335,yoffset+187, this);
	offg.drawImage(phil[2],xoffset+379,yoffset+261, this);
	offg.drawImage(phil[3],xoffset+245,yoffset+318, this);
	offg.drawImage(phil[4],xoffset+138,yoffset+247, this);

	  //offg.clearRect(slidexl+oldslide1, slide1y,16,16);
	    offg.drawLine(slidexl+oldslide1,slide1y+8,slidexl+oldslide1+16,slide1y+8);
	    offg.drawImage(bullet, slidexl+slide1, slide1y, this);
	    oldslide1=slide1;

	  //offg.clearRect(slidexl+oldslide2, slide2y,16,16);
	    offg.drawLine(slidexl+oldslide2,slide2y+8,slidexl+oldslide2+16,slide2y+8);
	    offg.drawImage(bullet, slidexl+slide2, slide2y, this);
	    oldslide2=slide2;

	  //offg.clearRect(slidexl+oldslide3, slide3y,16,16);
	    offg.drawLine(slidexl+oldslide3,slide3y+8,slidexl+oldslide3+16,slide3y+8);
	    offg.drawImage(bullet, slidexl+slide3, slide3y, this);
	    oldslide3=slide3;

	  g.drawImage(offimg, 0, 0, null);
      }

    public void update(Graphics g)
      {
	/* pretty cheesey, but gets rid of flash */
	paint(g);
      }

    public void run()
      {
/* starts threads, one for each phil, + one do keep track of whats up */
	int number;


	Thread.currentThread().setPriority(Thread.MIN_PRIORITY);
	number=getTicket();
	
	if(number>4) whatsup();
	else philosopher(number);
      }

    public boolean mouseDown(java.awt.Event evt, int x, int y)
      {
/* grab bullet */
	int by2;

	if(y<20)
	  {
	    System.out.println("eh?");
	    System.out.println("number of threads:"+Thread.activeCount());
	  }

	if((y>buttony)&&(y<buttony+16))
	   {
	     if((x>buttonx)&&(x<buttonx+16)) audio="eat";
	     if((x>buttonx+buttonspace)&&(x<buttonx+buttonspace+16)) audio="talk";
	     if((x>buttonx+buttonspace*2)&&(x<buttonx+buttonspace*2+16)) audio="laugh";
	     if((x>buttonx+buttonspace*3)&&(x<buttonx+buttonspace*3+16)) audio=null;
	   }

	if((y>60)&&(y<76)&&(x>(slide3-8))&&(x<(slide3+8))) slide3click=true;

	y=y-slide1y;
	x=x-slidexl-8;


	if((y>0 )&&(y<16)&&(x>(slide1-8))&&(x<(slide1+8))) slide1click=true;
	if((y>30)&&(y<46)&&(x>(slide2-8))&&(x<(slide2+8))) slide2click=true;
	if((y>60)&&(y<76)&&(x>(slide3-8))&&(x<(slide3+8))) slide3click=true;

	
	return true;
      }

    public boolean mouseExit(java.awt.Event evt)
      {
/* let go bullet */
	slide1click=false;
	slide2click=false;
	slide3click=false;
	return true;
      }

    public boolean mouseUp(java.awt.Event evt, int x, int y)
      {
/* let go bullet */
	slide1click=false;
	slide2click=false;
	slide3click=false;
	return true;
      }

    public boolean mouseDrag(java.awt.Event evt, int x, int y)
      {
/* handles sliders, and sets parameters */
	y=y-slide1y;
	x=x-slidexl-8;
	int len=slidexr-slidexl-16;

	    if(slide1click)
	      {
		if(x<=0) x=0;
		if(x>=len) x=len;
		speed=len-x;
		speed=(speed*speed)/len;
		slide1=x;
	      }


	    if(slide2click)
	      {
		if(x<=0) x=0;
		if(x>=len) x=len;
		ThinkChance=(float)x/len;
		ThinkChance*=ThinkChance;
		ThinkChance=1-ThinkChance;
		slide2=x;
	      }

	    if(slide3click)
	      {	
		if(x<=0) x=0;
		if(x>=len) x=len;
		EatChance=1-(float)x/len;
		EatChance=EatChance*EatChance;
		slide3=x;
	      }
	return true;
      }

    synchronized int getTicket()
      {
/* so each philnumber will be unique */	
	return ticketnumber++;
      }


    void initializeImages()
      {
/* load in lots of pretty pictures */
	int i,j;

	bullet=this.getImage(getCodeBase(), "images/b2.gif");
	if(bullet==null) System.out.println("no bullet");

	background=this.getImage(getCodeBase(), "images/background.gif");
	if(background==null) System.out.println("no picture ");

	for(i=0;i<5;i++)
	  {

	    for(j=0;j<4;j++)
	      {
		thinkingphil[i][j]=this.getImage(getCodeBase(), "images/thinking"+j+"."+i+".gif");
		if(thinkingphil[i][j]==null)
		  System.out.println("no picture "+i);
	      }

	    for(j=0;j<4;j++)
	      {
		hungryphil[i][j]=this.getImage(getCodeBase(), "images/hungry"+j+"."+i+".gif");
		if(hungryphil[i][j]==null) System.out.println("no picture "+i);
	      }

	    for(j=0;j<4;j++)
	      {
		eatingphil[i][j]=this.getImage(getCodeBase(), "images/eating"+j+"."+i+".gif");
		if(eatingphil[i][j]==null)
		  System.out.println("no picture "+i);
	      }

	  }
	phil[0]=thinkingphil[0][0];
	phil[1]=thinkingphil[1][0];
	phil[2]=thinkingphil[2][0];
	phil[3]=thinkingphil[3][0];
	phil[4]=thinkingphil[4][0];

      }

    void philosopher(int mynumber)
      {
/* the phil process */	
/*	System.out.println(mynumber);
*/
	for(;;)
	  {
	    think(mynumber);
	    PickUpSticks(mynumber);
	    eat(mynumber);
       	    DropSticks(mynumber);
	  }
      }
    
    void think(int mynumber)
      {
	int i=0;
	
	while(i<4)
	  {
	    phil[mynumber]=thinkingphil[mynumber][i];
	    i+= (Math.random()<ThinkChance) ? 1 : -1;
	try {Thread.sleep(speed*8);} catch (InterruptedException e){}
	    if(i<0) i=0;
	  }
	phil[mynumber]=thinkingphil[mynumber][0];
       
      }

    void eat(int mynumber)
      {
	do
	  {
	    phil[mynumber]=eatingphil[mynumber][0];
	try {Thread.sleep(speed);} catch (InterruptedException e){}
	    phil[mynumber]=eatingphil[mynumber][1];
	try {Thread.sleep(speed);} catch (InterruptedException e){}
	    phil[mynumber]=eatingphil[mynumber][2];

	    if(audio!=null) play(getCodeBase(), "audio/"+audio+mynumber+".au");

	try {Thread.sleep(speed);} catch (InterruptedException e){}
	    phil[mynumber]=eatingphil[mynumber][3];
	try {Thread.sleep(speed);} catch (InterruptedException e){}
	    phil[mynumber]=eatingphil[mynumber][2];
	try {Thread.sleep(speed);} catch (InterruptedException e){}
	    phil[mynumber]=eatingphil[mynumber][1];
	try {Thread.sleep(speed);} catch (InterruptedException e){}
	    phil[mynumber]=eatingphil[mynumber][0];
	try {Thread.sleep(speed);} catch (InterruptedException e){}
	    phil[mynumber]=thinkingphil[mynumber][0];
	try {Thread.sleep(speed);} catch (InterruptedException e){}
	  } while(Math.random()>EatChance);
      }

    void PickUpSticks(int n)
      {
/*  picks up stickes
a phil must have both sticks before it can eat*/

	int thisside,thatside;
	if(.5f>Math.random())
	  {
	    thisside= (n<4) ? n+1 : 0;
	    thatside= n;
	  }
	else
	  {
	    thatside= (n<4) ? n+1 : 0;
	    thisside= n;
	  }
/* pick up a stick */
	phil[n]=hungryphil[n][1];
	try {Thread.sleep(speed);} catch (InterruptedException e){}
	thishand[n]=Sticks[thisside].waitForStick();
	if(thishand[n]==7)
	  {
/* if its the magic stick, drop, and pick up other sticks */
	    phil[n]=hungryphil[n][2];
	try {Thread.sleep(speed);} catch (InterruptedException e){}
	    Sticks[thisside].returnStick(thishand[n]);
/* a deadlock is possible if the magic stick goes all the way around the 
   table to "thathand",  dont think it can happen though */


	    thathand[n]=Sticks[thatside].waitForStick();

	    phil[n]=hungryphil[n][3];
	try {Thread.sleep(speed);} catch (InterruptedException e){}
	    thishand[n]=Sticks[thisside].waitForStick();

	    phil[n]=hungryphil[n][0];
	try {Thread.sleep(speed);} catch (InterruptedException e){}
	    
	  }
	else
	  { 
/* get other stick */
	    phil[n]=hungryphil[n][0];
	try {Thread.sleep(speed);} catch (InterruptedException e){}
	    thathand[n]=Sticks[thatside].waitForStick();
	  }
      }

    void DropSticks(int n)
      {
/* drop sticks */
	int thisside,thatside;
	if(.5f>Math.random())
	  {
	    thisside= (n<4) ? n+1 : 0;
	    thatside= n;
	  }
	else
	  {
	    thatside= (n<4) ? n+1 : 0;
	    thisside= n;
	  }

       	Sticks[thisside].returnStick(thathand[n]);
	Sticks[thatside].returnStick(thishand[n]);
      }

    

    void whatsup()
      {
/* repaints the scene */
	for(;;)
	  {
	try {Thread.sleep(speed);} catch (InterruptedException e){}
	    repaint();
	  }
      }

  }

/* an instance of the class is created for each stick */
class sticksPB
{
  int Stick=0;

  int waitForStick()
    {
      return stickstuff(0);
    }
  void returnStick(int s)
    {
      stickstuff(s);
    }

  synchronized int stickstuff( int s)
/* make sure phils dont read and write at the same time */
    {
      if(s!=0)
	{
	  Stick=s;
	  notify();
	  return 0;
	}
      else
	{
	  if(Stick<1)
	    {
	      Stick=-4;
	      try {wait();} catch (InterruptedException e) {}
	    }
	  s=Stick;
	  Stick=0;
	  return s;
	}
    }
}
