//<pre>
import java.awt.*;
import java.awt.event.*;

public class World extends BufferedApplet
{

	// screen dimensions
   	int width, height;

	Graphics g;
	
   	Color shapeColor = Color.red;
   	double zoom = 1.0;
   							
	Camera myCamera;
	
	double frontClippingPlane = -2;
	double backClippingPlane = -100;

	// array for all objects in world
	Shape3D myShapes[];
	int numShapes = 0;	
	int numAsteroids = 2;
	
	Ship ship;
	
	// Transformation stack
	MatrixStack S;	
	
	double time;

		
	public World () {
	
		
		myCamera = new Camera(-5.0);
		
	
		// add objects to world
 		myShapes = new Shape3D[10];

		ship = new Ship(this);
		
		int i;
		for ( i = 0; i< numAsteroids; i++) {
			myShapes[i] = new Sphere(this, 4);
			setAsteroid(myShapes[i]);
		}
		numShapes = i;
		
		S = new MatrixStack();
		
	}

	public void render(Graphics g) {

		this.g = g;		
		if (width == 0) {
			width  = bounds().width;
			height = bounds().height;
		}

		g.setColor(Color.black);
		g.fillRect(0, 0, width, height);

		
		animate();


		
		// render every triangle of each shape to viewport
		for (int k = 0; k < numShapes; k++) {
			g.setColor(myShapes[k].getColor());
			drawShape(myShapes[k]);
		}
		ship.drawOn();
	}
	
	public void drawShape(Shape3D s) {
		int v0[], v1[], v2[];

		g.setColor(s.getColor());
		
		for (int i = 0; i < s.faces.length; i++) {
			v0 = viewportTransform(s.transformedVertices[s.faces[i][0]]);
			v1 = viewportTransform(s.transformedVertices[s.faces[i][1]]);
			v2 = viewportTransform(s.transformedVertices[s.faces[i][2]]);
			if (isVisible(v0) && isVisible(v1) && isVisible(v2)) {
				//System.out.println("z stuff: Camera is at " + myCamera.getZ() + " and three lines are at " + v0[2] + ", " + v1[2] + ", " + v2[2]);
				g.drawLine(	v0[0],v0[1],v1[0],v1[1]);
				g.drawLine(	v1[0],v1[1],v2[0],v2[1]);
				g.drawLine(	v2[0],v2[1],v0[0],v0[1]);
			}	
		}
	}
	
	public void animate( ) {

	    time = System.currentTimeMillis() / 1000.0;
		S.initialize();
 		myCamera.initialize();
 		
 		double groundLevel = -2.0;
		double followingDistance = 2.0;
		double groundSize = 0.5;
		double worldSize = 1000;
		

		myCamera.m().rotateY(0.1*(Math.cos(time)));
// 		myCamera.m().rotateX(1.0);
 		myCamera.moveAbs(0.0,0.0,ship.z+10);
 		myCamera.m().translate(myCamera.x,myCamera.y,myCamera.z);
		myCamera.m().inverse();
		
		S.m().copy(myCamera.m());
		S.m().scale(0.1,0.1,0.1);
		
		for (int i = 0; i < numAsteroids; i++) {
			if (isVisible(myShapes[i].z)) {
				myShapes[i].update(S.m());
			} else {
				setAsteroid(myShapes[i]);
			}
		}
		
		ship.animate(myCamera.m());

		animating = true;


	}

	// viewPort Transformation
	int[] viewportTransform(double[] src) {
		int dst[] = new int[3];

		dst[0] = (int)(width/2 + src[0]*width/4);
		dst[1] = (int)(height/2 + src[1]*width/4);
		dst[2] = (int)(src[2]);
	
		return dst;
	}
	
	public boolean isVisible(double [] point) {
		return (myCamera.z >= point[1]);
	}
		
	public boolean isVisible(double z) {
		return (myCamera.z <= z);
	}

	public boolean isVisible(int [] point) {
		return (myCamera.z >= point[2]);
	}
 
	// not used
   	public boolean mouseUp(Event e, int x, int y) {
		
		damage = true;
      	return true;
   	}
   
    // move camera
   	public boolean mouseDrag(Event e, int x, int y) {
		Matrix3D temp = new Matrix3D();
				
	 	damage = true;
	 	return true;
   	}
   	   		
   	// handle key events
   	public boolean keyDown(Event e, int key) {
      switch (key) {
      	case '\u03EC': ship.forward(); 	break;						// UP ARROW 	-- zoom in
      	case '\u03ED': ship.reverse(); 	break;						// DOWN ARROW 	-- zoom out
      	case '\u03EE': ship.left();		break;		// LEFT ARROW 	--
      	case '\u03EF': ship.right();		break;		// RIGHT ARROW 	--
      	case '\u0020': ship.jump(); 	break;
      	case '.': 									break;		// 				--
      	case '/': 									break;		// 				--

		}

		return true;
	}
	
	// not working
	public void setAsteroid(Shape3D s) {
		s.x = (Math.random()*200.0 - 100.0);
		s.y = (Math.random()*200.0 - 100.0);
		s.z = (Math.random()*-100.0) + myCamera.z;
		//System.out.println("Camera is at " + myCamera.z + " ship is at " + ship.z + " setting asteroid to " + s.x + " " + s.y + " " + s.z);
	}


}
