package sg;

import java.util.logging.Level;
import java.util.logging.Logger;

import sg.states.InGameState;
import sg.states.MenuState;

import com.jme.app.AbstractGame;
import com.jme.app.BaseGame;
import com.jme.input.KeyBindingManager;
import com.jme.input.KeyInput;
import com.jme.input.MouseInput;
import com.jme.input.joystick.JoystickInput;
import com.jme.renderer.ColorRGBA;
import com.jme.renderer.Renderer;
import com.jme.system.DisplaySystem;
import com.jme.system.JmeException;
import com.jme.util.GameTaskQueue;
import com.jme.util.GameTaskQueueManager;
import com.jme.util.TextureManager;
import com.jme.util.Timer;
import com.jmex.game.state.GameStateManager;

public class SpaceGame2 extends BaseGame {
	private static final Logger logger = Logger.getLogger(SpaceGame2.class.getName());
	public static final String TITLE = "SpaceGame";
	protected float tpf;	//Time per frame
	protected Timer timer;	//High resolution timer for jME.

	public static void main(String[] args) {
		SpaceGame2 game = new SpaceGame2();
		game.setConfigShowMode(ConfigShowMode.AlwaysShow);
		game.start(); 
	}

	/**
	 * Creates display, sets up camera, and binds keys. Called in
	 * BaseGame.start() directly after the dialog box.
	 * @see AbstractGame#initSystem()
	 */
	protected void initSystem() throws JmeException {
		logger.info(getVersion());
		try {
			/**
			 * Get a DisplaySystem acording to the renderer selected in the
			 * startup box.
			 */
			display = DisplaySystem.getDisplaySystem(settings.getRenderer() );

			// Alpha bits to use for the renderer. Any changes must be made prior to call of start().
			display.setMinAlphaBits( 0 );
			// Depth bits to use for the renderer. Any changes must be made prior to call of start().
			display.setMinDepthBits( 8 );
			// Stencil bits to use for the renderer. Any changes must be made prior to call of start().
			display.setMinStencilBits( 0 );
			// Number of samples to use for the multisample buffer. Any changes must be made prior to call of start().         
			display.setMinSamples( 0 );

			/** Create a window with the startup box's information. */
			display.createWindow(settings.getWidth(), settings.getHeight(),
					settings.getDepth(), settings.getFrequency(),
					settings.isFullscreen() );
			logger.info("Running on: " + display.getAdapter()
					+ "\nDriver version: " + display.getDriverVersion() + "\n"
					+ display.getDisplayVendor() + " - "
					+ display.getDisplayRenderer() + " - "
					+ display.getDisplayAPIVersion());


		} catch ( JmeException e ) {
			//If the displaysystem can't be initialized correctly, exit instantly.
			logger.log(Level.SEVERE, "Could not create displaySystem", e);
			System.exit( 1 );
		}

		display.getRenderer().setBackgroundColor( ColorRGBA.black.clone() );	//Set a black background.

		timer = Timer.getTimer();	//Get a high resolution timer for FPS updates.

		GameStateManager.create();
		KeyBindingManager manager = KeyBindingManager.getKeyBindingManager();
		manager.set("mem_report", KeyInput.KEY_TAB);
		manager.set("exit", KeyInput.KEY_ESCAPE);

		display.setTitle( TITLE );	//Sets the title of our display.

	}

	@Override
	protected void initGame() {
		GameStateManager.getInstance().cleanup();
		GameStateManager.getInstance().attachChild(new MenuState("menu"));
		GameStateManager.getInstance().attachChild(new InGameState("ingame"));
		GameStateManager.getInstance().activateChildNamed("ingame");

		timer.reset();
	}

	@Override
	protected void update(float interpolation) {
		timer.update();	//Recalculate the framerate.
		tpf = timer.getTimePerFrame();	//Update tpf to time per frame according to the Timer.

		// Execute updateQueue item
		GameTaskQueueManager.getManager().getQueue(GameTaskQueue.UPDATE).execute();
		GameStateManager.getInstance().update(tpf);


		if ( KeyBindingManager.getKeyBindingManager().isValidCommand("mem_report", false ) ) {
			long totMem = Runtime.getRuntime().totalMemory();
			long freeMem = Runtime.getRuntime().freeMemory();
			long maxMem = Runtime.getRuntime().maxMemory();

			logger.info("|*|*|  Memory Stats  |*|*|");
			logger.info("Total memory: "+(totMem>>10)+" kb");
			logger.info("Free memory: "+(freeMem>>10)+" kb");
			logger.info("Max memory: "+(maxMem>>10)+" kb");
		}
		if ( KeyBindingManager.getKeyBindingManager().isValidCommand( "exit", false ) ) {
			finish();
		}
	}

	/**
	 * Clears stats, the buffers and renders bounds and normals if on.
	 * @param interpolation unused in this implementation
	 * @see AbstractGame#render(float interpolation)
	 */
	protected void render( float interpolation ) {
		Renderer r = display.getRenderer();
		r.clearBuffers();	//Clears the previously rendered information.

		// Execute renderQueue item
		GameTaskQueueManager.getManager().getQueue(GameTaskQueue.RENDER).execute();
		GameStateManager.getInstance().render(tpf);
	}

	@Override
	protected void reinit() {

	}

	/**
	 * Cleans up the keyboard.
	 * @see AbstractGame#cleanup()
	 */
	protected void cleanup() {
		logger.info( "Cleaning up resources." );
		TextureManager.doTextureCleanup();
		if (display != null && display.getRenderer() != null)
			display.getRenderer().cleanup();
		KeyInput.destroyIfInitalized();
		MouseInput.destroyIfInitalized();
		JoystickInput.destroyIfInitalized();
	}

	/**
	 * Calls the quit of BaseGame to clean up the display and then closes the JVM.
	 */
	protected void quit() {
		super.quit();
		System.exit( 0 );
	}
}