/**
 * package for classes related to particle effects
 */
package simogl.effect.particle;

import java.io.File;
import java.io.IOException;
import java.util.Random;

import javax.media.opengl.GL;

import com.sun.opengl.util.texture.Texture;
import com.sun.opengl.util.texture.TextureIO;

import simogl.geometry.Point3D;

/**
 * This class represents an abstract particle effect. 
 * It uses particles and particle containers
 * @author Frank Bruns
 *
 */
public abstract class AbstractParticleEffect
{
	protected boolean enabled = true;
	protected boolean stopParticleGeneration = false;
	
	protected Random random = null;
	protected ParticleContainer particleContainer = null;
	protected Texture texture = null;
	
	protected float x = 0f;
	protected float y = 0f;
	protected float z = 0f;
	
	protected long maxPartAge = 1000L;
	protected long creationIntervall = 0L;
	protected long cumulatedTime = 0L;
	
	/**
	 * Creates a new particle effect with the specified parameters
	 * @param x x-coordinate
	 * @param y y-coordinate
	 * @param z z-coordinate
	 * @param numberOfParticles number of maximum particles to use
	 * @param maxPartAge maximum age of a particle
	 * @param creationIntervall intervall between the generation of two particles (in miliseconds)
	 */
	public AbstractParticleEffect(float x, float y, float z, int numberOfParticles, long maxPartAge, long creationIntervall)
	{
		this.x = x;
		this.y = y;
		this.z = z;
		this.random = new Random();		
		this.particleContainer = new ParticleContainer(numberOfParticles);
		this.maxPartAge = maxPartAge;
		this.creationIntervall = creationIntervall;
	}
	
	/**
	 * Sets the position of the effect
	 * @param position effect's position
	 */
	public void setPosition(Point3D position)
	{
		this.x = position.getX();
		this.y = position.getY();
		this.z = position.getZ();
	}
	
	/**
	 * Sets the position of the effect
	 * @param x x-coordinate
	 * @param y y-coordinate
	 * @param z z-coordinate
	 */
	public void setPosition(float x, float y, float z)
	{
		this.x = x;
		this.y = y;
		this.z = z;
	}
	
	/**
	 * Helper method to load the texture. 
	 * <br>
	 * <br>
	 * <b>Note: </b>The black colored area of the texture file
	 * will be transparent. Usually the edge areas of the texture are
	 * black colored, to get transparent. 
	 * @param file file with the texture
	 */
	protected void loadTexture(File file)
	{
		try
		{
			this.texture = TextureIO.newTexture(file,true);
		}
		catch(IOException exc)
		{
			System.out.println("Some particle texture could not be loaded");
		}
	}
	
	/**
	 * Helper method to continuously fill the particle container with new
	 * particles, if it is not full.
	 * <br>
	 * <b>Note: </b>Please use the operator "synchronized" when implementing
	 * this method.
	 *
	 */
	protected abstract void generateParticles(GL gl, long elapsedTime);
	
	/**
	 * Sets whether the particle effect shall be drawn
	 * @param enable draw particle effect? --> true = yes, false = no
	 */
	public void setEnabled(boolean enable)
	{
		this.enabled = enable;
	}
	
	/**
	 * Draws the particle effect to the scene
	 * @param gl
	 * @param elapsedTime time between two fames
	 */
	public synchronized void draw(GL gl, long elapsedTime)
	{		
		if(this.stopParticleGeneration == false)
		{
			this.generateParticles(gl, elapsedTime);
		}
		
		// only draw particle effect, if enabled
		if(this.enabled)
		{		
			this.stopParticleGeneration = false;
			for(AbstractParticle part : this.particleContainer.getParticles())
			{				
				part.draw(gl,this.x,this.y,this.z,this.texture);
			}
		}
		else
		{
			// stop particle generation, but draw the remaining particles
			this.stopParticleGeneration = true;
			for(AbstractParticle part : this.particleContainer.getParticles())
			{				
				part.draw(gl,this.x,this.y,this.z,this.texture);
			}			
		}
	}

	/**
	 * Updates the particles of the particle effect
	 * @param elapsedTime time between two frames
	 */
	public synchronized void update(long elapsedTime)
	{
		this.particleContainer.update(elapsedTime);		
	}
}
