#pragma once

#include "MW4.hpp"
#include <Adept\Resource.hpp>

namespace MechWarrior4
{
	class SalvageManager;
	class LancemateManager;
	class LancematePlug;
	class MWMission;
	class MWCampaign;
	class Mech;
	
	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// Mech Stream Plug
	//
	class MechTablePlug:
		public Stuff::Plug
	{
		friend class MWGame;

	public:
		MechTablePlug(Adept::ResourceID mech_resource_id, const Stuff::MString& mech_name, int mech_id, int is_new = 1) :
		  Plug(Plug::DefaultData),
		  m_mechName(mech_name)
		{
			m_mechResourceID = mech_resource_id;
			m_originalName = mech_name;
			m_isSelected = false;
			m_status = ReadyStatus;
			m_mechID = mech_id;
			m_isNew = is_new;
		}

		 MechTablePlug(Stuff::MemoryStream *stream) :
		  Plug(Plug::DefaultData)
		{
			Check_Pointer(stream);

			*stream >> m_mechResourceID;
			*stream >> m_mechName;
			*stream >> m_originalName;
			*stream >> m_status;
			*stream >> m_mechID;
			m_isNew = 0;
			m_isSelected = false;
		}

		~MechTablePlug() {}

		void
			SaveMechTablePlug(Stuff::MemoryStream *stream)
		{
			Check_Object(this);
			Check_Pointer(stream);
			
			*stream << m_mechResourceID;
			*stream << m_mechName;
			*stream << m_originalName;
			*stream << m_status;
			*stream << m_mechID;
		}

		enum{
			ReadyStatus = 0,
			DamagedStatus,
			DestroyedStatus
		};

		Adept::ResourceID
			GetMechResourceID()
				{Check_Object(this); return m_mechResourceID;}
		Stuff::MString
			GetMechName()
				{Check_Object(this); return m_mechName;}
		Stuff::MString
			GetOriginalName()
				{Check_Object(this); return m_originalName;}
		int
			GetStatus()
				{Check_Object(this); return m_status;}
		int
			GetMechID()
				{Check_Object(this); return m_mechID;}
		int
			IsNew()
				{Check_Object(this); return m_isNew;}
		void
			SetMechName(const Stuff::MString& new_name)
				{Check_Object(this); m_mechName = new_name;}
		void
			SetStatus(int new_status)
				{Check_Object(this); m_status = new_status;}

	protected:
		Stuff::MString
			m_mechName;
		Stuff::MString
			m_originalName;
		Adept::ResourceID
			m_mechResourceID;
		bool
			m_isSelected;
		int
			m_status;
		int
			m_mechID;
		int
			m_isNew;

	};

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// Pilot Plug
	//
	class PilotPlug:
		public Stuff::Plug
	{
		friend class MWGame;
	public:
		PilotPlug(LancematePlug *pilot_plug, bool is_leader = false) :
		  Plug(Plug::DefaultData)
		  {
			  m_mechPlug = NULL;
			  m_pilot = pilot_plug;
			  m_isLeader = is_leader;
			  m_isValid = false;
		  }

		void 
			SavePilotToStream(Stuff::MemoryStream *stream);

		~PilotPlug()
		{}
	
		void
			SetMech(MechTablePlug *mech)
				{Check_Object(this);
				m_mechPlug = mech;
				if(m_isLeader) {m_isValid = true; return;}
				if(m_pilot) m_isValid = true;}
		void
			SetLancePlug(LancematePlug *lance_plug)
				{Check_Object(this); m_pilot = lance_plug;
					if(m_pilot) m_isValid = true; else m_isValid = false;}
		LancematePlug *
			GetPilot()
				{Check_Object(this); return m_pilot;}
		MechTablePlug *
			GetMechPlug()
				{Check_Object(this); return m_mechPlug;}
		Stuff::MString
			GetMechName()
				{Check_Object(this); Check_Object(m_mechPlug); return m_mechPlug->GetMechName();}
		bool
			IsPlayer()
				{Check_Object(this); return m_isLeader;}
		bool
			IsValid()
				{Check_Object(this); return m_isValid;}

	protected:
		MechTablePlug
			*m_mechPlug;
		bool
			m_isLeader;
		LancematePlug
			*m_pilot;
		bool
			m_isValid;

	};

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// MWGame
	//
	class MWGame:
		public Stuff::Plug
	{
	public:
		MWGame(const char *game_file_name);
		MWGame(const char *game_file_name, const char *campaign_name);

		~MWGame();

		static void
			ConstructMWGameStream(NotationFile *notation_file, MemoryStream *stream);
		void
			SaveMWGame(const char *game_file_name, bool overwrite, bool save_mission = false);
		void
			SaveInMissionGame();
		void
			LoadMWGame(const char *game_file_name);
		void
			Reload();
		const char *
			GetGameName()
				{Check_Object(this); return (char *)m_gameName;}
		MWCampaign *
			GetCampaign()
				{Check_Object(this); return m_campaign;}

		//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
		// Mission Support
		//
		void
			ReactToEndMission(bool success);
        void EarlyReactToEndMission(); // jcem
		void
			StartMission(char *mission_name);
		void
			ResetSalvageManager();

		//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
		// Lancemate Support
		//
		public:
			void
				InitializePilots(int num);
			int
				SetLancemate(int lance_id, char *lance_name);
			int
				SetLancemateMech(int lance_id, char *mech_name);
			PilotPlug*
				GetPilot(int id);
			void
				SetPilot(int lance_id, const MString& lance_name);
			PilotPlug*
				GetPilotLeader()
					{Check_Object(this); return m_lancePilots.Find(0);}
			int
				VerifyLaunchData();
			void
				CreateMechTable(Stuff::MemoryStream *stream);
			void
				SaveMechTable(Stuff::MemoryStream *stream);

			enum{
				VersionResourceID = ResourceID::FirstFreeRecordID,
				GeneralGameResourceID,
				CampaignResourceID,
				SalvageResourceID,
				LancemateResourceID,
				MissionResourceID,
				SetupResourceID,
				MechTableResourceID	//Must be Last!  Mechs will follow!
			};

			Adept::ResourceFile*
				GetGameResourceFile()
					{Check_Object(this); return m_gameResourceFile.GetCurrent();}

			static MWGame*
				GetInstance()
			{
				return reinterpret_cast<MWGame *>( GlobalPointers::GetGlobalPointer(MWGameGlobalPointerIndex));
			};


			SalvageManager
				*m_salvageManager;
			MWMission
				*m_mission;
			MWCampaign
				*m_campaign;
			LancemateManager
				*m_lancemates;

			//Used for interface stuff...who is selected!
			PilotPlug*
				m_currentPilot;
			Stuff::SortedChainOf<PilotPlug *, int>
				m_lancePilots;
			Stuff::SortedChainOf<MechTablePlug *, Stuff::MString>
				m_mechTable;

			bool
				HasLaunched()
					{Check_Object(this); return m_hasLaunched;}
			bool
				m_isNewGame;
		protected:
		
			MString
				m_gameName;
			bool
				m_hasInGameSave;
			bool
				m_hasLaunched;

			Stuff::SlotOf<Adept::ResourceFile*>
				m_gameResourceFile;

		//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
		// Game Setup Support
		//
		public:
			void
				LoadGeneralGameData(Stuff::MemoryStream *stream);
			void
				SaveGeneralGameData(Stuff::MemoryStream *stream);
			void
				LoadGameSetup(Stuff::MemoryStream *stream);
			void
				SaveGameSetup(Stuff::MemoryStream *stream);

			int
				GetGameLevel()
					{Check_Object(this); return m_gameLevel;}

		protected:
			int
				m_gameLevel;

		//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
		// Mech Table Support
		//
		public:
			void
				InitializeMechTable(bool new_campaign = false);
			void
				GetAndAddMechInstance(const char *salvage_string, int is_new = 1);
			void
				AddMechInstance(Mech *mech);
			void
				SetCurrentMechPlug(MechTablePlug *current_plug)
					{Check_Object(this); m_currentMechPlug = current_plug;}
			MechTablePlug*
				GetCurrentMechPlug()
					{Check_Object(this); return m_currentMechPlug;}

		private:
			MechTablePlug*
				m_currentMechPlug;
		
	};
}

