/**
 * package for mesh factory classes
 */
package simogl.factory;

import java.io.File;
import java.io.IOException;

import javax.media.opengl.GL;

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

import simogl.geometry.Face;
import simogl.geometry.MeshDL;
import simogl.geometry.MeshVA;
import simogl.geometry.Point3D;
import simogl.geometry.Triangle;
import simogl.level.AbstractLevel;
import simogl.material.Material;
import simogl.model.modelloader.MD2Importer;

/**
 * This class is used as a factory class for mesh objects
 * @author Frank Bruns
 *
 */
public class MeshFactory
{
	private static MeshDL meshDL = null;
	private static MeshVA meshVA = null;
	private static Point3D p1 = null;
	private static Point3D p2 = null;
	private static Point3D p3 = null;
	private static Triangle triangle1 = null;
	private static Triangle triangle2 = null;
	private static Face face = null;
	
	
	/**
	 * Creates a box with the specified meassures
	 * @param gl
	 * @param height height of the box
	 * @param width width of the box
	 * @param length length of the box
	 * @return box
	 */
	public static MeshDL createBox(GL gl, float height, float width, float length)
	{
		meshDL = new MeshDL(gl);
		// Front
		p1 = new Point3D(0f,0f,0f);
		p2 = new Point3D(width,0f,0f);
		p3 = new Point3D(width,height,0f);		
		triangle1 = new Triangle(p1, p2, p3);
		p1 = new Point3D(width,height,0f);
		p2 = new Point3D(0f,height,0f);
		p3 = new Point3D(0f,0f,0f);
		triangle2 = new Triangle(p1, p2, p3);
		face = new Face(triangle1, triangle2);
		meshDL.addFace(face);
		
		// Rear
		p1 = new Point3D(0f,0f,-length);
		p2 = new Point3D(width,0f,-length);
		p3 = new Point3D(width,height,-length);		
		triangle1 = new Triangle(p1, p2, p3);
		p1 = new Point3D(width,height,-length);
		p2 = new Point3D(0f,height,-length);
		p3 = new Point3D(0f,0f,-length);
		triangle2 = new Triangle(p1, p2, p3);
		face = new Face(triangle1, triangle2);
		meshDL.addFace(face);
		
		// Left
		p1 = new Point3D(0f,0f,0f);
		p2 = new Point3D(0f,0f,-length);
		p3 = new Point3D(0f,height,-length);		
		triangle1 = new Triangle(p1, p2, p3);
		p1 = new Point3D(0f,height,-length);
		p2 = new Point3D(0f,height,0f);
		p3 = new Point3D(0f,0f,0f);
		triangle2 = new Triangle(p1, p2, p3);
		face = new Face(triangle1, triangle2);
		meshDL.addFace(face);
		
		// Right
		p1 = new Point3D(width,0f,0f);
		p2 = new Point3D(width,0f,-length);
		p3 = new Point3D(width,height,-length);				
		triangle1 = new Triangle(p1, p2, p3);
		p1 = new Point3D(width,height,-length);
		p2 = new Point3D(width,height,0f);
		p3 = new Point3D(width,0f,0f);
		triangle2 = new Triangle(p1, p2, p3);
		face = new Face(triangle1, triangle2);
		meshDL.addFace(face);
		
		// Top
		p1 = new Point3D(0f,height,0f);
		p2 = new Point3D(width,height,0f);
		p3 = new Point3D(width,height,-length);		
		triangle1 = new Triangle(p1, p2, p3);		
		p1 = new Point3D(width,height,-length);
		p2 = new Point3D(0f,height,-length);
		p3 = new Point3D(0f,height,0f);
		triangle2 = new Triangle(p1, p2, p3);
		face = new Face(triangle1, triangle2);
		meshDL.addFace(face);
		
		// Bottom
		p1 = new Point3D(0f,0f,0f);		
		p2 = new Point3D(width,0f,0f);
		p3 = new Point3D(width,0f,-length);
		triangle1 = new Triangle(p1, p2, p3);	
		p1 = new Point3D(width,0f,-length);		
		p2 = new Point3D(0f,0f,-length);
		p3 = new Point3D(0f,0f,0f);
		triangle2 = new Triangle(p1, p2, p3);
		face = new Face(triangle1, triangle2);
		meshDL.addFace(face);
		
		// add Texture to the mesh, if it has been specified
		//if(texture != null)	mesh.setTexture(texture);
		meshDL.createDisplayList(gl);
		
		return meshDL;
	}
	
