// Copyright 1996, David Neto
public class Ticker {
	private final int STOPPED=0;
	private final int GOING=1;
	private final int STEP=2;
	private final int KILLED=3;
	private Speed speed;
	int state;

	public Ticker(Speed speed) {
// System.out.println("Ticker Ticker construction");
		this.speed = speed;
		state = STOPPED;
	}

	public synchronized void killSortNow() {
// System.out.println("Ticker killSortNow");
		state = KILLED;
		notify();
	}

	public synchronized void stopForNow() {
// System.out.println("Ticker stopForNow");
		state = STOPPED;
		notify();
	}

	public synchronized void goForNow() {
// System.out.println("Ticker goForNow");
		state = GOING;
		notify();
	}

	public synchronized void takeAStep() {
// System.out.println("Ticker takeAStep");
		state = STEP;
		notify();
	}

	// Both GOING and STEP qualify as "going".
	public synchronized void waitForGo() 
	throws InterruptedException, KillSortException {
// System.out.println("Ticker waitForGo");
		while ( state != GOING && state != STEP ) {
			wait();
			if ( state == KILLED ) throw new KillSortException();
		}
	}

	public synchronized void pause()
	throws InterruptedException, KillSortException {
// System.out.println("Ticker entering pause, state=="+state+" 0=STOPPED 1=GOING 2=STEP 3=KILLED");
		switch (state) {
		case GOING:
			wait(speed.getDelay());	
			while ( state == STOPPED ) {
				wait();	
			}
			break;
		case STEP:
			break;
		case STOPPED:
			while ( state == STOPPED ) {
				wait();	
			}
			break;
		case KILLED:
			break;
		}
		if ( state == KILLED ) throw new KillSortException();
		if ( state == STEP ) state = STOPPED; // Return from this pause, but then stop.
// System.out.println("Ticker leaving pause, state=="+state+" 0=STOPPED 1=GOING 2=STEP 3=KILLED");
	}
}
