/*
 * @(#)RotationBSTAnimation.java
 *
 * Last Modified: 9/15/01
 */

 import java.util.*;
 import java.awt.*;
 import java.awt.geom.*;

/** *
 	* The Animation object that defines the Rotation of a BSTTree. Two constructors exist,
 	* one setting the animator and animation color Schemes, one setting those to defaults. <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.3 9/15/01
 	*/

public class RotationBSTAnimation extends AbstractAnimation {


	/**
     * The Default step size used in the animation (16).
	 */
	public final static int DEFAULT_STEP = 16;

	/**
	 * Defines a right rotation.
	 */
	public final static int RIGHT_ROTATION = 1;

	/**
	 * Defines a left rotation.
	 */
	public final static int LEFT_ROTATION  = 2;

	/**
	 * Constant that defines the starting location.
	 */
	private final int START_MOVE = 0;

	/**
	 * Constant that defines the root moving location.
	 */
	private final int ROOT_MOVE = 1;

	/**
	 * Constant that defines the link moving location.
	 */
	private final int LINK_MOVE = 2;

	/**
	 * Constant that defines the descendant moving location.
	 */
	private final int DESCENDANT_MOVE = 3;

	/**
	 * Constant the defines the final moving location.
	 */
	private final int FINAL_MOVE = 4;

	/**
	 * Private doubles used to hold the current and previous location steps.
	 */
	private double currentLocation = 0.0;

	/**
	 * The previous location of the animation.
	 */
	private double previousLocation;

	/**
	 * Holds the orientation of the rotation (left or right).
	 */
	private int rotationOrientation;

	/**
	 * The root moving nodes for the rotation.
	 */
	private MovingBSTTreeAnimation rootMovingNodes;
	/**
	 * The child moving nodes for the rotation.
	 */
	private MovingBSTTreeAnimation childMovingNodes;
	/**
	 * The child descendant moving nodes for the rotation.
	 */
	private MovingBSTTreeAnimation childDescendantMovingNodes;
	/**
	 * The descendant moving nodes for the rotation.
	 */
	private MovingBSTTreeAnimation descendantMovingNodes;
	/**
	 * The final moving nodes for the rotation.
	 */
	private MovingBSTTreeAnimation finalMovingNodes;
	/**
	 * The final moving nodes for the rotation.
	 */
	private MovingBSTTreeAnimation finalTreeMovingNodes;


	/**
	 * The root moving node.
	 */
	 private MovingBSTTree rootDraw;


	/**
	 * The root moving node.
	 */
	 private MovingBSTTree childDraw;


	/**
	 * The root moving node.
	 */
	 private MovingBSTTree grandChildDraw;

	/**
	 * The root of the rotation.
	 */
	private BSTTree rootNode;

	/**
	 * The child of the rotation.
	 */
	private BSTTree childNode;

	/**
	 * The grandchild of the rotation.
	 */
	private BSTTree grandChildNode;



	/**
	 * Color Scheme used for the animation of the root.
	 */
	private NodeSettings rootAnimationScheme;

	/**
	 * Color Scheme used for the animation of the child.
	 */
	private NodeSettings childAnimationScheme;

	/**
	 * Color Scheme used for the animation of the descedant.
	 */
	private NodeSettings descendantAnimationScheme;

	/**
	 * Color Scheme used as the original.
	 */
	private NodeSettings nodeOriginalScheme;

	/**
	 * Color Scheme used for the animation of the key.
	 */
	private KeySettings keyAnimationScheme;

	/**
	 * Color Scheme used for the original scheme of the key.
	 */
	 private KeySettings keyOriginalScheme;


	/**
	 * The constructor which initiates the status and sets the color Schemes to default. Also sets
	 * starting command to Animation.PLAY, and sets the step time to the default.
	 *
	 * @param head the BSTTree head of the rotation animation.
	 * @param child the BSTTree child of the rotation animation.
	 * @param rotationOrientation the rotation orientation defined (LEFT_ROTATION or RIGHT_ROTATION).
	 */
	public RotationBSTAnimation(BSTTree head, BSTTree child, int rotationOrientation) {
		this(head, child, rotationOrientation, null, null, null, null, null, null, Animation.PLAY, DEFAULT_STEP);
	}

	/**
	 * The constructor which initiates the status and prepares the color schemes.
	 *
	 * @param head the BSTTree head of the rotation animation.
	 * @param child the BSTTree child of the rotation animation.
	 * @param rotationOrientation the rotation orientation defined (LEFT_ROTATION or RIGHT_ROTATION).
	 * @param RootAnimationScheme animation scheme for the root.
	 * @param ChildAnimationScheme animation scheme for the child.
	 * @param DescendantAnimationScheme animation scheme for the descendant.
	 * @param NodeOriginalAnimationScheme original scheme for the root.
	 * @param KeyAnimationScheme animation scheme for the key.
	 * @param KeyOriginalScheme original scheme for the key.
	 * @param startingCmd the Animation command that should start.
	 * @param stepTime the time for each step of the Animation. Sets the initial value.
	 */
	public RotationBSTAnimation(BSTTree head, BSTTree child, int rotationOrientation, NodeSettings RootAnimationScheme, NodeSettings ChildAnimationScheme, NodeSettings DescendantAnimationScheme, NodeSettings NodeOriginalScheme, KeySettings KeyAnimationScheme, KeySettings KeyOriginalScheme, String startingCmd, int stepTime) {
		super();

		// Set defaults if no color schemes exist
		if (RootAnimationScheme == null) {
			RootAnimationScheme = new NodeSettings();
		}

		if (ChildAnimationScheme == null) {
			ChildAnimationScheme = new NodeSettings();
		}

		if (DescendantAnimationScheme == null) {
			DescendantAnimationScheme = new NodeSettings();
		}

		if (NodeOriginalScheme == null) {
			NodeOriginalScheme = new NodeSettings();
		}

		if (KeyAnimationScheme == null) {
			KeyAnimationScheme = new KeySettings();
		}

		if (KeyOriginalScheme == null) {
			KeyOriginalScheme = new KeySettings();
		}

		// Set color schemes
		setRootAnimationScheme((NodeSettings)RootAnimationScheme.clone());
		setChildAnimationScheme((NodeSettings)ChildAnimationScheme.clone());
		setDescendantAnimationScheme((NodeSettings)DescendantAnimationScheme.clone());
		setNodeOriginalScheme((NodeSettings)NodeOriginalScheme.clone());
		setKeyAnimationScheme((KeySettings)KeyAnimationScheme.clone());
		setKeyOriginalScheme((KeySettings)KeyOriginalScheme.clone());

		this.rotationOrientation = rotationOrientation;

		// Sets the root and child nodes
		setRootNode(head);
		setChildNode(child);

		// Create the moving nodes
		createRootMovingNodes();
		createChildMovingNodes();
		createDescendantMovingNodes();
		createFinalMovingNodes();
		finalTreeMovingNodes = new MovingBSTTreeAnimation(getNodeOriginalScheme(), getKeyOriginalScheme());

		setStartingCommand(startingCmd);
		setStepTime(stepTime);
	}

