#pragma once

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

namespace MechWarrior4
{
	class MWCampaign;

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// MWCampaign Interface Plug
	//
	class MWMissionMapPoint:
		public Stuff::Plug
	{
	public:
		MWMissionMapPoint(Stuff::MemoryStream *stream) :
		  Plug(Plug::DefaultData)
		{
			Check_Pointer(stream);

			*stream >> m_pointType;
			*stream >> m_xLoc;
			*stream >> m_yLoc;
			*stream >> m_width;
			*stream >> m_height;
			*stream >> m_textID;
			*stream >> m_rolltextID;
			*stream >> m_rclicktextID;
			if(m_pointType >= InfoPointType) 
				*stream >> m_iconName;
		}

		~MWMissionMapPoint() {}

		static void
			ConstructMissionMapPointStream(Stuff::Page *page, Stuff::MemoryStream *stream);
	public:
		enum{
			DropPointType = 0,
			NavPointType,
			InfoPointType,
			GeneralInfoPointType
		};

		int
			m_pointType,
			m_xLoc,
			m_yLoc,
			m_width,
			m_height,
			m_textID,
			m_rolltextID,
			m_rclicktextID;
		Stuff::MString
			m_iconName;
	};

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// MWCampaign Interface Plug
	//

	class MWCampaignInterfacePlug:
		public Stuff::Plug
	{
	public:
		MWCampaignInterfacePlug(Stuff::MemoryStream *stream);
		~MWCampaignInterfacePlug();

		static void
			ConstructCampaignInterfaceStream(Stuff::MemoryStream *stream, Stuff::Page *page);
		int
			GetXLocation()
				{Check_Object(this); return m_xLoc;}
		int
			GetYLocation()
				{Check_Object(this); return m_yLoc;}
		int
			GetHeight()
				{Check_Object(this); return m_height;}
		int
			GetWidth()
				{Check_Object(this); return m_width;}
		int
			GetID()
				{Check_Object(this); return m_ID;}
		int
			GetRollOverID()
				{Check_Object(this); return m_rollOverID;}
		int
			GetRightClickID()
				{Check_Object(this); return m_rightClickID;}
		Stuff::MString
			GetIconName()
				{Check_Object(this); return m_iconName;}
		Stuff::MString
			GetMapTextureName()
				{Check_Object(this); return m_mapTextureName;}
	public:
		Stuff::ChainOf<MWMissionMapPoint *>
			m_navPoints;
		Stuff::ChainOf<MWMissionMapPoint *>
			m_dropPoints;
		Stuff::ChainOf<MWMissionMapPoint *>
			m_infoPoints;
		Stuff::ChainOf<MWMissionMapPoint *>
			m_generalInfoPoints;

	private:
		int
			m_xLoc,
			m_yLoc,
			m_height,
			m_width,
			m_ID,
			m_rollOverID,
			m_rightClickID;
		Stuff::MString
			m_iconName,
			m_mapTextureName;
			

	};

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// Campaign Mission Plug
	//

	class CampaignMissionPlug:
		public Stuff::Plug
	{
	public:
		CampaignMissionPlug(const char *mission_name);

		~CampaignMissionPlug();

		void
			SetTriggerMission(CampaignMissionPlug *mission_plug, int percent);
		void
			AddDisplayDependancy(CampaignMissionPlug *mission_plug);
		void
			RemoveDisplayDependancy(CampaignMissionPlug *mission_plug);
		void
			WriteToText(Stuff::Page *page);
		void
			SetStatus(int new_status)
				{Check_Object(this); m_status = new_status;}
		void
			SetType(int new_type)
				{Check_Object(this); m_type = new_type;}
		void
			SetDisplayNameIndex(int index)
				{Check_Object(this); m_displayNameIndex = index;}
		void
			SetOpNumber(int op_number)
				{Check_Object(this); m_opNumber = op_number;}
		void 
			SetNumLancemates (int num)
				{Check_Object(this); m_NumLancemates = num;}
		void
			SetInterfacePlugID(Adept::ResourceID resource_id)
				{Check_Object(this); m_interfacePlugID = resource_id;}
		void
			SetAdvanceToOperation(int new_op)
				{Check_Object(this); m_advacnceToOperation = new_op;}

		MString
			m_missionName;
		CampaignMissionPlug
			*m_triggerMission;
		int
			m_status;
		int
			m_triggerPercentage;
		int
			m_type;

		Stuff::ChainOf<CampaignMissionPlug *>
			m_missionsNeededToDisplay;
		Adept::ResourceID
			m_interfacePlugID;
		int
			m_displayNameIndex;
		int
			m_opNumber;
		int 
			m_NumLancemates;
		int
			m_advacnceToOperation;
		int
			m_doesEnd;
		int
			m_canChangeTime;
		Stuff::MString
			m_finalMovieName;
	
	};

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// Operation Plug
	//