	/**
	 * Creates a simple square with the specified meassures
	 * @param gl
	 * @param height height of the square
	 * @param width width of the square
	 * @return square
	 */
	public static MeshDL createSquare(GL gl, float height, float width)
	{	
		meshDL = new MeshDL(gl);
		p1 = new Point3D(0f,0f,0f);
		p2 = new Point3D(width,0f,0f);
		p3 = new Point3D(width,height,0f);		
		triangle1 = new Triangle(p1, p2, p3);
		p1 = new Point3D(width,height,0f);
		p2 = new Point3D(0f,height,0f);
		p3 = new Point3D(0f,0f,0f);
		triangle2 = new Triangle(p1, p2, p3);
		face = new Face(triangle1, triangle2);
		meshDL.addFace(face);
		
		// add Texture to the mesh, if it has been specified
		//if(texture != null)	mesh.setTexture(texture);
		meshDL.createDisplayList(gl);
		
		return meshDL;
	}
	
	/**
	 * Creates a simple triangle with the specified meassures
	 * @param gl
	 * @param height height of the triangle
	 * @param width width of the triangle
	 * @return triangle
	 */
	/*
	public static Mesh createTriangle(GL gl, float height, float width)
	{
		mesh = new Mesh(gl);
		p1 = new Point3D(0f,0f,0f);
		p2 = new Point3D(width,0f,0f);
		p3 = new Point3D(width,height,0f);
		triangle = new Triangle(p1, p2, p3);
		mesh.addFace(triangle);	
		
		// add Texture to the mesh, if it has been specified
		//if(texture != null)	mesh.setTexture(texture);
		mesh.createDisplayList(gl);
		
		return mesh;
	}
	*/
	
	/**
	 * Returns a new instance of a goblin model. Be aware, that shadows
	 * can only be drawn, if at least one light source exist. If there is
	 * none, this method can produce a runtime error, if the drawShadow 
	 * flag is set to true
	 * @param gl
	 * @param drawShadow draw shadow? --> true = yes, false = no
	 * @return goblin model
	 */
	public static MeshVA createGoblin(GL gl, boolean drawShadow)
	{
		try
		{
			meshVA = MD2Importer.importModel(new File("models/goblin/goblin.md2"),0,0,
					TextureIO.newTexture(new File("./resources/models/goblin/goblin.bmp"),true),0.05f);
		}
		catch(IOException ioexc)
		{
			ioexc.printStackTrace();
			System.out.println("Goblin texture could not be loaded.");
		}		
		meshVA.setMaterial(new Material(1f,1f,1f,0.5f));
		meshVA.createVertexArray();
		
		if(drawShadow == true) meshVA.setDrawShadow(true,AbstractLevel.lights.get(0));
		
		return meshVA;
	}
	
	/**
	 * Returns a new instance of a house model. Be aware, that shadows
	 * can only be drawn, if at least one light source exist. If there is
	 * none, this method can produce a runtime error, if the drawShadow 
	 * flag is set to true
	 * @param gl
	 * @param drawShadow draw shadow? --> true = yes, false = no
	 * @return house model
	 */
	public static MeshVA createHouse(GL gl, boolean drawShadow)
	{
		try
		{
			meshVA = MD2Importer.importModel(new File("models/house/house.md2"),0,0,
					TextureIO.newTexture(new File("models/house/house.jpg"),true),0.08f);
		}
		catch(IOException ioexc)
		{
			ioexc.printStackTrace();
			System.out.println("House texture could not be loaded.");
		}		
		meshVA.setMaterial(new Material(1f,1f,1f,0.5f));
		meshVA.createVertexArray();
		
		if(drawShadow == true) meshVA.setDrawShadow(true,AbstractLevel.lights.get(0));			
		
		return meshVA;
	}
}
