/*
 * @(#)AbstractAnimation.java
 *
 * Last Modified: 9/15/01
 */

 import java.util.*;
 import java.awt.*;

/** *
 	* The Abstract Animation object defines numerous methods of an Animation that are independent
 	* of the specific type of Animation, resulting in much repeated code. Therefore, that code has been
 	* inserted in this abstract class that many Animations extend to take use of these methods.<p>
	* <code>drawAnimation</code> must be defined to extend this class appropriately.<p>
	*
	* @author  Corey Sanders
	* @version 2.1 9/15/01
 	*/

public abstract class AbstractAnimation implements Animation {

	/**
	 * The list of listeners to this Animation Object. Used when the command <code>addAnimationListener</code>
	 * is used.
	 */
	protected LinkedList listeners;

	/**
	 * The description to this given Animation Object, which is set using <code>addDescription</code>,
	 * part of the Animation interface.
	 */
	private String description = null;

	/**
	 * The step time of the animation, which is modifiable with <code>setStepSize</code>.
	 */
	private double stepSize;

	/**
	 * The boolean flag to determine whether step is on.
	 */
	private boolean step = false;

	/**
	 * Holds the current Status of the animation.
	 */
	private String currentStatus;

	/**
	 * Holds the conversion factor between step time and step size.
	 */
	private int stepConversion;

	/**
	 * Holds the starting Command for this animation.
	 */
	private String startingCommand;

	/**
     * The Default step size used in the animation (16).
	 */
	public final static int DEFAULT_STEP = 16;

	/**
	 * The Default step conversion used in animation (400).
	 */
	 public final static int DEFAULT_CONVERSION = 400;

	/**
	 * The constructor which initiates the abstract animation.
	 *
	 */
	public AbstractAnimation() {

		// Set the listeners to the Animation object
		listeners = new LinkedList();

		// Set step conversion
		setStepConversion(DEFAULT_CONVERSION);

		// Set step size
		setStepTime(DEFAULT_STEP);

		// Set beginning status
		setStatus(Animation.BEGIN);

	}


	/************************/
	/* Accessor methods     */
	/************************/

	/**
	 * Gets the starting command for the current animation. The starting command is used when the
	 * command is uncertain (Animation.BEGIN status).
	 *
	 * @return String starting command.
	 */
	protected String getStartingCommand() {
		return startingCommand;
	}


	/**
	 * Gets the conversion factor for step size and step time. The integer dividend for the
	 * step time passed to make the step size.
	 *
	 * @return int conversion factor for a step.
	 */
	protected int getStepConversion() {
		return stepConversion;
	}

	/**
	 * Gets the step size for the animation.
	 *
	 * @return double step size
	 */
	protected double getStepSize() {
		return stepSize;
	}

	/**
	 * Gets the step time for the animation.
	 *
	 * @return int step time
	 */
	public int getStepTime() {
		return (int)(stepSize*(double)getStepConversion());
	}


	/**
	 * Gets the description added with <code>addDescription</code> and should be accessed through the listener.
 	 *
 	 * @return the string defining the description.
	 */
	public String getDescription() {
		return description;
	}

	/**
	 * Gets whether the current animation is in stepping mode or not. Step mode indicates
	 * skipping the intermediary drawings in the animation and going instantly from one step
	 * to the next. Generally useful for fast-forward.
	 *
 	 * @return boolean defining whether it is skipping.
	 */
	public boolean getStep() {
		return step;
	}


	/**
	 * Gets the status of the Animation using a command within <code>Animation</code> interface.
	 *
	 * @return the Animation's status.
	 */
	public String getStatus() {
		return currentStatus;
	}


	/**
	 * Returns an array of all the listeners that were added to this Animation with
	 * <code>addAnimationListener</code>.
	 *
	 * <p> If no such listener list exists, then an empty array is returned.
	 *
	 * @return array of <code>AnimationListeners</code>.
	 */
	public AnimationListener[] getListeners() {
		if (listeners.isEmpty())
			return null;
		return (AnimationListener[])listeners.toArray();
	}


	/************************/
	/* Mutator methods     */
	/************************/

	/**
	 * Sets the starting command for the current animation. The starting command is used when the
	 * command is uncertain (Animation.BEGIN status).
	 *
	 * @param command String starting command.
	 */
	protected void setStartingCommand(String command) {
		startingCommand = command;
	}



	/**
	 * Sets the conversion factor for step size and step time. The integer dividend for the
	 * step time passed to make the step size.
	 *
	 * @param conversion factor of conversion for step time to step size.
	 */
	protected void setStepConversion(int conversion) {
		stepConversion = conversion;
	}


	/**
	 * Sets the step size for the animation.
	 *
	 * @param t the step size
	 */
	protected void setStepSize(double t) {
		stepSize = t;
	}

