package simogl.level;

import javax.media.opengl.GL;

import simogl.geometry.MeshDL;
import simogl.material.Material;
import simogl.util.Calc;

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


/**
 * This class represents the skybox of the scene
 * @author Frank Bruns
 *
 */
public class SkyBox extends MeshDL
{
	private Texture texNorth = null;
	private Texture texSouth = null;
	private Texture texEast = null;
	private Texture texWest = null;
	private Texture textTop = null;
	private Texture texBottom = null;
	
	private static Material material = null;
	private float height = 0f;
	private float width = 0f;
	private float length = 0f;
	private int id = 1;
	
	/**
	 * Creates a new skybox for the scene with the specified size. Don't
	 * forget to assign textures to its six planes and finally call the
	 * method to create the display list.
	 * @param gl
	 * @param height heiht of the skybox
	 * @param width width of the skybox
	 * @param length length of the skybox
	 */
	public SkyBox(GL gl, float height, float width, float length)
	{
		super(gl);
		this.height = height;
		this.width = width;
		this.length = length;
		material = new Material(1f,1f,1f,1f);
	}
	
	/**
	 * Sets the northern texture of the skybox
	 * @param texture northern skybox texture
	 */
	public void setTextureNorth(Texture texture)
	{
		this.texNorth = texture;
	}
	
	/**
	 * Sets the southern texture of the skybox
	 * @param texture southern skybox texture
	 */
	public void setTextureSouth(Texture texture)
	{
		this.texSouth = texture;
	}
	
	/**
	 * Sets the eastern texture of the skybox
	 * @param texture eastern skybox texture
	 */
	public void setTextureEast(Texture texture)
	{
		this.texEast = texture;

	}
	
	/**
	 * Sets the western texture of the skybox
	 * @param texture western skybox texture
	 */
	public void setTextureWest(Texture texture)
	{
		this.texWest = texture;
	}
	
	/**
	 * Sets the top texture of the skybox
	 * @param texture top skybox texture
	 */
	public void setTextureTop(Texture texture)
	{
		this.textTop = texture;
	}
	
	/**
	 * Sets the bottom texture of the skybox
	 * @param texture bottom skybox texture
	 */
	public void setTextureBottom(Texture texture)
	{
		this.texBottom = texture;
	}
	
	/**
	 * Creates the display list for the skybox. This method must be 
	 * called after the assignment of textures to the skyboxes planes.
	 * @param gl
	 */
	@Override
	public void createDisplayList(GL gl)
	{
		gl.glNewList(this.id, GL.GL_COMPILE);	
		
			//north				
			this.texSouth.bind();
			gl.glBegin(GL.GL_QUADS);
				gl.glTexCoord2f(0.0f, 0.0f); gl.glVertex3f(-width/2f,height,length/2f);			
				gl.glTexCoord2f(0.0f, 1.0f); gl.glVertex3f(-width/2f,0f,length/2f);			
				gl.glTexCoord2f(1.0f, 1.0f);gl.glVertex3f(width/2f,0f,length/2f);
				gl.glTexCoord2f(1.0f, 0.0f);gl.glVertex3f(width/2f,height,length/2f);
			gl.glEnd();
			
			// south
			this.texNorth.bind();
			gl.glBegin(GL.GL_QUADS);
				gl.glTexCoord2f(0.0f, 0.0f); gl.glVertex3f(-width/2f,height,-length/2f);			
				gl.glTexCoord2f(0.0f, 1.0f); gl.glVertex3f(-width/2f,0f,-length/2f);			
				gl.glTexCoord2f(1.0f, 1.0f);gl.glVertex3f(width/2f,0f,-length/2f);
				gl.glTexCoord2f(1.0f, 0.0f);gl.glVertex3f(width/2f,height,-length/2f);
			gl.glEnd();
			
			// east
			this.texEast.bind();
			gl.glBegin(GL.GL_QUADS);
				gl.glTexCoord2f(0.0f, 0.0f); gl.glVertex3f(-width/2f,height,length/2f);			
				gl.glTexCoord2f(0.0f, 1.0f); gl.glVertex3f(-width/2f,0f,length/2f);			
				gl.glTexCoord2f(1.0f, 1.0f);gl.glVertex3f(-width/2f,0f,-length/2f);
				gl.glTexCoord2f(1.0f, 0.0f);gl.glVertex3f(-width/2f,height,-length/2f);
			gl.glEnd();
			
			// west
			this.texWest.bind();
			gl.glBegin(GL.GL_QUADS);
				gl.glTexCoord2f(0.0f, 0.0f); gl.glVertex3f(width/2f,height,-length/2f);			
				gl.glTexCoord2f(0.0f, 1.0f); gl.glVertex3f(width/2f,0f,-length/2f);			
				gl.glTexCoord2f(1.0f, 1.0f);gl.glVertex3f(width/2f,0f,length/2f);
				gl.glTexCoord2f(1.0f, 0.0f);gl.glVertex3f(width/2f,height,length/2f);
			gl.glEnd();
			
			// top
			this.textTop.bind();
			gl.glBegin(GL.GL_QUADS);
				gl.glTexCoord2f(0.0f, 0.0f); gl.glVertex3f(-width/2f,height,length/2f);			
				gl.glTexCoord2f(0.0f, 1.0f); gl.glVertex3f(-width/2f,height,-length/2f);			
				gl.glTexCoord2f(1.0f, 1.0f);gl.glVertex3f(width/2f,height,-length/2f);
				gl.glTexCoord2f(1.0f, 0.0f);gl.glVertex3f(width/2f,height,length/2f);
			gl.glEnd();
			
			// bottom
			this.texBottom.bind();
			gl.glBegin(GL.GL_QUADS);
				gl.glTexCoord2f(0.0f, 0.0f); gl.glVertex3f(-width/2f,0f,length/2f);			
				gl.glTexCoord2f(0.0f, 1.0f); gl.glVertex3f(-width/2f,0f,-length/2f);			
				gl.glTexCoord2f(1.0f, 1.0f);gl.glVertex3f(width/2f,0f,-length/2f);
				gl.glTexCoord2f(1.0f, 0.0f);gl.glVertex3f(width/2f,0f,length/2f);
			gl.glEnd();
		gl.glEndList();
	}
	
	/**
	 * Static method to set the material color of the skybox from
	 * virtually everywhere
	 * @param red amount of red
	 * @param green amount of green
	 * @param blue amount of blue
	 * @param alpha amount of alpha
	 */
	public static void setMaterialAmbDiff(float red, float green, float blue, float alpha)
	{
		material.setMaterialColorAmbDiff(red,green,blue,alpha);
	}
	
	/**
	 * Draws the skybox to the scene
	 * @param gl
	 */
	@Override
	public void draw(GL gl)
	{
		//gl.glDisable(GL.GL_LIGHTING);
		gl.glMaterialfv(GL.GL_FRONT_AND_BACK, GL.GL_AMBIENT_AND_DIFFUSE,this.material.getMaterialColorAmbDiff(),0);
		gl.glEnable(GL.GL_TEXTURE_2D);
			
		gl.glDepthMask(false);
		gl.glPushMatrix();
			gl.glLoadMatrixf(Calc.removeTranslations(gl),0);
			gl.glTranslatef(this.getPositionX(),this.getPositionY(),this.getPositionZ());
			gl.glCallList(this.id);
		gl.glPopMatrix();
		gl.glDepthMask(true);
		gl.glDisable(GL.GL_TEXTURE_2D);
		//gl.glEnable(GL.GL_LIGHTING);
	}
}