	class OperationPlug:
		public Stuff::Plug
	{
	public:
		OperationPlug(Stuff::MemoryStream *stream) :
			Plug(Plug::DefaultData),
			m_missions(NULL)
		{
			Check_Pointer(stream);
			
			m_id = -1;
			*stream >> m_nameIndex;
			*stream >> m_mapTextureName;
		}

		~OperationPlug() {}

		static void
			ConstructOperationStream(Stuff::Page *page, Stuff::MemoryStream *stream);
		void
			SaveToStream(Stuff::MemoryStream *stream);
		int
			GetID()
				{Check_Object(this); return m_id;}
		int
			GetNameIndex()
				{Check_Object(this); return m_nameIndex;}
		Stuff::MString
			GetMapTextureName()
				{Check_Object(this); return m_mapTextureName;}

		void
			SetID(int new_id)
				{Check_Object(this); m_id = new_id;}

		Stuff::ChainOf<CampaignMissionPlug *>
			m_missions;

	private:
		int
			m_id;
		int
			m_nameIndex;
		Stuff::MString
			m_mapTextureName;
	};

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// Movie Plug
	//
	class MoviePlug :
		public Stuff::Plug
	{
	public:
		MoviePlug(Stuff::MemoryStream *stream) : 
			Plug(Plug::DefaultData)
		{
			Check_Pointer(stream);

			*stream >> m_movieName;
			*stream >> m_type;
			*stream >> m_delay;
			*stream >> m_hasPlayed;
			*stream >> m_triggerName;
			m_playedThisSelection = false;
		}

		static void 
			ConstructMoviePlugStream(Stuff::Page *page, Stuff::MemoryStream *stream);
		void
			SaveToStream(Stuff::MemoryStream *stream);
	
	public:
		enum{
			MissionSuccessType = 0,
			MissionSelectionType,
			LancemateDeathType,
			LancemateReturnType
		};

		static int
			MovieTypeStringToAscii(const char *type_string);
		Stuff::MString
			GetMovieName()
				{Check_Object(this); return m_movieName;}
		int
			GetMovieType()
				{Check_Object(this); return m_type;}
		int
			GetMovieDelay()
				{Check_Object(this); return m_delay;}
		bool
			HasPlayed()
				{Check_Object(this); return m_hasPlayed;}
		Stuff::MString
			GetTriggerName()
				{Check_Object(this); return m_triggerName;}

		//This is used only for movies played on selecting the mission region
		bool
			m_playedThisSelection;

	private:
		Stuff::MString
			m_movieName;
		int
			m_type;
		int
			m_delay;
		bool
			m_hasPlayed;
		Stuff::MString
			m_triggerName;

	};

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// Movie Manager
	//
	class MWMovieManager
	{
	public:
		MWMovieManager(); 
		~MWMovieManager();

	public:
		void
			ExecuteMissionSuccess(const char *mission_name);
		void
			ExecuteMissionSelection(const char *mission_name);
		void
			ExecuteLancemateDeath(const char *lance_name);
		void
			ExecuteLancemateReturn(const char *lance_name);
		void
			AddMoviePlug(MoviePlug *new_movie);
		void
			SaveToStream(Stuff::MemoryStream *stream);
		void
			StartMovie(MoviePlug *movie_plug);
		void
			Execute();

		SortedChainOf<MoviePlug *, Stuff::Time>
			m_delayedMovies;

		Stuff::ChainOf<MoviePlug *>
			m_successMovies;
		Stuff::ChainOf<MoviePlug *>
			m_selectionMovies;
		Stuff::ChainOf<MoviePlug *>
			m_lancemateDeathMovies;
		Stuff::ChainOf<MoviePlug *>
			m_lancemateReturnMovies;

	};

	typedef Receiver__ClassData				Campaign__ClassData;
	typedef Receiver__Message				Campaign__Message;

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// Internal Damage Object class
	//
	class MWCampaign:
		public Adept::Receiver
	{
	
	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// Inheritance Support
	//
	public:
		typedef Campaign__ClassData			ClassData;
		typedef Campaign__Message		  	Message;

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// Construction, Destruction, Testing
	//
	public:
		static void
			InitializeClass();
		static void
			TerminateClass();

		static HGOSHEAP
			s_Heap;

		static void
			ConstructCampaignStream(
				Stuff::MemoryStream *stream,
				NotationFile *notation_file
			);

		static MWCampaign*
			MakeNewCampaign(const char *campaign_name);
		static MWCampaign*
			MakeNewCampaign(const ResourceID& campaign_id);

		void
			Save(MemoryStream *stream);
		void
			WriteToText(const char *file_name);

		MWCampaign(Stuff::MemoryStream *stream);

		~MWCampaign();

		void
      		TestInstance();
	
	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// Class Data support
	//
	public:
		static ClassData
			*DefaultData;

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// Execution Support
	//
	public:
		enum{
			Hidden = 0,
			Displayed,
			Completed
		};
		enum{
			NormalMissionType = 0,
			DefendMissionType,
			RescueMissionType
		};

		static int
			StatusTextToAscii(const char *status_string);
		static const char *
			StatusAsciiToText(int status);
		static int
			MissionTypeTextToAscii(const char *type_string);
		static const char *
			MissionTypeAsciiToText(int type);
		void
			MissionSuccess();
		const char*
			GetNextMission();
		CampaignMissionPlug*
			GetNextMissionPlug();
		CampaignMissionPlug*
			FindMission(MString mission_name);
		CampaignMissionPlug*
			FindMission(int display_index);
		void
			TransferToNextOp();
		int
			GetOPMissionCount();

		Stuff::ChainOf<CampaignMissionPlug*>
			m_missions;
		Stuff::SortedChainOf<OperationPlug *, int>
			m_operations;
		Stuff::ChainIteratorOf<CampaignMissionPlug*>
			*m_missionsIterator;

		CampaignMissionPlug*
			m_currentMissionPlug;
		CampaignMissionPlug*
			m_lastMissionPlug;

		MWMovieManager 
			*m_movieManager;
		Stuff::MString
			m_finalMovieName;

		static MWCampaign
			*Instance;
		static MWCampaign
			*TrainingInstance;
		static MWCampaign
			*MasterTrialsInstance;
		static MWCampaign
			*WaveInstance;
		int
			m_currentOp;
		bool
			m_hasRescuedHostage;
		
	};
}