	/**
	 * Sets the step time for the animation.
	 *
	 * @param t the step time
	 */
	public void setStepTime(int t) {
		stepSize = ((double)t/(double)getStepConversion());
	}


	/**
	 * Adds a description that may be used to describe to the listener the type of event occuring.
	 * The value of teh description may be retrieved through <code>getDescription</code>.
 	 *
 	 * @param d the string defining the description.
	 */
	public void addDescription(String d) {
		description = d;
	}


	/**
	 * Sets whether the current animation is in stepping mode or not. Step mode indicates
	 * skipping the intermediary drawings in the animation and going instantly from one step
	 * to the next. Generally useful for fast-forward.
 	 * @param b boolean defining whether it is skipping.
	 */
	public void setStep(boolean b) {
		step = b;
	}

	/**
	 * Sets the status of the Animation using a command within <code>Animation</code> interface.
	 *
	 * @param cmd cmd that the Animation's status is set to.
	 */
	public void setStatus(String cmd) {
		currentStatus = cmd;
	}


	/**
	 * Adds an animationListener that recieves meaningful events from the animation, according to
	 * the Animation interface and the <code>AnimationEvent</code>.
	 *
	 * @param l the listener for the AnimationEvents occuring within this Animation.
	 */
	public void addAnimationListener(AnimationListener l) {
		listeners.add(l);
	}

	/**
	 * Removes an animationListener from the animation, according to
	 * the Animation interface and the <code>AnimationEvent</code>.
	 *
	 * @param l the listener removed from recieving the AnimationEvents occuring within this Animation.
	 */
	public void removeAnimationListener(AnimationListener l) {
		listeners.remove(l);
	}




	/**
	 * Calls all of the listeners of the current Animation and passes information regarding the
	 * progress and status of the current Animation. Additionally, the id of the type of animation is
	 * passed. Within, the <code>animationEventPerformed</code> method is called.
	 *
	 * @param id int id for the animation
	 * @param cmd String Animation command passed instead of the current Status.
	 * @param description String description for messages.
	 * @param progress double progress of the animation
	 */
	protected void animationAction(int id, String cmd, String description, double progress) {
		AnimationEvent animationEvent = new AnimationEvent(this, id, cmd, description, progress);
			ListIterator list = listeners.listIterator(0);
			while (list.hasNext()) {
				((AnimationListener)list.next()).animationEventPerformed(animationEvent);
			}
	}

	/**
	 * Calls all of the listeners of the current Animation and passed information regarding the
	 * progress and status of the current Animation. The id <code>ABSTRACT_ANIMATION</code> is passed.
	 * Within, the <code>animationEventPerformed</code> method is called.
	 *
	 * @param cmd String Animation command passed instead of the current Status.
	 * @param description String description for messages.
	 */
	protected void animationAction(String cmd, String description) {
		animationAction(AnimationEvent.ABSTRACT_ANIMATION, cmd, description, 0);
	}


	/**
	 * Calls all of the listeners of the current Animation and passed information regarding the
	 * progress and status of the current Animation.  The id <code>ABSTRACT_ANIMATION</code> is passed.
	 * The current status and current decription are passed.
	 * Within, the <code>animationEventPerformed</code> method is called.
	 */
	protected void animationAction() {
		animationAction(getStatus(), getDescription());
	}


	/**
	 * Calls animationAction with an ANIMATION_MESSAGE, sending the message to all of its
	 * listeners. The message is represented in the description string and the status string
	 * is <code>Animation.ANIMATION_MESSAGE</code>.<p>
	 *
	 * @param msg the message sent to all of the listeners as an Animation.ANIMATION_MESSAGE.
	 */
	protected void messageAction(String msg) {
		animationAction(Animation.ANIMATION_MESSAGE, msg);
	}


	/************************/
	/* Animation Methods    */
	/************************/

	/**
     * Draws the animation of the next step, using the status of the animation (Animation.PLAY, Animation.PAUSE and so forth).
	 * After completing the drawing, the Animation sends an AnimationEvent to all its listeners, indicating
	 * any information that the listerners may wish to use. <p>
	 * The starting status used for the animation is the one previously defined.
 	 *
 	 * @param b boolean defining whether it is skipping.
	 */
	public void drawAnimation(Graphics2D g2) {
		drawAnimation(g2, getStartingCommand());
	}

	/**
	 * Draws the animation of the next step, using the status of the animation (Animation.PLAY, Animation.PAUSE and so forth).
	 * This must be declared to extend this abstract class.
	 *
	 * @param g2 the graphics to which the animation step should be drawn.
	 * @param startingStatus the status used as the starting command of animation, if needed.
	 */
	public void drawAnimation(Graphics2D g2, String startingStatus) {
	}


}
