/* ****************************************************************************
 * IBM Confidential
 * OCO Source Materials
 * %ProductName%
 * © Copyright IBM Corp. 2003-2004
 *
 * The source code for this program is not published or 
 * otherwise divested of its trade secrets, irrespective of what 
 * has been deposited with the U.S. Copyright Office.
 * ****************************************************************************
 * Created on 27 April 2004
 */
package philosopher;

/**
 * A philosopher eats and thinks up to 5 times.
 * He gets left fork, thinks for a time, gets right forks, eats for a time,
 * then releases both forks, and thinks for a time...
 */
public class Philosopher extends Thread
{
  public static final String S_NOT_YET_STARTED="Not yet stared";
  public static final String S_WAITING_LEFT_FORK = "Waiting for left fork";
  public static final String S_WAITING_RIGHT_FORK = "Waiting for left fork";
  public static final String S_THINKING = "Thinking";
  public static final String S_EATING = "Eating";
  public static final String S_FINISHED = "Finished";
  
  protected Fork left_fork, right_fork ;
  protected String id;
  protected static int Id;
  protected String state;
  
  /**
   * Create a philosopher.
   */
  public Philosopher()
  {
    id = getKindName()+"#"+(Id++);
    setName( id );
    state=S_NOT_YET_STARTED;
  }
  
  /**
   * @return philosopher kind name.
   */
  public String getKindName() { return "philo"; }
  
  /**
   * @return current state of philosopher.
   */
  public String getState() { return state; }
  
  /**
   * Set left fork used by this philosopher.
   */
  public void setLeftFork( Fork f ) 
  {
    left_fork = f;
  }
  
  /**
   * Set right fork used by this philosopher.
   */
  public void setRightFork( Fork f ) 
  {
    right_fork = f;
  }
  
  /**
   * Utility method.
   * @param ms delay to sleep.
   */
  public static void Sleep( int ms )
  {
    if( ms <= 0 ) return ;
    try
    {
      Thread.sleep( ms );
    }
    catch( InterruptedException e )
    {
      e.printStackTrace();
    }
  }
  
  /** 
   * Print philosopher name and a message.
   */
  protected void trace( String msg )
  {
    System.out.println( id + ": "+msg );
  }
  
  /**
   * Dine getting both fork, and think up to 5 times..
   * If you implement another philosopher, take care to report its real state,
   * otherwise watchdog might not works properly.
   */
  public void run()
  {
    for( int i=0; i<5; i++ )
    {
      trace("waiting for left "+left_fork.getName());
      //get left fork
      state = S_WAITING_LEFT_FORK;
      synchronized( left_fork )
      {
        trace("got left "+left_fork.getName()+", thinking for 50 ms");
        state = S_THINKING;
        
        //this delay lets other philosopher get the right fork he's waiting for.
        //in other words until you comment the line below, philosopher dinner will fail
        //in a dead lock ... because all philosophers will wait for right fork.
        Sleep( 50 ); 
        
        trace("waiting for right "+right_fork.getName());
        state = S_WAITING_RIGHT_FORK;
        //get right fork
        synchronized( right_fork )
        {
          state = S_EATING;
          trace("got right "+right_fork.getName()+", eating for 50 ms");
          Sleep(50);
          trace("right "+right_fork.getName()+" released");
        }
        trace("left "+left_fork.getName()+" release, thinking for 30 ms");        
      }
      state = S_THINKING;
      Sleep(30);
    }
    state = S_FINISHED;
    trace("finished");
  }
}
