/****************************************************************************************


		MCString.h


		Copyright: (c) 2001 Eovia Corp. All rights reserved.


		Author:	Ian (from RDSource)
		Date:	12/10/97

		Revision History

		when		who			what & why
		==========	==========	======================================================
		12/9/99		Ian			Added CompareQuick().
		11/3/99		Gerald		Added a virtual destructor on TMCString (derived classes could not
								properly be destroyed if deletion was done on an abstract TMCString*,
								=> Tons of possible leaks ! )
		10/13/99	Ian			AdaptToPlatform() was rolled into TranslateAfterRead().
		09/28/99	Guillaume	Moved Operator== and Operator!= within TMCString
		6/30/99		Yann		Fixed returned type of ToInt32() from uint32 to int32
		5/17/99		Ian			Added high-ascii translation accessors.
		2/16/99		Eml			separated asciiTranslationTable global in MCStringTable.cpp/h
		11/15/98	tsh			change kUndefinedIndex to 0xFFFFFFFF to make it unsigned,
								make ToPPtr and FromPPtr take uint8*
		11/5/98		Pbk			Changed String Indexing from 0 based to 0 based,
		11/5/98		Ian			Added GetSubStrByteLength(), and a constructor from an
								existing string, index and length.
		10/12/98	Nba			added copy constructor for TMCDynamicString
		6/11/98		Laurel		operator[]: call to GetChar() now uses a 0 based index.
									operator[] ought to also be 0 based for consistency.
		06/04/98	Nba			Had to make TMCString virtual, for DynamicStrings to work
		05/14/98	Nba			Added operator= for overriding default operator
								Changed void void return to type for operator = and +=
		5/05/98		Eml			removed dependency on TMCiostream
		4/30/98		Ian			Oops, when I converted all int32's to uint32's I changed
								the one for FromInt32(), just changed it back.
		4/30/98		Ian			Added MaxLength(), so you can find out what the maximum
								storage of the string is.
		4/14/98		link		Added FromFourCharT and ToFourCharT conversions.
		4/3/98		Laurel		TMCString::Erase(): now returns false if nothing was
									erased and true if something was erased.
		4/2/98		Ian			Added SetLength(), and made all int32's uint32's, there
								is no need to take int32's for most things, it just leaves
								us open to problems.
		4/2/98		Ian			Moved operators into MCStreamOperators.
		3/24/98		Laurel		Added FromReal32().
		3/23/98		Laurel		Changed instances of double to real64.
								ToDouble() -> ToReal64().
								FromDouble() -> FromReal64().
								Added ToReal32().

*****************************************************************************************/

#ifndef __MCString__
#define __MCString__

#if CP_PRAGMA_ONCE
#pragma once
#endif

#include "MCBasicTypes.h"
#include "ITranscoder.h"

#define kUndefinedIndex (0xFFFFFFFF)
#define kStartIndex (0)


/// \addtogroup MCCore
/// \{

/// class to convert characters between windows and mac encoding
///
class TMCAsciiTranslationTable : public TMCObject
{
public:
			TMCAsciiTranslationTable();
			~TMCAsciiTranslationTable();

	void	InitFromResourceData		(uint8* data, uint32 length);
	uint8*	FindEscapeChar				(uint8 ch, boolean inverse);
	
	uint8	fTable[256];
	uint8	fITable[256];
	uint8*	fEscapes;
	uint8*	fIEscapes;
};

/// \}


/// \addtogroup MCCore
/// \{

/// <P>TMCString is the base class from which all the different classes that represent strings are derived. <BR>
/// TMCString15, TMCString31, TMCString63, TMCString255 and TMCString1023 use a fix sized buffer (in bytes) to store their 
/// content. <BR>
/// On the other hand, TMCDynamicString reallocates its buffer whenever it needs to. </P>
///
/// When the application is compiled in double byte mode (for asian systems), strings use characters that can be encoded
/// over two bytes (but not every character is). The documentation precises which methods are "double byte aware".
///
class TMCString : public TMCObject0
{
public:

	/// Virtual Destructor for clean destructions
	///
	virtual	~TMCString(void) {}
	
	virtual TMCString&	operator=				(const TMCString& ss);
	virtual TMCString&	operator+=				(const TMCString& ss);
	virtual TMCString&	operator+=				(uint16 c);
	virtual boolean		operator<				(const TMCString& ss) const;
	virtual boolean		operator>				(const TMCString& ss) const;
	virtual boolean		operator<=				(const TMCString& ss) const;
	virtual boolean		operator>=				(const TMCString& ss) const;
	virtual boolean		operator==				(const TMCString& ss) const;
	virtual boolean		operator!=				(const TMCString& ss) const;