	/************************/
	/* Accessor methods     */
	/************************/

	/**
	 * Gets the root node being drawn during the rotation.
	 *
	 * @return BSTTree of the root node.
	 */
	private BSTTree getRootNode() {
		return rootNode;
	}

	/**
	 * Gets the root moving node being drawn during the rotation.
	 *
	 * @return MovingBSTTree of the root node.
	 */
	private MovingBSTTree getRootDraw() {
		return rootDraw;
	}

	/**
	 * Gets the child moving node being drawn during the rotation.
	 *
	 * @return MovingBSTTree of the root node.
	 */
	private MovingBSTTree getChildDraw() {
		return childDraw;
	}

	/**
	 * Gets the grandchild moving node being drawn during the rotation.
	 *
	 * @return MovingBSTTree of the root node.
	 */
	private MovingBSTTree getGrandChildDraw() {
		return grandChildDraw;
	}

	/**
	 * Gets the child node being drawn during the rotation.
	 *
	 * @return BSTTree of the child node.
	 */
	private BSTTree getChildNode() {
		return childNode;
	}

	/**
	 * Gets the grandchild node being drawn during the rotation.
	 *
	 * @return BSTTree of the child node.
	 */
	private BSTTree getGrandChildNode() {
		return grandChildNode;
	}

	/**
	 * Gets the NodeSettings for the root animation scheme for the rotation.
	 *
	 * @return NodeSettings for the root node.
	 */
	public NodeSettings getRootAnimationScheme() {
		return rootAnimationScheme;
	}

	/**
	 * Gets the NodeSettings for the child animation scheme for the rotation.
	 *
	 * @return NodeSettings for the child node.
	 */
	public NodeSettings getChildAnimationScheme() {
		return childAnimationScheme;
	}

	/**
	 * Gets the NodeSettings for the descendant animation scheme for the rotation.
	 *
	 * @return NodeSettings for the descendant node.
	 */
	public NodeSettings getDescendantAnimationScheme() {
		return descendantAnimationScheme;
	}

	/**
	 * Gets the NodeSettings for the original node scheme for the rotation.
	 *
	 * @return NodeSettings for the original node scheme.
	 */
	public NodeSettings getNodeOriginalScheme() {
		return nodeOriginalScheme;
	}

	/**
	 * Gets the KeySettings for the animation scheme for the key during rotation.
	 *
	 * @return KeySettings for the animation of the key.
	 */
	public KeySettings getKeyAnimationScheme() {
		return keyAnimationScheme;
	}

	/**
	 * Gets the KeySettings for the original scheme of the key.
	 *
	 * @return KeySettings for the original key scheme.
	 */
	public KeySettings getKeyOriginalScheme() {
		return keyOriginalScheme;
	}

	/************************/
	/* Mutator methods     */
	/************************/

	/**
	 * Sets the root node being drawn during the rotation.
	 *
	 * @param node BSTTree of the root node.
	 */
	private void setRootNode(BSTTree node) {
		rootNode = node;
	}

	/**
	 * Sets the root moving node being drawn during the rotation.
	 *
	 * @param node MovingBSTTree of the root node.
	 */
	private void setRootDraw(MovingBSTTree rootDraw) {
		this.rootDraw = rootDraw;
	}

	/**
	 * Sets the root moving node being drawn during the rotation.
	 *
	 * @param node MovingBSTTree of the root node.
	 */
	private void setChildDraw(MovingBSTTree childDraw) {
		this.childDraw = childDraw;
	}

	/**
	 * Sets the root moving node being drawn during the rotation.
	 *
	 * @param node MovingBSTTree of the root node.
	 */
	private void setGrandChildDraw(MovingBSTTree grandChildDraw) {
		this.grandChildDraw = grandChildDraw;
	}

	/**
	 * Sets the child node being drawn during the rotation.
	 *
	 * @return node BSTTree of the child node.
	 */
	private void setChildNode(BSTTree node) {
		childNode = node;
	}

	/**
	 * Sets the grandChild node being drawn during the rotation.
	 *
	 * @return BSTTree of the grandchild node.
	 */
	private void setGrandChildNode(BSTTree node) {
		grandChildNode = node;
	}

	/**
	 * Sets the NodeSettings for the root animation scheme for the rotation.
	 *
	 * @param scheme NodeSettings for the root node.
	 */
	public void setRootAnimationScheme(NodeSettings scheme) {
		rootAnimationScheme = scheme;
	}

	/**
	 * Sets the NodeSettings for the child animation scheme for the rotation.
	 *
	 * @param scheme NodeSettings for the child node.
	 */
	public void setChildAnimationScheme(NodeSettings scheme) {
		childAnimationScheme = scheme;
	}

	/**
	 * Sets the NodeSettings for the descendant animation scheme for the rotation.
	 *
	 * @param scheme NodeSettings for the descendant node.
	 */
	public void setDescendantAnimationScheme(NodeSettings scheme) {
		descendantAnimationScheme = scheme;
	}

	/**
	 * Sets the NodeSettings for the original scheme for the rotation.
	 *
	 * @param scheme NodeSettings for the original scheme.
	 */
	public void setNodeOriginalScheme(NodeSettings scheme) {
		nodeOriginalScheme = scheme;
	}

	/**
	 * Sets the KeySettings for the animation scheme for the key during rotation.
	 *
	 * @param scheme KeySettings for the animation of the key.
	 */
	public void setKeyAnimationScheme(KeySettings scheme) {
		keyAnimationScheme = scheme;
	}

	/**
	 * Sets the KeySettings for the original scheme of the key during rotation.
	 *
	 * @param scheme KeySettings for the original of the key.
	 */
	public void setKeyOriginalScheme(KeySettings scheme) {
		keyOriginalScheme = scheme;
	}

	/*****************************/
	/* Entire Animators Mutators */
	/*****************************/

	/**
	 * Sets the step size for all of the animations according to the step size of this animation.
	 *
	 * @param size the step size being set for all animations.
	 *
	 */
	private void setAnimatorsStepTime(int size) {
		childMovingNodes.setStepTime(size);
		childDescendantMovingNodes.setStepTime(size);
		rootMovingNodes.setStepTime(size);
		descendantMovingNodes.setStepTime(size);
		finalMovingNodes.setStepTime(size);
		finalTreeMovingNodes.setStepTime(size);
	}


