package simogl.collision;

import javax.media.opengl.GL;

import simogl.geometry.AbstractMesh;
import simogl.geometry.Face;

/**
 * This class can be used as a bounding box for a mesh
 * @author Frank Bruns
 *
 */
public class BoundingBox
{
	private AbstractMesh mesh = null;
	private float width = 0f;
	private float height = 0f;
	private float length = 0f;
	
	/**
	 * Creates a bounding box for the meshes current triangle coordinates
	 * @param mesh mesh to create a bounding box for
	 */
	public BoundingBox(AbstractMesh mesh)
	{
		this.mesh = mesh;
		this.calculateWidth();
		this.calculateHeight();
		this.calculateLength();
	}
	
	/**
	 * Helper method to calculate the width of a mesh
	 *
	 */
	private void calculateWidth()
	{
		float[] xCoords = new float[this.mesh.getFaces().size()*2*3];
		float minCoord = 100000000f;
		float maxCoord = -100000000f;
		int i = 0;		
		
		// loop through the faces of the mesh and retrieve the minimum
		// and maximum x-coordinate
		for(Face face : this.mesh.getFaces())
		{
			// check triangle 1
			// look in vertex 1
			xCoords[i] = face.getTriangle1().getVertex1().getX();
			minCoord = Math.min(minCoord,xCoords[i]);
			maxCoord = Math.max(maxCoord,xCoords[i]);

			// look in vertex 2
			xCoords[i] = face.getTriangle1().getVertex2().getX();
			minCoord = Math.min(minCoord,xCoords[i]);
			maxCoord = Math.max(maxCoord,xCoords[i]);
			
			// look in vertex 3
			xCoords[i] = face.getTriangle1().getVertex3().getX();
			minCoord = Math.min(minCoord,xCoords[i]);
			maxCoord = Math.max(maxCoord,xCoords[i]);
			
			
			
			// check triangle 2
			// look in vertex 1
			xCoords[i] = face.getTriangle2().getVertex1().getX();
			minCoord = Math.min(minCoord,xCoords[i]);
			maxCoord = Math.max(maxCoord,xCoords[i]);

			// look in vertex 2
			xCoords[i] = face.getTriangle2().getVertex2().getX();
			minCoord = Math.min(minCoord,xCoords[i]);
			maxCoord = Math.max(maxCoord,xCoords[i]);
			
			// look in vertex 3
			xCoords[i] = face.getTriangle2().getVertex3().getX();
			minCoord = Math.min(minCoord,xCoords[i]);
			maxCoord = Math.max(maxCoord,xCoords[i]);
			
			i++;
		}
		this.width = maxCoord - minCoord;
	}
	
	/**
	 * Helper method to calculate the height of a mesh
	 *
	 */
	private void calculateHeight()
	{
		float[] yCoords = new float[this.mesh.getFaces().size()*2*3];
		float minCoord = 100000000f;
		float maxCoord = -100000000f;
		int i = 0;		
		
		// loop through the faces of the mesh and retrieve the minimum
		// and maximum y-coordinate
		for(Face face : this.mesh.getFaces())
		{
			// check triangle 1
			// look in vertex 1
			yCoords[i] = face.getTriangle1().getVertex1().getY();
			minCoord = Math.min(minCoord,yCoords[i]);
			maxCoord = Math.max(maxCoord,yCoords[i]);
			
			// look in vertex 2
			yCoords[i] = face.getTriangle1().getVertex2().getY();
			minCoord = Math.min(minCoord,yCoords[i]);
			maxCoord = Math.max(maxCoord,yCoords[i]);
			
			// look in vertex 3
			yCoords[i] = face.getTriangle1().getVertex3().getY();
			minCoord = Math.min(minCoord,yCoords[i]);
			maxCoord = Math.max(maxCoord,yCoords[i]);
			
			
			
			//check triangle 2
			// look in vertex 1
			yCoords[i] = face.getTriangle2().getVertex1().getY();
			minCoord = Math.min(minCoord,yCoords[i]);
			maxCoord = Math.max(maxCoord,yCoords[i]);
			
			// look in vertex 2
			yCoords[i] = face.getTriangle2().getVertex2().getY();
			minCoord = Math.min(minCoord,yCoords[i]);
			maxCoord = Math.max(maxCoord,yCoords[i]);
			
			// look in vertex 3
			yCoords[i] = face.getTriangle2().getVertex3().getY();
			minCoord = Math.min(minCoord,yCoords[i]);
			maxCoord = Math.max(maxCoord,yCoords[i]);
			i++;
		}
		this.height = maxCoord - minCoord;
	}
	
