/** 
 * MaineGame.
 * 
 *  @author Bruno Augier 
 *  @version 2.0 - 01/04/2009
 *  @seealso http://dzzd.net/
 */

import net.dzzd.access.*;
import net.dzzd.*;

import java.awt.event.KeyEvent;
import java.awt.event.*;

import java.awt.*;

public class MainGame implements Runnable
{
	IRender3D render;
	IScene3D scene;
	ICamera3D camera;
	IDirectInput input;
	public ITimer timer;
	boolean mustRun;
		
	private Car testCar;	
	
	IPoint3D follow=DzzD.newPoint3D();
	
	public MainGame(IScene3D s,IRender3D r)
	{
		this.mustRun=false;
		this.timer=DzzD.newTimer();
		this.render=r;
		this.scene=s;
		this.input=this.render.getDirectInput();
		this.camera=this.scene.getCurrentCamera3D();
		this.testCar=new Car(this.scene);
		//camera.getPosition().setZ(camera.getPosition().getZ()+1000);
		IMesh3D car=this.scene.getMesh3DByName("CAR");	
		follow.copy(car.getPosition());
		//camera.setFOV(80);
		

	}
	
	public void run()
	{
		while(this.mustRun)
		{
			
			this.scene.setScene3DObjectToWorld();
			
			
			while(this.doLogic()==0)
			{
				//System.out.println(".");
				DzzD.sleep(1);			
			}
			
			//System.out.printll(this.doLogic());	
			this.renderSingleFrame();
					
			Thread.yield();
		}
	}
	
	public void start()
	{
		if(this.mustRun)
			return;
		
		this.mustRun=true;
		Thread t=new Thread(this);
		t.start();
	}
	
	public void stop()
	{
		this.mustRun=false;
	}	
	
	private long gameLogicLastTime=-1;
	private long gameLogicRate=15;
	//private long gameLogicRate=45;

	public int doLogic()
	{
		//	DzzD.sleep(20);
		//DzzD.sleep(10);
		this.testCar.doKeyboardInput(this.input);
		
		
		long time=this.timer.getTime();
		
		//First call ?
		if(this.gameLogicLastTime==-1)
		{
			this.gameLogicLastTime=time;
			return 0;
		}
		
		//Compute elapsed time since last game logic
		long elapsedTime=time-this.gameLogicLastTime;
		
		
		//If elapsed time lower than logic rate return
		if(elapsedTime<this.gameLogicRate)
			return 0;
			
		
		//Compute number of game logics to perform	
		int nbGameLogic=(int)(elapsedTime/this.gameLogicRate);



		for(int gameLogicCount=0;gameLogicCount<nbGameLogic;gameLogicCount++)		
		{
			this.testCar.move(this.scene);
			this.scene.setScene3DObjectToWorld();
			
			IMesh3D car=this.scene.getMesh3DByName("CAR");	
			IPoint3D moveFollow=DzzD.newPoint3D();
			moveFollow.copy(car.getPosition());
			moveFollow.setY(moveFollow.getY()+150);
			moveFollow.sub(follow);
			moveFollow.mul(0.2);	
			follow.add(moveFollow);
			this.cameraLookAt(follow);//car.getPosition());
		}
		

		

		
	
		this.gameLogicLastTime+=nbGameLogic*this.gameLogicRate;	



		
		IMesh3D sky=this.scene.getMesh3DByName("SKY");
		if(sky!=null)
		{
			//System.out.println(sky.getPosition());
			sky.getRotation().set(0,0,0);
			sky.getPosition().copy(this.camera.getPosition());
		}
		
		return nbGameLogic;
			
	}
	
	IPoint3D localTarget=DzzD.newPoint3D();
	private void cameraLookAt(IPoint3D target)
	{
		localTarget.copy(target).sub(camera.getPosition());
		double distance=localTarget.length();
		localTarget.mul(1.0/distance);
		double rx=Math.asin(localTarget.getY());

		localTarget.copy(target).sub(camera.getPosition());
		localTarget.setY(0);
		distance=localTarget.length();
		localTarget.mul(1.0/distance);
		double ry=-Math.asin(localTarget.getX());
		if(localTarget.getZ()<0)
			ry=Math.PI-ry;
	
		
		
		camera.getRotation().set(rx,ry,0);
		

		double move=(distance-400)*0.5;
		localTarget.copy(camera.getAxis3D().getAZ()).sub(camera.getAxis3D().getOrigin()).mul(move);
		
		camera.getPosition().add(localTarget);
		camera.getPosition().setY(target.getY()+100);	
		
	}
	

	

	public void renderSingleFrame()
	{
		//Set the scene to world space
		this.scene.setScene3DObjectToWorld();
		
		//Set the scene to active camera space
		this.scene.setScene3DObjectToCamera();
		
		//Tell the 3D render to compute & draw the frame
		this.render.renderScene3D(this.scene);
	}
}