#include "MW4Headers.hpp"

#include "MWCampaign.hpp"
#include "MWMission.hpp"
#include "MW4Shell.hpp"
#include "MWApplication.hpp"

#include <Adept\Tool.hpp>
#include <Stuff\NameList.hpp>

//#############################################################################
//####################     MWMissionMapPoint   ################################
//#############################################################################

void
	MWMissionMapPoint::ConstructMissionMapPointStream(Stuff::Page *page, Stuff::MemoryStream *stream)
{
	Check_Object(page);
	Check_Pointer(stream);

	const char *type_string;
	int type = 0;
	page->GetEntry("Type", &type_string, true);
	if(!_stricmp(type_string, "NavPoint"))
		type = NavPointType;
	else if(!_stricmp(type_string, "DropPoint"))
		type = DropPointType;
	else if(!_stricmp(type_string, "InfoPoint"))
		type = InfoPointType;
	else if(!_stricmp(type_string, "GeneralInfoPoint"))
		type = GeneralInfoPointType;
	else
		STOP(("%s Is not a valid map point type", type_string));

	*stream << type;

	int value;
	page->GetEntry("XLocation", &value, true);
	*stream << value;
	page->GetEntry("YLocation", &value, true);
	*stream << value;
	page->GetEntry("Width", &value, true);
	*stream << value;
	page->GetEntry("Height", &value, true);
	*stream << value;

	page->GetEntry("PointNameIndex", &value, true);
	*stream << value;
	page->GetEntry("RollOverIndex", &value, true);
	*stream << value;
	page->GetEntry("RightClickIndex", &value, true);
	*stream << value;

	if(type >= InfoPointType)
	{
		const char *icon_name;
		MString icon_mstring;
		page->GetEntry("IconName", &icon_name, true);
		icon_mstring = icon_name;
		*stream << icon_mstring;
	}
}

//#############################################################################
//####################     MWCampaignInterfacePlug   ##########################
//#############################################################################

