/*
 * @(#)MovingBSTTreeAnimation.java
 *
 * Last Modified: 9/15/01
 */

 import java.util.*;
 import java.awt.*;

/** *
 	* The Animation object that defines the Moving of a MovingBSTTree. Two constructors exist,
 	* one setting the animator and animation color Schemes. This animation is the core of many
 	* other animations that involve moving (Rotation). <p>
 	*
	* The object restores all values changed in the given nodes, however, if the object
	* is never allowed to finish, the restoring of values becomes impossible. On any exception occuring
	* elsewhere, the object may not restore the conditions correctly.
	*
	* @author  Corey Sanders
	* @version 1.4 9/15/01
 	*/

public class MovingBSTTreeAnimation extends AbstractAnimation {



	/**
	 * Private doubles used to hold the current and previous location steps.
	 */
	private double currentLocation = 0.0;
	private double previousLocation = 0.0;


	/**
	 * Private boolean defining if the node has already been made, just not drawn.
	 */
	 private boolean animationMade = false;

	/**
	 * Refers to the linked list which will store the moving nodes used in the animation.
	 */
	private LinkedList movingNodes;

	/**
	 * Refers to the linked list which will store the nodes that correspond to each moving
	 * node in the previous LinkedList.
	 */
	private LinkedList nodes;

	/**
	 * Color Scheme used for the animator, using one of the NodeSettings Schemes.
	 */
	private NodeSettings nodeAnimationScheme;

	/**
	 * Color Scheme used for the key of the animator, using one of the KeySettings Schemes.
	 */
	private KeySettings keyAnimationScheme;


	/**
	 * The constructor which initiates the status as <code>Animation.PLAY</code>, default step size,
	 * the default NodeAnimationScheme and KeyAnimationScheme.
	 */
	public MovingBSTTreeAnimation() {
		this(null, null, Animation.PLAY, DEFAULT_STEP);
	}

	/**
	 * The constructor which initiates the status as <code>Animation.PLAY</code>, default step size,
	 * the given NodeAnimationScheme and KeyAnimationScheme.
	 *
	 * @param NodeAnimationScheme the NodeSettings which the nodes uses during animation.
	 * @param KeyAnimationScheme the KeySettings which the key in each moving node is drawn.
	 */
	public MovingBSTTreeAnimation(NodeSettings NodeAnimationScheme, KeySettings KeyAnimationScheme) {
		this(NodeAnimationScheme, KeyAnimationScheme, Animation.PLAY, DEFAULT_STEP);
	}


	/**
	 * The constructor which initiates the status and prepares the color Schemes.
	 *
	 * @param NodeAnimationScheme the NodeSettings which the nodes uses during animation.
	 * @param KeyAnimationScheme the KeySettings which the key in each moving node is drawn.
	 * @param startingCmd the Animation command that this should start.
	 * @param stepTime the time for each step of the Animation. Sets the initial value.
	 */
	public MovingBSTTreeAnimation(NodeSettings NodeAnimationScheme, KeySettings KeyAnimationScheme, String startingCmd, int stepTime) {
		super();

		// Set defaults if no color schemes exist
		if (NodeAnimationScheme == null) {
			NodeAnimationScheme = new NodeSettings();
		}

		if (KeyAnimationScheme == null) {
			KeyAnimationScheme = new KeySettings();
		}


		movingNodes = new LinkedList();

		nodes = new LinkedList();

		setAnimationScheme((NodeSettings)NodeAnimationScheme.clone(), (KeySettings)KeyAnimationScheme.clone());

		// Set the starting command.
		setStartingCommand(startingCmd);
		// Set Step size
		setStepTime(stepTime);

	}



	/************************/
	/* Accessor methods     */
	/************************/

	/**
	 * Gets the moving nodes used in the <code>Animation</code>. The return is the clone
	 * of the LinkedList used within the class. Cloning of a <code>LinkedList</code> is a shallow
	 * copy.
	 *
	 * return <code>LinkedList</code> representing the movingBSTTrees.
	 */
	public LinkedList getMovingNodes() {
		return (LinkedList)movingNodes.clone();
	}

	/**
	 * Gets the node Animationg scheme for each moving node.
	 *
	 * @return animation scheme for the moving nodes.
	 */
	public NodeSettings getNodeAnimationScheme() {
		return nodeAnimationScheme;
	}


	/**
	 * Gets the BSTTree nodes used in the <code>Animation</code>. The return is the clone
	 * of the LinkedList used within the class. Cloning of a <code>LinkedList</code> is a shallow
	 * copy.
	 *
	 * return <code>LinkedList</code> representing the BSTTrees that the movingBSTTrees imitate.
	 */
	public LinkedList getNodes() {
		return (LinkedList)nodes.clone();
	}