	/**
	 * Sets the step for all of the animations according to the step of this animation.
	 *
	 * @param step the step being set for all animations.
	 *
	 */
	private void setAnimatorsStep(boolean step) {
		childMovingNodes.setStep(step);
		childDescendantMovingNodes.setStep(step);
		rootMovingNodes.setStep(step);
		descendantMovingNodes.setStep(step);
		finalMovingNodes.setStep(step);
		finalTreeMovingNodes.setStep(step);
	}

	/**
	 * Sets the Animators status as the same status passed.
	 *
	 * @param status the Animation setting for all of the animators.
	 */
	private void setAnimatorsStatus(String status) {
		setAnimatorsStatus(status, status, status, status, status, status);
	}

	/**
	 * Sets the Animators status for each animator as the status passed.
	 *
	 * @param rootStatus the Animation status for the root animation.
	 * @param childStatus the Animation status for the child animation.
	 * @param childDescendantStatus the Animation status for the child descendant animation.
	 * @param descendantStatus the Animation status for the descendant animation.
	 * @param finalStatus the Animation status for the final animation.
	 */
	private void setAnimatorsStatus(String rootStatus, String childStatus, String childDescendantStatus, String descendantStatus, String finalStatus, String finalTreeStatus) {
		rootMovingNodes.setStatus(rootStatus);
		childMovingNodes.setStatus(childStatus);
		childDescendantMovingNodes.setStatus(childDescendantStatus);
		descendantMovingNodes.setStatus(descendantStatus);
		finalMovingNodes.setStatus(finalStatus);
		finalTreeMovingNodes.setStatus(finalTreeStatus);
	}



	/**
	 * Creates the moving nodes corresponding to the root of the rotation.
	 */
	private void createRootMovingNodes() {
		// Intialize
		rootMovingNodes = new MovingBSTTreeAnimation(getRootAnimationScheme(), getKeyAnimationScheme());

		// Set listeners
		rootMovingNodes.addAnimationListener(getRootNode());
		getRootNode().addAnimator(rootMovingNodes);

		MovingBSTTree rootDraw = new MovingBSTTree(getRootNode());

		setRootDraw(rootDraw);

		// rotate right
		if (rotationOrientation == RIGHT_ROTATION) {
			// Move position
			rootDraw.setMovePosition(MovingBSTTree.DOWN_RIGHT);

			// Add root moving node to list of root nodes
			rootMovingNodes.add(rootDraw, getRootNode());

			// Add all children
			addNode(getRootNode().getRightTree(), rootMovingNodes, MovingBSTTree.FOLLOW_PARENT_RIGHT, rootDraw);
		}

		// rotate left
		if (rotationOrientation == LEFT_ROTATION) {
			// Move position
			rootDraw.setMovePosition(MovingBSTTree.DOWN_LEFT);

			// Add root moving node to list of root nodes
			rootMovingNodes.add(rootDraw, getRootNode());

			// Add all children
			addNode(getRootNode().getLeftTree(), rootMovingNodes, MovingBSTTree.FOLLOW_PARENT_LEFT, rootDraw);
		}

	}

	/**
	 * Creates the moving nodes corresponding to the child of the rotation.
	 */
	private void createChildMovingNodes() {
		// Initialize
		childMovingNodes = new MovingBSTTreeAnimation(getChildAnimationScheme(), getKeyAnimationScheme());

		// Descendants of the child (move differently)
		childDescendantMovingNodes = new MovingBSTTreeAnimation(getChildAnimationScheme(), getKeyAnimationScheme());

		// Child
		MovingBSTTree childMovingNode = new MovingBSTTree(getChildNode());

		// Set listeners
		childMovingNodes.addAnimationListener(getChildNode());
		getChildNode().addAnimator(childMovingNodes);

		// Add child to moving nodes animation
		childMovingNodes.add(childMovingNode, getChildNode());

		setChildDraw(childMovingNode);

		// rotate right
		if (rotationOrientation == RIGHT_ROTATION) {
			childMovingNode.setRightTree(getRootDraw());

			// move position
			childMovingNode.setMovePosition(MovingBSTTree.UP_RIGHT);

			// Add left children to child moving animation
			addNode((BSTTree)getChildNode().getLeftTree(), childMovingNodes, MovingBSTTree.FOLLOW_PARENT_LEFT, childMovingNode);

			// Add right children to childMovingDescendant animation
			addNode((BSTTree)getChildNode().getRightTree(), childDescendantMovingNodes, MovingBSTTree.FOLLOW_PARENT_RIGHT, childMovingNode);

			// Set getGrandChildNode().
			setGrandChildNode((BSTTree)getChildNode().getRightTree());
		}
		//rotate left
		else {
			childMovingNode.setLeftTree(getRootDraw());

			// move position
			childMovingNode.setMovePosition(MovingBSTTree.UP_LEFT);

			// Add right children to child moving animation
			addNode((BSTTree)getChildNode().getRightTree(), childMovingNodes, MovingBSTTree.FOLLOW_PARENT_RIGHT, childMovingNode);

			// Add right children to childMovingDescendant animation
			addNode((BSTTree)getChildNode().getLeftTree(), childDescendantMovingNodes, MovingBSTTree.FOLLOW_PARENT_LEFT, childMovingNode);

			// Set getGrandChildNode().
			setGrandChildNode((BSTTree)getChildNode().getLeftTree());

		}

	}

	/**
	 * Creates the moving nodes corresponding to the descendant of the rotation.
	 */
	private void createDescendantMovingNodes() {
		// Intialize
		descendantMovingNodes = new MovingBSTTreeAnimation(getDescendantAnimationScheme(), getKeyAnimationScheme());
		// Grand child node.
		MovingBSTTree grandChildMovingNode;

		// If there is a grandchild.
		if (!getGrandChildNode().isEmpty()) {
			grandChildMovingNode = new MovingBSTTree(getGrandChildNode());

			setGrandChildDraw(grandChildMovingNode);

			// Add grandchild to descendant animation
			descendantMovingNodes.add(grandChildMovingNode, getGrandChildNode());

			if (rotationOrientation == RIGHT_ROTATION) {
				grandChildMovingNode.setMovePosition(MovingBSTTree.DOWN_LEFT);
			}
			else {
				grandChildMovingNode.setMovePosition(MovingBSTTree.DOWN_RIGHT);
			}

			// Set listeners
			descendantMovingNodes.addAnimationListener(getGrandChildNode());
			getGrandChildNode().addAnimator(descendantMovingNodes);

			// Add all children
			addNode((BSTTree)getGrandChildNode().getLeftTree(), descendantMovingNodes, MovingBSTTree.FOLLOW_PARENT_LEFT, grandChildMovingNode);
			addNode((BSTTree)getGrandChildNode().getRightTree(), descendantMovingNodes, MovingBSTTree.FOLLOW_PARENT_RIGHT, grandChildMovingNode);

		}

	}

