#pragma once
#pragma warning (disable:4786)
#pragma warning (push)
#include <stlport\vector>
#include <stlport\map>
#include <stlport\string>
#pragma warning (pop)

namespace MechWarrior4
{
	class Vehicle;
	class CBucket;

	const int BUCKET_AFFECT_ONE = 0;
	const int BUCKET_AFFECT_ALL = 1;
	const int MAX_BUCKET_NAME = 32;

	void BucketSecurityCheckStart();
	void BucketSecurityCheckStop();



	class CBucketManager
	{
	public:
		enum Bucket_Type {
			KILL_LINK		= 0,				// linked to mission scoring system
			DEATH_LINK		= 1,       // linked to mission scoring system
													// mods
			KILLS					= 2,
			FRIENDLY_KILLS			= 3,
			ENEMY_KILLS				= 4,
			KILLS_BY_TONNAGE		= 5,
			FRIENDLY_KILLS_BY_TONNAGE = 6,
			ENEMY_KILLS_BY_TONNAGE	= 7,
			DEATHS					= 8,
			SUICIDES				= 9,
			DAMAGE_INFLICT			= 10,
			FRIENDLY_DAMAGE_INFLICT	= 11,
			ENEMY_DAMAGE_INFLICT	= 12,
			DAMAGE_RECEIVE			= 13,
			FRIENDLY_DAMAGE_RECEIVE	= 14,
			ENEMY_DAMAGE_RECEIVE	= 15,
			COMPONENT_KILLS			= 16,
			COMPONENT_DEATHS		= 17,
			FRIENDLY_COMPONENT_KILLS = 18,
			FRIENDLY_COMPONENT_DEATHS = 19,
			ENEMY_COMPONENT_KILLS	= 20,
			ENEMY_COMPONENT_DEATHS	= 21,
			DFA						= 22,
			SHOTS_HIT				= 23,
			SHOTS_FIRED				= 24,
			HEAD_SHOTS				= 25,
			ARM_SHOTS				= 26,
			LEG_SHOTS				= 27,
			TORSO_SHOTS				= 28,
			KILLS_PC				= 29,
			KILLS_AI				= 30,
			BLANK					= 31,		// used just to hold values
	// these are automatically checked
			SHUTDOWN_TIMER			= 32,
			OBJECTIVE				= 33,	  // mod2 is distance
			OBJECTIVE_CONTESTED		= 34,
			OBJECTIVE_UNCONTESTED	= 35,
			FLAGS_TAKEN				= 36,
			FLAGS_DROPPED			= 37,
			FLAGS_CAPTURED			= 38,
			FLAG_HOLD_TIME			= 39,
			TIME					= 40,
			ALIVE_PLAYERS			= 41,
			DEAD_PLAYERS			= 42,
			CUSTOM					= 43,
// MSL 5.04 bucket
//			MAX_TYPES				= 44
			ENEMY_TURRET_KILLS		= 44,	
			FRIENDLY_TURRET_KILLS	= 45,
			ENEMY_BUILDING_KILLS	= 46,
			FRIENDLY_BUILDING_KILLS	= 47,
			MAX_TYPES				= 48
		};
	

	private:
		struct Track_Data{
			Bucket_Type buckettype;
			int mod2;
			int objid;
			bool visible;
			Track_Data (Bucket_Type p1,int p2,int p3,bool p4)
			{
				buckettype = p1;
				mod2 = p2;
				objid = p3;
				visible = p4;
			}
		};

		struct Custom_Parameter
		{
			Bucket_Type bucket_type;
			int bucket_multiplier;

			Custom_Parameter(Bucket_Type _bucket_type, int _bucket_multiplier)
			{
				bucket_type = _bucket_type;
				bucket_multiplier = _bucket_multiplier;
			}
		};

        int m_aMultipliers[MAX_TYPES];

		stlport::vector <CBucket *> m_Buckets;
		stlport::vector <CBucket *> m_VisibleBuckets;
		stlport::vector <CBucket *> m_BucketArray[MAX_TYPES];
		stlport::map < Adept::ReplicatorID , stlport::vector<CBucket *> > m_PlayersBuckets;

		stlport::vector <CBucket *> m_TrackedBuckets;					// for auto add and remove based on players joining and leaving
		stlport::vector <Track_Data> m_TrackedData;

		stlport::vector <Custom_Parameter> m_CustomParameters;

		stlport::vector<MechWarrior4::Vehicle*> m_VehiclesInsideObjectiveArea;

		stlport::string m_CustomBucketName;

		Stuff::Scalar m_LastScoreRefresh;
		bool m_NeedScoreRefresh;

		Stuff::Scalar m_AccumulatedTimeSlice;

		void SetupTrackData (int id);
		void NewTrackBucket (int id,const Adept::ReplicatorID& repid);
		void NewTeamBucket(int id, int team_number);

		bool m_bucketFormatDirty;

		void UpdateShutdownFrame(int int_time_slice);
		void UpdateObjectiveFrame(int int_time_slice);
		void UpdateTimeFrame(int int_time_slice);
		void UpdateScoreDirty ();
		void UpdateTeamBucketVisibility();
		void SortVisibleBuckets();

	public: // jcem
        struct PVP_Rec
        {
        public:
            Adept::ReplicatorID m_Inf;
            Adept::ReplicatorID m_Rcv;
            int m_nKills;
            int m_nScore;
        public:
            PVP_Rec(const Adept::ReplicatorID& Inf, const Adept::ReplicatorID& Rcv)
                : m_Inf(Inf), m_Rcv(Rcv), m_nKills(0), m_nScore(0)
            {
            }
        };
        stlport::vector <PVP_Rec> m_aPVP_Recs;
        int RelativeGetScore4Player(const ReplicatorID& me, const ReplicatorID& whom, int& nKills, int& nDeaths) const; // jcem
	public:
		CBucketManager (void);
		~CBucketManager (void);

