#pragma once

#include "MW4.hpp"

#include "NavPoint.hpp"

namespace MechWarrior4
{

	//##########################################################################
	//###########################   Flag    ################################
	//##########################################################################

	typedef NavPoint__ClassData					Flag__ClassData;
	typedef NavPoint__Message					Flag__Message;
	typedef NavPoint__CreateMessage				Flag__CreateMessage;
	typedef NavPoint__GameModel					Flag__GameModel;
	typedef NavPoint__ExecutionStateEngine		Flag__ExecutionStateEngine;
	

	class Flag : public NavPoint
	{
	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// Inheritance support
	//
	public:
		typedef Flag__ClassData							ClassData;
		typedef Flag__GameModel							GameModel;
		typedef Flag__Message								Message;
		typedef Flag__ExecutionStateEngine	ExecutionStateEngine;
		typedef Flag__CreateMessage					CreateMessage;

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// Static Methods
	//
	public:
		static void InitializeClass();
		static void TerminateClass();

		typedef NavPoint BaseClass;

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// Run-time Construction and Destruction Support
	//
	public:
		static Flag* Make(CreateMessage *message,ReplicatorID *base_id);

	protected:
		Flag(ClassData *class_data,CreateMessage *message,ReplicatorID *base_id,ElementRenderer::Element *element);

		~Flag();

		void Reuse(const CreateMessage *message,ReplicatorID *base_id);

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// Flag Support
	//
	public:
		enum
		{
			IsVisibleBit = BaseClass::NextFlagBit,
			NextFlagBit
		};

		enum
		{
			IsVisibleFlag = 1<<IsVisibleBit
		};

		enum
		{
			DefaultFlags = ~IsVisibleFlag
		};

		bool IsVisible()
		  {Check_Object(this); return (replicatorFlags&IsVisibleFlag) != 0;}
		void SetVisibleFlag()
				{Check_Object(this); replicatorFlags |= IsVisibleFlag;}
		void ClearVisibleFlag()
				{Check_Object(this); replicatorFlags &= ~IsVisibleFlag;}

		void FindGoodDropSpot(Stuff::Point3D& point, Stuff::Scalar desired_height);

		int
			GetExecutionSlot();

		void
			AddStatsToString(std::string& s);

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// Shared Data support
	//
	public:
		static ClassData *DefaultData;

// MSL 5.03 Fixed Flag_Taken
		enum FlagEvent
		{
			FLAG_NONE		= 0,
			FLAG_TAKEN		= 1,
			FLAG_CAPTURED	= 2,
			FLAG_RETURNED	= 3,
			FLAG_TAKEN_BY_ME= 4,
		};


	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// Simulation Support
	//
	protected:
		Stuff::Time m_StartAttachTime;
		Stuff::SlotOf<Adept::Entity*> m_AttachedTo;
		Adept::Site *m_AttachSite;
		Stuff::Time m_DeactiveTime;
		Stuff::Time m_WaitAfterCaptureTime;
		Stuff::Scalar m_AttachRadius;
		int m_Team;
		int m_DisplayIncValue;
		LinearMatrix4D m_Origin;
		bool m_FirstFrame;
		bool m_UseDropNames;
		Stuff::Scalar m_HoldTimeLastUpdate;
		bool m_Visible;
		Stuff::Scalar m_LastAnimateTime;
		FlagEvent m_LastFlagEvent;

	public:
		enum{
			FirstFlagAnimationState = 0,
			SecondFlagAnimationState,
			ThirdFlagAnimationState,
			FourthFlagAnimationState, 
			FifthFlagAnimationState,
			SixthFlagAnimationState,
			MaxFlagAnimationState
		};
		
	public:
		void RevealFlag();
		void HideFlag();
		void SetToDisplay()
			{Check_Object(this); visualRepresentation=FirstFlagAnimationState; ExecuteComponentWebs();}

		int GetTableArray()
				{Check_Object(this); return NameTable::FlagArray;}

		Stuff::Time TimeAttached (void);
		Adept::Entity *Attached (void);

		void DeactiveTime (Stuff::Time time)
		{ m_DeactiveTime = gos_GetElapsedTime () + time; }
		void AttachRadius (Stuff::Scalar value)
		{ m_AttachRadius = value; }

		void PreCollisionExecute(Stuff::Time till);
		void PostCollisionExecute(Stuff::Time till);

		int GetTeam() const;
		void SetTeam(int team);

		void Execute_ReturnToOrigin();
		void Execute_AttachTo(Adept::Entity* entity);
		void Execute_Drop();
		void Execute_Capture();

		void Attach(Adept::Entity *who);

		void Respawn(Adept::Entity::CreateMessage *message);

		static void RemoveAllFlagsFrom(Adept::Entity& entity);
		static void ResetAllFlags();
		static bool AnyFlagsAttachedTo(Adept::Entity& entity);

		void PlaySound_FlagTaken();
		void PlaySound_FlagTakenByMe();
		void PlaySound_FlagReturned();
		void PlaySound_FlagCaptured();

		void Broadcast_FlagTaken(Adept::Entity& entity);
		void Broadcast_FlagReturned();
		void Broadcast_FlagCaptured();

		void SaveInstanceText(Stuff::Page *page);

		void ReactToFlagEvent(FlagEvent event);

		FlagEvent GetLastFlagEvent() const;
		void SetLastFlagEvent(FlagEvent event);

	  protected:
		static void Notify(const std::string& s);
		static void NotifyFlagTaken(int flag_team, int taker_team, const char* taker_name);
		static void NotifyFlagDropped(int flag_team, int dropper_team, const char* dropper_name);
		static void NotifyFlagCaptured(int flag_team, int capturer_team, const char* capturer_name);
		static void NotifyFlagReturned(int flag_team);

		int CurrentTeamDropZone();

		int NumFlagsCarriedBy(Adept::Entity& entity);
		bool EntityCanCarryMe(Adept::Entity& entity);
		bool EntityCanReturnMe(Adept::Entity& entity);
		bool CarrierCanStillCarryMe();
		bool CarrierCanCaptureMe();
		bool CanDropTeamFlagHere(int team);

		void UpdateAttached();
		void UpdateUnattached();
		void UpdateWaitAfterCapture();

		void UpdateFlagObjectOnGround();
		void UpdateFlagObjectAttached();

		void LookForSomeoneToAttachTo();

		int FlagDropNameToTeamNumber(char* name) const;

		static int GetFlagDropReturnTime();
		static int GetFlagCaptureReturnTime();

		void GetFlagsCarriedBy(Adept::Entity& entity, std::vector<Flag*>& flags);

		int GetMyIndex();

		bool UseDropNames();

		void IncrementScore(int bucket_type, const Adept::ReplicatorID& id);

		bool Enabled();

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// Test Support
	//
	public:
		void TestInstance() const;

	public:	
		void
			BecomeInteresting(bool render_me); /// need this for texture remapping decals

	};
}