MWCampaignInterfacePlug::MWCampaignInterfacePlug(Stuff::MemoryStream *stream) :
	Plug(Plug::DefaultData),
	m_navPoints(NULL),
	m_dropPoints(NULL),
	m_infoPoints(NULL),
	m_generalInfoPoints(NULL)
{
	*stream >> m_xLoc;
	*stream >> m_yLoc;
	*stream >> m_height;
	*stream >> m_width;
	*stream >> m_ID;
	*stream >> m_rollOverID;
	*stream >> m_rightClickID;
	*stream >> m_iconName;
	*stream >> m_mapTextureName;

	//read in the mission point streams
	int point_count;
	*stream >> point_count;
	for(int i=0; i< point_count; i++)
	{
		MWMissionMapPoint *map_point = new MWMissionMapPoint(stream);
		Check_Object(map_point);

		switch(map_point->m_pointType)
		{
		case MWMissionMapPoint::NavPointType:
			m_navPoints.Add(map_point);
			break;
		case MWMissionMapPoint::DropPointType:
			m_dropPoints.Add(map_point);
			break;
		case MWMissionMapPoint::InfoPointType:
			m_infoPoints.Add(map_point);
		case MWMissionMapPoint::GeneralInfoPointType:
			m_generalInfoPoints.Add(map_point);
		}
	}
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
MWCampaignInterfacePlug::~MWCampaignInterfacePlug()
{
	m_navPoints.DeletePlugs();
	m_dropPoints.DeletePlugs();
	m_infoPoints.DeletePlugs();
	m_generalInfoPoints.DeletePlugs();
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	MWCampaignInterfacePlug::ConstructCampaignInterfaceStream(MemoryStream *stream, Page *page)
{
	Check_Object(page);
	Check_Pointer(stream);
	
	int value = 0;
	page->GetEntry("MissionRegionXLocation", &value);
	*stream << value;
	value = 0;
	page->GetEntry("MissionRegionYLocation", &value);
	*stream << value;
	value = 0;
	page->GetEntry("MissionRegionHeight", &value);
	*stream << value;
	value = 0;
	page->GetEntry("MissionRegionWidth", &value);
	*stream << value;
	value = 0;
	page->GetEntry("DisplayNameIndex", &value);
	*stream << value;
	value = 0;
	page->GetEntry("RollOverIndex", &value);
	*stream << value;
	value = 0;
	page->GetEntry("RightClickIndex", &value);
	*stream << value;

	const char *name;
	MString m_string = " ";
	if(page->GetEntry("MapIconName", &name))
		m_string = name;
	*stream << m_string;
	m_string = " ";
	if(page->GetEntry("MapTextureName", &name))
		m_string = name;
	*stream << m_string;

	//Now we need to build in all the mission parameters
	const char *map_info_file;
	int point_count = 0;
	if(page->GetEntry("MissionMapInfo", &map_info_file))
	{
		NotationFile *note_file = new NotationFile(map_info_file);
		Check_Object(note_file);
		NotationFile::PageIterator *pages = note_file->MakePageIterator();
		Page *point_page;
		Check_Object(pages);
		*stream << pages->GetSize();
		while((point_page = pages->ReadAndNext()) != NULL)
		{
			Check_Object(point_page);
			MWMissionMapPoint::ConstructMissionMapPointStream(point_page, stream);
		}
		delete pages;
		delete note_file;
	}
	else
	{
		*stream << point_count;
	}
}

//#############################################################################
//####################     CampaignMissionPlug   ##############################
//#############################################################################

CampaignMissionPlug::CampaignMissionPlug(const char *mission_name) :
	Plug(Plug::DefaultData),
	m_missionsNeededToDisplay(NULL)
{
	Check_Pointer(mission_name);
	
	m_missionName = mission_name;
	m_status = -1;
	m_type = MWCampaign::NormalMissionType;
	m_triggerPercentage = 100;
	m_triggerMission = NULL;
	m_opNumber = -1;
	m_displayNameIndex = -1;
	m_NumLancemates = 1;
	m_interfacePlugID = ResourceID::Null;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
CampaignMissionPlug::~CampaignMissionPlug()
{
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	CampaignMissionPlug::SetTriggerMission(CampaignMissionPlug *mission_plug, int percent)
{
	Check_Object(this);
	Check_Object(mission_plug);

	m_triggerMission = mission_plug;
	m_triggerPercentage = percent;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	CampaignMissionPlug::AddDisplayDependancy(CampaignMissionPlug *mission_plug)
{
	Check_Object(this);
	Check_Object(mission_plug);

	m_missionsNeededToDisplay.Add(mission_plug);
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	CampaignMissionPlug::RemoveDisplayDependancy(CampaignMissionPlug *mission_plug)
{
	Check_Object(this);
	Check_Object(mission_plug);

	m_missionsNeededToDisplay.Remove(mission_plug);
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	CampaignMissionPlug::WriteToText(Stuff::Page *page)
{
	Check_Object(this);
	Check_Pointer(page);

	page->SetEntry("Status", MWCampaign::StatusAsciiToText(m_status));
	page->SetEntry("NumLancemates",	m_NumLancemates);

	page->SetEntry("Type", MWCampaign::MissionTypeAsciiToText(m_type));
	if(m_triggerMission)
	{
		page->SetEntry("TriggerMission", m_triggerMission->m_missionName);
		page->SetEntry("TriggerPercentage", m_triggerPercentage);
	}

	ChainIteratorOf<CampaignMissionPlug *> iterator(&m_missionsNeededToDisplay);
	CampaignMissionPlug *mission_plug;
	while((mission_plug = iterator.ReadAndNext()) != NULL)
	{
		Check_Object(mission_plug);
		page->AppendEntry("MissionNeededToDisplay", mission_plug->m_missionName);
	}
}

//#############################################################################
//####################     OperationPlug   ####################################
//#############################################################################

void
	OperationPlug::ConstructOperationStream(Page *page, MemoryStream *stream)
{
	Check_Pointer(page);
	Check_Pointer(stream);
	
	int name_index = -1;
	page->GetEntry("OperationNameIndex", &name_index, true);
	*stream << name_index;

	const char *texture_name;
	MString texture_string;

	page->GetEntry("MapTextureName", &texture_name, true);
	texture_string = texture_name;
	*stream << texture_string;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	OperationPlug::SaveToStream(Stuff::MemoryStream *stream)
{
	Check_Pointer(stream);
	
	*stream << m_nameIndex;
	*stream << m_mapTextureName;
}

//#############################################################################
//####################     MoviePlug   ########################################
//#############################################################################
void
	MoviePlug::ConstructMoviePlugStream(Page *page, MemoryStream *stream)
{
	Check_Pointer(page);
	Check_Pointer(stream);

	const char *temp_string;
	MString stream_string;

	page->GetEntry("MovieName", &temp_string, true);
	stream_string = temp_string;
	*stream << stream_string;

	int type;
	page->GetEntry("Type", &temp_string, true);
	type = MovieTypeStringToAscii(temp_string);
	*stream << type;

	int delay = 0;
	page->GetEntry("Delay", &delay);
	*stream << delay;

	//This is just needed to fill the default stream since this will always be false
	bool has_played = false;
	*stream << has_played;

	page->GetEntry("TriggerName", &temp_string, true);
	stream_string = temp_string;
	*stream << stream_string;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	MoviePlug::SaveToStream(MemoryStream *stream)
{
	Check_Object(this);
	Check_Pointer(stream);

	*stream << m_movieName;
	*stream << m_type;
	*stream << m_delay;
	*stream << m_hasPlayed;
	*stream << m_triggerName;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
int
	MoviePlug::MovieTypeStringToAscii(const char *type_string)
{	
	if(!_stricmp(type_string, "MissionSuccess"))
		return MissionSuccessType;
	if(!_stricmp(type_string, "MissionSelection"))
		return MissionSelectionType;
	if(!_stricmp(type_string, "LancemateDeath"))
		return LancemateDeathType;
	if(!_stricmp(type_string, "LancemateReturn"))
		return LancemateReturnType;

	PAUSE(("That is a Movie Plug Type: %s", type_string));
	return -1;
}

//#############################################################################
//####################     MovieManager   #####################################
//#############################################################################

MWMovieManager::MWMovieManager() :
	m_successMovies(NULL),
	m_selectionMovies(NULL),
	m_lancemateDeathMovies(NULL),
	m_lancemateReturnMovies(NULL),
	m_delayedMovies(NULL, false)
{
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
MWMovieManager::~MWMovieManager()
{
	m_successMovies.DeletePlugs();
	m_selectionMovies.DeletePlugs();
	m_lancemateDeathMovies.DeletePlugs();
	m_lancemateReturnMovies.DeletePlugs();
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	MWMovieManager::ExecuteMissionSuccess(const char *mission_name)
{
	Check_Pointer(mission_name);

	//Ok here we want to run through and play all movies in the success chain
	ChainIteratorOf<MoviePlug *> iterator(&m_successMovies);
	MoviePlug *movie_plug;
	while((movie_plug = iterator.ReadAndNext()) != NULL)
	{
		Check_Object(movie_plug);
		if(!stricmp(movie_plug->GetTriggerName(), mission_name))
		{
			if(MW4Shell::Instance)
				StartMovie(movie_plug);
		}
	}
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	MWMovieManager::ExecuteMissionSelection(const char *mission_name)
{
	Check_Pointer(mission_name);
	ChainIteratorOf<MoviePlug *> iterator(&m_selectionMovies);
	MoviePlug *movie_plug;
	while((movie_plug = iterator.ReadAndNext()) != NULL)
	{
		Check_Object(movie_plug);
		if(!stricmp(movie_plug->GetTriggerName(), mission_name))
		{
			if((MW4Shell::Instance) && (!movie_plug->m_playedThisSelection))
			{
				StartMovie(movie_plug);
				movie_plug->m_playedThisSelection = true;
			}
		}
	}
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	MWMovieManager::ExecuteLancemateDeath(const char *lance_name)
{
	Check_Pointer(lance_name);
	ChainIteratorOf<MoviePlug *> iterator(&m_lancemateDeathMovies);
	MoviePlug *movie_plug;
	while((movie_plug = iterator.ReadAndNext()) != NULL)
	{
		Check_Object(movie_plug);
		if(!stricmp(movie_plug->GetTriggerName(), lance_name))
		{
			if(MW4Shell::Instance)
				StartMovie(movie_plug);
		}
	}
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	MWMovieManager::ExecuteLancemateReturn(const char *lance_name)
{
	Check_Pointer(lance_name);
	ChainIteratorOf<MoviePlug *> iterator(&m_lancemateReturnMovies);
	MoviePlug *movie_plug;
	while((movie_plug = iterator.ReadAndNext()) != NULL)
	{
		Check_Object(movie_plug);
		if(!stricmp(movie_plug->GetTriggerName(), lance_name))
		{
			if(MW4Shell::Instance)
				StartMovie(movie_plug);
		}
	}
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	MWMovieManager::StartMovie(MoviePlug *movie_plug)
{
	Check_Object(movie_plug);

	Time execute_time = gos_GetElapsedTime();
	execute_time += movie_plug->GetMovieDelay();
	m_delayedMovies.AddValue(movie_plug, execute_time);
}


//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	MWMovieManager::Execute()
{
	Time now_time = gos_GetElapsedTime();

	SortedChainIteratorOf<MoviePlug *, Time> iterator(&m_delayedMovies);
	while((iterator.GetCurrent() != NULL) && (iterator.GetValue() <= now_time))
	{
		MoviePlug *movie_plug;
		Time execute_time = iterator.GetValue();
		movie_plug = iterator.GetCurrent();
		iterator.Remove();

		if((!MW4Shell::Instance->m_moviePlaying) && (!MW4Shell::Instance->m_moviesStopped))
		{
			MW4Shell::Instance->m_moviePlaying = 1;
			MW4Shell::Instance->AddNewMovie(movie_plug->GetMovieName());
		}
		else
			m_delayedMovies.AddValue(movie_plug, execute_time + 0.28f);
	}
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	MWMovieManager::AddMoviePlug(MoviePlug *new_movie)
{
	Check_Object(new_movie);

	switch(new_movie->GetMovieType())
	{
	case MoviePlug::MissionSuccessType:
		m_successMovies.Add(new_movie);
		break;
	case MoviePlug::MissionSelectionType:
		m_selectionMovies.Add(new_movie);
		break;
	case MoviePlug::LancemateDeathType:
		m_lancemateDeathMovies.Add(new_movie);
		break;
	case MoviePlug::LancemateReturnType:
		m_lancemateReturnMovies.Add(new_movie);
		break;
	}
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	MWMovieManager::SaveToStream(MemoryStream *stream)
{
	Check_Pointer(stream);
	
	int num_movies = 0;
	num_movies += m_successMovies.GetSize();
	num_movies += m_selectionMovies.GetSize();
	num_movies += m_lancemateDeathMovies.GetSize();
	num_movies += m_lancemateReturnMovies.GetSize();

	*stream << num_movies;

	ChainIteratorOf<MoviePlug *> success_iterator(&m_successMovies);
	ChainIteratorOf<MoviePlug *> selection_iterator(&m_selectionMovies);
	ChainIteratorOf<MoviePlug *> lance_death_iterator(&m_lancemateDeathMovies);
	ChainIteratorOf<MoviePlug *> lance_return_iterator(&m_lancemateReturnMovies);
	MoviePlug *movie_plug;

	while((movie_plug = success_iterator.ReadAndNext()) != NULL)
	{
		Check_Object(movie_plug);
		movie_plug->SaveToStream(stream);
	}
	while((movie_plug = selection_iterator.ReadAndNext()) != NULL)
	{
		Check_Object(movie_plug);
		movie_plug->SaveToStream(stream);
	}
	while((movie_plug = lance_death_iterator.ReadAndNext()) != NULL)
	{
		Check_Object(movie_plug);
		movie_plug->SaveToStream(stream);
	}
	while((movie_plug = lance_return_iterator.ReadAndNext()) != NULL)
	{
		Check_Object(movie_plug);
		movie_plug->SaveToStream(stream);
	}

}

//#############################################################################
//###########################    Campaign   ###################################
//#############################################################################

MWCampaign::ClassData*
	MWCampaign::DefaultData = NULL;
MWCampaign*
	MWCampaign::Instance = NULL;
MWCampaign*
	MWCampaign::TrainingInstance = NULL;
MWCampaign*
	MWCampaign::WaveInstance = NULL;
MWCampaign*
	MWCampaign::MasterTrialsInstance = NULL;
HGOSHEAP
	MWCampaign::s_Heap = NULL;

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	MWCampaign::InitializeClass()
{
	Verify(!s_Heap);
	s_Heap = gos_CreateMemoryHeap("MWCampaign", 0, g_LibraryHeap);
	Check_Pointer(s_Heap);

	Verify(!DefaultData);
	DefaultData =
		new ClassData(
			MWCampaignClassID,
			"MechWarrior4::MWCampaign",
			Receiver::DefaultData,
			0,
			NULL
		);
	Check_Object(DefaultData);
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	MWCampaign::TerminateClass()
{
	Check_Object(DefaultData);
	delete DefaultData;
	DefaultData = NULL;

	Check_Pointer(s_Heap);
	gos_DestroyMemoryHeap(s_Heap);
	s_Heap = NULL;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
MWCampaign::MWCampaign(MemoryStream *stream):
	Receiver(DefaultData),
	m_missions(NULL),
	m_operations(NULL, true)
{
	Check_Pointer(stream);


	//Load the movies
	m_movieManager = new MWMovieManager();

	int num_movies;
	*stream >> num_movies;
	for(int i=0; i<num_movies; i++)
	{
		MoviePlug *movie_plug = new MoviePlug(stream);
		Check_Object(movie_plug);

		m_movieManager->AddMoviePlug(movie_plug);
	}

	//Load the Ops
	int num_ops;
	*stream >> num_ops;
	for(i=0; i<num_ops; i++)
	{
		OperationPlug *op_plug = new OperationPlug(stream);
		Check_Object(op_plug);

		op_plug->SetID(i);
		m_operations.AddValue(op_plug, i);
	}

	*stream >> m_currentOp;

	//Load the missions
	int num_missions;
	*stream >> num_missions;

	for(i=0; i<num_missions; i++)
	{
		MString mission_name;
		*stream >> mission_name;

		CampaignMissionPlug *mission_plug =
			new CampaignMissionPlug((const char *)mission_name);
		m_missions.AddPlug(mission_plug);
	}

	ChainIteratorOf<CampaignMissionPlug *> iterator(&m_missions);
	CampaignMissionPlug *mission_plug;

	while((mission_plug = iterator.ReadAndNext()) != NULL)
	{
		Check_Object(mission_plug);

		int display_index;
		*stream >> display_index;
		mission_plug->SetDisplayNameIndex(display_index);

		int status;
		*stream >> status;
		mission_plug->SetStatus(status);

		int numlance;
		*stream >> numlance;
		mission_plug->SetNumLancemates (numlance);

		int type;
		*stream >> type;
		mission_plug->SetType(type);

		int op_number;
		*stream >> op_number;
		mission_plug->SetOpNumber(op_number);

		int advance_to_op;
		*stream >> advance_to_op;
		mission_plug->SetAdvanceToOperation(advance_to_op);

		OperationPlug *op_plug = m_operations.Find(op_number);
		if(op_plug)
			op_plug->m_missions.AddPlug(op_plug);

		ResourceID interface_id;
		*stream >> interface_id;
		mission_plug->SetInterfacePlugID(interface_id);

		int does_end;
		*stream >> does_end;
		mission_plug->m_doesEnd = does_end;
		
		MString end_movie;
		*stream >> end_movie;
		mission_plug->m_finalMovieName = end_movie;

		int change_time;
		*stream >> change_time;
		mission_plug->m_canChangeTime = change_time;

		bool has_trigger;
		*stream >> has_trigger;
		if(has_trigger)
		{
			MString trigger_mission_name;
			int percentage;

			*stream >> trigger_mission_name;
			*stream >> percentage;
			
			CampaignMissionPlug *trigger_mission;
			trigger_mission = FindMission(trigger_mission_name);
			Check_Object(trigger_mission);
			mission_plug->SetTriggerMission(trigger_mission, percentage);
		}


		int mission_num;
		*stream >> mission_num;

		for(int i=0; i<mission_num; i++)
		{
			MString dependant_mission_name;
			*stream >> dependant_mission_name;
			CampaignMissionPlug *dependant_mission;

			dependant_mission = FindMission(dependant_mission_name);
			if(dependant_mission)
				mission_plug->AddDisplayDependancy(dependant_mission);
#if defined(LAB_ONLY)
			else
				PAUSE(("There is no mission with the name %s", (const char *)dependant_mission_name));
#endif
		}
		
	}
	
	MString last_mission_name;
	*stream >> last_mission_name;
	*stream >> m_finalMovieName;

	m_lastMissionPlug = FindMission(last_mission_name);
	m_missionsIterator = new ChainIteratorOf<CampaignMissionPlug*>(&m_missions);

	//Now walk the iterator to be at the current mission plug
	//DAVE HERE!!!!
	CampaignMissionPlug *temp_plug = m_missionsIterator->GetCurrent();
	if(temp_plug)
	{
		while((temp_plug != NULL) && ((temp_plug->m_status == Completed) || (temp_plug->m_opNumber != m_currentOp)))
		{
			if(temp_plug->m_status == Completed)
				m_lastMissionPlug = temp_plug;

			temp_plug = m_missionsIterator->GetCurrent();
			if(temp_plug)
				m_missionsIterator->Next();
		}
	}
	//Now do our set for the next mission
	m_currentMissionPlug = temp_plug;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
CampaignMissionPlug*
	MWCampaign::FindMission(MString mission_name)
{
	//
	// We can't use sorted chain or the data doesn't appear in the same order as the
	// campaign source file. But the normal chain does not have a find value.
	//
	Verify(mission_name);
	mission_name.ToLower();

	ChainIteratorOf<CampaignMissionPlug *> find_iterator(&m_missions);
	CampaignMissionPlug *cur_mission;
	while ((cur_mission = find_iterator.ReadAndNext()) != NULL)
	{
	if (cur_mission->m_missionName == mission_name)
	  break;
	}
	return cur_mission;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
CampaignMissionPlug*
	MWCampaign::FindMission(int display_index)
{
	ChainIteratorOf<CampaignMissionPlug *> find_iterator(&m_missions);
	CampaignMissionPlug *cur_mission;
	while ((cur_mission = find_iterator.ReadAndNext()) != NULL)
	{
	if (cur_mission->m_displayNameIndex == display_index)
	  break;
	}
	return cur_mission;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
MWCampaign::~MWCampaign()
{
	Check_Object(this);
	m_missionsIterator->DeletePlugs();
	m_operations.DeletePlugs();
	delete m_missionsIterator;
	delete m_movieManager;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
MWCampaign*
	MWCampaign::MakeNewCampaign(const char *campaign_name)
{
	Check_Pointer(campaign_name);

	Resource campaign_resource(campaign_name);
	Verify(campaign_resource.DoesResourceExist());
	campaign_resource.LoadData();

	gos_PushCurrentHeap(s_Heap);
	MWCampaign *new_campaign;
	new_campaign = new MWCampaign(&campaign_resource);
	Check_Object(new_campaign);
	gos_PopCurrentHeap();

	return new_campaign;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
MWCampaign*
	MWCampaign::MakeNewCampaign(const ResourceID& campaign_id)
{
	Verify(campaign_id != ResourceID::Null);

	Resource campaign_resource(campaign_id);
	Verify(campaign_resource.DoesResourceExist());
	campaign_resource.LoadData();

	gos_PushCurrentHeap(s_Heap);
	MWCampaign *new_campaign;
	new_campaign = new MWCampaign(&campaign_resource);
	Check_Object(new_campaign);
	gos_PopCurrentHeap();

	return new_campaign;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	MWCampaign::ConstructCampaignStream(
		MemoryStream *stream,
		NotationFile *notation_file
	)
{
	Check_Pointer(stream);

	NotationFile::PageIterator *pages = notation_file->MakePageIterator();
	Check_Object(pages);

	Page *page;
	int op_size = 0;
	int mission_size = 0;
	int movie_size = 0;
	//First figure out the sizes
	while((page = pages->ReadAndNext()) != NULL)
	{
		Check_Object(page);
		const char *page_name = page->GetName();
		if(strstr(page_name, "operation"))
			op_size ++;
		else if(strstr(page_name, "movie"))
			movie_size ++;
		else
			mission_size ++;
	}
	//First we do the movies
	*stream << movie_size;
	pages->First();
	while((page = pages->ReadAndNext()) != NULL)
	{
		Check_Pointer(page);
		const char *page_name = page->GetName();
		if(strstr(page_name, "movie"))
		{
			MoviePlug::ConstructMoviePlugStream(page, stream);
		}
	}
	//Second we do the Operations
	*stream << op_size;
	pages->First();
	while((page = pages->ReadAndNext()) != NULL)
	{
		Check_Pointer(page);
		const char *page_name = page->GetName();
		if(strstr(page_name, "operation"))
		{
			OperationPlug::ConstructOperationStream(page, stream);
		}
	}
	
	int current_op = 0;
	*stream << current_op;
	//Now do the missions

	*stream << mission_size;
	pages->First();
	while((page = pages->ReadAndNext()) != NULL)
	{
		Check_Pointer(page);
		const char *page_name = page->GetName();
		if((!strstr(page_name, "operation")) && (!strstr(page_name, "movie")))
		{
			MString instance_string = page_name;
			*stream << instance_string;
		}
	}
	pages->First();
	MString first_mission_name;
	while((page = pages->ReadAndNext()) != NULL)
	{
		Check_Pointer(page);

		const char *page_name = page->GetName();
		if((!strstr(page_name, "operation")) && (!strstr(page_name, "movie")))
		{
			if(!first_mission_name)
				first_mission_name = page_name;

			int display_index = -1;
			page->GetEntry("DisplayNameIndex", &display_index);
			*stream << display_index;

			const char *status_string;
			page->GetEntry("Status", &status_string, true);

			*stream << StatusTextToAscii(status_string);

			int numlance = 1;
			page->GetEntry("NumLancemates",&numlance);
			*stream << numlance;

			const char *type_string;
			int type = NormalMissionType;
			if(page->GetEntry("Type", &type_string))
			{
				type = MissionTypeTextToAscii(type_string);
			}

			*stream << type;

			int op_number = 0;
			page->GetEntry("OPNumber", &op_number);

			*stream << op_number;

			int advance_to_op = op_number;
			page->GetEntry("AdvanceToOpNumber", &advance_to_op);
			
			*stream << advance_to_op;
			
			DynamicMemoryStream interface_stream;
			MWCampaignInterfacePlug::ConstructCampaignInterfaceStream(&interface_stream, page);
			if(interface_stream.GetSize() > 0)
			{
				MString interface_resource_name = page_name;
				interface_resource_name += "{CampaignInterfacePlug}";
				Resource campaign_interface_resource(interface_resource_name);
				FileDependencies dependencies(*notation_file->GetFileDependencies());
				campaign_interface_resource.Save(&interface_stream, &dependencies);
				*stream << campaign_interface_resource.GetResourceID();
			}
			else
			{
				*stream << ResourceID::Null;
			}

			int does_end = 0;
			page->GetEntry("DoesEndCampaign", &does_end);
			*stream << does_end;

			const char *end_movie = "";
			MString end_movie_string;
			page->GetEntry("TriggerEndMovieName", &end_movie);
			end_movie_string = end_movie;
			*stream << end_movie_string;

			int change_time = 1;
			page->GetEntry("CanChangeTime", &change_time);
			*stream << change_time;

			const char *trigger_mission_name;
			if(page->GetEntry("TriggerMission", &trigger_mission_name))
			{
				MString trigger_name = trigger_mission_name;
				int percentage = 100;
				bool has_trigger = true;

				page->GetEntry("TriggerPercentage", &percentage);
				*stream << has_trigger;
				*stream << trigger_name;
				*stream << percentage;
			}
			else
			{
				bool has_trigger = false;
				*stream << has_trigger;
			}

			ChainOf<Note*> *missions = page->MakeNoteChain("RevealOnComplete");
			Check_Object(missions);
			Page::NoteIterator mission_list(missions);
			Note *mission_entry;
			*stream << mission_list.GetSize();
			while ((mission_entry = mission_list.ReadAndNext()) != NULL)
			{
				Check_Object(mission_entry);
				const char *mission_data = NULL;
				mission_entry->GetEntry(&mission_data);
				Check_Pointer(mission_data);

				MString mission_name = mission_data;
				
				*stream << mission_name;
			}
			delete missions;
		}
	}

	//Save out the first mission name
	*stream << first_mission_name;
	MString end_movie_name;
	*stream << end_movie_name;
	delete pages;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	MWCampaign::Save(MemoryStream *stream)
{
	Check_Object(this);
	Check_Pointer(stream);

	//First save all the movies in the movie manager
	m_movieManager->SaveToStream(stream);

	//Second save all the operations
	SortedChainIteratorOf<OperationPlug *, int> op_iterator(&m_operations);
	OperationPlug *op_plug;

	int op_size = op_iterator.GetSize();

	*stream << op_size;
	while((op_plug = op_iterator.ReadAndNext()) != NULL)
	{
		Check_Object(op_plug);
		op_plug->SaveToStream(stream);
	}
	
	*stream << m_currentOp;

	//Last save all the mission data
	ChainIteratorOf<CampaignMissionPlug*> iterator(&m_missions);
	CampaignMissionPlug *mission_plug;

	int size = iterator.GetSize();

	*stream << size;
	while((mission_plug = iterator.ReadAndNext()) != NULL)
	{
		Check_Object(mission_plug);
		*stream << mission_plug->m_missionName;
	}

	iterator.First();
	while((mission_plug = iterator.ReadAndNext()) != NULL)
	{
		Check_Object(mission_plug);

		*stream << mission_plug->m_displayNameIndex;
		*stream << mission_plug->m_status;
		*stream << mission_plug->m_NumLancemates;
		*stream << mission_plug->m_type;
		*stream << mission_plug->m_opNumber;
		*stream << mission_plug->m_advacnceToOperation;
		*stream << mission_plug->m_interfacePlugID;
		*stream << mission_plug->m_doesEnd;
		*stream << mission_plug->m_finalMovieName;
		*stream << mission_plug->m_canChangeTime;

		bool does_trigger_mission = false;
		if(mission_plug->m_triggerMission != NULL)
		{
			does_trigger_mission = true;
		}
		*stream << does_trigger_mission;

		if(does_trigger_mission)
		{
			*stream << mission_plug->m_triggerMission->m_missionName;
			*stream << mission_plug->m_triggerPercentage;
		}

		ChainIteratorOf<CampaignMissionPlug *> display_missions(&mission_plug->m_missionsNeededToDisplay);
		CampaignMissionPlug *display_plug;

		size = display_missions.GetSize();
		*stream << size;
		while ((display_plug = display_missions.ReadAndNext()) != NULL)
		{
			Check_Object(display_plug);
			*stream << display_plug->m_missionName;
		}
	}
	*stream << m_currentMissionPlug->m_missionName;
	*stream << m_finalMovieName;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	MWCampaign::WriteToText(const char *file_name)
{
	
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
int
	MWCampaign::StatusTextToAscii(const char *status_string)
{

	if(!_stricmp(status_string, "Hidden"))
		return Hidden;
	if(!_stricmp(status_string, "Displayed"))
		return Displayed;
	if(!_stricmp(status_string, "Completed"))
		return Completed;

	PAUSE(("That is not a valid status string %s", status_string));
	return -1;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
const char *
	MWCampaign::StatusAsciiToText(int status)
{
	switch(status)
	{
	case Hidden:
		return "Hidden";
	case Displayed:
		return "Displayed";
	case Completed:
		return "Completed";
	}

	PAUSE(("That is not a valid status value"));
	return "Bad";
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
int
	MWCampaign::MissionTypeTextToAscii(const char *type_string)
{

	if(!_stricmp(type_string, "Normal"))
		return NormalMissionType;
	if(!_stricmp(type_string, "Defend"))
		return DefendMissionType;
	if(!_stricmp(type_string, "Rescue"))
		return RescueMissionType;

	PAUSE(("That is not a valid mission type string %s", type_string));
	return -1;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
const char *
	MWCampaign::MissionTypeAsciiToText(int type)
{
	switch(type)
	{
	case NormalMissionType:
		return "Normal";
	case DefendMissionType:
		return "Defend";
	case RescueMissionType:
		return "Rescue";
	}

	PAUSE(("That is not a valid Mission Type"));
	return "Bad";
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
const char *
	MWCampaign::GetNextMission()
{
	Check_Object(this);

	CampaignMissionPlug *mission;
	mission = m_missionsIterator->GetCurrent();
	m_missionsIterator->Next();
	if(!m_missionsIterator->GetCurrent())
		m_missionsIterator->First();

	return mission->m_missionName;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
CampaignMissionPlug*
	MWCampaign::GetNextMissionPlug()
{
	Check_Object(this);

	CampaignMissionPlug *mission;
	mission = m_missionsIterator->GetCurrent();
	if(mission)
	{
		m_missionsIterator->Next();
	}
	if(!m_missionsIterator->GetCurrent())
		m_missionsIterator->First();

	//This means that there is only one mission in the chain
	if(!mission)
		mission = m_missionsIterator->GetCurrent();

	return mission;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	MWCampaign::MissionSuccess()
{
	Check_Object(this);

	if(m_currentMissionPlug)
	{
		m_currentMissionPlug->SetStatus(Completed);
		m_currentOp = m_currentMissionPlug->m_advacnceToOperation;
		if(!m_currentMissionPlug->m_doesEnd)
			m_finalMovieName = m_currentMissionPlug->m_finalMovieName;

		//
		//--------------------------------------
		//Check if we need to rescue a lancemate
		//--------------------------------------
		//
		if(m_currentMissionPlug->m_triggerMission)
		{
			if((m_currentMissionPlug->m_triggerMission->m_type == RescueMissionType) &&
				(m_currentMissionPlug->m_triggerMission->m_status != Completed))
				//&& we lost a lancemate
			{	
				m_currentMissionPlug->m_triggerMission->SetStatus(Displayed);
			}
		}

		//
		//-----------------------------------------------------
		//Run Through the missions and check their dependancies
		//-----------------------------------------------------
		//
		CampaignMissionPlug *mission;
		ChainIteratorOf<CampaignMissionPlug *> iterator(&m_missions);
		while((mission = iterator.ReadAndNext()) != NULL)
		{
			Check_Object(mission);
			if(mission->m_missionsNeededToDisplay.IsPlugMember(m_currentMissionPlug))
			{
				mission->m_missionsNeededToDisplay.Remove(m_currentMissionPlug);
				if(mission->m_missionsNeededToDisplay.IsEmpty())
					mission->SetStatus(Displayed);
			}
		}

		//
		//-----------------------------------------------------------------
		//Check to see if we are going to be attacked...if so set the timer
		//-----------------------------------------------------------------
		//
		if(m_currentMissionPlug->m_triggerMission)
		{
			if((m_currentMissionPlug->m_triggerMission->m_type == DefendMissionType) &&
				(m_currentMissionPlug->m_triggerMission->m_status != Completed))
				//&& we lost a lancemate
			{	
				//We need to some how set a timer here....and then launch!
				m_currentMissionPlug->m_triggerMission->SetStatus(Displayed);
			}
		}
	}
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
int
	MWCampaign::GetOPMissionCount()
{
	Check_Object(this);

	CampaignMissionPlug *mission;
	ChainIteratorOf<CampaignMissionPlug *> iterator(&m_missions);
	int mission_count = 0;
	while((mission = iterator.ReadAndNext()) != NULL)
	{
		Check_Object(mission);
		if((mission->m_status != Hidden) && (mission->m_opNumber == m_currentOp))
			mission_count ++;
	}

	return mission_count;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	MWCampaign::TestInstance()
{
	Verify(IsDerivedFrom(DefaultData));
}