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

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

#include "AI/PathNetwork.h"

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

namespace Game
{	
	//=================================================================================================================
	//=================================================================================================================
	
	class GameEnemy;
	class GamePlayer;
	class GameMap;
	class AIMover;
	class DoomLevel;

	//=================================================================================================================
	/// @brief		This class is responsible for controlling and moving an AI. It maintains the current state of the 
	///				AI and it's current goals and objectives.
	//=================================================================================================================

	class AIController
	{
		public:
		
			//=========================================================================================================
			// Enums
			//=========================================================================================================
			
				/// Enum representing the current state of the AI or it's high level objective
				
				enum State
				{
					/// AI is pursuing the player. The AI will constantly pursue the player until it finds the player.
					
					AIS_PURSUIT , 
					
					/// AI is attacking the player.
					
					AIS_ATTACK ,
					
					/// AI is attacking and stopping to fire
					
					AIS_ATTACK_FIRE ,
					
					/// AI is waiting for an ambush
					
					AIS_AMBUSH ,
					
					/// AI is patrolling the world
					
					AIS_PATROL ,
					
					/// An invalid state. Any state with a number higher than this is invalid
					
					AIS_INVALID
				};
		
			//=========================================================================================================
			// Functions
			//=========================================================================================================
		
				//=====================================================================================================	
				/// @brief		Creates the AIController module
				/// @param		enemy - enemy that the controller controls
				//=====================================================================================================
				
				AIController( GameEnemy & enemy );
				
				//=====================================================================================================
				/// @brief		Destroys the AI controller.
				//=====================================================================================================
				
				~AIController();
				
				//=====================================================================================================
				/// @brief		Gets the current state of the AI module
				/// @returns	Current state of the AI module
				//=====================================================================================================
				
				State GetState() const { return m_state; }
				
				//=====================================================================================================
				/// @brief		Sets the current state of the AI module
				/// @param		state - new state of the AI module
				/// @pre		Given state must not be invalid
				//=====================================================================================================
				
				inline void SetState( State state )
				{
					// Make sure ok
					
					ENSURE( unsigned(state) <= unsigned(AIS_INVALID) , "Given state must not be invalid" )
					
					// Save:
					
					m_state = state;
				}
				
				//=====================================================================================================
				/// @brief		Updates the AI and performs all AI actions
				/// @param		time_delta - amount of time elapsed
				//=====================================================================================================
				
				void Update( float time_delta );
				
				//=====================================================================================================
				/// @brief		Picks a random state for the AI. State can either be AIS_PATROL, AIS_PURSUIT, or
				///				AIS_AMBUSH. Also resets other state information. This is done after a respawn.
				//=====================================================================================================
				
				void ResetState();

				/// Alerts the AI of noise from the given player

				void NoiseAlert( GamePlayer & player );

				/// Alerts the AI of damage from the given player

				void DamageAlert( GamePlayer & player );
				
		private:

			//=========================================================================================================
			// Constants
			//=========================================================================================================
			
				/// Amount of time it takes for an enemy to 'notice' the player
				
				static const float PLAYER_NOTICE_TIME;
				
				/// If the enemy is within this radius of a destination point (patrol point etc) then the AI is considered 'at' the destination.
				
				static const float DESTINATION_RADIUS;
				
				/// Amount of randomness to the chosen ambush point's position to add
				
				static const float AMBUSH_POSITION_RANDOMNESS;
				
				/// Amount of randomness to the chosen ambush point's direction to add
				
				static const float AMBUSH_DIRECTION_RANDOMNESS;
				
				/// How much to smooth the position of the point we are moving towards
				
				static const float MOVE_POINT_SMOOTHING;
				
				/// How far the AI attempts to get to the player when attacking before stopping
				
				static const float ATTACK_DISTANCE;
				
				/// This is the amount of time it takes for the AI to 'forget' and give up chasing the player it is attacking
				
