/**
 * Class representing shopper in store
 * @author kim
 * 05/11/04
 */
public class Person extends Thread {
	// Constants representing possible states of Person
	private static final int WAITING = 0;
	private static final int SHOPPING = 1;
	private static final int ON_ELEVATOR = 2;
	private static final int DONE = 3;

	private int status = WAITING;  // What person is doing
	// floors that shopper must visit
	private final int[] itinerary;
	private final String name;		// name of shopper
	// how long it takes to shop on one floor
	private final int busyTimeMS;	
	// where shopping takes place
	private final Building building;
	// index of floor in itinerary shopping in now
	private int itemNumber;
	private int currentFloor;	// floor shopping in now

	/**
	 * Create person with
	 * @param name  -- person's name
	 * @param itinerary -- array of floors will shop at
	 * @param busyTimeSecs -- how long it takes to shop
	 * @param startingFloor -- floor person begins at
	 * @param building  -- building where shopping
	 */
	public Person(String name, int[] itinerary,int busyTimeMS,
			int startingFloor, Building building) {
		super("Person " + name);
		this.name = name;
		this.itinerary = itinerary;
		this.busyTimeMS = busyTimeMS;
		this.itemNumber = 0;
		this.currentFloor = startingFloor;
		this.building = building;
		// sanity checking that parameters are OK
		for (int i = 0; i < itinerary.length; i++)
			checkFloor(itinerary[i], building);
		checkFloor(currentFloor, building);
		if (busyTimeMS < 0)
			busyTimeMS = 0;
	}

	// post: if floor not legal floor in building office then throw exception
	private void checkFloor(int floor, Building office) {
		if (floor < 0 || floor >= office.NUM_FLOORS)
			throw new RuntimeException("Illegal floor " + floor);
	}

	// Have shopper move through store using elevators to get to new
	// floors.  Prints out all changes
	public void run() {
		
		while (itemNumber < itinerary.length) {
			
			int dest = itinerary[itemNumber];
			
			// If I'm on elevator, check to see if on the floor I want to 
			// be on to get off 
			if (dest == currentFloor && status == ON_ELEVATOR) {
				System.out.println(name+" exiting elevator on floor "+dest
						+" at time "+ System.currentTimeMillis());
				shopOnFloor();
				System.out.println(name+" done shopping on floor "+dest
						+" at time "+ System.currentTimeMillis());
				itemNumber++;
			}
			// take the next elevator to my floor
			else {
				System.out.println( name + " waiting on " + currentFloor
						+ " for floor " + dest+" at time "+ System.currentTimeMillis());

				// wait for an elevator
				Elevator elevatorHere = building.callElevator(currentFloor, dest > currentFloor);

				// found one --- try to get on
				System.out.println(name + " tries to get on " + elevatorHere + " to floor "
						+ dest+" at time "+ System.currentTimeMillis());
				status = ON_ELEVATOR;
				currentFloor = elevatorHere.takeElevator(dest, currentFloor, this);

				if (currentFloor != dest) {  // no room for me
					status = WAITING;
					System.out.println(
						"oops! " + name + " didn't make it onto elevator to " + dest);
					building.waitForElevatorToCome();
				}
			}
		}
		System.out.println(name + " is done shopping");
	}
	
	// post: printed message about starting shopping and then shop
	// for busyTimeSecs. 
	private void shopOnFloor() {
		System.out.println(name + " arrived at floor " + currentFloor
				+" at time "+ System.currentTimeMillis());
		status = SHOPPING;
		try {
			Thread.sleep(busyTimeMS);
		} catch (InterruptedException e) {
			System.exit(1); // just die
		}
		status = WAITING;
	}

	// return name of shopper
	public String toString() {
		return name;
	}
}
