/*
	Lan Wars.
	Copyright (c) 2009, 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_MAP_H
#define GAME_MAP_H

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

#include "Game\GameObjectManager.h"
#include "GameObjects\GameObjectBase.h"
#include "Graphics\Texture.h"
#include "Graphics\PixelShader.h"
#include "Graphics\VertexShader.h"
#include "Graphics\VertexFormat.h"

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

namespace Game
{
	//=================================================================================================================
	//=================================================================================================================
	
	class DoomLevel;
	class PathNetwork;

	//=================================================================================================================
	/// @brief		This class represents the map and all the rooms. The map is loaded from a Doom wad internally.
	///				This class simply is a managing wrapper around the WAD and it's data.
	//=================================================================================================================

	class GameMap : public GameObjectBase
	{
		public:
	
			//=========================================================================================================
			// Friends
			//=========================================================================================================
			
				/// The game object manager is a friend of this class. Only it can set id's for objects.
				
				friend class GameObjectManager;

			//=========================================================================================================
			// Functions
			//=========================================================================================================
			
				/// Default constructor. Creates the map. This is for the server only where we don't have to give a net id and owner id.
				
				GameMap();
				
				/// Constructor. Creates the map and assigns it the given net id
				
				GameMap( unsigned net_id );
				
				/// Destructor. Destroys the map.
				
				~GameMap();
				
				//=====================================================================================================
				/// @brief		Returns a singleton instance of the level.
				/// @pre		The level must exist in the game
				//=====================================================================================================
				
				static inline GameMap & GetSingleton()
				{ 
					// Make sure ok:
					
					ENSURE( s_this != 0 , "The level must exist in the game" )
					
					// Return
				
					return * s_this;	
				}
				
				//=====================================================================================================
				/// @brief		Tells the object to announce it's type name: this is the type name without the 
				///				Game:: namespace
				/// @returns	The type name of the object.
				//=====================================================================================================
				
				virtual const char * GetTypeName() const { return "GameMap"; }
				
				/// Update function. called once for every frame. 
				
				virtual void OnUpdate( float time_delta );

				/// Draw function. Makes the object render itself.
				
				virtual void OnDraw( Camera3D * c );
				
				/// Returns the doom level
				
				const DoomLevel & GetLevel() const { return * m_doom_level; }
				
				//=====================================================================================================
				/// @brief		Returns the path network for the Doom level
				/// @pre		This should only be called on the server
				//=====================================================================================================

				PathNetwork & GetPathNetwork() 
				{ 
					// Make sure ok

					ENSURE( IsServer() , "This should only be called on the server" )

					// Return:

					return * m_path_network; 
				}
				
				/// Picks a starting position for a player
				
				Vec3f PickStartPosition();
				
				/// Picks a starting position for an enemy
				
				Vec3f PickEnemyStartPosition();
				
				/// Called when the object is added into the game world
				
				virtual void OnGameAdded();				
				
				//=====================================================================================================
				/// @brief		Returns the number of patrol points:
				/// @returns	The number of patrol points
				/// @pre		This can only be called on the server
				//=====================================================================================================
				
				inline unsigned GetNumPatrolPoints() const 
				{ 
					// Make sure ok
				
					ENSURE( IsServer() , "This can only be called on the server" )
					
					// Return
					
					return m_patrol_points.size();
				}
				
				//=====================================================================================================
				/// @brief		Returns the patrol point with the given index
				/// @param		index - index or number of the patrol point desired
				/// @returns	The patrol point with the given index
				/// @pre		Given index must be in range
				/// @pre		This can only be called on the server
				//=====================================================================================================
				
				inline const Vec3f & GetPatrolPoint( unsigned index ) const
				{
					// Make sure ok
					
					ENSURE( IsServer() , "This can only be called on the server" ) 
				
					// Make sure ok
					
					ENSURE( index < GetNumPatrolPoints() , "Given index must be in range" )
					
					// Return:
					
					return m_patrol_points[index];
				}
				
				//=====================================================================================================
				/// @brief		Returns the number of ambush points
				/// @pre		This can only be called on the server
				//=====================================================================================================
				
				inline unsigned GetNumAmbushPoints() const 
				{ 
					// Make sure ok
				
					ENSURE( IsServer() , "This can only be called on the server" )
					
					// Return
					
					return m_ambush_point_positions.size();
				}
				
				//=====================================================================================================
				/// @brief		Returns the position of the ambush point with the given index
				/// @param		index - index or number of the ambush point desired
				/// @returns	The ambush point with the given index
				/// @pre		Given index must be in range
				/// @pre		This can only be called on the server
				//=====================================================================================================
				
				inline const Vec3f & GetAmbushPointPosition( unsigned index ) const
				{
					// Make sure ok
					
					ENSURE( IsServer() , "This can only be called on the server" ) 
				
					// Make sure ok
					
					ENSURE( index < GetNumAmbushPoints() , "Given index must be in range" )
					
					// Return:
					
					return m_ambush_point_positions[index];
				}
				
				//=====================================================================================================
				/// @brief		Returns the direction about the Y axis the AI must face at the ambush point with the 
				///				given index.
				/// @param		index - index or number of the ambush point desired
				/// @returns	The direction the AI must face at the ambush point with the given index
				/// @pre		Given index must be in range
				/// @pre		This can only be called on the server
				//=====================================================================================================				
				
				inline float GetAmbushPointDirection( unsigned index ) const
				{
					// Make sure ok
					
					ENSURE( IsServer() , "This can only be called on the server" ) 
				
					// Make sure ok
					
					ENSURE( index < GetNumAmbushPoints() , "Given index must be in range" )
					
					// Return:
					
					return m_ambush_point_directions[index];
				}				
				
		private:
		
			//=========================================================================================================
			// Functions
			//=========================================================================================================
			
				/// Creates the map. This is called from both constructors.
				
				void Create();
				
				/// Generates a list of start positions in the level
				
				void GenerateStartPositions();
				
				/// Generates a list of patrol points in the level
				
				void GeneratePatrolPoints();
				
				/// Generates a list of ambush points in the level
				
				void GenerateAmbushPoints();
				
				/// Creates all the ammo boxes for the level
				
				void CreateAmmoBoxes();

				/// Creates all the health boxes for the level
				
				void CreateHealthBoxes();

				/// Creates all monsters: also populates the enemy start point list

				void CreateMonsters();

				// Debug only functions

				#ifdef USE_DEBUG_CONSOLE

					/// Debug only console command: enables / disables showing of the current subsector
				
					static bool ConCmd_R_ShowSubsector( bool arg , bool arg_given );

					/// Debug only console command: enables / disables rendering of all subsectors
				
					static bool ConCmd_R_RenderAllSubsectors( bool arg , bool arg_given );
					
					/// Debug only console command: enables / disables rendering of the test raycast
				
					static bool ConCmd_R_ShowTestCast( bool arg , bool arg_given );

					/// Debug only console command: enables / disables wireframe rendering
				
					static bool ConCmd_R_WireframeLevel( bool arg , bool arg_given );

					/// Debug only console command: enables / disables drawing of the reject map
				
					static bool ConCmd_R_DrawReject( bool arg , bool arg_given );
					
					/// Debug only console command: enables / disables drawing of path nodes
				
					static bool ConCmd_A_DrawPathNodes( bool arg , bool arg_given );
					
					/// Debug only console command: sets the start point of the test point to the camera position
					
					static void ConCmd_A_SetTestPathStart();
					
					/// Debug only console command: enables / disables drawing of the test path find
					
					static bool ConCmd_A_DrawTestPath( bool arg , bool arg_given );

				#endif			
		
			//=========================================================================================================
			// Variables
			//=========================================================================================================
			
				/// This is to allow easy access to the level
				
				static GameMap * s_this;
			
				/// Our doom level
				
				DoomLevel * m_doom_level;
				
				/// This is a pathfinding network for the level for use with pathfinding
				
				PathNetwork * m_path_network;
				
				/// These are a list of player start points in the level
				
				std::vector<Vec3f> m_start_points;
				
				/// These are a list of enemy start points in the level
				
				std::vector<Vec3f> m_enemy_start_points;
				
				/// These are a list of ambush points:
				
				std::vector<Vec3f> m_ambush_point_positions;
				
				/// These are the directions that the enemy must face at each ambush point:
				
				std::vector<float> m_ambush_point_directions;
				
				/// These are a list of patrol points:
				
				std::vector<Vec3f> m_patrol_points;
				
				/// A random number generator for picking start points
				
				Random m_random;

				// Debug only variables:

				#ifdef USE_DEBUG_CONSOLE

					/// If true then the current subsector of the doom map will be drawn
					
					static bool s_show_subsector;
					
					/// If true then we draw all the subsectors
					
					static bool s_render_all_subsectors;
					
					/// If true then we show the current raycast. Raycast is redone by left clicking.
					
					static bool s_show_testcast;
					
					/// The start point of the current test raycast 
					
					static Vec3f s_testcast_start;

					/// The start point of the current test raycast 
					
					static Vec3f s_testcast_end;
					
					/// Switches on and off wireframe
					
					static bool s_wireframe_level;

					/// Turns on/off drawing of the reject map

					static bool s_draw_reject_map;
					
					/// Turns on/off drawing of path nodes
					
					static bool s_draw_path_nodes;
					
					/// Start point for the test path-find
					
					static Vec3f s_test_pathfind_start;
					
					/// If true then we draw a test path-find
					
					static bool s_draw_test_pathfind;

				#endif
	};
};

#endif 