		bool BucketFormatDirty () {return m_bucketFormatDirty;}
		void CleandBucketFormat() {m_bucketFormatDirty = false;}

		stlport::vector <Track_Data>*GetTrackedData(){return &m_TrackedData;}
		int GetBucketCount(){return m_Buckets.size();}

		int AddBucket (Bucket_Type type,int bucketaffects=0,int mod2=0);
		int AddBucket (Bucket_Type type,const Adept::ReplicatorID& id,int bucketaffects=0,int mod2=0);
		int AddBucket (CBucket *bucket);
		void KillBucket (int id);
		void KillBucket (Bucket_Type type,int bucketaffects=0,int mod2=0);
		void KillBucket (Bucket_Type type,const Adept::ReplicatorID& id,int bucketaffects=0,int mod2=0);
		CBucket *Bucket (int id);
		int BucketValue (int id) const;
		void BucketValue (int id, int value);
		void BucketMult (int id, int mult);
		void AddToScoreDisplay (CBucket *bucket);
		void ShowBucket (int id);
		void HideBucket (int id);
		void RescanBucketsForHUD (void);

		void AddTeamPoints(int team, int points);

		#ifdef LAB_ONLY
		void UpdateGameInfo(const Adept::ReplicatorID& id, Bucket_Type type);
		#endif

		int NumTrackedBuckets (void) const;
		int NumPlayerBuckets (const ReplicatorID& repid) const;
		CBucket *PlayerBucket (const ReplicatorID& repid,int index);
		CBucket *PlayerBucket (const ReplicatorID& repid, Bucket_Type type);

		void FillTeamBuckets(int team_number, stlport::vector<CBucket*>& buckets);
	
		int FindBucketValue(Bucket_Type type, const Adept::ReplicatorID& repid);
		int FindBucketValue(Bucket_Type type, int affects);

		CBucket* FindBucket (Bucket_Type type, const Adept::ReplicatorID& repid);
		CBucket* FindBucket (Bucket_Type type, int affects);

		int FindBucket (Bucket_Type type,const Adept::ReplicatorID& repid,int bucketaffects,int mod2=0,int objid=-2);
		void SetupTrack (Bucket_Type type, int mod2=0, bool visible=false, bool can_replace = true);
		void SetupTrackObject (Bucket_Type type,int objid,int distance,bool visible=false);
		void SetupTrackNet(Bucket_Type p1, int p2, int p3,bool visible);

		//void NotifyAction (Bucket_Type type,const Adept::ReplicatorID& id, int mod2, int value);
		void NotifyAction (Bucket_Type type,const Adept::ReplicatorID& id, int value, const Adept::ReplicatorID& id2 = *(const Adept::ReplicatorID*)NULL);

		void NotifyAddPlayer (const Adept::ReplicatorID& repid);
		void NotifyRemovePlayer (const Adept::ReplicatorID& repid);
		void UpdateFrame (Stuff::Scalar time_slice);

		void AddCustomBucketParameter(Bucket_Type bucket_type, int bucket_multiplier);
		int GetCustomBucketValue(const Adept::ReplicatorID& rep_id);
		int GetCustomBucketValue(int affects);
		void SetCustomBucketName(char* name);
		const char* GetCustomBucketName();

		void AddToCustomScore(const Adept::ReplicatorID& rep_id, int value);

		const stlport::vector<Vehicle*>& GetVehiclesInsideObjectiveArea() const;
	};

	class CBucket
	{
	private:
		static char buf[256];
		int m_Value;
		CBucketManager::Bucket_Type m_BucketType;
		int m_BucketAffects;			// 0 means just the one, 1 means all, negative means team (abs is team number)
		int m_Mod2;
		int m_ObjectID;						// could be an objective, flag, etc
		int m_ID;
		Adept::ReplicatorID m_Replicator;
		bool m_Tracked;
		int m_Team;
		bool m_Visible;

	public:
		CBucket (CBucketManager::Bucket_Type type,int bucketaffects=0,int mod2=0);
		CBucket (CBucketManager::Bucket_Type type,const Adept::ReplicatorID& id,int bucketaffects=0,int mod2=0);
		~CBucket (void);

		const char *Text (void) const;
		int Value(void) const;
		void Value (int value);

		int ComputedValue() const;

		void ObjectID (int id)
		{ m_ObjectID = id; }
		int ObjectID (void) const
		{ return m_ObjectID; }

		int Affects (void) const
		{ return m_BucketAffects; }
		int Mod2 (void) const
		{ return m_Mod2; }
		CBucketManager::Bucket_Type Type (void) const
		{ return m_BucketType; }
		const Adept::ReplicatorID& RepID (void) const
		{ return m_Replicator; }

		int ID (void) const
		{ return m_ID; }
		void ID (int newid)
		{ m_ID = newid; }

		void AddValue(int value);
		void SubtractValue(int value);

		bool Tracked(void) const
		{ return m_Tracked; }
		void Tracked(bool p1)
		{ m_Tracked = p1; }

		int Team();

		bool GetVisible() const;
		void SetVisible(bool visible);
	};

	inline int CBucketManager::AddBucket (CBucketManager::Bucket_Type type,int bucketaffects,int mod2)
	{
		return AddBucket (new CBucket (type,bucketaffects,mod2));
	}

	inline int CBucketManager::AddBucket (CBucketManager::Bucket_Type type,const Adept::ReplicatorID& id,int bucketaffects,int mod2)
	{
		return AddBucket (new CBucket (type,id,bucketaffects,mod2));
	}
}
