package de.rico.adventure.actions.custom;

import javax.media.opengl.GL;

import de.rico.adventure.actions.AbstractAction;
import de.rico.adventure.actions.ActionScheduler;
import de.rico.adventure.entity.AbstractEntity;
import de.rico.adventure.enums.State;
import de.rico.adventure.structure.StateManager;

/**
 * This concurrent game action can be used to move an entity backwards
 * for a certain time with a certain speed.
 * @author Frank Bruns
 *
 */
public class MoveBackward extends AbstractAction
{
	private float speed = 0f;
	private int dur = 0;
	private float distanceToGo = 0f;
	private float distanceSoFar = 0f; // the so far moved distance
	private long cumulatedTime = 0L;

	private State backupState = null;

	/**
	 * Moves the specified entity backwards with the specified speed
	 * and time.
	 * @param entity entity to move
	 * @param speed movement speed
	 * @param duration duration of movement
	 */
	public MoveBackward(AbstractEntity entity, float speed, int duration)
	{
		super(entity);
		this.speed = speed;
		this.dur = duration;

		// calculate the the dinstance that the entity should be
		// moved on the whole
		this.distanceToGo = this.speed * this.dur;
	}

	/* (non-Javadoc)
	 * @see de.rico.adventure.actions.AbstractConcurrentAction#update(long)
	 */
	@Override
	public void update(long elapsedTime)
	{
		this.cumulatedTime += elapsedTime;

		// save original game state
		if(this.backupState == null)
			this.backupState = StateManager.getInstance().getState();

		// only set to NO_INPUT state, if the state is not already in
		// NO_INPUT_CINEMATIC state
		if(!StateManager.getInstance().equals(State.NO_INPUT_CINEMATIC))
			StateManager.getInstance().setState(State.NO_INPUT);

		if(this.cumulatedTime < this.dur)
		{
			this.getEntity().getMesh().moveBackwardsGlobal(this.speed, elapsedTime);

			// calculate the distance that has been moved already
			this.distanceSoFar += this.speed*elapsedTime;
		}
		else
		{
			ActionScheduler.getInstance().removeFirst();
		}

	}

	/* (non-Javadoc)
	 * @see de.rico.adventure.actions.AbstractAction#draw(javax.media.opengl.GL)
	 */
	@Override
	public void draw(GL gl)
	{
		// TODO Auto-generated method stub

	}

	/* (non-Javadoc)
	 * @see de.rico.adventure.actions.AbstractConcurrentAction#finishUp()
	 */
	@Override
	public void finishUp()
	{
		// if the framerate is low, it could happen that
		// the elapsed time in the first loop of the update method
		// is already higher than the duration to move the entity.
		// Thus the entity wouldn't get moved at all. Because of
		// this we have to move the remaining distance all at one
		// before leaving this game action
		this.distanceToGo -= this.distanceSoFar;
		if(this.distanceToGo > 0f)
			this.getEntity().getMesh().translateZ(this.distanceToGo);

		// restore old state
		StateManager.getInstance().setState(this.backupState);
	}
}
