//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose: 
//
//=====================================================================================//

#include "stdafx.h"
#include "Manifest.h"
#include "CustomMessages.h"
#include "GlobalFunctions.h"
#include "MainFrm.h"
#include "MapDoc.h"
#include "MapSolid.h"
#include "MapWorld.h"
#include "MapInstance.h"
#include "ToolManager.h"
#include "ChunkFile.h"
#include "ManifestDialog.h"
#include "History.h"
#include "HelperFactory.h"
#include "SaveInfo.h"
#include "tier2/tier2.h"
#include "p4lib/ip4.h"

// memdbgon must be the last include file in a .cpp file!!!
#include <tier0/memdbgon.h>

IMPLEMENT_DYNCREATE(CManifest, CMapDoc)


BEGIN_MESSAGE_MAP(CManifest, CMapDoc)
	//{{AFX_MSG_MAP(CManifest)
	ON_COMMAND(ID_FILE_SAVE_AS, OnFileSaveAs)
	//}}AFX_MSG_MAP
END_MESSAGE_MAP()


IMPLEMENT_MAPCLASS( CManifestInstance )


//-----------------------------------------------------------------------------
// Purpose: default constructor
//-----------------------------------------------------------------------------
CManifestMap::CManifestMap( void )
{
	m_Map = NULL;
	m_RelativeMapFileName = "";
	m_AbsoluteMapFileName = "";
	m_FriendlyName = "unnamed";
	m_bTopLevelMap = false;
	m_bPrimaryMap = false;
	m_bProtected = false;
	m_bReadOnly = false;
	m_bIsVersionControlled = false;
	m_bCheckedOut = false;
	m_bDefaultCheckin = false;
	m_bVisible = true;
	m_Entity = NULL;
	m_InternalID = 0;
}


//-----------------------------------------------------------------------------
// Purpose: returns true if the manifest map is editable
//-----------------------------------------------------------------------------
bool CManifestMap::IsEditable( void )
{
	return ( m_bProtected == false && m_bReadOnly == false && m_bPrimaryMap );
}


//-----------------------------------------------------------------------------
// Purpose: default constructor
//-----------------------------------------------------------------------------
CManifestInstance::CManifestInstance( void ) :
	CMapEntity()
{
	m_pManifestMap = NULL;
}


//-----------------------------------------------------------------------------
// Purpose: default constructor
//-----------------------------------------------------------------------------
CManifestInstance::CManifestInstance( CManifestMap *pManifestMap ) :
	CMapEntity()
{
	m_pManifestMap = pManifestMap;
}


//-----------------------------------------------------------------------------
// Purpose: returns true if the manifest map this instance owns is editable
//-----------------------------------------------------------------------------
bool CManifestInstance::IsEditable( void )
{
	return m_pManifestMap->IsEditable();
}


//-----------------------------------------------------------------------------
// Purpose: default constructor
//-----------------------------------------------------------------------------
CManifest::CManifest( void ) :
	CMapDoc()
{
	m_bIsValid = false;
	m_bRelocateSave = false;
	m_ManifestDir[ 0 ] = 0;
	m_pPrimaryMap = NULL;
	m_ManifestWorld = NULL;
	m_NextInternalID = 1;
	m_bManifestChanged = false;
	m_bManifestUserPrefsChanged = false;
	m_pSaveUndo = m_pUndo;
	m_pSaveRedo = m_pRedo;
	m_bReadOnly = true;
	m_bIsVersionControlled = false;
	m_bCheckedOut = false;
	m_bDefaultCheckin = false;
}


//-----------------------------------------------------------------------------
// Purpose: default destructor
//-----------------------------------------------------------------------------
CManifest::~CManifest( void )
{
	m_Maps.PurgeAndDeleteElements();
}


//-----------------------------------------------------------------------------
// Purpose: this function will parse through the known keys for the manifest map entry
// Input  : szKey - the key name
//			szValue - the value
//			pManifestMap - the manifest map this belongs to
// Output : ChunkFileResult_t - result of the parsing
//-----------------------------------------------------------------------------
ChunkFileResult_t CManifest::LoadKeyInfoCallback( const char *szKey, const char *szValue, CManifest *pDoc )
{
	if ( !stricmp( szKey, "NextInternalID" ) )
	{
		pDoc->m_NextInternalID = atoi( szValue );
	}

	return ChunkFile_Ok;
}


//-----------------------------------------------------------------------------
// Purpose: this function is responsible for setting up the manifest map about to be read in
// Input  : pFile - the chunk file being read
//			pDoc - the owning manifest document
// Output : ChunkFileResult_t - result of the parsing
//-----------------------------------------------------------------------------
ChunkFileResult_t CManifest::LoadManifestInfoCallback( CChunkFile *pFile, CManifest *pDoc )
{
	ChunkFileResult_t eResult = pFile->ReadChunk( ( KeyHandler_t )LoadKeyInfoCallback, pDoc );

	return( eResult );
}


//-----------------------------------------------------------------------------
// Purpose: this function will parse through the known keys for the manifest map entry
// Input  : szKey - the key name
//			szValue - the value
//			pManifestMap - the manifest map this belongs to
// Output : ChunkFileResult_t - result of the parsing
//-----------------------------------------------------------------------------
ChunkFileResult_t CManifest::LoadKeyCallback( const char *szKey, const char *szValue, CManifestMap *pManifestMap )
{
	if ( !stricmp( szKey, "InternalID" ) )
	{
		pManifestMap->m_InternalID = atoi( szValue );
	}
	else if ( !stricmp( szKey, "Name" ) )
	{
		pManifestMap->m_FriendlyName = szValue;
	}
	else if ( !stricmp( szKey, "File" ) )
	{
		pManifestMap->m_RelativeMapFileName = szValue;
		pManifestMap->m_AbsoluteMapFileName += szValue;
		if ( !pManifestMap->m_Map->LoadVMF( pManifestMap->m_AbsoluteMapFileName, VMF_LOAD_ACTIVATE | VMF_LOAD_IS_SUBMAP ) )
		{
			delete pManifestMap->m_Map;
			pManifestMap->m_Map = NULL;
		}
		pManifestMap->m_bReadOnly = true;
	}
	else if ( !stricmp( szKey, "TopLevel" ) )
	{
		pManifestMap->m_bTopLevelMap = ( atoi( szValue ) == 1 );
	}

	return ChunkFile_Ok;
}


