//===========================================================================//
// File:        resource.hh                                                  //
// Project: MUNGA           Brick: Resource Manager                          //
// Contents: Implementation Details of resource management                   //
//---------------------------------------------------------------------------//
//   Date    Who  Modification                                               //
// --------  ---  ---------------------------------------------------------- //
// 01/20/95  GSY  Initial coding.                                            //
// 01/20/95  GAH  Added MUNGA style comments and assertions.                 //
//---------------------------------------------------------------------------//
// Copyright (C) 1994-1995, Virtual World Entertainment, Inc.                //
//                      PROPRIETARY AND CONFIDENTIAL                         //
//===========================================================================//

#if !defined(RESOURCE_HPP)
#	define RESOURCE_HPP

#	if !defined(FILESTRM_HPP)
#		include <filestrm.hpp>
#	endif

	//##########################################################################
	//####################    ResourceDirectories    ###########################
	//##########################################################################

	struct ResourcePhysicalFormat;
	class ResourceFile;

	struct ResourceDirectories
	{
		const char *modelDirectory;
		const char *mapDirectory;
		const char *collisionDirectory;
		const char *audioDirectory;
		const char *videoDirectory;
		const char *gaugeDirectory;
		const char *animationDirectory;
	};

	//##########################################################################
	//###################    ResourceDescription    ############################
	//##########################################################################

	class ResourceDescription SIGNATURED
	{
		friend class ResourceFile;
      friend class StreamableResourceFile;

	//##########################################################################
	// Resource ID stuff
	//
	public:
		typedef int ResourceID;

		enum {
			NullResourceID = -1
		};

		ResourceID
			resourceID;

	//##########################################################################
	// Resource Lock stuff
	//
	public:
		void
			Lock()
				{if (!lockCount++) LoadResource();}
		void
			Unlock()
				{--lockCount;}

		Logical
			IsLocked()
				{return lockCount > 0;}

		void
			ReleaseUnlockedResource();

	protected:
		int
			lockCount;

	//##########################################################################
	// Resource Type stuff
	//
	public:
		typedef int ResourceType;

		enum
		{
			NullResourceType,

			//
			//      ONLY LIST RESOURCE TYPES HERE -- These Are Really OBSOLETE
			//
			ModelListResourceType,
			MapListResourceType,
			AudioStreamListResourceType,
			VideoListResourceType,
			SubsystemListResourceType,
			ControlMappingsListResourceType,
			DamageZoneListResourceType,
			SkeletonListResourceType,

			FirstNonListResourceType,
			MaxListResourceType = FirstNonListResourceType - 1,
			//
			//      ALL OTHER RESOURCE TYPES
			//
			BoxedSolidStreamResourceType = FirstNonListResourceType,
			VideoModelResourceType,
			StaticAudioStreamResourceType,
			InternalAudioStreamResourceType,
			ExternalAudioStreamResourceType,
			MakeMessageStreamResourceType,
			GameModelResourceType,
			AnimationResourceType,
			SubsystemModelStreamResourceType,
			GaugeImageStreamResourceType,
			ControlMappingStreamResourceType,
			DamageZoneStreamResourceType,
			SkeletonStreamResourceType,
			DropZoneResourceType,
			EnvironmentZoneResourceType,
			InterestZoneResourceType,
			VehicleTableResourceType,
			ExistanceBoxStreamResourceType,
			CameraStreamResourceType,
			RegistryStaticObjectStreamResourceType,
			DamageLookupTableStreamResourceType,
			ExplosionTableStreamResourceType,
			GaugeAlarmStreamResourceType,
			GaugeMissionReviewStreamResourceType,
			ScenarioRoleResourceType
		};

		ResourceType
			resourceType;

	//##########################################################################
	// Resource Name stuff
	//
	public:
		enum {
			NameSize = 32
		};

		char
			resourceName[NameSize];

	//##########################################################################
	// Loading stuff
	//
	public:
		enum
		{
			LoadedBit=0,
			LoadOnDemandBit
		};
		enum
		{
			Preload = 0,		// HACK - for backwards compatability
			LoadedFlag = 1 << LoadedBit,
			LoadOnDemandFlag = 1 << LoadOnDemandBit,
		};

		int
			downloadPriority;

		LWord
			resourceFlags;

		size_t
			offsetInFile;

		void
			SetLoaded()
				{Check(this); resourceFlags |= LoadedFlag;}
		void
			SetNotLoaded()
				{Check(this); resourceFlags &= ~LoadedFlag;}
		Logical
			IsLoaded()
				{Check(this); return (resourceFlags&LoadedFlag) != 0;}

		void
			LoadOnDemand()
				{Check(this); resourceFlags |= LoadOnDemandFlag;}
		void
			MarkForPreload()
				{Check(this); resourceFlags &= ~LoadOnDemandFlag;}
		Logical
			IsPreloadable()
				{Check(this); return (resourceFlags&LoadOnDemandFlag) == 0;}

	//##########################################################################
	// Construction and Destruction
	//
	protected:
		ResourceDescription(
			ResourceFile *file,
			const char* name,
			ResourceType type,
			int priority,
			LWord resource_flags,
			const void* address,
			size_t size,
			ResourceID index=NullResourceID
		);

		~ResourceDescription();

		void
			LoadResource();

	protected:
		ResourceFile
			*resourceFile;

	//##########################################################################
	// Resource Data stuff
	//
	public:
		void
			*resourceAddress;

		size_t
			resourceSize;

	//##########################################################################
	// Test stuff
	//
	public:
		Logical
			TestInstance() const;
	};

	//##########################################################################
	//      Format in physical memory: FILE,ROM,CD...
	//
	struct ResourcePhysicalFormat
	{
		ResourceDescription::ResourceID
			resourceID;
		ResourceDescription::ResourceType
			resourceType;
		char
			resourceName[32];
		int
			downloadPriority;
		LWord
			resourceFlags;
		size_t
			resourceOffset,
			resourceLength;
	};

	inline MemoryStream&
		MemoryStream_Read(
			MemoryStream* stream,
			ResourcePhysicalFormat *ptr
		)
			{return stream->ReadBytes(ptr, sizeof(*ptr));}
	inline MemoryStream&
		MemoryStream_Write(
			MemoryStream* stream,
			const ResourcePhysicalFormat *ptr
		)
			{return stream->WriteBytes(ptr, sizeof(*ptr));}

	//##########################################################################
	//#######################    ResourceFile    ###############################
	//##########################################################################

	class ResourceFile SIGNATURED
	{
		friend class ResourceDescription;

	public:
		//
		//-----------------------------------------------------------------------
		// Constructors & destructors
		//-----------------------------------------------------------------------
		//
		ResourceFile();
		~ResourceFile();

	public:
		//
		//-----------------------------------------------------------------------
		// Public data
		//-----------------------------------------------------------------------
		//
		enum {
			IndexBlockSize = 50
		};

		Byte
			versionArray[4];
		int
			labOnly;

	protected:
		ResourceDescription**
			resourceArray;
		int
			resourceArraySize;
		ResourceDescription::ResourceID
			lastPreallocatedResourceID,
			maxResourceID;

		virtual void
			LoadResource(ResourceDescription* res)
				{Check(res); res->SetLoaded();}

	public:
		//
		//-----------------------------------------------------------------------
		// Public interface
		//-----------------------------------------------------------------------
		//
		ResourceDescription::ResourceID
			GetMaxResourceID()
				{Check(this); return maxResourceID;}
		void
			PreAllocateIDs(ResourceDescription::ResourceID last_id)
				{
					Verify(lastPreallocatedResourceID == ResourceDescription::NullResourceID);
					lastPreallocatedResourceID = last_id;
				}

		ResourceDescription*
			AddResource(
				const char* name,
				ResourceDescription::ResourceType type,
				int priority,
				LWord load_flag,
				const void* address,
				size_t size,
				ResourceDescription::ResourceID index=-1
			);
		ResourceDescription*
			AddResourceList(
				const char* name,
				ResourceDescription::ResourceType type,
				int priority,
				LWord load_flag,
				const ResourceDescription::ResourceID* address,
				int count,
				ResourceDescription::ResourceID index=-1
			);
		ResourceDescription*
			AddResourceMemoryStream(
				const char* name,
				ResourceDescription::ResourceType type,
				int priority,
				LWord load_flag,
				MemoryStream* memory_stream,
				ResourceDescription::ResourceID index=-1
			);
		void
			DeleteResource(ResourceDescription *resource);

		ResourceDescription*
			FindResourceDescription(
				const char* name,
				ResourceDescription::ResourceType type,
				ResourceDescription::ResourceID after=-1
			);
		ResourceDescription*
			FindResourceDescription(
				ResourceDescription::ResourceID index
			);

		ResourceDescription*
			SearchList(
				ResourceDescription::ResourceID list_id,
				ResourceDescription::ResourceType type
			);
		ResourceDescription*
			SearchList(
				ResourceDescription::ResourceID list_id,
				const char* name
			);

		void
			ReleaseUnlockedResources();
		void
			ReportLockedResources();

		//
		//---------------------------------------------------------------------------
		// Lab tests
		//---------------------------------------------------------------------------
		//
	public:
		Logical
			TestInstance() const;
		static Logical
			TestClass();
	};

	//##########################################################################
	//###################  StreamableResourceFile  #############################
	//##########################################################################

	class StreamableResourceFile:
		public ResourceFile
	{
	public:
		//
		//------------------------------------------------------------------------
		// Constructors & destructors
		//------------------------------------------------------------------------
		//
		enum {
			FileNameLength = 80
		};


		StreamableResourceFile();
		StreamableResourceFile(const char * name);
		StreamableResourceFile(
			const char * name,
			Byte version_array[3],
			int match_level=3
		);
		~StreamableResourceFile();

	protected:
		void
			LoadResource(ResourceDescription* res);

		FileStream
			diskFile;

		//
		//------------------------------------------------------------------------
		// Public data
		//------------------------------------------------------------------------
		//
	public:
		char
			resourceFilename[FileNameLength];

		int
			Open(const char *file_name);
		int
			Save();
		int
			SaveAs(const char* file_name);

		Logical
			TestInstance() const;

		static Logical
			TestClass();
	};

#endif