	/**
	 * Creates the moving nodes corresponding to the final correction of the rotation.
	 */
	private void createFinalMovingNodes() {
		// Initialize
		finalMovingNodes = new MovingBSTTreeAnimation(getNodeOriginalScheme(), getKeyOriginalScheme());

		// Add the root Nodes
		LinkedList rootMovingNodesList = rootMovingNodes.getMovingNodes();
		LinkedList rootNodesList = rootMovingNodes.getNodes();

		// Add the children nodes
		LinkedList childMovingNodesList = childMovingNodes.getMovingNodes();
		LinkedList childNodesList = childMovingNodes.getNodes();

		// Add the descendant nodes
		LinkedList descendantMovingNodesList = descendantMovingNodes.getMovingNodes();
		LinkedList descendantNodesList = descendantMovingNodes.getNodes();

		// Go through all the lists and add all of the nodes as FOLLOW_NODE, to correct their positions.
		for(int j = 0; j<rootNodesList.size(); j++) {
			finalMovingNodes.add((MovingBSTTree)rootMovingNodesList.get(j), (BSTTree)rootNodesList.get(j));
		}

		for(int j = 0; j<childNodesList.size(); j++) {
			finalMovingNodes.add((MovingBSTTree)childMovingNodesList.get(j), (BSTTree)childNodesList.get(j));
		}

		for(int j = 0; j<descendantNodesList.size(); j++) {
			finalMovingNodes.add((MovingBSTTree)descendantMovingNodesList.get(j), (BSTTree)descendantNodesList.get(j));
		}

	}

	/**
	 * Creates the moving nodes corresponding to the rest of the tree, not involved in the rotation.
	 */
	private void createFinalTreeMovingNodes() {
		// Intialize
		finalTreeMovingNodes = new MovingBSTTreeAnimation();

		// Head node
		BSTTree headNode = (BSTTree)getRootNode().getHead().getChild();


		if (headNode != getRootNode()) {

			MovingBSTTree headMovingNode = new MovingBSTTree(headNode);

			if (headNode.isAnimateDrawing()) {

				// Add grandchild to descendant animation
				finalTreeMovingNodes.add(headMovingNode, headNode);

				headMovingNode.setMovePosition(MovingBSTTree.FOLLOW_NODE);

				// Set listeners
				finalTreeMovingNodes.addAnimationListener(headNode);
				(headNode).addAnimator(finalTreeMovingNodes);

			}
			// Add all children
			addTreeNode((BSTTree)headNode.getLeftTree(), finalTreeMovingNodes, MovingBSTTree.FOLLOW_NODE, headMovingNode);
			addTreeNode((BSTTree)headNode.getRightTree(), finalTreeMovingNodes, MovingBSTTree.FOLLOW_NODE, headMovingNode);

		}

	}

	/**
	 * Adds all children nodes to the animator list, setting the Moving node as its parent. The move position
	 * defines the moving of the new node.
	 *
	 * @param node the node which the MovingBSTTree made imitates.
	 * @param animator the MovingBSTTreeAnimation to which the new MovingBSTTree node is added.
	 * @param movePostion the moving position of the new MovingBSTTree.
	 */
	private void addTreeNode(BSTTree node, MovingBSTTreeAnimation animator, int movePosition, MovingBSTTree parent) {
		if (node.isEmpty())
			return;

		if (node == getRootNode())
			return;

		// Create new MovingBSTTree
		MovingBSTTree movingNode = new MovingBSTTree(node, parent);


		if (node != getRootNode()) {

			if (node.isAnimateDrawing()) {
				// Sets the move position
				movingNode.setMovePosition(movePosition);

				// Adds the animator to the MovingBSTTreeAnimation
				animator.add(movingNode, node);

				// Adds the listener to the animation and the animation to the node.
				animator.addAnimationListener(node);
				node.addAnimator(animator);

			}

			// Recursively goes through children
			addTreeNode((BSTTree)node.getLeftTree(), animator, MovingBSTTree.FOLLOW_NODE, movingNode);
			addTreeNode((BSTTree)node.getRightTree(), animator, MovingBSTTree.FOLLOW_NODE, movingNode);


		}

	}

	/**
	 * Adds all children nodes to the animator list, setting the Moving node as its parent. The move position
	 * defines the moving of the new node.
	 *
	 * @param node the node which the MovingBSTTree made imitates.
	 * @param animator the MovingBSTTreeAnimation to which the new MovingBSTTree node is added.
	 * @param movePostion the moving position of the new MovingBSTTree.
	 */
	private void addNode(BSTTree node, MovingBSTTreeAnimation animator, int movePosition, MovingBSTTree parent) {
		if (node.isEmpty())
			return;

		// Create new MovingBSTTree
		MovingBSTTree movingNode = new MovingBSTTree(node, parent);

		// Sets the move position
		movingNode.setMovePosition(movePosition);

		// Adds the animator to the MovingBSTTreeAnimation
		animator.add(movingNode, node);

		// Adds the listener to the animation and the animation to the node.
		animator.addAnimationListener(node);
		node.addAnimator(animator);

		// Recursively goes through children
		addNode((BSTTree)node.getLeftTree(), animator, MovingBSTTree.FOLLOW_PARENT_LEFT, movingNode);
		addNode((BSTTree)node.getRightTree(), animator, MovingBSTTree.FOLLOW_PARENT_RIGHT, movingNode);


	}




	/**
	 * Draws all of the animators according to their status in the given Graphics2D and using
	 * the status as the starting status for all of the animators.
	 *
	 * @param g2 the Graphics2D to which the animators are drawn.
	 * @param status the starting status passed to all animators.
	 */
	private void drawAnimators(Graphics2D g2, String status) {
		drawAnimators(g2, status, status, status, status, status, status);
	}


	/**
	 * Draws all of the animators according to their status in the given Graphics2D and using
	 * the status as the starting status for all of the animators.
	 *
	 * @param g2 the Graphics2D to which the animators are drawn.
	 * @param rootStatus the Animation starting status for the root animation.
	 * @param childStatus the Animation starting status for the child animation.
	 * @param childDescendantStatus the Animation starting status for the child descendant animation.
	 * @param descendantStatus the Animation starting status for the descendant animation.
	 * @param finalStatus the Animation starting status for the final animation.
	 */
	private void drawAnimators(Graphics2D g2, String rootStatus, String childStatus, String childDescendantStatus, String descendantStatus, String finalStatus ,  String finalTreeStatus ) {
		rootMovingNodes.drawAnimation(g2, rootStatus);
		childMovingNodes.drawAnimation(g2, childStatus);
		childDescendantMovingNodes.drawAnimation(g2, childDescendantStatus);
		descendantMovingNodes.drawAnimation(g2, descendantStatus);
		finalMovingNodes.drawAnimation(g2, finalStatus);
		finalTreeMovingNodes.drawAnimation(g2, finalTreeStatus);
	}

