#pragma once

#include "Adept.hpp"

namespace Adept {

	typedef int
		ObjectID;

	class NameTableEntry :
		public Stuff::Plug
	{
	public:
	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// Run-time Construction and Destruction Support
	//
		NameTableEntry(void):
		  Stuff::Plug(Stuff::Plug::DefaultData),
		  objectName(NULL)
		{
			  dataPointer = new Stuff::SlotOf<Entity*>(NULL);
		}

		void
			SetNameTableEntry(const char *object_name, Entity *entity)
		{
			objectName = object_name;
			dataPointer->Remove();
			if(entity)
				dataPointer->Add(entity);
		}

		~NameTableEntry()
		{
			if(dataPointer)
			{
				Check_Object(dataPointer);
				delete dataPointer;
			}
		}

		NameTableEntry&
			operator=(const NameTableEntry &entry)
				{
					objectName = entry.objectName; 
					objectID = entry.objectID;
					dataPointer->Remove();
					if(entry.dataPointer->GetCurrent())
						dataPointer->Add(entry.dataPointer->GetCurrent());
					return *this;
				}

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// Public Data
	//
	public:
		ObjectID
			GetObjectID()
				{Check_Object(this); return objectID;}
		void
			SetObjectID(ObjectID id)
				{Check_Object(this), objectID = id;}
		static int
			GetArrayIndex(ObjectID id)
				{return id >> 24;}
		static int
			GetObjectIndex(ObjectID id)
				{return id & 0x00ffffff;}
		static int
			BuildObjectID(int array_index, int object_index)
				{return ((array_index << 24) + object_index);}

		Stuff::MString
			objectName;
		Stuff::SlotOf<Entity *>
			*dataPointer;

	protected:
		ObjectID
			objectID;
	};

//##########################################################################
//#########################    NameTable    ################################
//##########################################################################

	class NameTable :
		public Stuff::Plug
	{
		friend class Mission;

	public:

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// Run-time Construction and Destruction Support
	//
		static void
			InitializeClass();
		static void
			TerminateClass();
	
		static ClassData
			*DefaultData;

		NameTable();
		~NameTable();

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// Run Time simulation
	//
		enum{	//this is for Buildings and Vehicles too
			DefaultArray = 0,
			BuildingArray = 0,
			VehicleArray,
			DropZoneArray,
			PlayerArray,
			SoundArray,
			PathArray,
			NavArray,
			ObjectiveArray,
			AIArray,
			Groups_Reserved,
			EffectGeneratorArray,
			PlayerAIArray,
			CulturalArray,
			TurretArray,
			CameraShipArray,
			FlagArray,
			ObservationVehicleArray,
			TeamArray,
			TableSize
		};

		enum{
			NullObjectID = -1
		};


	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// Creation and Saving
	//
		void
			SaveTable(Stuff::MemoryStream *stream);
		void
			SaveTable(Stuff::NotationFile *table_file);
		void
			LoadTable(Stuff::MemoryStream *stream);
		void
			LoadTable(Stuff::NotationFile *table_file);
		void
			Clear();
		bool
			IsValid();

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// Table Manipulation
	//
		void
			AddEntry(
				Entity *entity, 
				int array_index = DefaultArray
			);
		ObjectID
			AddEntry(
				const char *entity_name,
				int array_index = DefaultArray
			);
		void
			RemoveEntry(NameTableEntry *entry);
		void
			RemoveEntry(ObjectID id);

		int
			GetLength(int array_index);

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// Table Searches
	//
		ObjectID
			FindID(const char *object_name);
		Entity
			*FindData(ObjectID id);
		void
			SetData(Entity *entity);
		void
			SetData(ObjectID id,Entity *entity);
		NameTableEntry
			*FindEntry(ObjectID id);
		NameTableEntry
			*FindEntry(const char *object_name);
		NameTableEntry
			*FindEntry(int array_index,int entry_index);
		const char
			*FindName(ObjectID id);
		void
			SetName(ObjectID id, const char *new_name);

		static NameTable*
			GetInstance() 
		{
			return reinterpret_cast<NameTable *>( GlobalPointers::GetGlobalPointer(NameTableGlobalPointerIndex));
		};


	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// Data
	//

	public:

		typedef Stuff::DynamicArrayOf<NameTableEntry> 
			NameTableEntryArray;

		Stuff::StaticArrayOf<NameTableEntryArray, TableSize>
			nameTableArray;

	};
}