/*
	Trig Wars.
	Copyright (c) 2008, Darragh Coy.
	All rights reserved.
	Original work(s), source code & author(s) details available at: http://www.darraghcoy.com

	Redistribution and use in source and binary forms, with or without modification, are permitted 
	provided that the following conditions are met:

		* 	Redistributions of source code must retain the above copyright notice, this list of 
			conditions and the following disclaimer.
		* 	Redistributions in binary form must reproduce the above copyright notice, this list of 
			conditions and the following disclaimer in the documentation.
		* 	Neither the name of the author nor the names of contributors may be used to endorse or 
			promote products derived from this software without specific prior written permission.
		* 	The use of any third party libraries, modules or data files provided with the source 
			form of the program must follow and respect the individual licensing terms of these 
			components. You do not have permission to modify or circumvent the licensing terms for 
			provided third party components unless the third party licenses specifically allow this. 
			If you do not agree to the terms of provided third party components then you do not have 
			permission to use them in your derived work(s).
		* 	The terms of this license do not apply to separate (but related) distributions if supplied 
			by the author(s), only to the contents of this source distribution, derived works, and the 
			binaries produced by either modified or unmodified versions of the source code. The terms 
			of this license do not also apply to any third party libraries or components provided with 
			the source distribution. Such third party elements are licensed under their own separate 
			agreements.

	THIS SOFTWARE IS PROVIDED BY DARRAGH COY ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, 
	BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 
	ARE DISCLAIMED. IN NO EVENT SHALL DARRAGH COY BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 
	EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 
	OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY 
	OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 
	IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

#ifndef GAME_H
#define GAME_H

//=====================================================================================================================
//=====================================================================================================================

#include "Windows\Window.h"
#include "Windows\WindowEventListener.h"

//=====================================================================================================================
//=====================================================================================================================

namespace Game
{
	//=================================================================================================================
	//=================================================================================================================
	
	class Window;
	class PixelShaderManager;
	class VertexShaderManager;
	class TextureManager;
	class BitmapFontManager;
	class GameObjectManager;
	class Camera2D;
	class PrimitivesRenderer;
	class BufferedPointRenderer;
	class BufferedLineRenderer;
	class GameHud;
	class BitmapFont;
	class GamePostFX;
	class ParticleEmitter;
	
	//=================================================================================================================
	/// @brief		This is the core game class. Handles the high level game logic.
	//=================================================================================================================

	class GameCore : public WindowEventListener
	{
		public:
		
			//=========================================================================================================
			// Enums
			//=========================================================================================================
			
				/// Current state of the game
				
				enum State
				{
					/// Show the game instructions and pause the game
				
					STATE_SHOW_INSTRUCTIONS	,
					
					/// Playing the game normally
					
					STATE_GAME_PLAYING ,
					
					/// Game is paused
					
					STATE_GAME_PAUSED ,
					
					/// Game is over and player is dead, but enemies continue moving
					
					STATE_GAME_OVER ,
					
					/// Game is over and the player has won
					
					STATE_GAME_WON
				};		
		
			//=========================================================================================================
			// Constants
			//=========================================================================================================
			
				/// Title for the game
				
				static const char * GAME_TITLE;
			
				/// Near plane value for the camera
				
				static const float CAM_Z_NEAR;
				
				/// Far plane value for the camera
				
				static const float CAM_Z_FAR;
				
				/// Native view area: any screen resolutions other than this are scaled - keeping aspect correctness
				
				static const Vec2i NATIVE_RES;
				
				/// Area of the map: this is the half extent of the map area about the origin
				
				static const Vec2f MAP_AREA;
								
				/// Target refresh interval in between game ticks - in seconds.
				
				static const float FRAME_INTERVAL;
				
				/// Maximum number of frames that we can try to make up from frame skipping if we are behind real time
				
				static const unsigned MAX_CATCHUP_FRAMES;
			
			//=========================================================================================================
			// Functions
			//=========================================================================================================
		
				/// Creates the game

				GameCore( Window * window );
				
				/// Destroys the game
				
				~GameCore();
				
				/// Gets the instance of the game
				
				static inline GameCore * GetSingleton(){ return s_this; }

				/// Tells the object to announce it's type name: this is the type name without the Game:: namespace

				virtual const char * GetTypeName() const;
				
				/// Gets the camera
				
				inline Camera2D * GetCamera(){ return m_camera; }
				
				/// Gets the texture manager
				
				inline TextureManager * GetTextureManager(){ return m_texture_manager; }
				
				/// Gets the vertex shader manager
				
				inline VertexShaderManager * GetVertexShaderManager(){ return m_vertex_shader_manager; }
				
				/// Gets the pixel shader manager
				
				inline PixelShaderManager * GetPixelShaderManager(){ return m_pixel_shader_manager; }
				
				/// Gets the bitmap font manager
				
				inline BitmapFontManager * GetBitmapFontManager(){ return m_bitmap_font_manager; }				
				
				/// Gets the game object manager
				
				inline GameObjectManager * GetObjectManager(){ return m_game_object_manager; } 
				
				/// Gets the primitives renderer
				
				inline PrimitivesRenderer * GetPrimitivesRenderer(){ return m_primitives_renderer; }

				/// Gets the buffered point renderer used by the game

				inline BufferedPointRenderer * GetBufferedPointRenderer(){ return m_buffered_point_renderer; }
				
				/// Gets the buffered line renderer used by the game
				
				inline BufferedLineRenderer * GetBufferedLineRenderer(){ return m_buffered_line_renderer; }
				
				/// Gets the font used by the game
				
				inline BitmapFont * GetFont(){ return m_font; }
				
				/// Gets the smaller font used by the game for rendering larger amounts of text
				
				inline BitmapFont * GetSmallFont(){ return m_small_font; }
				
				/// Gets the font used for rendering large amounts of readable text
				
				inline BitmapFont * GetReadingFont(){ return m_reading_font; }
				
				/// Gets the font used for rendering large amounts of readable text: black shadow
				
				inline BitmapFont * GetReadingShadowFont(){ return m_reading_shadow_font; }
				
				/// Gets the particle emitter which can be used to create particle effects
				
				inline ParticleEmitter * GetParticleEmitter(){ return m_particle_emitter; }
				
				/// Gets the player's score:
				
				inline float GetPlayerScore(){ return m_player_score; }
				
				/// Tells if all the enemies in the game have been killed
				
				bool AllEnemiesDead();
				
				//=====================================================================================================
				/// @brief		Sets the player's score:
				/// @param		s - new score
				/// @pre		Given score must be >= 0 
				//=====================================================================================================
				
				inline void SetPlayerScore( float s )
				{
					// Make sure ok:
				
					ENSURE( s > 0 , "Given score must be >= 0 " )
					
					// Set:
					
					m_player_score = s;
				}				
				
				/// Window redraw event - does the game loop
				
				virtual void OnWindowRedrawing();
				
				/// Window event - when a key is released
				
				virtual void OnKeyboardReleased( Keyboard::Key key_code );
				
				/// Gets the window used by the game:
				
				inline Window * GetWindow(){ return m_window; }			
				
				/// Returns the display for the game
				
				inline Display * GetDisplay(){ return m_window->GetDisplay(); }
				
				/// Returns the random number generator used by the game
				
				inline Random & GetRandom(){ return m_random; }
				
				/// Returns the stack used by the game for temporary storage
				
				inline Stack & GetStack(){ return m_stack; }

				/// Returns the secondary stack used by the game for temporary storage
				
				inline Stack & GetSecondaryStack(){ return m_secondary_stack; }
				
				/// Gets the current state of the game
				
				inline State GetCurrentState(){ return m_current_state; }
				
				#ifdef USE_DEBUG_CONSOLE
				
					/// Debug only: tells if enemies should not fire at the player
					
					bool NoTargetEnabled() const { return s_no_target; }
					
				#endif

		private:
		
			//=========================================================================================================
			// Functions
			//=========================================================================================================
			
				/// Called when the game is to do an update
				
				void OnUpdate();
				
				/// Called when the game is to do a render
				
				void OnRender();			
				
				#ifdef USE_DEBUG_CONSOLE
				
					/// Debug only console command: enables / disables showing map boundaries
				
					static bool ConCmd_G_ShowMapBoundaries( bool arg , bool arg_given );
					
					/// Debug only console command: enables / disables the unwrap test
				
					static bool ConCmd_G_ShowUnwrapTest( bool arg , bool arg_given );
					
					/// Debug only console command: enables / disables profiling of updates
				
					static bool ConCmd_G_Profile( bool arg , bool arg_given );
					
					/// Debug only console command: enables / disables profiling of rendering
				
					static bool ConCmd_R_Profile( bool arg , bool arg_given );				

					/// Debug only console command: enables / disables zoom and rendering of the entire map
				
					static bool ConCmd_R_EagleView( bool arg , bool arg_given );
					
					/// Debug only console command: turns off enemies firing at the player
					
					static bool ConCmd_G_NoTarget( bool arg , bool arg_given );
					
					/// Debug only: draws map boundaries
					
					void DrawMapBoundaries() const;
					
					/// Debug only: draws a unwrap test
					
					void DrawWrapUnwrapTest() const;				
				
				#endif			
				
				/// Updates what the current state of the game is
				
				void UpdateGameState();

			//=========================================================================================================
			// Variables
			//=========================================================================================================
			
				/// Random number generator used by the game
				
				Random m_random;						
			
				/// Pointer to an instance of the game
				
				static GameCore * s_this;
				
				/// Window used by the game 
				
				Window * m_window;
				
				/// Time since the last update
				
				float m_time_since_update;
				
				/// Was the last frame rendered ? 
				
				bool m_rendered_last_frame;

				/// Camera used by the game

				Camera2D * m_camera;

				/// HUD for the game

				GameHud * m_hud;
				
				/// Texture manager
				
				TextureManager * m_texture_manager;
				
				/// Pixel shader manager
				
				PixelShaderManager * m_pixel_shader_manager;
				
				/// Vertex shader manager
				
				VertexShaderManager * m_vertex_shader_manager;
				
				/// Bitmap font manager
				
				BitmapFontManager * m_bitmap_font_manager;		
				
				/// Game object manager for the game
				
				GameObjectManager * m_game_object_manager;
				
				/// A basic primitives renderer that can be used by all objects
				
				PrimitivesRenderer * m_primitives_renderer;
				
				/// A particle emitter that can be used to create particle effects
				
				ParticleEmitter * m_particle_emitter;
				
				/// A stack that can be used by game objects for various purposes. Allocated size is 1MB
				
				Stack m_stack;

				/// A secondary stack that can be used by game objects for various purposes. Allocated size is 1MB
				
				Stack m_secondary_stack;
			
				/// A buffered point renderer used to draw points quickly in batches

				BufferedPointRenderer * m_buffered_point_renderer;
				
				/// A buffered line renderer used to draw lines quickly in batches

				BufferedLineRenderer * m_buffered_line_renderer;
				
				/// Bitmap font used for drawing text
				
				BitmapFont * m_font;
				
				/// Bitmap font for rendering large amounts of readable text
				
				BitmapFont * m_reading_font;
				
				/// Bitmap font for rendering large amounts of readable text: shadow
				
				BitmapFont * m_reading_shadow_font;
				
				/// A smaller font for larger amounts of text
				
				BitmapFont * m_small_font;
				
				/// The post processing fx unit
				
				GamePostFX * m_post_fx;
				
				/// The player's current score:
				
				float m_player_score;
				
				/// The current state of the game:
				
				State m_current_state;
				
				#ifdef USE_DEBUG_CONSOLE
				
					///	Debug only flag. Show map boundaries ?
					
					static bool s_show_map_boundaries;

					/// Debug only flag. Show a wrap/unwrap test ?

					static bool s_show_unwrap_test;
					
					/// Debug only flag. Profile rendering ?
					
					static bool s_profile_render;
					
					/// Debug only flag. Profile update ?
					
					static bool s_profile_update;

					/// Debug only flag. Zoom out and draw the whole map ?

					static bool s_show_whole_map;
					
					/// Debug only flag. Should enemies stop firing at the player ?
					
					static bool s_no_target;
					
				#endif
	};
};

#endif
