/*
	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 AI_MANAGER_H
#define AI_MANAGER_H

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

#include "GameObjects\AIControlled.h"
#include "GameObjects\GameObjectBase.h"
#include "GameObjects\PlayerShip.h"

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

namespace Game
{
	//=================================================================================================================
	//=================================================================================================================

	class Camera2D;
	class QuadTree;
	class AIControlled;
	class PlayerShip;
	class ObstacleManager;
	class EnemyBulletManager;

	//=================================================================================================================
	/// @brief		This is the base class for all AI managers for the different types of enemies. This is a composite
	///				game object which actually holds sub game objects underneath it (AIControlled objects). 
	///				This base contains functionality common to all AI managers.
	//=================================================================================================================

	class AIManager : public GameObjectBase
	{
		public:		

			//=========================================================================================================
			// Functions
			//=========================================================================================================
			
				/// Constructor.
				
				AIManager();
				
				/// Destructor. Handles cleanup.
				
				virtual ~AIManager();

				/// Gets the quad tree used by this AIManager

				inline QuadTree * GetQuadTree(){ return m_quad_tree; }
				
				/// Update function. Updates all objects that are in the manager.

				virtual void OnUpdate( float time_delta );
				
				/// Draw function. Draws all AI objects.
				
				virtual void OnDraw( Camera2D * c );
				
				/// Called when the manager is added the game. Calls CreatePooledObjects() so derived classes can make their objects
				
				virtual void OnGameAdded();	
				
				/// Called when the manager is removed from the game. Calls DestroyPooledObjects() so derived classes can destroy their objects		

				virtual void OnGameRemoved();
				
				/// Picks a point on the map that is a certain distance away from the given point, and at least a given distance away from obstacles
				
				Vec2f PickPointAwayfrom( const Vec2f & p , float dist , float obstacle_dist = 0 );

				/// Gets the maximum bounding volume radius for the types of enemy ships this manager looks after

				virtual float GetShipBoundingCircleRadius() = 0;

				/// Gets the bullet manager for this type of AI manager:

				inline EnemyBulletManager * GetBulletManager(){ return m_bullet_manager; }
				
				//=====================================================================================================
				/// @brief		Picks a spawn location for an enemy that is at least a given distance away from the player
				/// @param		distance - Minimum distance we want the spawn point to be away from the player
				/// @param		obstacle_distance - Minimum distance we want to be away from obstacles
				/// @returns	Chosen spawn location
				/// @pre		The player must be in the game
				/// @remarks	If a satisfactory position cannot be found within 32 iterations, this function gives up.
				//=====================================================================================================
				
				inline Vec2f PickSpawnLocation( float distance , float obstacle_distance )
				{
					// Make sure this is ok:
					
					ENSURE( GetPlayerShip() != 0 , "The player must be in the game" );
					
					// Do it:
					
					return PickPointAwayfrom( GetPlayerShip()->GetPosition() , distance , obstacle_distance );
				}
				
				//=====================================================================================================
				/// @brief		Gives the number of AIControlled objects currently in use from the pool
				/// @returns	The number of objects that this AIManager has allocated
				/// @pre		The AIManager must be in the game
				//=====================================================================================================
				
				inline unsigned GetUsedObjectCount()
				{ 
					// Make sure ok:
					
					ENSURE( m_ai_pool != 0 , "The AIManager must be in the game" );				
				
					// Return this:
				
					return m_ai_pool->GetUsedCount(); 
				}
				
				//=====================================================================================================
				/// @brief		Gives the maximum number of AIControlled objects that can be allocated from the pool
				/// @returns	Maximum number of AIControlled objects that can be allocated from the pool
				/// @pre		The AIManager must be in the game
				//=====================================================================================================
				
				inline unsigned GetMaxObjectCount()
				{ 
					// Make sure ok:
					
					ENSURE( m_ai_pool != 0 , "The AIManager must be in the game" );
				
					// Return this:
				
					return m_ai_pool->GetSize(); 
				}
								
				//=====================================================================================================
				/// @brief		Fast track function for getting the player's ship: cached in the manager to avoid 
				///				constant searching. This is used by AIObjects contained within.
				/// @returns	pointer to the player ship, or null if it's not there.
				//=====================================================================================================
				
				inline PlayerShip * GetPlayerShip(){ return m_player_ship; }
				
				//=====================================================================================================
				/// @brief		Fast track function for getting the obstacle manager: cached in the manager to avoid 
				///				constant searching. This is used by AIObjects contained within.
				/// @returns	pointer to the obstacle manager, or null if it's not there.
				//=====================================================================================================
				
				inline ObstacleManager * GetObstacleManager(){ return m_obstacle_manager; }				
				
				/// Returns the pool of AI objects 
				
				inline Pool<AIControlled> * GetAIObjectPool(){ return m_ai_pool; }
			
				/// Spawns one AIControlled object from the pool and returns the object spawned.
				
				AIControlled * AllocatePooledObject();
				
				//'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
				/// Adds the given newly allocated object to the quad tree. Should be called after 
				/// calling AllocatedPooledObject() and after the object has been positioned.				
				//'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
				
				void InsertToQuadTree( AIControlled * object );				
				
		protected:

			//=========================================================================================================
			// Constants
			//=========================================================================================================

				/// This is the maximum number of bullets that can be fired by all enemies under an enemy manager

				static const unsigned MAX_BULLETS;
		
			//=========================================================================================================
			// Functions
			//=========================================================================================================			
				
				/// Kills one AIControlled object and removes it from the pool
				
				void ReleasePooledObject( AIControlled * object );			
		
				/// This virtual function creates the object pool for this type of manager:
				
				virtual void CreatePooledObjects( std::vector<AIControlled*> & pooled_objects ) = 0;
				
				/// This virtual function destroys the object pool for this type of manager:
				
				virtual void DestroyPooledObjects( std::vector<AIControlled*> & pooled_objects ) = 0;				
				
				/// This virtual function is called before all objects are update in the manager: allows for spawning and more to be done
				
				virtual void OnAIManagerUpdate( float time_delta ) = 0;
				
				/// This virtual function is called by the base class before all objects are drawn in the manager: allows for setting of rendering parameters.
				
				virtual void OnAIManagerDraw( Camera2D * c ) = 0;				
				
				/// Allows derived managers to update one AI object:
				
				virtual void UpdateAIObject( AIControlled * object , float time_delta ) = 0;
				
				/// Allows derived managers to draw one AI object:
				
				virtual void DrawAIObject( AIControlled * object , Camera2D * c ) = 0;				

			//=========================================================================================================
			// Variables
			//=========================================================================================================		

				/// A quad tree used to track each objects position. This is used for swarming and other things that require proximity search.

				QuadTree * m_quad_tree;
				
				//'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
				/// This is the bullet manager for this type of enemy manager, if the type of AI object does use bullets.
				/// It is up to derived classes to create this if their enemies want to fire bullets.
				//'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''

				EnemyBulletManager * m_bullet_manager;
				
		private:
		
			//=========================================================================================================
			// Variables
			//=========================================================================================================
			
				/// The object pool for this manager. These are all the AI characters the manager controls, or will control.
				
				Pool<AIControlled> * m_ai_pool;
				
				/// The player ship:
				
				PlayerShip * m_player_ship;
				
				/// The obstacle manager used by the game
				
				ObstacleManager * m_obstacle_manager;
				
				//'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
				/// The list of objects used by the pool: it is up to derived classes to populate this list and 
				/// free all objects that are contained within. See CreatePooledObjects() and DestroyPooledObjects().
				/// This list of objects should only be changed once these functions are called.
				//'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
				
				std::vector<AIControlled*> m_pooled_objects;
				
				//'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
				/// This stamp indicates the number of updates since the begining of the game: it is used to distribute
				/// updates for all AI objects over a number of frames. Only a certain number of AI objects do a full
				/// update for each frame, whilst the rest are simply kept moving at their current velocity.		
				//'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
				
				unsigned m_num_updates;
	};
};

#endif