	/**
	 * Gets the moving node within the Animation that imitates the passed BSTTree node.
	 * If the BSTTree node does not exist in the Animation, null is returned.
	 *
	 * @param node BSTTree node which the returning MovingBSTTree node imitates.
	 * @return <code>MovingBSTTree</code> which imitates the given node.
	 */
	public MovingBSTTree getMovingNode(BSTTree node) {
		int index = nodes.indexOf(node);

		if (index == -1)
			return null;
		else
			return (MovingBSTTree)movingNodes.get(index);
	}

	/**
	 * Gets the first moving node in the list.
	 *
	 * @return the first <code>MovingBSTTree</code> in the animation.
	 */
	public MovingBSTTree getFirstMovingNode() {
		return (MovingBSTTree)movingNodes.getFirst();
	}


	/**
	 * Returns true if the moving node list is empty.
	 *
	 * @return true if the animation contains no moving nodes.
	 */
	public boolean isEmpty() {
		return (movingNodes.isEmpty());
	}

	/**
	 * Gets the NodeSettings for the animation of the moving node.
	 *
	 * @return NodeSettings for the node animating.
	 */
	public NodeSettings getAnimationScheme() {
		return nodeAnimationScheme;
	}



	/**
	 * Gets the KeySettings for the animation key for the moving node.
	 *
	 * @return KeySettings for the key of the node animating.
	 */
	public KeySettings getKeyAnimationScheme() {
		return keyAnimationScheme;
	}

	/************************/
	/* Mutator methods     */
	/************************/

	/**
	 * Sets the animation scheme for each moving node.
	 *
	 * @param nodeScheme the NodeSettings for the animation of the moving node.
	 * @param keyScheme the KeySettings for the animationg of the key within the moving node.
	 */
	public void setAnimationScheme(NodeSettings nodeScheme, KeySettings keyScheme) {
		setNodeAnimationScheme(nodeScheme);
		setKeyAnimationScheme(keyScheme);
		// Sets settings of entire list
		setListSettings(getAnimationScheme(), getKeyAnimationScheme());
	}



	/**
	 * Adds the movingBSTTree along with the BSTTree node as a pair. The moving Node imitates
	 * the given nod.
	 *
	 * @param movingNode MovingBSTTree that is added to the animation.
	 * @param node BSTTree that is added to the animation.
	 */
	public void add(MovingBSTTree movingNode, BSTTree node) {
		movingNodes.add(movingNode);
		nodes.add(node);


	}


	/**
	 * Sets the NodeSettings for the animation of the moving node.
	 *
	 * @param scheme NodeSettings for the node animating.
	 */
	public void setNodeAnimationScheme(NodeSettings scheme) {
		nodeAnimationScheme = (NodeSettings)scheme.clone();
	}



	/**
	 * Sets the KeySettings for the animation key for the moving node.
	 *
	 * @param scheme KeySettings for the key of the node animating.
	 */
	public void setKeyAnimationScheme(KeySettings scheme) {
		keyAnimationScheme = (KeySettings)scheme.clone();
	}

	/**
	 * 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.
	 *
	 * @param g2 the graphics to which the animation step should be drawn.
	 * @param startingStatus the starting status used if necessary.
	 */
	public void drawAnimation(Graphics2D g2, String startingStatus) {


		// Sets starting command
		setStartingCommand(startingStatus);

		// Empty
		if (isEmpty()) {
			setStatus(Animation.FINISH);
			animationAction();
			return;
		}

		// BEGIN status
		if (getStatus().equals(Animation.BEGIN)) {
			currentLocation = 0.0;
			setStatus(getStartingCommand());
			animateList(g2, currentLocation);
			// Call listeners
			animationAction();
			return;
		}

		// Currently on a step and no changes have occured. Return to startingStatus
		if (getStatus().equals(Animation.STEP)) {
			setStatus(getStartingCommand());
		}

		// PLAY status
		if ((getStatus().equals(Animation.PLAY)) && (!animationMade)) {
			if (getStep()) {
				currentLocation = 1;
			}
			else {
				currentLocation += getStepSize();

				if (currentLocation > 1)
					currentLocation = 1;
			}

		}


		// REWIND status
		if ((getStatus().equals(Animation.REWIND)) && (!animationMade)) {
			if (getStep()) {
				currentLocation = 0;
			}
			else {
				currentLocation -= getStepSize();

				if (currentLocation < 0) {
					setStatus(Animation.STOP);
					currentLocation = 0;
					animationAction();
					return;
				}
			}

		}

		// PAUSE status
		if (getStatus().equals(Animation.PAUSE)) {

		}

		// STOP status
		if (getStatus().equals(Animation.STOP)) {
			return;
		}

		// FINISH status
		if (getStatus().equals(Animation.FINISH)) {
			animationAction();
			return;
		}

		// Draws entire list
		animateList(g2, currentLocation);

		// Call listeners
		animationAction();

		animationMade = false;

	}