	/**
     * 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 <code>AnimationEvent</code> 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 g2 Graphics2D to which the graphics are drawn.
 	 */
	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).
	 * After completing the drawing, the Animation sends an AnimationEvent to all its listeners, indicating
	 * any information that the listerners may wish to use.
	 *
	 * <b> BSTTreeHead calls: </b>
	 * <ul>
	 * <li><code>rotateUpTreeType</code> - called when animation does completes </li>
	 * </ul>
	 * <b> Other Animation Objects used: </b>
	 * <ul>
	 * <li>MovingBSTTreeAnimation</li>
	 * </ul>
	 *
	 * @param g2 the graphics to which the animation step should be drawn.
	 * @param startingStatus sent to the animators
	 */
	public void drawAnimation(Graphics2D g2, String startingStatus) {

		setStartingCommand(startingStatus);

		// Sets the animation step size.
		setAnimatorsStepTime(getStepTime());

		// Sets the animation step size.
		setAnimatorsStep(getStep());

		// FINISH status (set from outside)
		if (getStatus().equals(Animation.FINISH)) {

			if (previousLocation < DESCENDANT_MOVE) {

				// Actual rotation
				((BSTTreeHead)getChildNode().getHead()).rotateUpTreeType(getChildNode());
			}
		}

		// BEGIN status
		if (getStatus().equals(Animation.BEGIN)) {

			currentLocation = 0.0;
			previousLocation = 0.0;

			rootMovingNodes.setAnimationScheme(getNodeOriginalScheme(), getKeyOriginalScheme());
			childMovingNodes.setAnimationScheme(getNodeOriginalScheme(), getKeyOriginalScheme());
			childDescendantMovingNodes.setAnimationScheme(getNodeOriginalScheme(), getKeyOriginalScheme() );

			setAnimatorsStatus(Animation.BEGIN, Animation.BEGIN, Animation.BEGIN, Animation.STOP, Animation.STOP, Animation.STOP);

			if (rotationOrientation == RIGHT_ROTATION) {
				getRootDraw().getSettings().setLeftLinkComposite((Composite)AlphaComposite.getInstance(NodeSettings.linkRuleDefault, (float)(1.0)));
				getChildDraw().getSettings().setRightLinkComposite((Composite)AlphaComposite.getInstance(NodeSettings.linkRuleDefault, (float)(0.0) ));
			}
			else {
				getRootDraw().getSettings().setRightLinkComposite((Composite)AlphaComposite.getInstance(NodeSettings.linkRuleDefault, (float)(1.0)));
				getChildDraw().getSettings().setLeftLinkComposite((Composite)AlphaComposite.getInstance(NodeSettings.linkRuleDefault, (float)(0.0) ));

			}


			drawAnimators(g2, startingStatus);

			animationAction();

			setStatus(startingStatus);

			if (rotationOrientation == RIGHT_ROTATION) {
				getRootDraw().setLeftTree(getChildDraw());
				messageAction(Animation.BEGIN + " rotate right of "+getRootNode().getKey().toString());
			}
			else {
				getRootDraw().setRightTree(getChildDraw());
				messageAction(Animation.BEGIN + " rotate left of "+getRootNode().getKey().toString());
			}


			return;
		}

		// Currently on a step and no changes have occured. Return to startingStatus
		if (getStatus().equals(Animation.STEP)) {


			setStatus(startingStatus);
		}

		// PLAY status
		if (getStatus().equals(Animation.PLAY)) {
			messageAction(Animation.PLAY);

			previousLocation = currentLocation;

			if(getStep()) { // Skip middle animation steps.
				currentLocation = Math.ceil(currentLocation) + getStepSize();
			}
			else { // Normal step
				currentLocation += getStepSize();
			}

			// Root moving animation
			if (currentLocation < ROOT_MOVE && currentLocation >= START_MOVE) {
				// Previously started
				if (previousLocation <= START_MOVE) {
					// Sets Schemes
					rootMovingNodes.setAnimationScheme(getRootAnimationScheme(), getKeyAnimationScheme());
					childMovingNodes.setAnimationScheme(getNodeOriginalScheme(), getKeyOriginalScheme());
					childDescendantMovingNodes.setAnimationScheme(getNodeOriginalScheme(), getKeyOriginalScheme() );
					// Step Status
					setStatus(Animation.STEP);
				}

				float increasingToOne = 1.0F - ((float)(ROOT_MOVE - currentLocation)) - .2F;
				float decreasingFromOne = (((float)(ROOT_MOVE - currentLocation))-.2F);

				if (increasingToOne < 0) {
					increasingToOne = 0;
				}

				if (decreasingFromOne < 0) {
					decreasingFromOne = 0;
				}


				if (rotationOrientation == RIGHT_ROTATION) {
					getRootDraw().getSettings().setLeftLinkComposite((Composite)AlphaComposite.getInstance(NodeSettings.nodeRuleDefault,  decreasingFromOne));
					getChildDraw().getSettings().setRightLinkComposite((Composite)AlphaComposite.getInstance(NodeSettings.nodeRuleDefault, increasingToOne));
				}
				else {
					getRootDraw().getSettings().setRightLinkComposite((Composite)AlphaComposite.getInstance(NodeSettings.nodeRuleDefault, decreasingFromOne));
					getChildDraw().getSettings().setLeftLinkComposite((Composite)AlphaComposite.getInstance(NodeSettings.nodeRuleDefault, increasingToOne ));
				}


				// Set animation statuses (PLAY, PAUSE, PAUSE, STOP, STOP, STOP)
				setAnimatorsStatus(Animation.PLAY, Animation.PAUSE, Animation.PAUSE, Animation.STOP, Animation.STOP, Animation.STOP);
				// Draw animators
				drawAnimators(g2, Animation.PLAY);

				MovingBSTTree rootDraw = (rootMovingNodes.getFirstMovingNode());

			}

			// Child Moving animation
			if (currentLocation < LINK_MOVE && currentLocation >= ROOT_MOVE) {
				// Previously root animation
				if (previousLocation < ROOT_MOVE) {
					// Step Status
					setStatus(Animation.STEP);

					messageAction("Old root "+ getRootNode().getKey().toString()+" becomes child.");

					boolean temp = rootMovingNodes.getStep();

					// Set step, to finish the moving
					rootMovingNodes.setStep(true);

					// Set status (PLAY, PAUSE, PAUSE, STOP, STOP, STOP)
					setAnimatorsStatus(Animation.PLAY, Animation.PAUSE, Animation.PAUSE, Animation.STOP, Animation.STOP, Animation.STOP);
					// Draw
					drawAnimators(g2, Animation.PLAY);

					// Turn back step
					rootMovingNodes.setStep(temp);

					// Original scheme
					rootMovingNodes.setAnimationScheme(getNodeOriginalScheme(), getKeyOriginalScheme());
					// Set schemes for children
					childMovingNodes.setAnimationScheme(getChildAnimationScheme(), getKeyAnimationScheme());
					childDescendantMovingNodes.setAnimationScheme(getChildAnimationScheme(), getKeyAnimationScheme());
					// Set to start at beginning of child move (end of ROOT_MOVE)
					currentLocation = ROOT_MOVE;


					if (rotationOrientation == RIGHT_ROTATION) {
						// No Descendants
						if (descendantMovingNodes.isEmpty()) {
							getRootDraw().setLeftTree(null);
						}

						getRootDraw().getSettings().setLeftLinkComposite((Composite)AlphaComposite.getInstance(NodeSettings.nodeRuleDefault, (float)(0)));
					}
					else {
						// No Descendants
						if (descendantMovingNodes.isEmpty()) {
							getRootDraw().setRightTree(null);
						}

						getRootDraw().getSettings().setRightLinkComposite((Composite)AlphaComposite.getInstance(NodeSettings.nodeRuleDefault, (float)(0)));
					}
				}

				else {

					// No Descendants
					if (descendantMovingNodes.isEmpty()) {
						float increasingToOne = 1.0F - ((float)(LINK_MOVE - currentLocation)) - .2F;

						if (increasingToOne < 0) {
							increasingToOne = 0;
						}


						if (rotationOrientation == RIGHT_ROTATION) {
							getRootDraw().getSettings().setLeftLinkComposite((Composite)AlphaComposite.getInstance(NodeSettings.nodeRuleDefault, increasingToOne));
						}
						else {
							getRootDraw().getSettings().setRightLinkComposite((Composite)AlphaComposite.getInstance(NodeSettings.nodeRuleDefault, increasingToOne));
						}
					}

					// Set status (PAUSE, PLAY, PLAY, STOP, STOP, STOP)
					setAnimatorsStatus(Animation.PAUSE, Animation.PLAY, Animation.PLAY, Animation.STOP, Animation.STOP, Animation.STOP);
					// Draw
					drawAnimators(g2, Animation.PLAY);
				}

			}
			// Descendant Moving animation
			if (currentLocation < DESCENDANT_MOVE && currentLocation >= LINK_MOVE) {
				// Previously LINK_MOVE
				if (previousLocation < LINK_MOVE) {
					// Step Status
					setStatus(Animation.STEP);

					messageAction("Old child "+ getChildNode().getKey().toString()+" becomes root.");

					boolean tempChild = childMovingNodes.getStep();
					boolean tempChildDescendant = childDescendantMovingNodes.getStep();

					// Set step, to finish the moving
					childMovingNodes.setStep(true);
					childDescendantMovingNodes.setStep(true);

					// Set status (PAUSE, PLAY, PLAY, STOP, STOP, STOP)
					setAnimatorsStatus(Animation.PAUSE, Animation.PLAY, Animation.PLAY, Animation.STOP, Animation.STOP, Animation.STOP);

					// Draw
					drawAnimators(g2, Animation.PLAY);

					// Turn back step
					childMovingNodes.setStep(tempChild);
					childDescendantMovingNodes.setStep(tempChildDescendant);
					// Original Scheme
					childMovingNodes.setAnimationScheme(getNodeOriginalScheme(), getKeyOriginalScheme());
					// Set scheme for descendant
					descendantMovingNodes.setAnimationScheme(getDescendantAnimationScheme(), getKeyAnimationScheme());
					// Set to start at beginning of descendant move (end of LINK_MOVE)
					currentLocation = LINK_MOVE;

					// No descendant
					if (descendantMovingNodes.isEmpty()) {
						// Skip animation
						currentLocation = DESCENDANT_MOVE-getStepSize();
						setStatus(Animation.PLAY);
						animationAction();
						return;
					}
					else {
						// Build Descendant moving nodes from the final position of the first moving node of child descendant nodes
						MovingBSTTree childDescendantMovingNode = childDescendantMovingNodes.getFirstMovingNode();

						// Grand child node is first descendant moving node
						MovingBSTTree grandChildMovingNode = descendantMovingNodes.getFirstMovingNode();

						// Sets the starting locations as ending location of the childDescendantMovingNode
						grandChildMovingNode.setStartLevel(childDescendantMovingNode.getEndLevel());
						grandChildMovingNode.setStartTransform(childDescendantMovingNode.getEndTransform());

						setGrandChildDraw(grandChildMovingNode);

						if (rotationOrientation == RIGHT_ROTATION) {
							getRootDraw().getSettings().setLeftLinkComposite((Composite)AlphaComposite.getInstance(NodeSettings.nodeRuleDefault, (float)(0)));
						}
						else {
							getRootDraw().getSettings().setRightLinkComposite((Composite)AlphaComposite.getInstance(NodeSettings.nodeRuleDefault, (float)(0) ));
						}


						if (rotationOrientation == RIGHT_ROTATION) {
							messageAction("Right children of new root "+ getChildNode().getKey().toString()+" become\nleft children of old root "+getRootNode().getKey().toString()+".");
						}
						if (rotationOrientation == LEFT_ROTATION) {
							messageAction("Left children of new root "+ getChildNode().getKey().toString()+" become\nright children of old root "+getRootNode().getKey().toString()+".");
						}

					}

				}
				// Descendant animation
				else {

					// Set status (PAUSE, PAUSE, STOP, PLAY, STOP, STOP)
					setAnimatorsStatus(Animation.PAUSE, Animation.PAUSE, Animation.STOP, Animation.PLAY, Animation.STOP, Animation.STOP);
					// Draw
					drawAnimators(g2, Animation.PLAY);

					float increasingToOne = 1.0F - ((float)(DESCENDANT_MOVE - currentLocation))-.01F;

					if (increasingToOne < 0) {
						increasingToOne = 0;
					}

					if (rotationOrientation == RIGHT_ROTATION) {
						// Descendants
						getRootDraw().setLeftTree(getGrandChildDraw());
						getRootDraw().getSettings().setLeftLinkComposite((Composite)AlphaComposite.getInstance(NodeSettings.nodeRuleDefault, increasingToOne));
					}
					else {
						// Descendants
						getRootDraw().setRightTree(getGrandChildDraw());
						getRootDraw().getSettings().setRightLinkComposite((Composite)AlphaComposite.getInstance(NodeSettings.nodeRuleDefault, increasingToOne));
					}

				}

			}
			// Final Moving
			if (currentLocation < FINAL_MOVE && currentLocation >= DESCENDANT_MOVE) {

				// previously descendant animation
				if (previousLocation < DESCENDANT_MOVE) {
					// Step Status
					setStatus(Animation.STEP);

					boolean temp = descendantMovingNodes.getStep();

					// Set step, to finish animation.
					descendantMovingNodes.setStep(true);

					// Set status(PAUSE, PAUSE, STOP, PLAY, STOP, STOP)
					setAnimatorsStatus(Animation.PAUSE, Animation.PAUSE, Animation.STOP, Animation.PLAY, Animation.STOP, Animation.STOP);
					// Draw
					drawAnimators(g2, Animation.PLAY);

					// Turn back step
					descendantMovingNodes.setStep(temp);
					// Original Scheme
					descendantMovingNodes.setAnimationScheme(getNodeOriginalScheme(), getKeyOriginalScheme());
					// Original Scheme for final node animation
					finalMovingNodes.setAnimationScheme(getNodeOriginalScheme(), getKeyOriginalScheme());
					// Set to start at beginning of final move (end of DESCENDANT_MOVE)
					currentLocation = DESCENDANT_MOVE;

					// Create the final moving nodes
					createFinalTreeMovingNodes();

					// Gets the level of the tree.
					int tempLevel = ((BSTTreeHead)getChildNode().getHead()).getTreeLevel();

					// Actual rotation
					((BSTTreeHead)getChildNode().getHead()).rotateUpTreeType(getChildNode());

					// REDRAW message
					messageAction(Animation.REDRAW);

					// Only need final moving nodes if the level changed (section height has to have changed).
					if (tempLevel == ((BSTTreeHead)getChildNode().getHead()).getTreeLevel()) {
						// No change
						currentLocation = FINAL_MOVE - getStepSize();
						setStatus(Animation.PLAY);
						animationAction();
						return;
					}


					LinkedList finalMovingNodesList = finalMovingNodes.getMovingNodes();

					// Construct final moving
					for (int i=0; i< finalMovingNodesList.size(); i++) {
						// Get node
						MovingBSTTree finalNode = (MovingBSTTree)finalMovingNodesList.get(i);
						// Set start level as ending moving level
						int endLevel = finalNode.getEndLevel();
						finalNode.setStartLevel(endLevel);
						// Set start transfrom as ending moving transform
						AffineTransform endTransform = finalNode.getEndTransform();
						finalNode.setStartTransform(endTransform);
						// Set move position to follow
						finalNode.setMovePosition(MovingBSTTree.FOLLOW_NODE);
					}


				}
				// Final animation
				else {
					// Set Status(STOP, STOP, STOP, STOP, PLAY, PLAY)
					setAnimatorsStatus(Animation.STOP, Animation.STOP, Animation.STOP, Animation.STOP, Animation.PLAY, Animation.PLAY);
					// Draw
					drawAnimators(g2, Animation.PLAY);
				}
			}

			// Animation is completed
			if (currentLocation >= FINAL_MOVE) {
				// Set step, to finish the animation
				finalMovingNodes.setStep(true);
				// Set Status(STOP, STOP, STOP, STOP, PLAY, PLAY)
				setAnimatorsStatus(Animation.STOP, Animation.STOP, Animation.STOP, Animation.STOP, Animation.PLAY, Animation.PLAY);
				// Draw
				drawAnimators(g2, Animation.PLAY);
				// Set own status to FINISH
				setStatus(Animation.FINISH);

			}

		}

		// REWIND status
		if (getStatus().equals(Animation.REWIND)) {

			messageAction(Animation.REWIND);

			previousLocation = currentLocation;

			if(getStep()) { // Skip middle animation steps.
				currentLocation = Math.floor(currentLocation)-getStepSize();
			}
			else { // Normal step
				currentLocation -= getStepSize();
			}


			// Beginning of animation
			if (currentLocation <= START_MOVE) {
				// Pause animation
				setStatus(Animation.PAUSE);

				boolean temp = rootMovingNodes.getStep();

				// Set step to start again
				rootMovingNodes.setStep(true);

				// Set stats (REWIND, PAUSE, PAUSE, STOP, STOP, STOP)
				setAnimatorsStatus(Animation.REWIND, Animation.PAUSE, Animation.PAUSE, Animation.STOP, Animation.STOP, Animation.STOP);
				// Draw
				drawAnimators(g2, Animation.REWIND);
				// Turn back step
				rootMovingNodes.setStep(temp);
				// Set Original scheme
				rootMovingNodes.setAnimationScheme(getNodeOriginalScheme(), getKeyOriginalScheme());
				// Reset location
				currentLocation = 0.0;
			}
			// Root moving animation
			if (currentLocation < ROOT_MOVE && currentLocation >= START_MOVE) {
				// Previously Descendant animation
				if (previousLocation >= ROOT_MOVE) {
					// Step Status
					setStatus(Animation.STEP);

					boolean tempChild = childMovingNodes.getStep();
					boolean tempChildDescendant = childDescendantMovingNodes.getStep();

					// Set step, to finish the moving
					childMovingNodes.setStep(true);
					childDescendantMovingNodes.setStep(true);

					// Set status (PAUSE, REWIND, REWIND, STOP, STOP, STOP)
					setAnimatorsStatus(Animation.PAUSE, Animation.REWIND, Animation.REWIND, Animation.STOP, Animation.STOP, Animation.STOP);

					// Draw
					drawAnimators(g2, Animation.REWIND);

					// Turn back step
					childMovingNodes.setStep(tempChild);
					childDescendantMovingNodes.setStep(tempChildDescendant);

					// Set original schemes
					childMovingNodes.setAnimationScheme(getNodeOriginalScheme(), getKeyOriginalScheme());
					childDescendantMovingNodes.setAnimationScheme(getNodeOriginalScheme(), getKeyOriginalScheme());
					// Set scheme
					rootMovingNodes.setAnimationScheme(getRootAnimationScheme(), getKeyAnimationScheme());

					// Set location
					currentLocation = ROOT_MOVE-getStepSize();

				}
				// Root moving animation
				else {
					// Set status (REWIND, PAUSE, PAUSE, STOP, STOP, STOP)
					setAnimatorsStatus(Animation.REWIND, Animation.PAUSE, Animation.PAUSE, Animation.STOP, Animation.STOP, Animation.STOP);
					// Draw
					drawAnimators(g2, Animation.REWIND);
				}
			}
			// Child Animation
			if (currentLocation < LINK_MOVE && currentLocation >= ROOT_MOVE) {
				// Previously Descendant Animation
				if (previousLocation >= LINK_MOVE) {
					// Step Status
					setStatus(Animation.STEP);

					boolean temp = descendantMovingNodes.getStep();
					// Set step to finish animation
					descendantMovingNodes.setStep(true);
					// Set Status (PAUSE, PAUSE, STOP, REWIND, STOP, STOP)
					setAnimatorsStatus(Animation.PAUSE, Animation.PAUSE, Animation.STOP, Animation.REWIND, Animation.STOP, Animation.STOP);
					// Draw
					drawAnimators(g2, Animation.REWIND);
					// Turn step back
					descendantMovingNodes.setStep(temp);
					// Set original Schemes
					descendantMovingNodes.setAnimationScheme(getNodeOriginalScheme(), getKeyOriginalScheme());
					// Set child animation schemes
					childMovingNodes.setAnimationScheme(getChildAnimationScheme(), getKeyAnimationScheme());
					// Set location
					currentLocation = LINK_MOVE - getStepSize();

				}
				// Child moving animation
				else {
					// Set Status (PAUSE, REWIND, REWIND, STOP, STOP, STOP)
					setAnimatorsStatus(Animation.PAUSE, Animation.REWIND, Animation.REWIND, Animation.STOP, Animation.STOP, Animation.STOP);
					// Draw
					drawAnimators(g2,  Animation.REWIND);
				}

			}
			// Descendant Animation
			if (currentLocation < DESCENDANT_MOVE && currentLocation >= LINK_MOVE) {
				// Previously final Animation
				if (previousLocation >= DESCENDANT_MOVE) {
					// Step Status
					setStatus(Animation.STEP);

					boolean temp = finalMovingNodes.getStep();
					// Set step to finish animation
					finalMovingNodes.setStep(true);
					// Set Status (STOP, STOP, STOP, STOP, REWIND, REWIND)
					setAnimatorsStatus(Animation.STOP, Animation.STOP, Animation.STOP, Animation.STOP, Animation.REWIND, Animation.REWIND);
					// Draw
					drawAnimators(g2, Animation.REWIND);
					// Turn step back
					finalMovingNodes.setStep(temp);
					// Set original schemes
					finalMovingNodes.setAnimationScheme(getNodeOriginalScheme(), getKeyOriginalScheme());
					// Descendant animation scheme
					descendantMovingNodes.setAnimationScheme(getDescendantAnimationScheme(), getKeyAnimationScheme());
					// Set Location
					currentLocation = DESCENDANT_MOVE - getStepSize();
					// Skip if no descendant nodes
					if (descendantMovingNodes.isEmpty()) {
						currentLocation = LINK_MOVE + getStepSize();
						setStatus(Animation.REWIND);
						animationAction();
						return;
					}

				}
				// Descendant moving animation
				else {
					// Set Status (PAUSE, PAUSE,STOP, REWIND, STOP, STOP)
					setAnimatorsStatus(Animation.PAUSE, Animation.PAUSE, Animation.STOP, Animation.REWIND, Animation.STOP, Animation.STOP);
					// Draw
					drawAnimators(g2,  Animation.REWIND);
				}

			}
			// Final Animation
			if (currentLocation < FINAL_MOVE && currentLocation >= DESCENDANT_MOVE) {

				messageAction("Cannot Rewind : Correcting Size");
				currentLocation = previousLocation;

				// Cannot rewind Final animation
				setStatus(Animation.PAUSE);
				// Draw
				drawAnimation(g2, Animation.PAUSE);
			}


		}

		// PAUSE status
		if (getStatus().equals(Animation.PAUSE)) {
			messageAction(Animation.PAUSE);
			// Before Root Animation
			if (currentLocation <= ROOT_MOVE) {
				// (PAUSE, PAUSE, PAUSE, STOP, STOP, STOP)
				setAnimatorsStatus(Animation.PAUSE, Animation.PAUSE, Animation.PAUSE, Animation.STOP, Animation.STOP, Animation.STOP);
			}
			// Root Animation
			if (currentLocation < ROOT_MOVE && currentLocation >= START_MOVE) {
				// (PAUSE, PAUSE, PAUSE, STOP, STOP, STOP)
				setAnimatorsStatus(Animation.PAUSE, Animation.PAUSE, Animation.PAUSE, Animation.STOP, Animation.STOP, Animation.STOP);
			}
			// Child Animation
			if (currentLocation < LINK_MOVE && currentLocation >= ROOT_MOVE) {
				// (PAUSE, PAUSE, PAUSE, STOP, STOP, STOP)
				setAnimatorsStatus(Animation.PAUSE, Animation.PAUSE, Animation.PAUSE, Animation.STOP, Animation.STOP, Animation.STOP);
			}
			// Descendant Animation
			if (currentLocation < DESCENDANT_MOVE && currentLocation >= LINK_MOVE) {
				// (PAUSE, PAUSE, STOP, PAUSE, STOP, STOP)
				setAnimatorsStatus(Animation.PAUSE, Animation.PAUSE, Animation.STOP, Animation.PAUSE, Animation.STOP, Animation.STOP);
			}
			// Final Animation
			if (currentLocation < FINAL_MOVE && currentLocation >= DESCENDANT_MOVE) {
				// (STOP, STOP, STOP, STOP, PAUSE, PAUSE)
				setAnimatorsStatus(Animation.STOP, Animation.STOP, Animation.STOP, Animation.STOP, Animation.PAUSE, Animation.PAUSE);
			}
			// Draw
			drawAnimators(g2, Animation.PAUSE);

		}

		// STOP status
		if (getStatus().equals(Animation.STOP)) {
			messageAction(Animation.STOP);
			// Nothing happens
			setAnimatorsStatus(Animation.STOP, Animation.STOP, Animation.STOP, Animation.STOP, Animation.STOP, Animation.STOP);
			// Draw
			drawAnimators(g2, Animation.PAUSE);
		}


		// FINISH status
		if (getStatus().equals(Animation.FINISH)) {
			// Completion messages
			messageAction(Animation.FINISH);
			if (rotationOrientation == RIGHT_ROTATION) {
				messageAction("*------Rotation Right of "+getRootNode().getKey().toString()+"------*\n New Root: "+
								getChildNode().getKey().toString());
			}
			else {
				messageAction("*------Rotation Left of "+getRootNode().getKey().toString()+"------*\n New Root: "+
								getChildNode().getKey().toString());
			}

			// Set all status to FINISH
			setAnimatorsStatus(Animation.FINISH);
			// Draw
			drawAnimators(g2, startingStatus);
		}

		// Call listeners
		animationAction();

	}



	/**
	 * 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.ROTATION_BST_ANIMATION, cmd, description, currentLocation / 3.0);
	}

}
