//===========================================================================//
// File:	memstrm.hpp                                                         //
// Project: MUNGA           Brick: Resource Manager		                    //
// Contents: Implementation Details of resource management                   //
//---------------------------------------------------------------------------//
//   Date    Who  Modification                                               //
// --------  ---  ---------------------------------------------------------- //
//---------------------------------------------------------------------------//
// Copyright (C) 1994-1995, Virtual World Entertainment, Inc.                //
//                      PROPRIETARY AND CONFIDENTIAL                         //
//===========================================================================//

#if !defined(MEMSTRM_HPP)
#	define MEMSTRM_HPP

#	if !defined(STYLE_HPP)
#		include <style.hpp>
#	endif

	class MemoryStream;
	class DynamicMemoryStream;

	//##########################################################################
	//#######################    MemoryStream    ###############################
	//##########################################################################

	class MemoryStream SIGNATURED
	{
		friend MemoryStream&
			MemoryStream_Write(
				MemoryStream *stream,
				const MemoryStream *input_stream
			);

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// Constructors
	//
	public:
		MemoryStream(
			void *stream_start,
			size_t stream_size,
			size_t initial_offset=0
		);

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// Status functions
	//
	public:
		virtual void*
			GetPointer() const
				{Check(this); return currentPosition;}
		size_t
			GetIndex() const
				{Check(this); return currentPosition - streamStart;}
		size_t
			GetSize() const
				{Check(this); return streamSize;}

		size_t
			GetBytesUsed() const
				{Check(this); return currentPosition - streamStart;}
		virtual size_t
			GetBytesRemaining() const
				{Check(this); return streamSize - GetBytesUsed();}

		virtual void
			SetPointer(void *new_pointer)
				{
					Check_Pointer(this);
					currentPosition = (char*)new_pointer;
					Check(this);
				}
		void
			operator=(void *new_pointer)
				{SetPointer(new_pointer);}

		virtual void
			SetPointer(size_t index)
				{
					Check_Pointer(this);
					currentPosition = streamStart + index;
					Check(this);
				}
		void
			operator=(size_t index)
				{SetPointer(index);}

		void
			Rewind()
				{SetPointer(0U);}

		virtual Logical
			AllocateBytes(size_t count)
				{return GetBytesRemaining() <= count;}
		virtual MemoryStream&
			AdvancePointer(size_t count)
				{
					Check(this);
					currentPosition += count;
					Check(this);
					return *this;
				}
		MemoryStream&
			operator+=(size_t count)
				{return AdvancePointer(count);}

		virtual MemoryStream&
			RewindPointer(size_t count)
				{
					Check(this);
					currentPosition -= count;
					Check(this);
					return *this;
				}
		MemoryStream&
			operator-=(size_t count)
				{return RewindPointer(count);}

		virtual MemoryStream&
			ReadBytes(
				void *ptr,
				size_t number_of_bytes
			);
		virtual MemoryStream&
			WriteBytes(
				const void *ptr,
				size_t number_of_bytes
			);

		Logical
			TestInstance() const;

	protected:
		char
			*streamStart,
			*currentPosition;
		size_t
			streamSize;
	};

	//--------------------------------------------------------------------------
	// Extraction operators
	//
	template <class T> inline MemoryStream&
		operator>>(
			MemoryStream &stream,
			T &output
		)
			{return MemoryStream_Read(&stream, &output);}

	inline MemoryStream&
		MemoryStream_Read(
			MemoryStream* stream,
			char *output
		)
			{return stream->ReadBytes(output, sizeof(*output));}
	inline MemoryStream&
		MemoryStream_Read(
			MemoryStream* stream,
			Byte *output
		)
			{return stream->ReadBytes(output, sizeof(*output));}

	inline MemoryStream&
		MemoryStream_Read(
			MemoryStream* stream,
			short *output
		)
			{return stream->ReadBytes(output, sizeof(*output));}
	inline MemoryStream&
		MemoryStream_Read(
			MemoryStream* stream,
			Word *output
		)
			{return stream->ReadBytes(output, sizeof(*output));}

	inline MemoryStream&
		MemoryStream_Read(
			MemoryStream* stream,
			int *output
		)
			{return stream->ReadBytes(output, sizeof(*output));}
	inline MemoryStream&
		MemoryStream_Read(
			MemoryStream* stream,
			unsigned *output
		)
			{return stream->ReadBytes(output, sizeof(*output));}

	inline MemoryStream&
		MemoryStream_Read(
			MemoryStream* stream,
			long *output
		)
			{return stream->ReadBytes(output, sizeof(*output));}
	inline MemoryStream&
		MemoryStream_Read(
			MemoryStream* stream,
			LWord *output
		)
			{return stream->ReadBytes(output, sizeof(*output));}

	//--------------------------------------------------------------------------
	// Insertion operators
	//
	template <class T> inline MemoryStream&
		operator<<(
			MemoryStream &stream,
			const T &input
		)
			{return MemoryStream_Write(&stream, &input);}

	inline MemoryStream&
		MemoryStream_Write(
			MemoryStream* stream,
			const char *input
		)
			{return stream->WriteBytes(input, sizeof(*input));}
	inline MemoryStream&
		MemoryStream_Write(
			MemoryStream* stream,
			const Byte *input
		)
			{return stream->WriteBytes(input, sizeof(*input));}

	inline MemoryStream&
		MemoryStream_Write(
			MemoryStream* stream,
			const short *input
		)
			{return stream->WriteBytes(input, sizeof(*input));}
	inline MemoryStream&
		MemoryStream_Write(
			MemoryStream* stream,
			const Word *input
		)
			{return stream->WriteBytes(input, sizeof(*input));}

	inline MemoryStream&
		MemoryStream_Write(
			MemoryStream* stream,
			const int *input
		)
			{return stream->WriteBytes(input, sizeof(*input));}
	inline MemoryStream&
		MemoryStream_Write(
			MemoryStream* stream,
			const unsigned *input
		)
			{return stream->WriteBytes(input, sizeof(*input));}

	inline MemoryStream&
		MemoryStream_Write(
			MemoryStream* stream,
			const long *input
		)
			{return stream->WriteBytes(input, sizeof(*input));}
	inline MemoryStream&
		MemoryStream_Write(
			MemoryStream* stream,
			const LWord *input
		)
			{return stream->WriteBytes(input, sizeof(*input));}

	MemoryStream&
		MemoryStream_Write(
			MemoryStream* stream,
			istream *input
		);
	MemoryStream&
		MemoryStream_Write(
			MemoryStream* stream,
			const MemoryStream* input_stream
		);

	#define MEM_STRM_WRITE_ENTRY(stream, name_list, type, name)\
		{\
			type name;\
			Check(name_list);\
			const char* data = (const char*)(name_list)->FindData(#name);\
			if (!data)\
			{\
				DEBUG_STREAM << "DYN_MEM_STRM_WRITE_ENTRY - #name == ";\
				DEBUG_STREAM << #name << "\n";\
				Fail("DYN_MEM_STRM_WRITE_ENTRY - (name_list)->FindData(#name) == NULL");\
			}\
			Check_Pointer(data);\
			Convert_From_Ascii(data, &name);\
			stream << name;\
		}

	//##########################################################################
	//###################    DynamicMemoryStream    ############################
	//##########################################################################

	class DynamicMemoryStream:
		public MemoryStream
	{
	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// Construction, Destruction, and Testing
	//
	public:
		DynamicMemoryStream(size_t stream_size=0);
		DynamicMemoryStream(
			void *stream_start,
			size_t stream_size,
			size_t initial_offset=0
		);
		~DynamicMemoryStream();

		Logical
			TestInstance() const
				{
					return
						(size_t)(currentPosition - streamStart) <= streamSize
						 && streamLength <= streamSize;
				}

		size_t
			GetBytesRemaining() const
				{
					Check(this);
					return streamLength - GetBytesUsed();
				}

		Logical
			AllocateBytes(size_t count);

		MemoryStream&
			WriteBytes(
				const void *ptr,
				size_t number_of_bytes
			);

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// Private data
	//
	private:
		size_t
			streamLength;
		Logical
			ownsStream;
	};

#endif