//-----------------------------------------------------------------------------
// Purpose: this function is responsible for setting up the manifest map about to be read in
// Input  : pFile - the chunk file being read
//			pDoc - the owning manifest document
// Output : ChunkFileResult_t - result of the parsing
//-----------------------------------------------------------------------------
ChunkFileResult_t CManifest::LoadManifestVMFCallback( CChunkFile *pFile, CManifest *pDoc )
{
	char FileName[ MAX_PATH ];

	strcpy( FileName, pDoc->m_ManifestDir );

	CManifestMap	*pManifestMap = pDoc->CreateNewMap( FileName, "", false );
	SetActiveMapDoc( pManifestMap->m_Map );

	ChunkFileResult_t eResult = pFile->ReadChunk( ( KeyHandler_t )LoadKeyCallback, pManifestMap );

	if ( pManifestMap->m_Map )
	{
		pManifestMap->m_Map->SetEditable( false );
	}
	SetActiveMapDoc( pDoc );

	return( eResult );
}


//-----------------------------------------------------------------------------
// Purpose: this function will load the VMF chunk
// Input  : pFile - the chunk file being read
//			pDoc - the owning manifest document
// Output : ChunkFileResult_t - result of the parsing
//-----------------------------------------------------------------------------
ChunkFileResult_t CManifest::LoadManifestMapsCallback( CChunkFile *pFile, CManifest *pDoc )
{
	CChunkHandlerMap Handlers;
	Handlers.AddHandler( "VMF", ( ChunkHandler_t )LoadManifestVMFCallback, pDoc );
	pFile->PushHandlers(&Handlers);

	ChunkFileResult_t eResult = ChunkFile_Ok;

	eResult = pFile->ReadChunk();

	pFile->PopHandlers();

	return( eResult );
}


typedef struct SManifestLoadPrefs
{
	CManifest		*pDoc;
	CManifestMap	*pManifestMap;
} TManifestLoadPrefs;


//-----------------------------------------------------------------------------
// Purpose: this function will parse through the known keys for the manifest map entry
// Input  : szKey - the key name
//			szValue - the value
//			pManifestMap - the manifest map this belongs to
// Output : ChunkFileResult_t - result of the parsing
//-----------------------------------------------------------------------------
ChunkFileResult_t CManifest::LoadKeyPrefsCallback( const char *szKey, const char *szValue, TManifestLoadPrefs *pManifestLoadPrefs )
{
	if ( !stricmp( szKey, "InternalID" ) )
	{
		pManifestLoadPrefs->pManifestMap = pManifestLoadPrefs->pDoc->FindMapByID( atoi( szValue ) );
	}
	else if ( !stricmp( szKey, "IsPrimary" ) )
	{
		if ( pManifestLoadPrefs->pManifestMap )
		{
			pManifestLoadPrefs->pManifestMap->m_bPrimaryMap = ( atoi( szValue ) == 1 );
		}
	}
	else if ( !stricmp( szKey, "IsProtected" ) )
	{
		if ( pManifestLoadPrefs->pManifestMap )
		{
			pManifestLoadPrefs->pManifestMap->m_bProtected = ( atoi( szValue ) == 1 );
		}
	}
	else if ( !stricmp( szKey, "IsVisible" ) )
	{
		if ( pManifestLoadPrefs->pManifestMap )
		{
			pManifestLoadPrefs->pManifestMap->m_bVisible = ( atoi( szValue ) == 1 );
		}
	}

	return ChunkFile_Ok;
}


//-----------------------------------------------------------------------------
// Purpose: this function is responsible for setting up the manifest map about to be read in
// Input  : pFile - the chunk file being read
//			pDoc - the owning manifest document
// Output : ChunkFileResult_t - result of the parsing
//-----------------------------------------------------------------------------
ChunkFileResult_t CManifest::LoadManifestVMFPrefsCallback( CChunkFile *pFile, CManifest *pDoc )
{
	TManifestLoadPrefs	ManifestLoadPrefs;
	
	ManifestLoadPrefs.pDoc = pDoc;
	ManifestLoadPrefs.pManifestMap = NULL;

	ChunkFileResult_t eResult = pFile->ReadChunk( ( KeyHandler_t )LoadKeyPrefsCallback, &ManifestLoadPrefs );

	return( eResult );
}


//-----------------------------------------------------------------------------
// Purpose: this function will load the VMF chunk
// Input  : pFile - the chunk file being read
//			pDoc - the owning manifest document
// Output : ChunkFileResult_t - result of the parsing
//-----------------------------------------------------------------------------
ChunkFileResult_t CManifest::LoadManifestMapsPrefsCallback( CChunkFile *pFile, CManifest *pDoc )
{
	CChunkHandlerMap Handlers;
	Handlers.AddHandler( "VMF", ( ChunkHandler_t )LoadManifestVMFPrefsCallback, pDoc );
	pFile->PushHandlers(&Handlers);

	ChunkFileResult_t eResult = ChunkFile_Ok;

	eResult = pFile->ReadChunk();

	pFile->PopHandlers();

	return( eResult );
}


//-----------------------------------------------------------------------------
// Purpose: 
// Input  : 
// Output : 
//-----------------------------------------------------------------------------
ChunkFileResult_t CManifest::LoadManifestCordoningPrefsCallback( CChunkFile *pFile, CManifest *pDoc )
{
	CChunkHandlerMap Handlers;
	Handlers.AddHandler( "cordons", ( ChunkHandler_t )CMapDoc::LoadCordonCallback, pDoc );
	pFile->PushHandlers(&Handlers);

	ChunkFileResult_t eResult = ChunkFile_Ok;

	eResult = pFile->ReadChunk();

	pFile->PopHandlers();

	return( eResult );
}


