package de.rico.adventure.script.trigger;

import java.util.List;

import javax.media.opengl.GL;

import de.rico.adventure.entity.character.AbstractCharacter;
import de.rico.engine.geometry.MeshFactory;

/**
 * This class represents a circular trigger area.
 * @author Frank Bruns
 */
public class CircleTriggerArea extends AbstractTrigger
{
	private float radius = 0f;

	private float meshRadius = 0;

	/**
	 * Creates a new circular trigger area with no candidates for
	 * firering the trigger initially assigned.
	 * @param scriptId id for reference purposes in script files
	 * @param x x-coordinate of the trigger center
	 * @param z z-coordinate of the trigger center
	 * @param radius radius of the trigger circle
	 */
	public CircleTriggerArea(String scriptId, float x, float z, float radius)
	{
		super(scriptId,x,z);
		this.radius = radius;
	}

	/**
	 * Creates a new circular trigger area with the
	 * specified character as the only one that can fire the
	 * trigger.
	 * @param scriptId id for reference purposes in script files
	 * @param x x-coordinate of the trigger center
	 * @param z z-coordinate of the trigger center
	 * @param radius radius of the trigger circle
	 * @param c only character that can fire the trigger
	 */
	public CircleTriggerArea(String scriptId, float x, float z, float radius, AbstractCharacter c)
	{
		super(scriptId,x,z,c);
		this.radius = radius;
	}

	/**
	 * Creates a new circular trigger area with the specified list
	 * of characters that can fire the trigger.
	 * @param scriptId id for reference purposes in script files
	 * @param x x-coordinate of the trigger center
	 * @param z z-coordinate of the trigger center
	 * @param radius radius of the trigger circle
	 * @param candiates candiates for firering the trigger
	 */
	public CircleTriggerArea(String scriptId, float x, float z, float radius, List<AbstractCharacter> candiates)
	{
		super(scriptId,x,z,candiates);
		this.radius = radius;
	}

	/**
	 * Returns the radius of the trigger area.
	 * @return radius of the trigger area
	 */
	public float getRadius()
	{
		return this.radius;
	}

	/**
	 * Sets a new radius for the trigger area.
	 * @param radius new radius for the trigger
	 */
	public void setRadius(float radius)
	{
		this.radius = radius;
	}

	/* (non-Javadoc)
	 * @see de.rico.adventure.script.trigger.AbstractTrigger#isCandiateOnTrigger()
	 */
	@Override
	public boolean isCandiateOnTrigger()
	{
		for(AbstractCharacter c : this.getCandidates())
		{
			// calculate distance between trigger center (x,z) and
			// the character's center (x,z)
			float dx = this.getX() - c.getMesh().getPosX();
			float dz = this.getZ() - c.getMesh().getPosZ();

			float distSquared = dx*dx + dz*dz;

			if(distSquared < this.radius*this.radius)
				return true; // candiate is on the trigger
		}

		return false; // no candidate is on the trigger
	}

	/* (non-Javadoc)
	 * @see de.rico.adventure.script.trigger.AbstractTrigger#draw(javax.media.opengl.GL)
	 */
	@Override
	public void draw(GL gl)
	{
		if(this.visMesh != null) this.visMesh.draw(gl);
	}


	/**
	 * This method updates the special things of the circular
	 * trigger area and calls the update() method of the super class
	 * {@link de.rico.adventure.script.trigger.AbstractTrigger#update(long)}, too.
	 * @param elapsedTime time between two frames
	 */
	@Override
	public void update(long elapsedTime)
	{
		super.update(elapsedTime);

		if(this.visMesh == null)
		{
			this.visMesh = MeshFactory.createDisc(this.radius, 50, false);
			this.visMesh.setPosition(this.getX(), 0f, this.getZ());
			this.meshRadius = this.radius;
		}

		// resize the mesh by reconstructing it in the next update()
		// call if the trigger size changed
		if(this.radius != this.meshRadius)
		{
			this.visMesh.destroy();
			this.visMesh = null;
		}
	}

}
