import java.awt.Color;
import java.util.Enumeration;

public class DrunkPhilosopher extends RandomWalker {
    // OVERVIEW: A DrunkPhilosopher is a philosopher who walks around randomly until finding a
    //    colleague (that is, a neighboring object that is also a DrunkPhilosopher).
    //    When a philosopher finds a colleague, and the start philosophizing (and stop
    //    wandering randomly).

    private boolean inTurn; // Currently in the middle of a turn (used for coloring)
    private DrunkPhilosopher colleague;
    private boolean isPhilosophizing;
    private boolean isArguing;
    private String quote;
    private String name;

    // We want our philosophers to have different names, so we use a class instance variable
    // to count the number of philosophers created.

    static private int counter = 0;

    static synchronized private String getNextName () {
	counter++;
	return "Philo" + counter;
    }

    public DrunkPhilosopher () {
	inTurn = false;
	colleague = null;
	isPhilosophizing = false;
	isArguing = false;
	quote = "I drink, therefore I am."; // All drunk philosophers philosophize the same way (but they still argue).
	name = getNextName ();
    }

    public Color getColor()
    {
	if (inTurn) {
	    return Color.white;
	} else {
	    if (isArguing) {
		return Color.red;
	    } else if (isPhilosophizing) {
		return Color.green;
	    } else {
		return Color.yellow;
	    }
	}
    } //@nowarn NonNullResult // ESC/Java doesn't know Color constants are not null

    public synchronized void philosophize () {
	isPhilosophizing = true;
	isArguing = false;

	System.err.println (name + "[Thread " + Thread.currentThread().getName () + "] says " + quote);
	delay (1000);

	if (colleague != null) { // Need a colleague to start and argument.
	    colleague.argue ();
	} 
    }

    public synchronized void argue () {
	isPhilosophizing = false;
	isArguing = true;
	System.err.println (name + "[Thread " + Thread.currentThread().getName () + "] argues: No! " + quote);
	// delay (600);
	isArguing = false;
    }

    synchronized public void executeTurn () throws RuntimeException
       // Note: requires isInitialized is inherited from SimObject
       // EFFECTS: Picks a random direction and tries to move that way. 
       //          If the move is successful, return true. If the move fails
       //          because the spot being attempted to move into is already
       //          occupied then return false.

    {
	inTurn = true;

	if (colleague != null) {
	    if (!isPhilosophizing && !isArguing) {
		philosophize ();
		// delay (600);
	    }
	} else {
	    synchronized (getGrid ()) {
		super.executeTurn (); // Continue walking around randomly
		Enumeration neighbors = getNeighbors ();
		
		while (neighbors.hasMoreElements ()) {
		    SimObject neighbor = (SimObject) neighbors.nextElement ();
		    
		    if (neighbor instanceof DrunkPhilosopher) {
			// Found a colleague!
			DrunkPhilosopher philo = (DrunkPhilosopher) neighbor;
			
			System.err.println (name + "[Thread " + Thread.currentThread().getName () + "] found a colleague: " +
					    philo.name);

			synchronized (philo) { // Make sure philo doesn't get a different colleague before setting.
			    if (philo.colleague == null) {
				colleague = philo;
				philo.colleague = this; 
				break; // out of the while loop, only need one colleague
			    }
			}
		    }
		}
	    }
	}

	inTurn = false;
    }
}