//-----------------------------------------------------------------------------
// Purpose: This function will load in a vmf manifest
// Input  : pszFileName - the file name of the manifest to load
// Output : returns true if the load was successful
//-----------------------------------------------------------------------------
bool CManifest::LoadVMFManifest( const char *pszFileName )
{
	FILE *fp = fopen( pszFileName, "rb" );
	if ( !fp )
	{
		return false;
	}

	V_StripExtension( pszFileName, m_ManifestDir, sizeof( m_ManifestDir ) );
	strcat( m_ManifestDir, "\\" );

	CChunkFile File;
	ChunkFileResult_t eResult = File.Open( pszFileName, ChunkFile_Read );

	m_bLoading = true;

	if (eResult == ChunkFile_Ok)
	{
		//
		// Set up handlers for the subchunks that we are interested in.
		//
		CChunkHandlerMap Handlers;
		Handlers.AddHandler( "Info", ( ChunkHandler_t )CManifest::LoadManifestInfoCallback, this );
		Handlers.AddHandler( "Maps", ( ChunkHandler_t )CManifest::LoadManifestMapsCallback, this );

		Handlers.SetErrorHandler( ( ChunkErrorHandler_t )CMapDoc::HandleLoadError, this);

		File.PushHandlers(&Handlers);

		while (eResult == ChunkFile_Ok)
		{
			eResult = File.ReadChunk();
		}

		if (eResult == ChunkFile_EOF)
		{
			eResult = ChunkFile_Ok;
		}

		File.PopHandlers();
	}

	if (eResult == ChunkFile_Ok)
	{
	}
	else
	{
		GetMainWnd()->MessageBox( File.GetErrorText( eResult ), "Error loading manifest!", MB_OK | MB_ICONEXCLAMATION );
	}

	if ( GetNumMaps() == 0 )
	{
		GetMainWnd()->MessageBox( File.GetErrorText( eResult ), "Manifest file does not contain any maps!", MB_OK | MB_ICONEXCLAMATION );
		return false;
	}

	SetActiveMapDoc( this );
	Postload( pszFileName );
	m_ManifestWorld->PostloadWorld();

	bool bSetIDs = false;

	for( int i = 0; i < GetNumMaps(); i++ )
	{
		CManifestMap	*pManifestMap = GetMap( i );

		if ( pManifestMap->m_InternalID == 0 )
		{
			pManifestMap->m_InternalID = m_NextInternalID;
			m_NextInternalID++;
			bSetIDs = true;
		}

		if ( pManifestMap->m_Map == NULL || pManifestMap->m_Map->GetMapWorld() == NULL )
		{
			pManifestMap->m_bPrimaryMap = false;
			RemoveSubMap( pManifestMap );
			i = -1;
		}
	}

	LoadVMFManifestUserPrefs( pszFileName );

	for( int i = 0; i < GetNumMaps(); i++ )
	{
		CManifestMap	*pManifestMap = GetMap( i );

		if ( pManifestMap->m_bPrimaryMap )
		{
			SetPrimaryMap( pManifestMap );
		}
	}

	if ( !m_pPrimaryMap )
	{
		SetPrimaryMap( GetMap( 0 ) );
	}

	m_bLoading = false;
	m_bIsValid = true;

	m_bManifestChanged = bSetIDs;

	GetMainWnd()->m_ManifestFilterControl.UpdateManifestList();

	return true;
}


//-----------------------------------------------------------------------------
// Purpose: this function will load the user prefs for the manifest file.
// Input  : pszFileName - the manifest file name.
// Output : true if prefs were loaded.
//-----------------------------------------------------------------------------
bool CManifest::LoadVMFManifestUserPrefs( const char *pszFileName )
{
	char		UserName[ MAX_PATH ], FileName[ MAX_PATH ], UserPrefsFileName[ MAX_PATH ];
	DWORD		UserNameSize;

	m_bManifestUserPrefsChanged = false;

	UserNameSize = sizeof( UserName );
	if ( GetUserName( UserName, &UserNameSize ) == 0 )
	{
		strcpy( UserPrefsFileName, "default" );
	}

	strcpy( FileName, m_ManifestDir );
	sprintf( UserPrefsFileName, "%s.vmm_prefs", UserName );
	strcat( FileName, UserPrefsFileName );

	FILE *fp = fopen( FileName, "rb" );
	if ( !fp )
	{
		return false;
	}

	CChunkFile File;
	ChunkFileResult_t eResult = File.Open( FileName, ChunkFile_Read );

	m_bLoading = true;

	if ( eResult == ChunkFile_Ok )
	{
		//
		// Set up handlers for the subchunks that we are interested in.
		//
		CChunkHandlerMap Handlers;
		Handlers.AddHandler( "Maps", ( ChunkHandler_t )CManifest::LoadManifestMapsPrefsCallback, this );
		Handlers.AddHandler( "cordoning", ( ChunkHandler_t )CManifest::LoadManifestCordoningPrefsCallback, this );

		Handlers.SetErrorHandler( ( ChunkErrorHandler_t )CMapDoc::HandleLoadError, this);

		File.PushHandlers(&Handlers);

		while( eResult == ChunkFile_Ok )
		{
			eResult = File.ReadChunk();
		}

		if ( eResult == ChunkFile_EOF )
		{
			eResult = ChunkFile_Ok;
		}

		File.PopHandlers();
	}

	if ( eResult == ChunkFile_Ok )
	{
	}
	else
	{
		// no pref message for now
//		GetMainWnd()->MessageBox( File.GetErrorText( eResult ), "Error loading manifest!", MB_OK | MB_ICONEXCLAMATION );
	}

	return true;
}


//-----------------------------------------------------------------------------
// Purpose: this function will load in a manifest file ( and its user prefs )
// Input  : pszFileName - the name of the manifest file.
// Output : returns true if the manifest was loaded.
//-----------------------------------------------------------------------------
bool CManifest::Load( const char *pszFileName )
{
	if ( !LoadVMFManifest( pszFileName ) )
	{
		return false;
	}

	return true;
}


//-----------------------------------------------------------------------------
// Purpose: This function will save the manifest, the associated maps, and user prefs. 
// Input  : pszFileName - the name of the manifest
//			bForce - if true, we need to save all files, as we are relocating.
// Output : returns true if all files saved successfully.
//-----------------------------------------------------------------------------
bool CManifest::Save( const char *pszFileName, bool bForce )
{
	bool	bSuccess = true;

	if ( bForce || m_bManifestChanged )
	{
		if ( !SaveVMFManifest( pszFileName ) )
		{
			bSuccess = false;
		}
	}

	if ( !SaveVMFManifestMaps( pszFileName ) )
	{
		bSuccess = false;
	}

//	if ( bForce || m_bManifestUserPrefsChanged )
	{
		if ( !SaveVMFManifestUserPrefs( pszFileName ) )
		{
			bSuccess = false;
		}
	}

	return bSuccess;
}


