package alice.kareluser;

import org.alice.apis.moveandturn.Color;

import alice.kareltherobot.Direction;
import alice.kareltherobot.Robot;

import com.jbergin.util.Die;

/** A class of philosopher robots designed to simulate the classic
 * Dining Philosophers simulation (with 4 philosophers). 
 * @author Joseph Bergin
 *
 */
public class Philosopher extends Robot implements Runnable
{

	public Philosopher(int street, int avenue, Direction direction)
	{
		super(street, avenue, direction);
	}

	public Philosopher(int street, int avenue, Direction direction, int beepers)
	{
		super(street, avenue, direction, beepers);
	}

	public Philosopher(int street, int avenue, Direction direction, int beepers,
			Color color)
	{
		super(street, avenue, direction, beepers, color);
	}

	/**
	 * Turn right by making three left turns
	 */
	public void turnRight()
	{
		turnLeft();
		turnLeft();
		turnLeft();
	}

	/**
	 * Turn around by making two left turns
	 */
	public void turnAround()
	{
		turnLeft();
		turnLeft();
	}

	/**
	 * Back up one block and face the original direction. Will fail if the rear is blocked
	 * by a wall.
	 */
	public void backUp()
	{
		turnAround();
		move();
		turnAround();
	}

	/**
	 * This is the method used by the thread system (doTogether). It will be invoked
	 * automatically. This is the task for one Philosopher robot. A robot thinks for a 
	 * random period, then tries to eat (for a random period), but must first pick up two
	 * "forks" (beepers) to its left and right. But there are only four forks. 
	 */
	public void run()
	{
		while (true)
		{
			think(d.roll());
			getForks();
			eat(d.roll());
			say("burp");
			putForks();
		}
	}

	/** Philosopher backs away from the table to think, and 
	 * occasionally makes an exclamation.*/
	private void think(int time)
	{
		for (int i = 0; i < time; ++i)
		{
			backUp();
			int r = d.roll();
			if (r < 3)
			{
				think("???  ?");
			} else if (r == 6)
			{
				say("Eureka!");
			}

			move();
		}
	}

	/** Philosopher moves in to the table to eat and occasionally
	 * comments on the food. */
	private void eat(int time)
	{
		for (int i = 0; i < time; ++i)
		{
			move();
			int r = d.roll();
			if (r < 4)
			{
				say("yum");
			}
			backUp();
		}
	}

	/**
	 * Philosopher picks up a fork from its left and one from its right, but waits until
	 * they are available.
	 */
	private void getForks()
	{
		turnLeft();
		move();
		while (!anyBeepersInBeeperBag())
		{
			while (!nextToABeeper())
			{
				turnAround();
				turnAround();
			} // nothing, but with panache
			pickBeeper();
			think("Found 1 fork.");
		}
		turnAround();
		move();
		putBeeper();
		move();
		while (!anyBeepersInBeeperBag())
		{
			while (!nextToABeeper())
			{
				turnAround();
				turnAround();
			} // nothing
			pickBeeper();
			think("Found the other fork.");
		}
		turnAround();
		move();
		putBeeper();
		turnRight();
		// showState("Eat ");
	}

	/**
	 * Philosopher puts down both of its forks, one to the left and one to the right.
	 */
	private void putForks()
	{
		pickBeeper();
		pickBeeper();
		turnLeft();
		move();
		putBeeper();
		turnAround();
		move();
		move();
		putBeeper();
		turnAround();
		move();
		turnRight();
		// showState("Think ");
	}

	private Die d = new Die(6);

}