	/**
	 * Helper method to calculate the length of a mesh
	 *
	 */
	private void calculateLength()
	{
		float[] zCoords = new float[this.mesh.getFaces().size()*2*3];
		float minCoord = 100000000f;
		float maxCoord = -100000000f;
		int i = 0;		
		
		// loop through the faces of the mesh and retrieve the minimum
		// and maximum y-coordinate
		for(Face face : this.mesh.getFaces())
		{
			// check triangle 1
			// look in vertex 1
			zCoords[i] = face.getTriangle1().getVertex1().getZ();
			minCoord = Math.min(minCoord,zCoords[i]);
			maxCoord = Math.max(maxCoord,zCoords[i]);
			
			// look in vertex 2
			zCoords[i] = face.getTriangle1().getVertex2().getZ();
			minCoord = Math.min(minCoord,zCoords[i]);
			maxCoord = Math.max(maxCoord,zCoords[i]);
			
			// look in vertex 3
			zCoords[i] = face.getTriangle1().getVertex3().getZ();
			minCoord = Math.min(minCoord,zCoords[i]);
			maxCoord = Math.max(maxCoord,zCoords[i]);
			
			
			
			// check triangle 2
			// look in vertex 1
			zCoords[i] = face.getTriangle2().getVertex1().getZ();
			minCoord = Math.min(minCoord,zCoords[i]);
			maxCoord = Math.max(maxCoord,zCoords[i]);
			
			// look in vertex 2
			zCoords[i] = face.getTriangle2().getVertex2().getZ();
			minCoord = Math.min(minCoord,zCoords[i]);
			maxCoord = Math.max(maxCoord,zCoords[i]);
			
			// look in vertex 3
			zCoords[i] = face.getTriangle2().getVertex3().getZ();
			minCoord = Math.min(minCoord,zCoords[i]);
			maxCoord = Math.max(maxCoord,zCoords[i]);
			i++;
		}
		this.length = maxCoord - minCoord;
	}
	
	/**
	 * Returns the width of the bounding box.
	 * @return width of the bounding box
	 */
	public float getWidth()
	{
		return this.width;
	}
	
	/**
	 * Returns the height of the bounding box.
	 * @return height of the bounding box
	 */
	public float getHeight()
	{
		return this.height;
	}
	
	/**
	 * Returns the length of the bounding box.
	 * @return length of the bounding box
	 */
	public float getLength()
	{
		return this.length;
	}
	
	/**
	 * This method can be used to draw the bounding box
	 * @param gl
	 */
	public void draw(GL gl)
	{
		// use green color for the box
		float[] color = {0f,1f,0f,1f};
		gl.glMaterialfv(GL.GL_FRONT_AND_BACK, GL.GL_AMBIENT_AND_DIFFUSE, color,0);
		
		gl.glBegin(GL.GL_LINES);
			// front square
			gl.glVertex3f(0f,0f,0f);
			gl.glVertex3f(width,0f,0f);			
			gl.glVertex3f(width,0f,0f);
			gl.glVertex3f(width,height,0f);			
			gl.glVertex3f(width,height,0f);
			gl.glVertex3f(0f,height,0f);			
			gl.glVertex3f(0f,height,0f);
			gl.glVertex3f(0f,0f,0f);
			
			// back square
			gl.glVertex3f(0f,0f,-length);
			gl.glVertex3f(width,0f,-length);			
			gl.glVertex3f(width,0f,-length);
			gl.glVertex3f(width,height,-length);			
			gl.glVertex3f(width,height,-length);
			gl.glVertex3f(0f,height,-length);			
			gl.glVertex3f(0f,height,-length);
			gl.glVertex3f(0f,0f,-length);
			
			// left square
			gl.glVertex3f(0f,0f,0f);
			gl.glVertex3f(0f,height,0f);
			gl.glVertex3f(0f,height,0f);
			gl.glVertex3f(0f,height,-length);
			gl.glVertex3f(0f,height,-length);
			gl.glVertex3f(0f,0f,-length);
			gl.glVertex3f(0f,0f,-length);	
			gl.glVertex3f(0f,0f,0f);
			
			// right square
			gl.glVertex3f(width,0f,0f);
			gl.glVertex3f(width,height,0f);
			gl.glVertex3f(width,height,0f);
			gl.glVertex3f(width,height,-length);
			gl.glVertex3f(width,height,-length);
			gl.glVertex3f(width,0f,-length);
			gl.glVertex3f(width,0f,-length);	
			gl.glVertex3f(width,0f,0f);			
		gl.glEnd();
	}
}