//-----------------------------------------------------------------------------
// Purpose: this function will save the manifest file and all modified maps.  If we are
//			relocating the manifest to a new place, all maps will be saved relative to 
//			the new place
// Input  : the file name the manifest should be saved as
// Output : returns true if the save was completely successful.  A partial save will
//			return false.
//-----------------------------------------------------------------------------
bool CManifest::SaveVMFManifest( const char *pszFileName )
{
	bool		bSaved = true;
	CChunkFile	File;	

	ChunkFileResult_t eResult = File.Open( pszFileName, ChunkFile_Write );
	if (eResult != ChunkFile_Ok)
	{
		GetMainWnd()->MessageBox( File.GetErrorText( eResult ), "Error saving Manifest!" , MB_OK | MB_ICONEXCLAMATION );
		bSaved = false;
	}
	else
	{
		eResult = File.BeginChunk( "Info" );
		eResult = File.WriteKeyValueInt( "NextInternalID", m_NextInternalID );
		eResult = File.EndChunk();

		eResult = File.BeginChunk( "Maps" );
		if (eResult == ChunkFile_Ok)
		{
			for( int i = 0; i < GetNumMaps(); i++ )
			{
				CManifestMap	*pManifestMap = GetMap( i );

				eResult = File.BeginChunk("VMF");
				if (eResult == ChunkFile_Ok)
				{
					eResult = File.WriteKeyValue( "Name", pManifestMap->m_FriendlyName );
					eResult = File.WriteKeyValue( "File", pManifestMap->m_RelativeMapFileName );
					eResult = File.WriteKeyValueInt( "InternalID", pManifestMap->m_InternalID );
					if ( pManifestMap->m_bTopLevelMap == true )
					{
						eResult = File.WriteKeyValue( "TopLevel", "1" );
					}

					eResult = File.EndChunk();
				}
			}
		}

		if (eResult == ChunkFile_Ok)
		{
			eResult = File.EndChunk();
		}
		else
		{
			GetMainWnd()->MessageBox( File.GetErrorText( eResult ), "Error saving Manifest!", MB_OK | MB_ICONEXCLAMATION );
			bSaved = false;
		}

		File.Close();
	}

	V_StripExtension( pszFileName, m_ManifestDir, sizeof( m_ManifestDir ) );
	CreateDirectory( m_ManifestDir, NULL );
	strcat( m_ManifestDir, "\\" );

	if ( bSaved )
	{
		m_bManifestChanged = false;
	}

	return bSaved;
}


//-----------------------------------------------------------------------------
// Purpose: This function will save all maps associated with a manifest.  Only modified
//			maps are saved unless we are relocating the manifest.
// Input  : pszFileName - the name of the manifest file
// Output : returns true if the maps were saved successfully.
//-----------------------------------------------------------------------------
bool CManifest::SaveVMFManifestMaps( const char *pszFileName )
{
	bool	bSaved = true;

	for( int i = 0; i < GetNumMaps(); i++ )
	{
		CManifestMap	*pManifestMap = GetMap( i );

		if ( m_bRelocateSave )
		{
			char FileName[ MAX_PATH ];

			strcpy( FileName, m_ManifestDir );
			strcat( FileName, pManifestMap->m_RelativeMapFileName );
			pManifestMap->m_AbsoluteMapFileName = FileName;
		}

		if ( ( pManifestMap->m_Map->IsModified() || m_bRelocateSave ) )
		{
			if ( pManifestMap->m_Map->SaveVMF( pManifestMap->m_AbsoluteMapFileName, 0 ) == false )
			{
				bSaved = false;
			}
		}
	}

	if ( !bSaved )
	{
		GetMainWnd()->MessageBox( "Not all pieces of the manifest were saved!", "Error saving Manifest!", MB_OK | MB_ICONEXCLAMATION );
	}

	return bSaved;
}


//-----------------------------------------------------------------------------
// Purpose: this function will save the user prefs of the manifest.
// Input  : pszFileName - the name of the manifest file.
// Output : returns true if the prefs were saved.
//-----------------------------------------------------------------------------
bool CManifest::SaveVMFManifestUserPrefs( const char *pszFileName )
{
	bool		bSaved = true;
	CChunkFile	File;	
	char		UserName[ MAX_PATH ], FileName[ MAX_PATH ], UserPrefsFileName[ MAX_PATH ];
	DWORD		UserNameSize;

	UserNameSize = sizeof( UserName );
	if ( GetUserName( UserName, &UserNameSize ) == 0 )
	{
		strcpy( UserPrefsFileName, "default" );
	}

	strcpy( FileName, m_ManifestDir );
	sprintf( UserPrefsFileName, "%s.vmm_prefs", UserName );
	strcat( FileName, UserPrefsFileName );

	ChunkFileResult_t eResult = File.Open( FileName, ChunkFile_Write );
	if (eResult != ChunkFile_Ok)
	{
		GetMainWnd()->MessageBox( File.GetErrorText( eResult ), "Error saving Manifest User Prefs!" , MB_OK | MB_ICONEXCLAMATION );
		bSaved = false;
	}
	else
	{
		eResult = File.BeginChunk( "Maps" );
		if (eResult == ChunkFile_Ok)
		{
			for( int i = 0; i < GetNumMaps(); i++ )
			{
				CManifestMap	*pManifestMap = GetMap( i );

				eResult = File.BeginChunk("VMF");
				if (eResult == ChunkFile_Ok)
				{
					eResult = File.WriteKeyValueInt( "InternalID", pManifestMap->m_InternalID );
					if ( pManifestMap->m_bPrimaryMap )
					{
						eResult = File.WriteKeyValue( "IsPrimary", "1" );
					}
					if ( pManifestMap->m_bProtected == true )
					{
						eResult = File.WriteKeyValue( "IsProtected", "1" );
					}
					if ( pManifestMap->m_bVisible == false )
					{
						eResult = File.WriteKeyValue( "IsVisible", "0" );
					}

					eResult = File.EndChunk();
				}
			}
		}

		if (eResult == ChunkFile_Ok)
		{
			eResult = File.EndChunk();
		}
		else
		{
			GetMainWnd()->MessageBox( File.GetErrorText( eResult ), "Error saving Manifest User Prefs!", MB_OK | MB_ICONEXCLAMATION );
			bSaved = false;
		}

		eResult = File.BeginChunk( "cordoning" );
		eResult = CordonSaveVMF( &File, NULL );

		if ( m_bIsCordoning )
		{
			CSaveInfo	SaveInfo;

			SaveInfo.SetVisiblesOnly( false );
			CMapWorld *pCordonWorld = CordonCreateWorld();
			eResult = pCordonWorld->SaveSolids( &File, &SaveInfo, 0 );
		}

		eResult = File.EndChunk();

		File.Close();
	}

	if ( bSaved )
	{
		m_bManifestUserPrefsChanged = false;
	}

	return bSaved;
}


//-----------------------------------------------------------------------------
// Purpose: this function will initialize the manifest
//-----------------------------------------------------------------------------
void CManifest::Initialize( void )
{
	__super::Initialize();

	m_ManifestWorld = new CMapWorld( this );
	m_ManifestWorld->CullTree_Build();
}