	/// Insert string ss at nIndex(1,String Length).
	///
	virtual void InsertStr			(const TMCString& ss, uint32 nIndex);
	
	/// Erase nCount characters from this string starting from nIndex.
	/// \note nIndex is 0 based & this routine is double-byte aware.
	///
	boolean	EraseStr				(uint32 nIndex, uint32 nCount);
	
	/// Make this string into a substring consisting of nCount characters starting at nIndex.
	/// \note nIndex is 0 based & this routine is double-byte aware.
	///
	void	SubString				(uint32 nIndex, uint32 nCount);
	
	/// Return the location of string ss in this, start the search at nIndex.
	/// \note nIndex is 0 based.
	///
	uint32	SearchStr				(const TMCString& ss, uint32 nIndex = kStartIndex) const;
	
	/// Replace each occurence of ss by replace, start the search at nIndex.
	/// Return the number of occurence replaced.
	/// \note nIndex is 0 based.
	///
	uint32  ReplaceStr				(const TMCString& ss, const TMCString& replace, uint32 nIndex = kStartIndex);

	/// Search forward for the location of character c in this, start the search at nIndex.
	/// \note nIndex is 0 based, this routine is double-byte aware.
	///
	uint32	FindCharPos				(uint16 c, uint32 nIndex = kStartIndex) const;
	
	/// Search backwards for the location of character c in this, start the search at the end of the string.
	/// \note This routine is double-byte aware.
	///
	uint32	FindCharPosFromRight	(uint16 c) const 
	{
		return FindCharPosFromRight(c, fLength-1);
	};
	
	/// Search backwards for the location of character c in this, start the search at nIndex
	/// \note nIndex is 0 based, this routine is double-byte aware.
	///
	uint32	FindCharPosFromRight	(uint16 c, uint32 nIndex) const;
	
	/// Return a const pointer to the string data contained in this string.
	///
	const	int8* StrGet			(void) const;
	
	/// Calculate the bytelength of a sub-string.
	///
	uint32	GetSubStringByteLength	(uint32 inIndex, uint32 inLength) const;
	
	/// Return the number of bytes used in this string.
	///
	uint32	ByteLength				(void) const
	{
		return fByteLength;
	};
	
	/// Return the number of characters in this string.
	/// \note This routine is double-byte aware.
	///
	uint32	Length					(void) const 
	{
		return fLength;
	};
	
	/// Set the number of characters in this string.
	/// \note This routine is double-byte aware.
	///
	void	SetLength				(uint32 inLength);
	
	/// Assign c to the nIndex character of this string.
	/// \note nIdex is 0 based, trying to set an out of range character does nothing.
	/// This routine is double-byte aware.
	///
	void	SetCharAt				(uint16 c, uint32 nIndex); 
	
	/// Retrieve the nIndex character of this string.
	/// \note nIndex is 0 based, trying to get an out of range character returns zero
	/// This routine is double-byte aware.
	uint16	GetCharAt				(uint32 nIndex) const;
	
	/// Fill in data as a c-style (NULL terminated) copy of this string.
	/// \note Data MUST be large enough to hold the string or you will corrupt memory.
	///
	void	ToCPtr					(int8* data) const;
	
	/// Fill in data as a pascal-style (length prefixed) copy of this string.
	/// \note Data MUST be large enough to hold the string or you will corrupt memory.
	///
	void	ToPPtr					(uint8* data) const;

	/// Fill in this string from an existing c-style (NULL terminated) string.
	/// \note If this is a static length string, trying to assign more characters
	/// than were declared for storage will ignore the extra characters
	void	FromUTF8Ptr				(const uint8* data)		{ FromCAsciiPtr((int8*)data); }
	
	/// Fill in data as a UTF-8 encoded (NULL terminated) copy of this string.
	/// \note Data MUST be large enough to hold the string or you will corrupt memory
	///
	void	ToUTF8Ptr				(uint8* data) const;

	/// Fill in this string from an existing c-style (NULL terminated) string.
	/// \note If this is a static length string, trying to assign more characters
	/// than were declared for storage will ignore the extra characters
	///
	void	FromCPtr				(const int8* data)		{ FromCAsciiPtr(data); }
	void	FromCAsciiPtr			(const int8* data);
	
	/// Fill in this string from an existing pascal-style (length prefixed) string.
	/// \note If this is a static length string, trying to assign more characters
	/// than were declared for storage will ignore the extra characters
	///
	void	FromPPtr				(const uint8* data);

	/// Fill in this string from an exsiting NULL terminated string that is
	/// encoded with the given encoding
	/// \note If this is a static length string, trying to assign more characters
	/// than were declared for storage will ignore the extra characters
	///
	void	FromEncodedPtr			(const uint8* data, ITranscoder* transcoder);

