//===========================================================================//
// File:     string.hpp                                                      //
// Title:    Definition of CString class.                                    //
// Project:  Munga                                                           //
// Author:   Eric Huffman                                                    //
//---------------------------------------------------------------------------//
//   Date    Who  Modification                                               //
// --------  ---  ---------------------------------------------------------- //
// 03/21/95  ECH  Initial coding                                                                                                                          //
//---------------------------------------------------------------------------//
// Copyright (c) 1994-1995 Virtual World Entertainment, Inc.                 //
//   All rights reserved worldwide.                                          //
// This unpublished source code is PROPRIETARY and CONFIDENTIAL.             //
//===========================================================================//

#if !defined(CSTR_HPP)
#	define CSTR_HPP

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

	class CStringRepresentation;
	class CString;

	class MemoryStream;

	class StringRepresentation;
	class pString;
	class pcString;
	typedef StringRepresentation& rString;
	typedef const StringRepresentation& rcString;

	//##########################################################################
	//####################    StringRepresentation    ##########################
	//##########################################################################

	class StringRepresentation
	{
	private:
		char firstByte;

		//
		// A new string cannot be created directly.  It must already exist in
		// RAM and simply be pointed where needed
		//
		StringRepresentation();
		StringRepresentation(rcString string);

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// Accessor functions
	//
	public:
		const char&
			operator[](size_t index) const
				{Check(this); return (&firstByte)[index];}
		char&
			operator[](size_t index)
				{Check(this); return (&firstByte)[index];}

		operator const char*() const
			{Check(this); return &firstByte;}
		operator char*()
			{Check(this); return &firstByte;}

		size_t
			GetLength() const
				{Check(this); return strlen(&firstByte);}

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// Assignment functions
	//
	public:
		rString
			operator=(const char* string)
				{
					Check(this); Check_Pointer(string);
					strcpy(&firstByte, string); return *this;
				}
		rString
			operator=(rcString string)
				{
					Check(this); Check(&string);
					strcpy(&firstByte, &string.firstByte); return *this;
				}
		rString
			operator=(char byte)
				{Check(this); firstByte = byte; return *this;}


		rString
			operator+=(const char* string)
				{
					Check(this); Check_Pointer(string);
					strcat(&firstByte, string); return *this;
				}
		rString
			operator+=(char chr);

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// Comparison functions
	//
	public:
		int
			Compare(const char *string) const
				{return strcmp(&firstByte, string);}
		int
			Compare(
				const char *string,
				size_t length
			) const
				{return strncmp(&firstByte, string, length);}
		int
			CaselessCompare(const char *string) const
				{return stricmp(&firstByte, string);}
		int
			CaselessCompare(
				const char *string,
				size_t length
			) const
				{return strnicmp(&firstByte, string, length);}

		Logical
			operator<(const char* string) const
				{return Compare(string) < 0;}
		Logical
			operator<=(const char* string) const
				{return Compare(string) <= 0;}
		Logical
			operator>(const char* string) const
				{return Compare(string) > 0;}
		Logical
			operator>=(const char* string) const
				{return Compare(string) >= 0;}
		Logical
			operator==(const char* string) const
				{return Compare(string) == 0;}
		Logical
			operator!=(const char* string) const
				{return Compare(string) != 0;}

		Logical
			operator<(char chr) const
				{return firstByte < chr;}
		Logical
			operator<=(char chr) const
				{return firstByte <= chr;}
		Logical
			operator>(char chr) const
				{return firstByte > chr;}
		Logical
			operator>=(char chr) const
				{return firstByte >= chr;}
		Logical
			operator==(char chr) const
				{return firstByte == chr;}
		Logical
			operator!=(char chr) const
				{return firstByte != chr;}

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// Stream functions
	//
	public:
		friend ostream&
			operator <<(
				ostream &strm,
				rcString str
			)
				{return strm << &str.firstByte;}

		friend MemoryStream&
			MemoryStream_Read(
				MemoryStream* stream,
				StringRepresentation *str
			);

		friend MemoryStream&
			MemoryStream_Write(
				MemoryStream* stream,
				const StringRepresentation *str
			);

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// Test support
	//
	public:
		#if defined(USE_SIGNATURE)
			friend int
				Is_Signature_Bad(const StringRepresentation *p);
		#endif

		Logical
			TestInstance() const
				{return True;}
	};

	//##########################################################################
	//###########################    pString    ################################
	//##########################################################################

	class pString SIGNATURED
	{
		friend class pcString;

	protected:
		StringRepresentation* stringText;

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// Constructors
	//
	public:
		pString(char *string = NULL)
			{stringText = (StringRepresentation*)string;}
		pString(rString string)
			{stringText = &string;}
		pString(const pString& string)
			{stringText = string.stringText;}

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// Assignment functions
	//
	public:
		pString&
			operator=(char *string)
				{stringText = (StringRepresentation*)string; return *this;}
		pString&
			operator=(rString string)
				{stringText = &string; return *this;}
		pString&
			operator=(const pString& string)
				{stringText = string.stringText; return *this;}

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// Search functions
	//
	public:
		pString&
			operator++()
				{++SKIPPY_CAST(char*,stringText); return *this;}
		pString
			operator++(int)
				{return pString(SKIPPY_CAST(char*,stringText)++);}
		pString&
			operator--()
				{--SKIPPY_CAST(char*,stringText); return *this;}
		pString
			operator--(int)
				{return pString(SKIPPY_CAST(char*,stringText)--);}

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// Accessor functions
	//
	public:
		rString
			operator*() const
				{return *stringText;}
		StringRepresentation*
			operator->() const
				{return stringText;}

		char&
			operator[](size_t index) const
				{Check(this); return (*stringText)[index];}

		operator char*() const
			{Check(this); return (char*)stringText;}
		Logical
			operator!() const
				{return !stringText;}

		char**
			GetTextPtr()
				{return (char**)&stringText;}

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// Stream functions
	//
	public:
		friend MemoryStream&
			MemoryStream_Read(
				MemoryStream* stream,
				pString str
			)
				{return MemoryStream_Read(stream, str.stringText);}

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// Test support
	//
	public:
		Logical
			TestInstance() const
				{return True;}
	};

	//##########################################################################
	//#######################    pcString    #############################
	//##########################################################################

	class pcString SIGNATURED
	{
	protected:
		const StringRepresentation* stringText;

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// Constructors
	//
	public:
		pcString(const char *string = NULL)
			{stringText = (const StringRepresentation*)string;}
		pcString(rcString string)
			{stringText = &string;}
		pcString(const pString& string)
			{stringText = string.stringText;}
		pcString(const pcString& string)
			{stringText = string.stringText;}

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// Assignment functions
	//
	public:
		pcString&
			operator=(const char *string)
				{stringText = (const StringRepresentation*)string; return *this;}
		pcString&
			operator=(rcString string)
				{stringText = &string; return *this;}
		pcString&
			operator=(const pString& string)
				{stringText = string.stringText; return *this;}
		pcString&
			operator=(const pcString& string)
				{stringText = string.stringText; return *this;}

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// Search functions
	//
	public:
		pcString&
			operator++()
				{++SKIPPY_CAST(const char*,stringText); return *this;}
		pcString
			operator++(int)
				{return pcString(SKIPPY_CAST(const char*,stringText)++);}
		pcString&
			operator--()
				{--SKIPPY_CAST(const char*,stringText); return *this;}
		pcString
			operator--(int)
				{return pcString(SKIPPY_CAST(const char*,stringText)--);}

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// Accessor functions
	//
	public:
		rcString
			operator*() const
				{return *stringText;}
		const StringRepresentation*
			operator->() const
				{return stringText;}

		const char&
			operator[](size_t index) const
				{Check(this); return (*stringText)[index];}

		operator const char*() const
			{Check(this); return (const char*)stringText;}
		Logical
			operator!() const
				{return !stringText;}

		const char**
			GetTextPtr()
				{return (const char**)&stringText;}

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// Test support
	//
	public:
		Logical
			TestInstance() const
				{return True;}
	};

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// ASCII Conversions
	//
	void
		Convert_From_Ascii(
			const char* str,
			char* value
		);
	void
		Convert_From_Ascii(
			const char* str,
			Byte* value
		);
	void
		Convert_From_Ascii(
			const char* str,
			short* value
		);
	void
		Convert_From_Ascii(
			const char* str,
			Word* value
		);
	void
		Convert_From_Ascii(
			const char* str,
			int* value
		);
	void
		Convert_From_Ascii(
			const char* str,
			unsigned* value
		);
	void
		Convert_From_Ascii(
			const char* str,
			long* value
		);
	void
		Convert_From_Ascii(
			const char* str,
			LWord* value
		);

	//##########################################################################
	//#####################    CStringRepresentation    ########################
	//##########################################################################

	class CStringRepresentation SIGNATURED
	{
		friend CString;

		friend CString
			operator + (
				const CString &str1,
				const CString &str2
			);

		friend CString
			operator + (
				const CString &str1,
				char ch
			);

		friend MemoryStream&
			MemoryStream_Read(
				MemoryStream* stream,
				CString *str
			);

		friend void
			Convert_From_Ascii(
				const char *str,
				CString *value
			);

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// Construction, Destruction
	//
	private:
		CStringRepresentation();
		CStringRepresentation(const CStringRepresentation &str);
		CStringRepresentation(const char *cstr);

	public:
		~CStringRepresentation();

		Logical
			TestInstance() const;

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// Length, Size
	//
	private:
		//
		// Length returns strlen of string
		//
		size_t
			Length() const;
		//
		// Size returns memory allocation size
		//
		size_t
			Size() const;

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// Accesors & Manipulation
	//
	private:
		//
		// create a c-string from CStringRepresentation method
		// HACK - ECH 11/1/95 - Remove const to support 3rd party libs
		//
		operator char*() const;

		//
		// assignment method
		//
		CStringRepresentation
			operator = (const CStringRepresentation &str);
		CStringRepresentation
			operator = (const char *cstr);

		//
		// concatenation methods
		//
		friend CStringRepresentation
			operator + (
				const CStringRepresentation &str1,
				const CStringRepresentation &str2
			);

		friend CStringRepresentation
			operator + (
				const CStringRepresentation & str1,
				char ch
			);

		void
			operator += (const CStringRepresentation &str);
		void
			operator += (char ch);

		//
		// comparison methods
		//
		int
			Compare(const CStringRepresentation &str) const;

		int
			operator < (const CStringRepresentation &str) const;
		int
			operator > (const CStringRepresentation &str) const;
		int
			operator <= (const CStringRepresentation &str) const;
		int
			operator >= (const CStringRepresentation &str) const;
		int
			operator == (const CStringRepresentation &str) const;
		int
			operator != (const CStringRepresentation &str) const;

		//
		// character retrieval method
		//
		char
			operator [] (size_t pos) const;

		CStringRepresentation
			GetNthToken(
				size_t nth_token,
				char *delimiters=NULL
			) const;

		//
		// case-modification methods
		//
		#if 0
		void
			ToUpper();
		void
			ToLower();
		#endif

		//
		// stream input/output methods
		//
		friend ostream&
			operator << (
				ostream &strm,
				const CStringRepresentation &str
			);

		friend MemoryStream&
			MemoryStream_Read(
				MemoryStream* stream,
				CStringRepresentation *str
			);

		friend MemoryStream&
			MemoryStream_Write(
				MemoryStream* stream,
				const CStringRepresentation& str
			);

		friend void
			Convert_From_Ascii(
				const char *str,
				CStringRepresentation *value
			);

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// Reference count methods
	//
	private:
		void
			IncrementReferenceCount();

		void
			DecrementReferenceCount();

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// Private Data
	//
	private:
		//
		// class constant
		//
		static size_t
			allocationIncrement;

		//
		// calc alloc size for needed bytes
		//
		static size_t
			CalculateSize(size_t needed);

		//
		// instance variables
		//
		size_t
			stringSize;
		size_t
			stringLength;
		char
			*stringText;

		//
		// reference count
		//
		int
			referenceCount;
	};

	//~~~~~~~~~~~~~~~~~~~~~~~~ CStringRepresentation inlines ~~~~~~~~~~~~~~~~~~~

	// value return methods
	inline size_t
		CStringRepresentation::Length() const
	{
		Check(this);
		return stringLength;
	}

	inline size_t
		CStringRepresentation::Size() const
	{
		Check(this);
		return stringSize;
	}

	// create a c-string from CStringRepresentation method
	// HACK - ECH 11/1/95 - Remove const to support 3rd party libs
	inline
		CStringRepresentation::operator char*() const
   {
      Check(this);
		return stringText;
   }

	// concatenation methods
	inline void
		CStringRepresentation::operator += (const CStringRepresentation &str)
	{
		Check(this);
		*this = *this + str;
	}

	inline void
		CStringRepresentation::operator += (char ch)
	{
		Check(this);
		*this = *this + ch;
	}

	// comparison methods
	inline int
		CStringRepresentation::operator < (const CStringRepresentation &str) const
	{
		return (Compare(str) < 0);
   }

	inline int
		CStringRepresentation::operator > (const CStringRepresentation &str) const
   {
		return (Compare(str) > 0);
	}

	inline int
		CStringRepresentation::operator <= (const CStringRepresentation &str) const
	{
      return !(Compare(str) > 0);
   }

	inline int
		CStringRepresentation::operator >= (const CStringRepresentation &str) const
	{
      return !(Compare(str) < 0);
	}

	inline int
		CStringRepresentation::operator == (const CStringRepresentation &str) const
   {
      return (Compare(str) == 0);
   }

	inline int
		CStringRepresentation::operator != (const CStringRepresentation &str) const
	{
		return (Compare(str) != 0);
   }

	// character retrieval method
	inline char
		CStringRepresentation::operator [] (size_t pos) const
	{
		Check(this);
		return (pos >= stringLength) ? ('\x00') : (stringText[pos]);
	}

	// stream input/output methods
	inline ostream&
		operator << (ostream &strm, const CStringRepresentation &str)
	{
	  Check(&str);
	  strm << str.stringText;
	  return strm;
	}

	// Reference count methods
	inline void
		CStringRepresentation::IncrementReferenceCount()
	{
		Check(this);
		Verify(referenceCount >= 0);
		referenceCount++;
	}

	inline void
		CStringRepresentation::DecrementReferenceCount()
	{
		Check(this);
		Verify(referenceCount > 0);
		if (--referenceCount == 0)
		{
			Unregister_Object(this);
			delete this;
		}
	}

	//##########################################################################
	//############################    CString    ###############################
	//##########################################################################

	class CString SIGNATURED
	{
	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// Construction, Destruction
	//
	public:
		CString();
		CString(const CString &str);
		CString(const char *cstr);

		~CString();

		Logical
			TestInstance() const;
		static Logical
			TestClass();

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// Length, Size
	//
	public:
		//
		// Length returns strlen of string
		//
		size_t
			Length() const;
		//
		// Size returns memory allocation size
		//
		size_t
			Size() const;

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// Accesors & Manipulation
	//
	public:
		//
		// create a c-string from CString method
		// HACK - ECH 11/1/95 - Remove const to support 3rd party libs
		//
		operator char*() const;

		//
		// assignment method
		//
		CString
			operator = (const CString &str);
		CString
			operator = (const char *cstr);

		//
		// concatenation methods
		//
		friend CString
			operator + (
				const CString &str1, 
				const CString &str2
			);

		friend CString
			operator + (
				const CString & str1,
				char ch
			);

		void
			operator += (const CString &str);
		void
			operator += (char ch);

		//
		// comparison methods
		//
		int
			Compare(const CString &str) const;

		int
			operator < (const CString &str) const;
		int
			operator > (const CString &str) const;
		int
			operator <= (const CString &str) const;
		int
			operator >= (const CString &str) const;
		int
			operator == (const CString &str) const;
		int
			operator != (const CString &str) const;

		//
		// character retrieval method
		//
		char
			operator [] (size_t pos) const;
	
		CString
			GetNthToken(
				size_t nth_token,
				char *delimiters=NULL
			) const;

		//
		// stream input/output methods
		//
		friend
			ostream & operator << (
				ostream &strm,
				const CString &str
			);

		friend MemoryStream&
			MemoryStream_Read(
				MemoryStream* stream,
				CString* str
			);

		friend MemoryStream&
			MemoryStream_Write(
				MemoryStream* stream,
				const CString* str
			);

		friend void
			Convert_From_Ascii(
				const char *str,
				CString *value
			);

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// Private Data
	//
	private:
		CStringRepresentation
			*representation;
	};

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~ CString inlines ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

	// construction, destruction, testing
	inline
		CString::CString()
	{
		representation = new CStringRepresentation;
		Register_Object(representation);
		representation->IncrementReferenceCount();
		Verify(representation->referenceCount == 1);
	}

	inline
		CString::CString(const CString &str)
	{
		Check(&str);
		representation = str.representation;
		Check(representation);
		representation->IncrementReferenceCount();
	}

	inline
		CString::CString(const char *cstr)
	{
		representation = new CStringRepresentation(cstr);
		Register_Object(representation);
		representation->IncrementReferenceCount();
		Verify(representation->referenceCount == 1);
	}

	inline
		CString::~CString()
	{
		Check(representation);
		representation->DecrementReferenceCount();
	}

	inline Logical
		CString::TestInstance() const
	{
		Check(representation);
		return True;
	}

	// length, size
	inline size_t
		CString::Length() const
	{
		Check(representation);
		return representation->Length();
	}

	inline size_t
		CString::Size() const
	{
		Check(representation);
		return representation->Size();
	}

	// create a c-string from CString method
	// HACK - ECH 11/1/95 - Remove const to support 3rd party libs
	inline
		CString::operator char*() const
	{
		Check(representation);
		return representation->stringText;
	}

	// concatenation methods
	inline CString
		operator + (
			const CString &str1,
			const CString &str2
		)
	{
		Check(&str1);
		Check(&str2);
		CStringRepresentation temp = *str1.representation + *str2.representation;
		return CString(temp.stringText);
	}

	inline CString
		operator + (
			const CString &str1,
			char ch
		)
	{
		Check(&str1);
		CStringRepresentation temp = *str1.representation + ch;
		return CString(temp.stringText);
	}

	inline void
		CString::operator += (const CString &str)
	{
		Check(this);
		Check(&str);
		*this = *this + str;
	}

	inline void
		CString::operator += (char ch)
	{
		Check(this);
		*this = *this + ch;
	}

	// comparison methods
	inline int
		CString::Compare(const CString &str) const
	{
		Check(&str);
		Check(representation);
		return representation->Compare(*str.representation);
   }

	inline int
		CString::operator < (const CString &str) const
	{
      return (Compare(str) < 0);
   }

	inline int
		CString::operator > (const CString &str) const
   {
      return (Compare(str) > 0);
   }

	inline int
		CString::operator <= (const CString &str) const
   {
		return !(Compare(str) > 0);
   }

	inline int
		CString::operator >= (const CString &str) const
   {
      return !(Compare(str) < 0);
   }

	inline int
		CString::operator == (const CString &str) const
   {
		return (Compare(str) == 0);
	}

	inline int
		CString::operator != (const CString &str) const
   {
      return (Compare(str) != 0);
   }

	// character retrieval method
	inline char
		CString::operator [] (size_t pos) const
	{
		Check(representation);
		return (*representation)[pos];
	}

	inline CString
		CString::GetNthToken(
			size_t nth_token,
			char *delimiters
		) const
	{
		Check(representation);
		CStringRepresentation temp =
			representation->GetNthToken(nth_token, delimiters);
		return CString(temp.stringText);
	}

	// stream input/output methods
	inline ostream&
		operator << (
			ostream &strm,
			const CString &str
		)
	{
		Check(&str);
		strm << *str.representation;
		return strm;
	}

	inline MemoryStream&
		MemoryStream_Write(
			MemoryStream* stream,
			const CString* str
		)
	{
		return MemoryStream_Write(stream, *str->representation);
	}

#endif