//-----------------------------------------------------------------------------
// Purpose: this function will update the manifest and all of its sub maps
//-----------------------------------------------------------------------------
void CManifest::Update( void )
{
	__super::Update();

	for( int i = 0; i < GetNumMaps(); i++ )
	{
		CManifestMap	*pManifestMap = GetMap( i );

		pManifestMap->m_Map->Update();
	}
}


//-----------------------------------------------------------------------------
// Purpose: this function allows you to indicate if the user prefs have been modified.
// Input  : bModified - the new status of the user prefs
//-----------------------------------------------------------------------------
void CManifest::SetManifestPrefsModifiedFlag( bool bModified )
{
	m_bManifestUserPrefsChanged = bModified;
}


//-----------------------------------------------------------------------------
// Purpose: this function handles the routing of the manifest's modified flag down to the primary map
// Input  : bModified - the new modified status
//-----------------------------------------------------------------------------
void CManifest::SetModifiedFlag( BOOL bModified )
{
	if ( m_pPrimaryMap )
	{
		m_pPrimaryMap->m_Map->SetModifiedFlag( bModified );
	}
	
	if ( bModified == false )
	{
		for( int i = 0; i < GetNumMaps(); i++ )
		{
			CManifestMap	*pManifestMap = GetMap( i );

			if ( pManifestMap->m_Map->IsModified() )
			{
				bModified = true;
				break;
			}
		}
	}

	if ( bModified != IsModified() )
	{
		GetMainWnd()->m_ManifestFilterControl.Invalidate();
	}

	__super::SetModifiedFlag( bModified );
}


//-----------------------------------------------------------------------------
// Purpose: this function will return the full path to a sub map.
// Input  : pManifestMapFileName - the relative name of the sub map
// Output : pOutputPath - the full path to the sub map
//-----------------------------------------------------------------------------
void CManifest::GetFullMapPath( const char *pManifestMapFileName, char *pOutputPath )
{
	strcpy( pOutputPath, m_ManifestDir );
	strcat( pOutputPath, pManifestMapFileName );
}


//-----------------------------------------------------------------------------
// Purpose: this function will attempt to find the manifest map that owns the map doc
// Input  : pMap - the map doc to look up
// Output : returns a pointer to the owning manifest map, otherwise NULL
//-----------------------------------------------------------------------------
CManifestMap *CManifest::FindMap( CMapDoc *pMap )
{
	for( int i = 0; i < GetNumMaps(); i++ )
	{
		CManifestMap	*pManifestMap = GetMap( i );

		if ( pManifestMap->m_Map == pMap )
		{
			return pManifestMap;
		}
	}

	return NULL;
}


//-----------------------------------------------------------------------------
// Purpose: this function will attempt to look up a map by its internal id.
// Input  : InternalID - the internal ID.
// Output : returns the manifest map if one is found.
//-----------------------------------------------------------------------------
CManifestMap *CManifest::FindMapByID( int InternalID )
{
	for( int i = 0; i < GetNumMaps(); i++ )
	{
		CManifestMap	*pManifestMap = GetMap( i );

		if ( pManifestMap->m_InternalID == InternalID )
		{
			return pManifestMap;
		}
	}

	return NULL;
}


//-----------------------------------------------------------------------------
// Purpose: this function will set the manifest map as the primary map.  All entity / brush 
//			operations happen exclusively on the primary map.
// Input  : pManifestMap - the manifest map to make primary
//-----------------------------------------------------------------------------
void CManifest::SetPrimaryMap( CManifestMap	*pManifestMap )
{
	if ( m_pPrimaryMap )
	{
		m_pPrimaryMap->m_bPrimaryMap = false;
		m_pPrimaryMap->m_Map->m_nNextMapObjectID = m_nNextMapObjectID;
		m_pPrimaryMap->m_Map->m_nNextMapObjectID = m_nNextNodeID;
		m_pPrimaryMap->m_Map->SetEditable( false );
	}

	ClearSelection();
	CheckFileStatus();

	m_pPrimaryMap = pManifestMap;
	if ( m_pPrimaryMap )
	{
		m_pPrimaryMap->m_bPrimaryMap = true;
		m_pWorld = m_pPrimaryMap->m_Map->GetMapWorld();
		m_VisGroups = m_pPrimaryMap->m_Map->m_VisGroups;
		m_RootVisGroups = m_pPrimaryMap->m_Map->m_RootVisGroups;
		m_nNextMapObjectID = m_pPrimaryMap->m_Map->m_nNextMapObjectID;
		m_nNextNodeID = m_pPrimaryMap->m_Map->m_nNextMapObjectID;
		m_pPrimaryMap->m_Map->SetEditable( !m_pPrimaryMap->m_bReadOnly );

		m_pUndo = m_pPrimaryMap->m_Map->m_pUndo;
		m_pRedo = m_pPrimaryMap->m_Map->m_pRedo;
		CHistory::SetHistory( m_pPrimaryMap->m_Map->m_pUndo );

//		m_pSelection = m_pPrimaryMap->m_Map->m_pSelection;
	}

	m_bManifestUserPrefsChanged = true;

	GetMainWnd()->GlobalNotify( WM_MAPDOC_CHANGED );
	GetMainWnd()->m_ManifestFilterControl.Invalidate();
	UpdateAllViews( MAPVIEW_UPDATE_SELECTION | MAPVIEW_UPDATE_TOOL | MAPVIEW_RENDER_NOW );
}


//-----------------------------------------------------------------------------
// Purpose: sets the visibility flag of a sub map.
// Input  : pManifestMap - the map to set the flag
//			bIsVisible - the visiblity status
//-----------------------------------------------------------------------------
void CManifest::SetVisibility( CManifestMap	*pManifestMap, bool bIsVisible )
{
	pManifestMap->m_bVisible = bIsVisible;

	GetMainWnd()->m_ManifestFilterControl.Invalidate();
	UpdateAllViews( MAPVIEW_UPDATE_SELECTION | MAPVIEW_UPDATE_TOOL | MAPVIEW_RENDER_NOW );
}