	/// Fill in this string from an existing UCS (Unicode NULL terminated) string.
	/// \note If this is a static length string, trying to assign more characters
	/// than were declared for storage will ignore the extra characters
	///
	void	FromUnicode				(const uint16* data);

	/// Fill in data as a UCS (Unicode NULL terminated) copy of this string.
	/// \note if the buffer is too small, the function will assert and clip the string
	///
	void	ToUnicode				(uint16* data, int32 dataSize) const;
	
	/// Fill in this string from a memory buffer and a length.
	/// \note If this is a static length string, trying to assign more characters
	/// than were declared for storage will ignore the extra characters
	///
	void	FromText				(const int8* data, uint32 length);
	
	/// Assign string data from a FourCharT.
	///
	void	FromFourCharT			(const FourCharT inCode, boolean inDontCheckValue);
	
	/// Convert string to a FourCharT.
	///
	FourCharT ToFourCharT			(void) const;
	
	/// Compare this string to another disregarding the case of the string.
	/// \return true if the strings are equivalent, false if not.
	/// \note This routine is double-byte aware, and SLOW.
	///
	boolean IsEqualNotCaseSensitive	(const TMCString& other) const;
	
	/// Compare this string to another disregarding the current language. <BR>
	/// Returns negative if this is less than other.<BR>
	/// Returns zero if this is equal to other.<BR>
	/// Returns positive if this is greater than other.<BR>
	///
	int8 CompareQuick(const TMCString& other) const;
	
	/// Convert the contents of this string to upper case.
	/// \note This routine is double-byte aware.
	///
	void	ToUpper					(void);
	
	/// Convert the contents of this string to lower case.
	/// \note This routine is double-byte aware.
	///
	void	ToLower					(void);
	
	/// Make the string lowercase and then make the first character (if it is a letter) uppercase.
	/// \note This routine is double-byte aware (meaning it won't do anything to a double-byte string).
	///
	void	Capitalize				(void);
	
	/// Fill in this string by convering the passed in value to a string.
	///
	void	FromInt32				(int32 x);
	
	/// Return this string as an int32 value.
	///
	int32	ToInt32					(void) const;
	
	/// Fill in this string by converting the passed in real32 to a string, using the number of decimals passed in.
	///
	void	FromReal32				(real32 inValue, uint8 inDecimals);
	
	/// Return this string as a real32 value.
	///
	real32	ToReal32				(void) const;
	
	/// Assign the character representation of the real64 value passed in with a %.pG print format (p= inPrecision)
	///
	void	FromReal64				(real64 inValue, uint8 inPrecision);
	
	/// Fill in this string by convering the passed in value to a string.
	/// \note The value will be truncated to 2 places of decimal precision (%.2f format);
	///
	void	FromReal64				(real64 xx);
	
	/// Return this string as a double value.
	///
	real64	ToReal64				(void) const;
	
	/// Returns true if this string represents a numerical value, false otherwise.
	///
	boolean IsNumericString			(void) const;
	
	/// Returns the character at inIndex position in the string.
	/// \note inIndex is 0 based.
	///
	uint16 operator[]				(uint32 inIndex) const 
	{
		return GetCharAt(inIndex);
	};
	
	void	TranslateAscii			(boolean inverse);	//Mac To PC and PC To Mac
	void	TranslateBeforeWrite	(TMCString& translatedString);
	void	TranslateAfterRead		(void);

	/// Converts line feed (\\r, \\n or \\r\\n) to mac format \\r
	enum ELineFeed
	{
		kMacLineFeed, ///< \\r
		kUnixLineFeed, ///< \\n
		kWinLineFeed, ///< \\r\\n
	};
	void	ConvertLineFeed(ELineFeed toType = kMacLineFeed);
	
	uint32	MaxLength				(void) const;
	
	// JulienDB
	// Methods dedicated to the simple byte version of Carrara ( to read Western ressources ) to 
	// be able to run it on a double byte OS version.
	void	TranslateSBAfterRead		(void);
	// JulienDB
	//Return the location of string ss in this, start the search at nIndex.
	//Note: nIndex is 0 based. Work only with Single Byte strings
	uint32	SearchSBStr				(const TMCString& ss, uint32 nIndex = kStartIndex) const;
	// JulienDB
	//Search forward for the location of character c in this, start the search at nIndex.
	//Note: nIndex is 0 based, this routine works only with single-byte strings
	uint32	FindSBCharPos			(int8 c, uint32 nIndex = kStartIndex) const;
	// JulienDB
	//Retrieve the nIndex character of this string.
	//Note: nIndex is 0 based, trying to get an out of range character returns '\0'.
	//This routine works only in single byte
	int8	GetSBCharAt				(uint32 nIndex) const;
	//Erase nCount characters from this string starting from nIndex.
	//Note: nIndex is 0 based & this routine is double-byte aware.
	boolean	EraseSBStr				(const uint32 nIndex, uint32 nCount);
	
	
protected:
	
