#ifndef _CSTR_
#define _CSTR_

#include <MCCoordTypes.h>
#if GS_WIN
#include <TextUtils.h>
#endif

#include <FPNumerics.h>



short GS_API StrLen(const char *s);
void GS_API LongestValidStr(const char *start, char *end);
void GS_API CopyC2CStr(const char *src, char *dest, short maxLen);
void GS_API CopyP2CStr(ConstStr255Param ps, char *dest, short maxLen);
void GS_API CatCStr(const char *src, char *dest, short maxLen);

const char dfStyleFloat = 0;
const char dfStyleFixed = 1;


#define CSTR_INTERFACE(len) \
	class CStr##len { \
		private: \
			char		buf[len+1]; 					\
														\
		private:										\
			void Copy(const char *src)					{ CopyC2CStr(src,buf,len); } \
			void CopyPStr(ConstStr255Param ps)			{ CopyP2CStr(ps,buf,len); } \
														\
		public: 										\
			CStr##len()									{ buf[0] = 0;} \
			CStr##len(const char *s)					{ this->Copy(s); } \
			CStr##len(ConstStr255Param s)				{ this->CopyPStr(s); } \
			GS_API CStr##len(const long l);					\
			GS_API CStr##len(const double_t& d, const short digits = 6, const char style = dfStyleFixed); \
														\
			void GS_API LoadString(short id);					\
			void GS_API LoadIndString(short list, short index);\
			void GS_API LoadText(short id);					\
														\
			void GS_API ToPStr(StringPtr s, short maxLen) const;\
			double_t ToDouble()							{ return str2num(buf); } \
														\
			operator char*()							{ return buf; } \
			operator const char*() const				{ return buf; } \
														\
			char& operator[](Byte i)					{ return buf[i]; } \
			const char operator[](Byte i) const 		{ return buf[i]; } \
														\
			CStr##len& operator=(ConstStr255Param s)	{ this->CopyPStr(s); return *this; } \
			CStr##len& operator=(const CStr##len &s)	{ this->Copy(s.buf); return *this; } \
			CStr##len& operator=(const char *s)			{ this->Copy(s); return *this; } \
														\
			short Length() const						{ return StrLen(buf); } \
														\
			Boolean operator==(const char *s) const 	{ return IUMagIDString(buf, s, this->Length(), StrLen(s)) == 0; } \
			Boolean operator!=(const char *s) const 	{ return IUMagIDString(buf, s, this->Length(), StrLen(s)) != 0; } \
			Boolean operator==(ConstStr255Param s) const { return IUMagIDString(buf, &(s[1]), this->Length(), s[0]) == 0; } \
			Boolean operator!=(ConstStr255Param s) const { return IUMagIDString(buf, &(s[1]), this->Length(), s[0]) != 0; } \
														\
			Boolean operator<(const char *s) const		{ return IUMagString(buf, s, this->Length(), StrLen(s)) < 0; } \
			Boolean operator<=(const char *s) const		{ return IUMagString(buf, s, this->Length(), StrLen(s)) <= 0; } \
			Boolean operator>(const char *s) const		{ return IUMagString(buf, s, this->Length(), StrLen(s)) > 0; } \
			Boolean operator>=(const char *s) const		{ return IUMagString(buf, s, this->Length(), StrLen(s)) >= 0; } \
														\
			Boolean operator==(char c) const			{ return (buf[0] == c && buf[1] == 0); } \
			Boolean operator!=(char c) const			{ return (buf[0] != c || buf[1] != 0); } \
														\
			void Append(const char *src)				{ CatCStr(src,buf,len); } \
			CStr##len& operator<<(const char *src)		{ CatCStr(src,buf,len); return *this; } \
														\
			void Clear()								{ buf[0] = 0; } \
			void GS_API Trunc(const short index);				\
	}

#ifndef WINVER
#define CSTR_IMPLEMENTATION(len) \
	CStr##len::CStr##len(const long l) \
		{ Str32 ps; NumToString(l,ps); this->CopyPStr(ps); } \
	CStr##len::CStr##len(const double_t& d,  const short digits, const char style) \
		{ Str32 ps; decform df; df.style = style; df.digits = digits; univ_num2str(df,d,(char*)ps); this->CopyPStr(ps);} \
	void CStr##len::LoadString(short id) \
		{ StringHandle sh = GetString(id); HLock((Handle)sh); this->CopyPStr(*sh); \
		  HUnlock((Handle)sh); ReleaseResource((Handle)sh); } \
	void CStr##len::LoadIndString(short list, short index) \
		{ Str255 s; GetIndString(s,list,index); this->CopyPStr(s); } \
	void CStr##len::LoadText(short id) \
		{ Handle t = GetResource('TEXT',id); if (!t) return; HLock(t); this->Copy(*t); \
		  HUnlock(t); ReleaseResource(t); } \
	void CStr##len::ToPStr(StringPtr s, short maxLen) const \
	{ \
		char *dest = (char*)s + 1; \
		const char *src = buf; \
		short count = 0; \
		while (*src && count++ < maxLen) \
			*dest++ = *src++; \
		s[0] = DemoteTo<unsigned char>(kDarick,PinTo<unsigned char>(kDarick, count)); \
	} \
	void CStr##len::Trunc(const short index) \
	{ \
		if (index > len)  \
			return; \
		 \
		char *dest = buf + index; \
		LongestValidStr(buf,dest); \
	} 
#else
#define CSTR_IMPLEMENTATION(len) \
	GS_API CStr##len::CStr##len(const long l) \
		{ Str32 ps; NumToString(l,(unsigned char *)ps); this->CopyPStr(ps); } \
	GS_API CStr##len::CStr##len(const double_t& d,  const short digits, const char style) \
		{ char ps[32]; decform df; df.style = style; df.digits = digits; univ_num2str(df,d,(char *)ps); this->Copy(ps);} \
	void GS_API CStr##len::LoadString(short id) \
		{ StringHandle sh = GetString(id); HLock((Handle)sh); this->CopyPStr(*sh); \
		  HUnlock((Handle)sh); ReleaseResource((Handle)sh); } \
	void GS_API CStr##len::LoadIndString(short list, short index) \
		{ Str255 s; GetIndString(s,list,index); this->CopyPStr(s); } \
	void GS_API CStr##len::LoadText(short id) \
		{ Handle t = GetResource('TEXT',id); if (!t) return; HLock(t); this->Copy(*t); \
		  HUnlock(t); ReleaseResource(t); } \
	void GS_API CStr##len::ToPStr(StringPtr s, short maxLen) const \
	{ \
		char *dest = (char*)s + 1; \
		const char *src = buf; \
		int idx = 0;\
		short count = 0; \
		while (src[idx] && count++ < maxLen) \
			*dest++ = src[idx++]; \
		s[0] = DemoteTo<unsigned char>(kDarick,PinTo<unsigned char>(kDarick, count)); \
	} \
	void GS_API CStr##len::Trunc(const short index) \
	{ \
		if (index > len)  \
			return; \
		 \
		char *dest = buf + index; \
		LongestValidStr(buf,dest); \
	}
#endif

CSTR_INTERFACE(255);
CSTR_INTERFACE(63);
CSTR_INTERFACE(31);
CSTR_INTERFACE(27);
CSTR_INTERFACE(15);

CSTR_INTERFACE(20);
CSTR_INTERFACE(7);


#endif