//-----------------------------------------------------------------------------
// Purpose: this function will create and default a new manifest map, add it to the world
// Input  : AbsoluteFileName - the full path of the vmf file
//			RelativeFileName - the relative path of the vmf file
// Output : returns a pointer to the newly created manifest map.
//-----------------------------------------------------------------------------
CManifestMap *CManifest::CreateNewMap( const char *AbsoluteFileName, const char *RelativeFileName, bool bSetID )
{
	CManifestMap	*pManifestMap = new CManifestMap();

	pManifestMap->m_AbsoluteMapFileName = AbsoluteFileName;
	pManifestMap->m_RelativeMapFileName = RelativeFileName;
	pManifestMap->m_Map = new CMapDoc();
	SetActiveMapDoc( pManifestMap->m_Map );
	pManifestMap->m_Map->SetManifest( this );
	pManifestMap->m_Map->SetEditable( false );

	pManifestMap->m_Entity = new CManifestInstance( pManifestMap );

	pManifestMap->m_Entity->SetPlaceholder( true );
	pManifestMap->m_Entity->SetOrigin( Vector( 0.0f, 0.0f, 0.0f ) );
	pManifestMap->m_Entity->SetClass( "func_instance" );
	pManifestMap->m_Entity->SetKeyValue( "classname", "func_instance" );

	// ensure we are a pure instance of only the instance helper!
	pManifestMap->m_Entity->RemoveAllChildren();
	CHelperInfo	HI;

	HI.SetName( "instance" );

	CMapClass *pHelper = CHelperFactory::CreateHelper( &HI, pManifestMap->m_Entity );
	if ( pHelper != NULL )
	{
		pManifestMap->m_Entity->AddHelper( pHelper, false );
	}

	if ( bSetID )
	{
		pManifestMap->m_InternalID = m_NextInternalID;
		m_NextInternalID++;
	}

	CMapInstance	*pMapInstance = pManifestMap->m_Entity->GetChildOfType( ( CMapInstance * )NULL );
	if ( pMapInstance )
	{
		pMapInstance->SetManifest( pManifestMap );
	}
	AddManifestObjectToWorld( pManifestMap->m_Entity );
	m_Maps.AddToTail( pManifestMap );

	m_bManifestChanged = true;

	return pManifestMap;
}


//-----------------------------------------------------------------------------
// Purpose: This function will move the selection of the active map to a new sub map.
// Input  : pManifestMap - the sub map the selection shoud be moved to
//			CenterContents - if the contents should be centered
//-----------------------------------------------------------------------------
void CManifest::MoveSelectionToSubmap( CManifestMap *pManifestMap, bool CenterContents )
{
#if 0
	if ( s_Clipboard.Objects.Count() != 0 )
	{
		return false;
	}
#endif

	CMapDoc *pDoc = CMapDoc::GetActiveMapDoc();
	if ( !pDoc )
	{
		return;
	}

	pDoc->Copy();
	if ( pDoc->GetClipboardCount() == 0 )
	{
		return;
	}
	pDoc->Delete();

	pManifestMap->m_Map->ManifestPaste( pManifestMap->m_Map->GetMapWorld(), Vector( 0.0f, 0.0f, 0.0f ), QAngle( 0.0f, 0.0f, 0.0f ), NULL, false, NULL );
	pManifestMap->m_Entity->CalcBounds( TRUE );
	
	UpdateAllViews( MAPVIEW_UPDATE_SELECTION | MAPVIEW_UPDATE_TOOL | MAPVIEW_RENDER_NOW );
}


//-----------------------------------------------------------------------------
// Purpose: this function will cut the selection and move it into a newly created 
//			map doc and manifest map.
// Input  : FriendlyName - this is the text friendly name that the user can refer 
//				to the map as
//			FileName - The relative file name for this new map to be saved as
//			CenterContents - whether or not we should center the contents in the new map
// Output : returns a pointer to the newly created manifest map.
//-----------------------------------------------------------------------------
CManifestMap *CManifest::MoveSelectionToNewSubmap( CString &FriendlyName, CString &FileName, bool CenterContents )
{
#if 0
	if ( s_Clipboard.Objects.Count() != 0 )
	{
		return false;
	}
#endif

	CMapDoc *pDoc = CMapDoc::GetActiveMapDoc();

	if ( !pDoc )
	{
		return NULL;
	}

	pDoc->Copy();
	if ( pDoc->GetClipboardCount() == 0 )
	{
		return NULL;
	}
	
	char AbsoluteFileName[ MAX_PATH ];

	strcpy( AbsoluteFileName, m_ManifestDir );
	strcat( AbsoluteFileName, FileName );

	CManifestMap	*pManifestMap = CreateNewMap( AbsoluteFileName, FileName, true );
	pManifestMap->m_FriendlyName = FriendlyName;

	pManifestMap->m_Map->Initialize();
	if ( pManifestMap->m_Map->SaveVMF( pManifestMap->m_AbsoluteMapFileName, 0 ) == false )
	{
		m_bLoading = false;
		SetActiveMapDoc( this );
		delete pManifestMap;
		return NULL;
	}
	pDoc->Delete();
	pManifestMap->m_Map->ManifestPaste( pManifestMap->m_Map->GetMapWorld(), Vector( 0.0f, 0.0f, 0.0f ), QAngle( 0.0f, 0.0f, 0.0f ), NULL, false, NULL );
	pManifestMap->m_Entity->CalcBounds( TRUE );
	SetPrimaryMap( pManifestMap );

	SetActiveMapDoc( this );
	__super::SetModifiedFlag( true );
	pDoc->SetModifiedFlag( true );
	pManifestMap->m_Map->SetModifiedFlag( true );

	UpdateAllViews( MAPVIEW_UPDATE_SELECTION | MAPVIEW_UPDATE_TOOL | MAPVIEW_RENDER_NOW );
	GetMainWnd()->m_ManifestFilterControl.UpdateManifestList();

	return pManifestMap;
}


//-----------------------------------------------------------------------------
// Purpose: this function will add a new sub map to the manifest.  
// Input  : FriendlyName - the friendly name string
//			FileName - the file name of the sub map
// Output : returns a pointer to the new manifest map.
//-----------------------------------------------------------------------------
CManifestMap *CManifest::AddNewSubmap( CString &FriendlyName, CString &FileName )
{
	char AbsoluteFileName[ MAX_PATH ];

	strcpy( AbsoluteFileName, m_ManifestDir );
	strcat( AbsoluteFileName, FileName );

	CManifestMap	*pManifestMap = CreateNewMap( AbsoluteFileName, FileName, true );

	pManifestMap->m_FriendlyName = FriendlyName;

	pManifestMap->m_Map->Initialize();
	pManifestMap->m_Entity->CalcBounds( TRUE );

	if ( pManifestMap->m_Map->SaveVMF( pManifestMap->m_AbsoluteMapFileName, 0 ) == false )
	{
		m_bLoading = false;
		SetActiveMapDoc( this );
		delete pManifestMap;
		return NULL;
	}

	SetPrimaryMap( pManifestMap );
	SetActiveMapDoc( this );
	__super::SetModifiedFlag( true );

	UpdateAllViews( MAPVIEW_UPDATE_SELECTION | MAPVIEW_UPDATE_TOOL | MAPVIEW_RENDER_NOW );
	GetMainWnd()->m_ManifestFilterControl.UpdateManifestList();

	return pManifestMap;
}


