
#pragma once
#ifndef AI_TACTICS_HPP
#define AI_TACTICS_HPP

#include <stuff\auto_container.hpp>
#pragma warning (push)
#include <stlport\string>
#include <stlport\vector>
#pragma warning (pop)
#include "AI_Behavior.hpp"
#include <Stuff\Scalar.hpp>



namespace Stuff { class Point3D; }
namespace MechWarrior4 { class Vehicle; }

namespace MW4AI
{
	namespace Tactics
	{
		enum TacticID
		{
			// NOTE: The keywords and constants here must exactly match those in MWCONST.ABI
			TACTIC_PICK_BEST		= 2000,		// update TACTIC_FIRST if you change this
			TACTIC_STOP_AND_FIRE	= 2001,
			TACTIC_RAM				= 2002,
			TACTIC_JOUST			= 2003,
			TACTIC_RUSH				= 2004,
			TACTIC_HIT_AND_RUN		= 2005,
			TACTIC_FRONT			= 2006,
			TACTIC_REAR				= 2007,
			TACTIC_CIRCLE_OF_DEATH	= 2008,
			TACTIC_BACK_UP_AND_FIRE	= 2009,
			TACTIC_RETREAT			= 2010,
			TACTIC_CIRCLE_HOVER		= 2011,
			TACTIC_STRAFE			= 2012,
			TACTIC_STAND_GROUND		= 2013,
			TACTIC_JUMP_AND_SHOOT	= 2014,
			TACTIC_SNIPE			= 2015,
			TACTIC_SHOOT_ONLY		= 2016,
			TACTIC_DEFEND			= 2017,
			TACTIC_LOCAL_PATROL		= 2018,
			TACTIC_SURRENDER		= 2019,
			TACTIC_AMBUSH			= 2020,
			TACTIC_DEATH_FROM_ABOVE = 2021,
			TACTIC_HELI_POPUP		= 2022,
			TACTIC_DIVE_BOMB		= 2023,
			TACTIC_FAST_CIRCLE		= 2024,
			TACTIC_STARE			= 2025		// update TACTIC_LAST if you change this
		};

		class Tactic
		{
		  public:
			virtual void Update(TacticInterface& i);

			virtual TacticID GetID() const = 0;
			virtual std::string GetName() const = 0;

			Tactic();
			virtual ~Tactic();

			virtual bool CanBeSelectedAutomatically(TacticInterface& iface) const;
			virtual bool ShouldIgnoreLOS() const;

			void SetExplicit(bool is_explicit);
			bool GetExplicit() const;

			bool ShouldAbandon(TacticInterface& i) const;
			virtual bool ShouldAbandonImmediately() const = 0;

			virtual Stuff::Scalar Evaluate(TacticInterface& iface) const;

			void SetIgnoreExplicitTactic(TacticID tactic);
			TacticID GetIgnoreExplicitTactic() const;

			bool Finished() const;

			void UpdateSatisfaction();

		  private:
			Stuff::Scalar GetDuration() const;
			bool IsIneffective() const;

			Stuff::Scalar m_CreationTime;
			Stuff::Scalar m_CreationMood;
			mutable bool m_Explicit;

			Stuff::Scalar m_Satisfaction;
			Stuff::Time m_LastSatisfactionUpdate;
			Stuff::Scalar m_AutoEndTime;

			TacticID m_TacticToIgnore;

		  protected:
			virtual bool IsHappy() const = 0;
		};

		enum
		{
			TACTIC_FIRST = TACTIC_PICK_BEST,
			TACTIC_LAST = TACTIC_STARE
		};

		void VerifyTactic(TacticID id);
		Stuff::Auto_Ptr<Tactic> CreateTactic(TacticInterface& i, TacticID id);

		class Registrar
		{
		  public:
			static void IncrementRefCount(TacticInterface& i);
			static void DecrementRefCount();
			static Registrar& GetInstance();

			Registrar(TacticInterface& i);
			~Registrar();

			TacticID SelectTactic(TacticInterface& i, const std::vector<TacticID>& most_recent_tactics) const;
			Tactic& GetTactic(TacticID id) const;

		  private:
			int m_RefCount;
			static Registrar* instance;
			typedef Stuff::Auto_Container<Tactic,std::vector<Tactic*> > tactic_container;
			tactic_container m_Tactics;
		};