	TMCString(void);
	
	//Setup this string. The string is copied from ll charcters of ss into myData, and sets
	//the strings maximum length as maxLength.
	void	Initialize				(int8* myData, uint32 maxLength, const int8* ss, uint32 ll);

	void	SetSBCharAt				(int8 c, int32 nIndex);//used by TranslateAscii
	
	//Resize the length of the text in this string, the resized string can not be
	//greater than the current maximum length.
	virtual void SetByteLength		(uint32 byteLength);

	//Sets the maximum Length (for strings that support reallocation
	virtual void SetMaxLength		(uint32 maxLength)		{}
	
	//Return a pointer to the internal storage of the string.
	virtual int8* GetString			() const=0;
	
	uint32 fLength;
	uint32 fByteLength;
	uint32 fMaxLength;
};

/// \}

inline uint32 TMCString::MaxLength(void) const{return fMaxLength;}

//For private use only?
#define DECLAREMCSTRING(size) \
class TMCString##size: public TMCString {\
public:\
	TMCString##size();\
	TMCString##size(const int8* ss);\
	TMCString##size(const int8* ss, uint32 length);\
	TMCString##size(const TMCString& astring);\
	TMCString##size(const TMCString& astring, uint32 inIndex, uint32 inLength = 0);\
	TMCString& operator=(const TMCString& ss);\
	TMCString##size &operator=(const TMCString##size& ss);\
protected:\
	virtual int8* GetString() const;\
	int8 fStringBuffer[size+1];\
	};

//Declare the common static storage strings.
DECLAREMCSTRING(15)
DECLAREMCSTRING(31)
DECLAREMCSTRING(63)
DECLAREMCSTRING(255)
DECLAREMCSTRING(1023)

/// \addtogroup MCCore
/// \{

/// \class TMCString15
///
/// TMCString class with a fixed buffer of 15+1 bytes
///

/// \class TMCString31
///
/// TMCString class with a fixed buffer of 31+1 bytes
///

/// \class TMCString63
///
/// TMCString class with a fixed buffer of 63+1 bytes
///

/// \class TMCString255
///
/// TMCString class with a fixed buffer of 255+1 bytes
///

/// \class TMCString1023
///
/// TMCString class with a fixed buffer of 1023+1 bytes
///

/// \}

/// \addtogroup MCCore
/// \{

/// String class with a dynamic buffer
///
class TMCDynamicString : public TMCString
{
	public:
		TMCDynamicString					();
		TMCDynamicString					(const int8* ss);
		TMCDynamicString					(const int8* ss, uint32 length);
		TMCDynamicString					(const TMCString& astring);
		TMCDynamicString					(const TMCString& astring, uint32 inIndex, uint32 inLength);
		TMCDynamicString					(const TMCDynamicString& astring);
		TMCDynamicString					(const TMCDynamicString& astring, uint32 inIndex, uint32 inLength);
		~TMCDynamicString					();
		TMCString& operator=				(const TMCString& ss);
		TMCDynamicString& operator=			(const TMCDynamicString& ss);
		TMCString& operator+=				(const TMCString& ss);
		TMCString& operator+=				(uint16 c);
		void InsertStr						(const TMCString& ss, uint32 nIndex);

		// appends a string
		void Append							(const int8* ss,uint32 byteCount);
	protected:
		void InitializeDynamic				(const int8* ss, uint32 length);
		//Resize the length of the text in this string, if the resized string would be
		//greater than the current maximum length, the storage is reallocated to fit the new length.
		virtual void SetByteLength			(uint32 byteLength);

		virtual void SetMaxLength			(uint32  maxLength);

		virtual void AllocateDynamicString	(uint32 byteLength);
		virtual int8* GetString				() const;

		int8*	fStringBuffer;
};	

/// \}

TMCString1023 operator+		(const TMCString& ss1, const TMCString& ss2);

extern const TMCString15 kNullString;

// simple class to manipulate unicode strings from TMCStrings
class TMCWideString {
public:
	TMCWideString();
	TMCWideString(const TMCString& string);
	TMCWideString(const int8* string);
	~TMCWideString();

	void			FromUnicode	(const uint16* data);

	TMCWideString&	operator=	(const TMCString& string);
	uint16&			operator[]	(uint32 index)		{ return fStringBuffer[index]; }

	uint32			Length()	{ return (fStringBuffer.GetElemCount() - 1); }
	uint16*			StrGet()	{ return fStringBuffer.ArrayData(); }

protected:
	void	FromString(const TMCString& string);

	TMCArray<uint16>	fStringBuffer;
};

#endif