//-----------------------------------------------------------------------------
// Purpose: This function add an external vmf file to the manifest
// Input  : pszFileName - the absolute file name of the vmf file
//			bFromInstance - if the map is coming from a func_instance somewhere
// Output : returns true if the map could be loaded and the manifest was created
//-----------------------------------------------------------------------------
bool CManifest::AddExistingMap( const char *pszFileName, bool bFromInstance )
{
	char AbsoluteFileName[ MAX_PATH ], RelativeFileName[ MAX_PATH ];

	char FileExt[ MAX_PATH ];

	_splitpath_s( pszFileName, NULL, 0, NULL, 0, RelativeFileName, sizeof( RelativeFileName ), FileExt, sizeof( FileExt ) );
	strcat( RelativeFileName, FileExt );

	strcpy( AbsoluteFileName, m_ManifestDir );
	strcat( AbsoluteFileName, RelativeFileName );
	CManifestMap	*pManifestMap = CreateNewMap( AbsoluteFileName, RelativeFileName, true );

	m_bLoading = true;
	if ( !pManifestMap->m_Map->LoadVMF( pszFileName, VMF_LOAD_ACTIVATE | VMF_LOAD_IS_SUBMAP ) )
	{
		m_bLoading = false;
		SetActiveMapDoc( this );
		delete pManifestMap;
		return false;
	}

	if ( pManifestMap->m_Map->SaveVMF( pManifestMap->m_AbsoluteMapFileName, 0 ) == false )
	{
		m_bLoading = false;
		SetActiveMapDoc( this );
		delete pManifestMap;
		return false;
	}

	pManifestMap->m_Map->GetMapWorld()->CullTree_Build();
	pManifestMap->m_Entity->PostUpdate( Notify_Changed );
	if ( m_Maps.Count() == 1 )
	{
		pManifestMap->m_bTopLevelMap = true;
	}

	SetPrimaryMap( pManifestMap );

	m_bLoading = false;

	SetActiveMapDoc( this );
	__super::SetModifiedFlag( true );

	GetMainWnd()->m_ManifestFilterControl.UpdateManifestList();

	if ( GetPathName().GetLength() == 0 )
	{
		char	ManifestFile[ MAX_PATH ];

		strcpy( ManifestFile, pszFileName );
		V_SetExtension( ManifestFile, ".vmm", sizeof( ManifestFile ) );

		m_bRelocateSave = true;
		OnSaveDocument( ManifestFile );
		m_bRelocateSave = false;

		SetPathName( ManifestFile, false );
	}

	return true;
}


//-----------------------------------------------------------------------------
// Purpose: This function will allow the user to browse to an exist map to add to the manifest.
//-----------------------------------------------------------------------------
bool CManifest::AddExistingMap( void )
{
	char szInitialDir[ MAX_PATH ];
	
	V_strcpy_safe( szInitialDir, GetPathName() );
	if ( szInitialDir[ 0 ] == '\0' )
	{
		strcpy( szInitialDir, g_pGameConfig->szMapDir );
	}

	CFileDialog dlg( TRUE, NULL, NULL, OFN_LONGNAMES | OFN_HIDEREADONLY | OFN_NOCHANGEDIR, "Valve Map Files (*.vmf)|*.vmf||" );
	dlg.m_ofn.lpstrInitialDir = szInitialDir;
	int iRvl = dlg.DoModal();

	if ( iRvl == IDCANCEL )
	{
		return false;
	}

	//
	// Get the directory they browsed to for next time.
	//
	CString str = dlg.GetPathName();
	int nSlash = str.ReverseFind( '\\' );
	if ( nSlash != -1 )
	{
		strcpy( szInitialDir, str.Left( nSlash ) );
	}

	if ( str.Find('.') == -1 )
	{
		switch ( dlg.m_ofn.nFilterIndex )
		{
			case 1:
				str += ".vmf";
				break;
		}
	}

	return AddExistingMap( str, false );
}


//-----------------------------------------------------------------------------
// Purpose: This function will remove the sub map from the manifest
// Input  : pManifestMap - the sub map to be removed
// Output : returns true if it was successful
//-----------------------------------------------------------------------------
bool CManifest::RemoveSubMap( CManifestMap *pManifestMap )
{
	if ( m_Maps.Count() > 1 )
	{
		m_Maps.FindAndRemove( pManifestMap );

		const CMapObjectList *pChildren = m_ManifestWorld->GetChildren();
		FOR_EACH_OBJ( *pChildren, pos )
		{
			CMapClass	*pChild = pChildren->Element( pos );
			CMapEntity	*pEntity = dynamic_cast< CMapEntity * >( pChild );

			if ( pEntity && stricmp( pEntity->GetClassName(), "func_instance" ) == 0 )
			{
				CMapInstance	*pMapInstance = pEntity->GetChildOfType( ( CMapInstance * )NULL );
				if ( pMapInstance )
				{
					if ( pMapInstance->GetManifestMap() == pManifestMap )
					{
						m_ManifestWorld->RemoveObjectFromWorld( pChild, true );
						break;
					}
				}
			}
		}

		delete pManifestMap;

		return true;
	}

	return false;
}


//-----------------------------------------------------------------------------
// Purpose: 
// Input  : 
// Output : 
//-----------------------------------------------------------------------------
bool CManifest::CheckOut( )
{
	if ( !p4 )
	{
		return false;
	}

	if ( !p4->OpenFileForEdit( GetPathName() ) )
	{
		return false;
	}

	CheckFileStatus();

	return true;
}


//-----------------------------------------------------------------------------
// Purpose: 
// Input  : 
// Output : 
//-----------------------------------------------------------------------------
bool CManifest::AddToVersionControl( )
{
	if ( !p4 )
	{
		return false;
	}

	if ( !p4->OpenFileForAdd( GetPathName() ) )
	{
		return false;
	}

	CheckFileStatus();

	return true;
}