				static const float ATTACK_GIVE_UP_TIME;
				
				/// Chance that the AI will fire at the player if it has sighting. 0-1.
				
				static const float ATTACK_FIRE_CHANCE;
				
				/// Time it takes for the AI to ready itself to fire
				
				static const float ATTACK_FIRE_TIME;

				//'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
				/// Cost during pathfinding of a monster being close to a pathfinding node. This cost is added to
				/// the costs of traversal for going to nodes where monsters are in already. This extra cost makes the 
				/// AI fan out and produces team-like behaviour.
				//'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''

				static const float AI_AT_NODE_G_COST;

			//=========================================================================================================
			// Structures
			//=========================================================================================================
			
				/// Structure representing a player in the game:
				
				struct Player
				{
					/// Pointer to the player
					
					GamePlayer * m_player;
					
					/// Time since this player was last spotted
					
					float m_time_since_sight;
					
					/// Amount of time this player has been in our sights for
					
					float m_time_in_sight;
					
					/// Time since this player last attacked us
					
					float m_time_since_attack;
				};

			//=========================================================================================================
			// Functions
			//=========================================================================================================
			
				/// Performs the pursuit goal
				
				void Goal_Pursuit( float time_delta );
				
				/// Performs the attack goal
				
				void Goal_Attack( float time_delta );
				
				/// Performs the attack fire goal
				
				void Goal_Attack_Fire( float time_delta );
				
				/// Performs the patrol goal
				
				void Goal_Patrol( float time_delta );
				
				/// Performs the ambush goal
				
				void Goal_Ambush( float time_delta );
				
				/// Sets the current target of the AI
				
				void SetTarget( GamePlayer * target );
				
				/// Updates the current list of players in the game
				
				void UpdatePlayerList( float time_delta );
				
				/// Picks a random state for the AI to be in. Picks one of the non-combat states.
				
				void PickRandomState();
				
				/// Picks a patrol point for the AI to head towards
				
				void PickPatrolPoint();
				
				/// Picks an ambush point for the AI to head towards
				
				void PickAmbushPoint();
				
				/// Performs a line of sight check between the AI and the given player
				
				bool InLineOfSight( GamePlayer * player );
				
				/// Returns the height of the given path node in the level
				
				float GetNodeHeight( const PathNetwork::Node & node );
				
				/// Checks if the monster can see any players and sets it into attack mode if it can
				
				bool CheckPlayerSight();				
				
				/// Moves the enemy character towards a given point
				
				void MoveToPoint( const Vec3f & point , float time_delta );
			
			//=========================================================================================================
			// Variables
			//=========================================================================================================
			
				/// This is the enemy that the controller controls
				
				GameEnemy * m_character;
				
				/// This is the doom level used by the controller for line of sight checks
				
				const DoomLevel * m_level;
				
				/// This is the map used by the controller
				
				GameMap * m_map;
				
				/// This is the movement module used for navigating
				
				AIMover * m_mover;
				
				/// This is the pathfinding network used by the AI to find it's way around the level
				
				PathNetwork * m_path_network;
				
				/// This is the current state of the AI
				
				State m_state;
				
				/// Current target of the AI
				
				GamePlayer * m_target;
				
				/// This is a list of players that are in the game
				
				std::vector<Player> m_players;
				
				/// A random number generator used by the AI
				
				Random m_random;
				
				/// Index of the last patrol point we went to
				
				unsigned m_last_patrol_point_index;
				
				/// Our destination position when heading towards a patrol point or an ambush point:
				
				Vec3f m_destination_point;
				
				/// The direction we must face when standing at an ambush point
				
				float m_destination_direction;
				
				/// This is the last point we moved towards last
				
				Vec3f m_last_move_point;
				
				/// Time the AI has been in the firing state
				
				float m_time_since_firing_began;
				
				/// Position the AI will attempt to fire at if firing
				
				Vec3f m_target_fire_position;
	};
};

#endif
