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() { //@nowarn Deadlock
		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 Post // ESC/Java doesn't know Color constants are not null

	public synchronized void philosophize() { //@nowarn Deadlock
		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() { //@nowarn Deadlock
		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.

	{ //@nowarn Deadlock
		inTurn = true;

		if (colleague != null) {
			if (!isPhilosophizing && !isArguing) {
				philosophize();
				// delay (600);
			}
		} else {
			synchronized (getGrid()) { //@nowarn Deadlock
				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);

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

		inTurn = false;
	}
}