//-----------------------------------------------------------------------------
// Purpose: 
// Input  : 
// Output : 
//-----------------------------------------------------------------------------
void CManifest::CheckFileStatus( void )
{
	P4File_t	FileInfo;

	m_bReadOnly = !g_pFullFileSystem->IsFileWritable( GetPathName() );
	m_bCheckedOut = false;
	m_bIsVersionControlled = false;
	if ( p4 != NULL && p4->GetFileInfo( GetPathName(), &FileInfo ) == true )
	{
		m_bIsVersionControlled = true;
		if ( FileInfo.m_eOpenState == P4FILE_OPENED_FOR_ADD || FileInfo.m_eOpenState == P4FILE_OPENED_FOR_EDIT )
		{
			m_bCheckedOut = true;
		}
	}

	for( int i = 0; i < GetNumMaps(); i++ )
	{
		CManifestMap	*pManifestMap = GetMap( i );

		pManifestMap->m_bReadOnly = !g_pFullFileSystem->IsFileWritable( pManifestMap->m_AbsoluteMapFileName );
		pManifestMap->m_bCheckedOut = false;
		pManifestMap->m_bIsVersionControlled = false;

		if ( p4 != NULL && p4->GetFileInfo( pManifestMap->m_AbsoluteMapFileName, &FileInfo ) == true )
		{
			pManifestMap->m_bIsVersionControlled = true;
			if ( FileInfo.m_eOpenState == P4FILE_OPENED_FOR_ADD || FileInfo.m_eOpenState == P4FILE_OPENED_FOR_EDIT )
			{
				pManifestMap->m_bCheckedOut = true;
			}
		}
	}
}


//-----------------------------------------------------------------------------
// Purpose: This function will clear the selection
//-----------------------------------------------------------------------------
void CManifest::ClearSelection( void )
{
	SelectFace( NULL, 0, scClear | scSaveChanges );
	SelectObject( NULL, scClear | scSaveChanges );
}


//-----------------------------------------------------------------------------
// Purpose: This function will add the object to the primary map of the manifest
// Input  : pObject - a pointer to the object to be added
//			pParent - a pointer to the parent of this object
//-----------------------------------------------------------------------------
void CManifest::AddObjectToWorld(CMapClass *pObject, CMapClass *pParent)
{
	m_pPrimaryMap->m_Map->AddObjectToWorld( pObject, pParent );

	m_pPrimaryMap->m_Entity->PostUpdate( Notify_Changed );
}


//-----------------------------------------------------------------------------
// Purpose: This function will pass on the notification that a map has been updated
// Input  : pInstanceMapDoc - the map that was updated
//-----------------------------------------------------------------------------
void CManifest::UpdateInstanceMap( CMapDoc *pInstanceMapDoc )
{
	const CMapObjectList *pChildren = m_ManifestWorld->GetChildren();
	FOR_EACH_OBJ( *pChildren, pos )
	{
		CMapClass	*pChild = pChildren->Element( pos );
		CMapEntity	*pEntity = dynamic_cast< CMapEntity * >( pChild );

		if ( pEntity && stricmp( pEntity->GetClassName(), "func_instance" ) == 0 )
		{
			CMapInstance	*pMapInstance = pEntity->GetChildOfType( ( CMapInstance * )NULL );
			if ( pMapInstance )
			{
				if ( pMapInstance->GetInstancedMap() == pInstanceMapDoc )
				{
					pMapInstance->UpdateInstanceMap();
					m_ManifestWorld->UpdateChild( pMapInstance );
				}
			}
		}
	}
}


//-----------------------------------------------------------------------------
// Purpose: this function will add the object to the local manifest world.  the
//			only objects that should be added are ManifestInstance.
// Input  : pObject - a pointer to the object to be added
//			pParent - a pointer to the parent of this object
//-----------------------------------------------------------------------------
void CManifest::AddManifestObjectToWorld( CMapClass *pObject, CMapClass *pParent )
{
	m_ManifestWorld->AddObjectToWorld( pObject, pParent );
}


//-----------------------------------------------------------------------------
// Purpose: Removes an object from the manifest world.
// Input  : pObject - object to remove from the world.
//			bChildren - whether we're removing the object's children as well.
//-----------------------------------------------------------------------------
void CManifest::RemoveManifestObjectFromWorld( CMapClass *pObject, bool bRemoveChildren )
{
	m_ManifestWorld->RemoveObjectFromWorld( pObject, bRemoveChildren );
}

//-----------------------------------------------------------------------------
// Purpose: this function will start the loading process for a manifest
// Input  : lpszPathName - the absoltue path of the manifest file
// Output : Returns TRUE on success, FALSE on failure.
//-----------------------------------------------------------------------------
BOOL CManifest::OnOpenDocument(LPCTSTR lpszPathName) 
{
	Initialize();

	if (!SelectDocType())
	{
		return FALSE;
	}

	//
	// Call any per-class PreloadWorld functions here.
	//
	CMapSolid::PreloadWorld();

	if ( !Load( lpszPathName ) )
	{
		return FALSE;
	}

	SetModifiedFlag( FALSE );
	Msg( mwStatus, "Opened %s", lpszPathName );
	SetActiveMapDoc( this );

	//
	// We set the active doc before loading for displacements (and maybe other
	// things), but visgroups aren't available until after map load. We have to refresh
	// the visgroups here or they won't be correct.
	//
	GetMainWnd()->GlobalNotify( WM_MAPDOC_CHANGED );

	m_pToolManager->SetTool( TOOL_POINTER );

	return(TRUE);
}


//-----------------------------------------------------------------------------
// Purpose: This function will save out the manifest
// Input  : lpszPathName - the absolute filename of the manifest
// Output : Returns TRUE on success, FALSE on failure.
//-----------------------------------------------------------------------------
BOOL CManifest::OnSaveDocument(LPCTSTR lpszPathName) 
{
	if ( !Save( lpszPathName, m_bRelocateSave ) )
	{
		return FALSE;
	}

	SetModifiedFlag( FALSE );

	return TRUE;
}


//-----------------------------------------------------------------------------
// Purpose: this function will be called when the use select Save As.  This will
//			allow all of the submaps to be relocated relative to a new save location
//			of the manifest itself.  Directories should be created automatically.
//-----------------------------------------------------------------------------
void CManifest::OnFileSaveAs(void)
{
	m_bRelocateSave = true;

	__super::OnFileSaveAs();

	m_bRelocateSave = false;
}


//-----------------------------------------------------------------------------
// Purpose: this function will delete the manifest world and rest of the contents.
//-----------------------------------------------------------------------------
void CManifest::DeleteContents( void )
{
	m_pSelection->RemoveAll();

	if ( m_ManifestWorld )
	{
		delete m_ManifestWorld;
		m_ManifestWorld = NULL;
	}

	m_pWorld = NULL;
	m_VisGroups = NULL;
	m_RootVisGroups = NULL;
	m_pUndo = m_pSaveUndo;
	m_pRedo = m_pSaveRedo;

	__super::DeleteContents();
}

#include <tier0/memdbgoff.h>