		#define BEGINDEF_TACTIC(classname,id,string_name,behavior_type)	\
			class classname:								\
				public Tactic								\
			{												\
			  protected:									\
				TacticID GetID() const { return (id); }					\
				std::string GetName() const { return (string_name); }	\
				bool ShouldAbandonImmediately() const { return (m_Implementation.ShouldStopImmediately()); }	\
				void Update(TacticInterface& i)							\
				{														\
					Tactic::Update(i);									\
					m_Implementation.Execute(i);						\
				}														\
				bool IsHappy() const { return (m_Implementation.IsHappy()); }	\
			  private:													\
			    behavior_type m_Implementation;

		#define ENDDEF_TACTIC };

		BEGINDEF_TACTIC(StopAndFire,TACTIC_STOP_AND_FIRE,"Stop and Fire",MW4AI::Behaviors::StopAndFire)
		ENDDEF_TACTIC

		BEGINDEF_TACTIC(Ram,TACTIC_RAM,"Ram",MW4AI::Behaviors::Ram)
		ENDDEF_TACTIC

		BEGINDEF_TACTIC(Joust,TACTIC_JOUST,"Joust",MW4AI::Behaviors::Joust);
		  public:
			bool CanBeSelectedAutomatically(TacticInterface& iface) const;
			Stuff::Scalar Evaluate(TacticInterface& iface) const;
		ENDDEF_TACTIC

		BEGINDEF_TACTIC(Rush,TACTIC_RUSH,"Rush",MW4AI::Behaviors::Rush)
		  public:
			bool CanBeSelectedAutomatically(TacticInterface& iface) const;
			Stuff::Scalar Evaluate(TacticInterface& iface) const;
		ENDDEF_TACTIC

		BEGINDEF_TACTIC(HitAndRun,TACTIC_HIT_AND_RUN,"Hit and Run",MW4AI::Behaviors::HitAndRun)
		  public:
			bool CanBeSelectedAutomatically(TacticInterface& iface) const;
			Stuff::Scalar Evaluate(TacticInterface& iface) const;
		ENDDEF_TACTIC

		BEGINDEF_TACTIC(Front,TACTIC_FRONT,"Front",MW4AI::Behaviors::Front)
		ENDDEF_TACTIC

		BEGINDEF_TACTIC(Rear,TACTIC_REAR,"Rear",MW4AI::Behaviors::Rear)
		  public:
			bool CanBeSelectedAutomatically(TacticInterface& iface) const;
			Stuff::Scalar Evaluate(TacticInterface& iface) const;
		ENDDEF_TACTIC

		BEGINDEF_TACTIC(Circle,TACTIC_CIRCLE_OF_DEATH,"Circle",MW4AI::Behaviors::CircleOfDeath)
		  public:
			bool CanBeSelectedAutomatically(TacticInterface& iface) const;
			Stuff::Scalar Evaluate(TacticInterface& iface) const;
		ENDDEF_TACTIC

		BEGINDEF_TACTIC(Retreat,TACTIC_RETREAT,"Retreat",MW4AI::Behaviors::Retreat)
		  public:
			bool CanBeSelectedAutomatically(TacticInterface& iface) const;
			Stuff::Scalar Evaluate(TacticInterface& iface) const;
		ENDDEF_TACTIC

		BEGINDEF_TACTIC(BackUpAndFire,TACTIC_BACK_UP_AND_FIRE,"Back Up and Fire",MW4AI::Behaviors::BackUpAndFire)
		ENDDEF_TACTIC

		BEGINDEF_TACTIC(CircleHover,TACTIC_CIRCLE_HOVER,"Circle Hover",MW4AI::Behaviors::CircleHover)
		ENDDEF_TACTIC

		BEGINDEF_TACTIC(Strafe,TACTIC_STRAFE,"Strafe",MW4AI::Behaviors::Strafe)
			virtual bool ShouldIgnoreLOS() const
			{
				return (true);
			}
		ENDDEF_TACTIC

		BEGINDEF_TACTIC(StandGround,TACTIC_STAND_GROUND,"Stand Ground",MW4AI::Behaviors::StandGround)
		ENDDEF_TACTIC

		BEGINDEF_TACTIC(JumpAndShoot,TACTIC_JUMP_AND_SHOOT,"Jump and Shoot",MW4AI::Behaviors::JumpAndShoot)
		ENDDEF_TACTIC

		BEGINDEF_TACTIC(Snipe,TACTIC_SNIPE,"Snipe",MW4AI::Behaviors::Snipe)
		ENDDEF_TACTIC

		BEGINDEF_TACTIC(ShootOnly,TACTIC_SHOOT_ONLY,"ShootOnly",MW4AI::Behaviors::ShootOnly)
		ENDDEF_TACTIC

		BEGINDEF_TACTIC(Defend,TACTIC_DEFEND,"Defend",MW4AI::Behaviors::Defend)
		ENDDEF_TACTIC

		BEGINDEF_TACTIC(LocalPatrol,TACTIC_LOCAL_PATROL,"Local Patrol",MW4AI::Behaviors::LocalPatrol)
		ENDDEF_TACTIC

		BEGINDEF_TACTIC(Surrender,TACTIC_SURRENDER,"Surrender",MW4AI::Behaviors::Surrender)
		ENDDEF_TACTIC

		BEGINDEF_TACTIC(Ambush,TACTIC_AMBUSH,"Ambush",MW4AI::Behaviors::Ambush)
		ENDDEF_TACTIC

		BEGINDEF_TACTIC(DeathFromAbove,TACTIC_DEATH_FROM_ABOVE,"Death From Above",MW4AI::Behaviors::DeathFromAbove)
		  public:
			bool CanBeSelectedAutomatically(TacticInterface& iface) const;
			Stuff::Scalar Evaluate(TacticInterface& iface) const;
		ENDDEF_TACTIC

		BEGINDEF_TACTIC(HeliPopup,TACTIC_HELI_POPUP,"Heli Popup",MW4AI::Behaviors::HeliPopup)
		ENDDEF_TACTIC

		BEGINDEF_TACTIC(DiveBomb,TACTIC_DIVE_BOMB,"Dive Bomb",MW4AI::Behaviors::DiveBomb)
		ENDDEF_TACTIC

		BEGINDEF_TACTIC(FastCircle,TACTIC_FAST_CIRCLE,"Fast Circle",MW4AI::Behaviors::FastCircle)
		ENDDEF_TACTIC

		BEGINDEF_TACTIC(Stare,TACTIC_STARE,"Stare",MW4AI::Behaviors::Stare)
		ENDDEF_TACTIC

		#undef BEGINDEF_TACTIC
		#undef ENDDEF_TACTIC
	};
};


#endif AI_TACTICS_HPP
