
#ifndef AI_SITUATIONAL_ANALYSIS_HPP
#define AI_SITUATIONAL_ANALYSIS_HPP

#include <Stuff\Point3D.hpp>
#pragma warning(push)
#include <stlport\vector>
#include <stlport\map>
#pragma warning(pop)
#include "AI_Fuzzy.hpp"
#include "AI_TacticInterface.hpp"



#define INTERFACE_PointEvaluator(post)							\
	public:														\
	  virtual Fuzzy Evaluate(TacticInterface& i,				\
							 const enemies_list& enemies,		\
							 const Stuff::Point3D& point) const ##post

#define PURE_PointEvaluator	   INTERFACE_PointEvaluator(=0;)
#define DERIVED_PointEvaluator INTERFACE_PointEvaluator(;)



#define INTERFACE_RegionGenerator(post)							\
	public:														\
	  virtual void Generate(TacticInterface& i,					\
							point_list& points,					\
							int iteration = 0) const ##post		\
	  virtual unsigned int Iterations() const ##post			\
	  virtual bool IgnoreMissionBounds(TacticInterface& i) const ##post

#define PURE_RegionGenerator	INTERFACE_RegionGenerator(=0;)
#define DERIVED_RegionGenerator INTERFACE_RegionGenerator(;)


namespace MechWarrior4
{
	class MWObject;
};

namespace MW4AI
{
	class TacticInterface;

	namespace SituationalAnalysis
	{
		typedef std::vector<Stuff::Point3D> point_list;
		typedef std::vector<MWObject*> enemies_list;
		typedef std::multimap<const Fuzzy,Stuff::Point3D> ranked_point_list;
		typedef std::pair<const Fuzzy,Stuff::Point3D> ranked_point;

		class PointEvaluator
		{
			PURE_PointEvaluator;
			virtual ~PointEvaluator() {};

		  public:
			static void SetEvaluationState(bool post_evaluation);

		  protected:
			bool GetEvaluationState() const { return (m_PostEvaluationState); }

		  private:
			static bool m_PostEvaluationState;
		};

		class RegionGenerator	{	PURE_RegionGenerator; virtual ~RegionGenerator() {};	};

		enum DistanceQualifier
		{
			NEAREST,
			FARTHEST
		};

		enum FromWho
		{
			FROM_SELF,
			FROM_TARGET,
			FROM_NEAREST_ENEMY,
			FROM_ALL_ENEMIES,
			INVALID
		};

		//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
		// Evaluate(): the pluggable evaluation function
		//

		Stuff::Point3D Evaluate(TacticInterface& iface,
								const RegionGenerator& search_region_generator,
								const PointEvaluator& evaluator,
								Stuff::Scalar minimum_distance = 0);

		Fuzzy EvaluatePoint(TacticInterface& iface,
							const Stuff::Point3D& point,
							const PointEvaluator& evaluator,
							const enemies_list* enemies = 0);

		Fuzzy GetWaterValue(const Stuff::Point3D& point);

		//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
		// Evaluators
		//

		class Evaluator_DistanceFrom
			: public PointEvaluator
		{
			DERIVED_PointEvaluator;
		  public:
			Evaluator_DistanceFrom(FromWho who,
								   Stuff::Scalar min,
								   Stuff::Scalar max,
								   DistanceQualifier want_nearest);
		  protected:
			const Stuff::Scalar m_Min;
			const Stuff::Scalar m_Max;
			const DistanceQualifier m_WantNearest;
		    const FromWho m_Who;
		};

		class Evaluator_Random
			: public PointEvaluator
		{
			DERIVED_PointEvaluator;
		};

		class Evaluator_WeightedAverage
			: public PointEvaluator
		{
			DERIVED_PointEvaluator;
		  public:
			Evaluator_WeightedAverage(Stuff::Scalar weight1, PointEvaluator& evaluator1,
									  Stuff::Scalar weight2, PointEvaluator& evaluator2);
			Evaluator_WeightedAverage(Stuff::Scalar weight1, PointEvaluator& evaluator1,
									  Stuff::Scalar weight2, PointEvaluator& evaluator2,
									  Stuff::Scalar weight3, PointEvaluator& evaluator3);
		  protected:
			std::vector<Stuff::Scalar> m_Weights;
			std::vector<PointEvaluator*> m_Evaluators;
		};

		class Evaluator_InFrontOf
			: public PointEvaluator
		{
			DERIVED_PointEvaluator;

		  public:
			Evaluator_InFrontOf(FromWho who,
								bool in_front,
								bool use_torso = false);
		  private:
			const FromWho m_Who;
			const bool m_InFront;
			const bool m_UseTorso;
		};

		class Evaluator_45DegreesInFront
			: public PointEvaluator
		{
			DERIVED_PointEvaluator;

		  public:
			Evaluator_45DegreesInFront(bool random);

		  private:
			const bool m_Random;
		};

		class Evaluator_ToSideOf
			: public PointEvaluator
		{
			DERIVED_PointEvaluator;
		  public:
			Evaluator_ToSideOf(FromWho who,
							   bool to_side);
		  private:
			const FromWho m_Who;
			const bool m_ToSide;
		};

		//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
		// Generators
		//

		class Generator_EscapeRegion
			: public RegionGenerator
		{
			DERIVED_RegionGenerator;
		};

		class Generator_Circle
			: public RegionGenerator
		{
			DERIVED_RegionGenerator;
		  public:
			Generator_Circle(FromWho who,
							 Stuff::Scalar magnitude,
							 Stuff::Scalar points_on_circumference = 12.0f,
							 Stuff::Scalar shrink_rate = 0.8f);
			Generator_Circle(const Stuff::Point3D& origin,
							 Stuff::Scalar magnitude,
							 Stuff::Scalar points_on_circumference = 12.0f,
							 Stuff::Scalar shrink_Rate = 0.8f);
		  private:
		    const FromWho m_Who;
			const Stuff::Point3D m_Origin;
			const Stuff::Scalar m_Magnitude;
			const Stuff::Scalar m_Points;
			const Stuff::Scalar m_ShrinkRate;
		};

		class Generator_InFrontOf
			: public RegionGenerator
		{
			DERIVED_RegionGenerator;
		  public:
			Generator_InFrontOf(FromWho who,
								Stuff::Scalar length,
								Stuff::Scalar random_skew = 0);
		  private:
			const FromWho m_Who;
			const Stuff::Scalar m_Length;
			const Stuff::Scalar m_RandomSkew;
		};
	};
};



#undef INTERFACE_PointEvaluator
#undef PURE_PointEvaluator
#undef DERIVED_PointEvaluator

#undef INTERFACE_RegionGenerator
#undef PURE_RegionGenerator
#undef DERIVED_RegionGenerator



#endif // AI_SITUATIONAL_ANALYSIS_HPP
