#pragma once

#ifndef __gx_game_h__
	#define __gx_game_h__

#include "foundation.h"
#include "mouse.h"
#include "keyboard.h"
#include "gameclock.h"
#include "gamemode.h"
#include "gamestepper.h"
#include "gamecamera.h"
#include "graphicsdevice.h"

#include <string>

namespace Gx
{
	class Window;
	struct EventArgs;
	struct SizeEventArgs;

	class GX_API Game
	{
	public:
		Game();
		virtual ~Game();

		void run();

		void setTitle(const std::string& title);

		Mouse& getMouse() {
			return Mouse::getInstance();
		}

		Keyboard& getKeyboard() {
			return Keyboard::getInstance();
		}

		GameClock& getClock() {
			return m_clock;
		}

		GameStepper& getStepper() {
			return m_stepper;
		}

		GameCamera& getCamera() {
			return m_camera;
		}

		GraphicsDevice& getGraphics() {
			return *m_graphicsDevice.get();
		}

		ContentManager& getContent() {
			return m_graphicsDevice->getContentManager();
		}

		virtual void input(GxF32 elapsedTime) = 0;
		virtual void update(GxF32 elapsedTime) = 0;
		virtual void render(GxF32 elapsedTime) = 0;

	protected:
		virtual void initialize() = 0;
		virtual void release() = 0;
		virtual void reshape(GxU32 width, GxU32 height) = 0;
		
		void preferAntialising(GxU8 samples) {
			m_graphicsDesc.aliasingSamples = samples;
		}

		void preferVersion(GxU32 major, GxU32 minor) {
			m_graphicsDesc.majorVersion = major;
			m_graphicsDesc.minorVersion = minor;
		}

		void preferSurfaceSize(GxU32 width, GxU32 height) {
			m_graphicsDesc.surfaceWidth = width;
			m_graphicsDesc.surfaceHeight = height;
		}

		void preferSurfaceFormat(GxU32 depthBits, GxU32 stencilBits) {
			m_graphicsDesc.depthBits = depthBits;
			m_graphicsDesc.stencilBits = stencilBits;
		}

		void preferSurfacePixelFormat(GxU32 colorBits, GxU32 alphaBits) {
			m_graphicsDesc.colorBits = colorBits;
			m_graphicsDesc.alphaBits = alphaBits;
		}

		void setFullScreen(bool isFullScreen);
		void setGameMode(const GameMode& gameMode);

	private:
		bool m_isActive;
		bool m_isInGameMode;
		GameClock m_clock;
		GameStepper m_stepper;
		GameCamera m_camera;
		GraphicsDeviceDesc m_graphicsDesc;
		std::unique_ptr<GraphicsDevice> m_graphicsDevice;

		void tick();
		void lockThreadToProcessor();

		void onActivate(Window*, const EventArgs* e);
		void onDeactivate(Window*, const EventArgs* e);
		void onSuspend(Window*, const EventArgs* e);
		void onResume(Window*, const EventArgs* e);
		void onResize(Window*, const SizeEventArgs* e);
	};
}

#endif /* __gx_game_h__ */