	/**
	 * Makes the animation of the next step, using the status of the animation (Animation.PLAY, Animation.PAUSE and so forth).
	 * After completing the making, nodeMade is set to true, so when the animation is actually drawn, it will not skip a step.
	 *
	 * @param g2 the graphics to which the animation step should be drawn.
	 * @param startingStatus the starting status used if necessary.
	 */
	public void makeAnimation(Graphics2D g2, String startingStatus) {


		// Sets starting command
		setStartingCommand(startingStatus);

		// Empty
		if (isEmpty()) {
			setStatus(Animation.FINISH);
			animationAction();
			return;
		}


		// BEGIN status
		if (getStatus().equals(Animation.BEGIN)) {
			currentLocation = 0.0;
			setStatus(getStartingCommand());
			animateList(g2, currentLocation);
			// Call listeners
			animationAction();
			return;
		}

		// Currently on a step and no changes have occured. Return to startingStatus
		if (getStatus().equals(Animation.STEP)) {
			setStatus(getStartingCommand());
		}

		// PLAY status
		if (getStatus().equals(Animation.PLAY)) {

			if (getStep()) {
				currentLocation = 1;
			}
			else {
				currentLocation += getStepSize();

				if (currentLocation > 1)
					currentLocation = 1;
			}

		}


		// REWIND status
		if (getStatus().equals(Animation.REWIND)) {
			if (getStep()) {
				currentLocation = 0;
			}
			else {
				currentLocation -= getStepSize();

				if (currentLocation < 0) {
					setStatus(Animation.STOP);
					currentLocation = 0;
					animationAction();
					return;
				}
			}

		}

		// PAUSE status
		if (getStatus().equals(Animation.PAUSE)) {

		}

		// STOP status
		if (getStatus().equals(Animation.STOP)) {
			return;
		}

		// FINISH status
		if (getStatus().equals(Animation.FINISH)) {
			animationAction();
			return;
		}

		// Draws entire list
		makeList(g2, currentLocation);

		animationMade=true;
	}

	/**
	 * Animates the entire list of moving Nodes. The animation is drawn to the graphics2D, using
	 * the step. The step must be between 0 and 1, 0 being the beginning of the movement and 1
	 * being the end.
	 *
	 * @param g2 Graphics2D to which the moving node is drawn.
	 * @param step double between 0 and 1, indicating the progress of the movement.
	 */
	private void animateList(Graphics2D g2, double step) {
		int size = movingNodes.size();
		for(int i=0; i < size; i++) {
			((MovingBSTTree)movingNodes.get(i)).drawNodeAndLink(g2, step);
		}
	}

	/**
	 * Makes the entire list of moving Nodes. The animation is made within the graphics2D, using
	 * the step. The step must be between 0 and 1, 0 being the beginning of the movement and 1
	 * being the end.
	 *
	 * @param g2 Graphics2D to which the moving node is drawn.
	 * @param step double between 0 and 1, indicating the progress of the movement.
	 */
	private void makeList(Graphics2D g2, double step) {
		int size = movingNodes.size();
		for(int i=0; i < size; i++) {
			((MovingBSTTree)movingNodes.get(i)).makeNode(g2, step);
		}
	}

	/**
	 * Sets the settings of every moving node in the list. Both the NodeSettings and KeySettings
	 * must be set.
	 *
	 * @param s NodeSettings used to set the node settings of every moving node.
	 * @param k KeySettings used to set the key settings of every moving node.
	 */
	private void setListSettings(NodeSettings s, KeySettings k) {
		int size = movingNodes.size();
		for(int i=0; i < size; i++) {
			((MovingBSTTree)movingNodes.get(i)).setNodeSettings(s);
			((DrawableKey)((MovingBSTTree)movingNodes.get(i)).getValue()).setKeySettings(k);
		}
	}


	/**
	 * Calls all of the listeners of the current Animation and passed 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 cmd String Animation command passed instead of the current Status.
	 * @param description String description for messages.
	 */
	protected void animationAction(String cmd, String description) {
		super.animationAction(AnimationEvent.MOVING_NODES_ANIMATION, cmd, description, currentLocation);
	}


}







