/*
================
idCollisionModelManagerLocal::LoadCollisionModelFile
================
*/
bool idCollisionModelManagerLocal::LoadCollisionModelFile( const char* name, unsigned int mapFileCRC )
{
	idToken token;
	idLexer* src;
	unsigned int crc;
	
	// load it
	idStrStatic< MAX_OSPATH > fileName = name;
	
	// check for generated file
	idStrStatic< MAX_OSPATH > generatedFileName = fileName;
	generatedFileName.Insert( "generated/", 0 );
	generatedFileName.SetFileExtension( CM_BINARYFILE_EXT );
	
	// if we are reloading the same map, check the timestamp
	// and try to skip all the work
	ID_TIME_T currentTimeStamp = fileSystem->GetTimestamp( fileName );
	
	// see if we have a generated version of this
	bool loaded = false;
	idFileLocal file( fileSystem->OpenFileReadMemory( generatedFileName ) );
	if( file != NULL )
	{
		int numEntries = 0;
		file->ReadBig( numEntries );
		file->ReadString( mapName );
		file->ReadBig( crc );
		idStrStatic< 32 > fileID;
		idStrStatic< 32 > fileVersion;
		file->ReadString( fileID );
		file->ReadString( fileVersion );
		if( fileID == CM_FILEID && fileVersion == CM_FILEVERSION && crc == mapFileCRC && numEntries > 0 )
		{
			loaded = true; // DG: moved this up here to prevent segfaults, see below
			for( int i = 0; i < numEntries; i++ )
			{
				cm_model_t* model = LoadBinaryModelFromFile( file, currentTimeStamp );
				// DG: handle the case that loading the binary model fails gracefully
				//     (otherwise we'll get a segfault when someone wants to use models[numModels])
				if( model == NULL )
				{
					loaded = false;
					break;
				}
				// DG end
				models[ numModels ] = model;
				numModels++;
			}
		}
	}
	
	if( !loaded )
	{
	
		fileName.SetFileExtension( CM_FILE_EXT );
		src = new( TAG_COLLISION ) idLexer( fileName );
		src->SetFlags( LEXFL_NOSTRINGCONCAT | LEXFL_NODOLLARPRECOMPILE );
		if( !src->IsLoaded() )
		{
			delete src;
			return false;
		}
		
		int numEntries = 0;
		idFileLocal outputFile( fileSystem->OpenFileWrite( generatedFileName, "fs_basepath" ) );
		if( outputFile != NULL )
		{
			outputFile->WriteBig( numEntries );
			outputFile->WriteString( mapName );
			outputFile->WriteBig( mapFileCRC );
			outputFile->WriteString( CM_FILEID );
			outputFile->WriteString( CM_FILEVERSION );
		}
		
		if( !src->ExpectTokenString( CM_FILEID ) )
		{
			common->Warning( "%s is not an CM file.", fileName.c_str() );
			delete src;
			return false;
		}
		
		if( !src->ReadToken( &token ) || token != CM_FILEVERSION )
		{
			common->Warning( "%s has version %s instead of %s", fileName.c_str(), token.c_str(), CM_FILEVERSION );
			delete src;
			return false;
		}
		
		if( !src->ExpectTokenType( TT_NUMBER, TT_INTEGER, &token ) )
		{
			common->Warning( "%s has no map file CRC", fileName.c_str() );
			delete src;
			return false;
		}
		
		crc = token.GetUnsignedLongValue();
		if( mapFileCRC && crc != mapFileCRC )
		{
			common->Printf( "%s is out of date\n", fileName.c_str() );
			delete src;
			return false;
		}
		
		// parse the file
		while( 1 )
		{
			if( !src->ReadToken( &token ) )
			{
				break;
			}
			
			if( token == "collisionModel" )
			{
				cm_model_t* model = ParseCollisionModel( src );
				if( model == NULL )
				{
					delete src;
					return false;
				}
				if( outputFile != NULL )
				{
					WriteBinaryModelToFile( model, outputFile, currentTimeStamp );
					numEntries++;
				}
				continue;
			}
			
			src->Error( "idCollisionModelManagerLocal::LoadCollisionModelFile: bad token \"%s\"", token.c_str() );
		}
		delete src;
		if( outputFile != NULL )
		{
			outputFile->Seek( 0, FS_SEEK_SET );
			outputFile->WriteBig( numEntries );
		}
	}
	
	return true;
}
/*
================
idCollisionModelManagerLocal::LoadCollisionModelFile
================
*/
bool idCollisionModelManagerLocal::LoadCollisionModelFile( const char *name, unsigned int mapFileCRC ) {
	idStr fileName;
	idToken token;
	idLexer *src;
	unsigned int crc;

	// load it
	fileName = name;
	fileName.SetFileExtension( CM_FILE_EXT );
	src = new idLexer( fileName );
	src->SetFlags( LEXFL_NOSTRINGCONCAT | LEXFL_NODOLLARPRECOMPILE );
	if ( !src->IsLoaded() ) {
		delete src;
		return false;
	}

	if ( !src->ExpectTokenString( CM_FILEID ) ) {
		common->Warning( "%s is not an CM file.", fileName.c_str() );
		delete src;
		return false;
	}

	if ( !src->ReadToken( &token ) || token != CM_FILEVERSION ) {
		common->Warning( "%s has version %s instead of %s", fileName.c_str(), token.c_str(), CM_FILEVERSION );
		delete src;
		return false;
	}

	if ( !src->ExpectTokenType( TT_NUMBER, TT_INTEGER, &token ) ) {
		common->Warning( "%s has no map file CRC", fileName.c_str() );
		delete src;
		return false;
	}

	crc = token.GetUnsignedLongValue();
	if ( mapFileCRC && crc != mapFileCRC ) {
		common->Printf( "%s is out of date\n", fileName.c_str() );
		delete src;
		return false;
	}

	// parse the file
	while ( 1 ) {
		if ( !src->ReadToken( &token ) ) {
			break;
		}

		if ( token == "collisionModel" ) {
			if ( !ParseCollisionModel( src ) ) {
				delete src;
				return false;
			}
			continue;
		}

		src->Error( "idCollisionModelManagerLocal::LoadCollisionModelFile: bad token \"%s\"", token.c_str() );
	}

	delete src;

	return true;
}