#ifndef _COMMON_STRING_HPP_
#define _COMMON_STRING_HPP_
#include <string.h>
#ifndef _COMMON_STDLIB_HPP_
#include <common/stdlib.hpp>
#endif
#ifndef _COMMON_WINDOWS_HPP_
#include <common/windows.hpp>
#endif

template <class T>
class Block;
class istream;
class ostream;
class String;

istream &operator>>(istream &stream,String &someString);
ostream &operator<<(ostream &stream,const String &someString);

String operator+(const char *str,const String &string);

class String
{
public:
	enum{MaxString=128};
	String(void);
	String(const char *npStr);
	String(const String &newString);
	String(int resourceStringID);
	String(int resourceStringID,HINSTANCE hInstance);
	String(char characterItem);
	virtual ~String();
	int operator!=(const String &someString)const;
	int operator!=(const char *someCharStar)const;
	int operator==(const String &someString)const;
	int operator==(const char *someCharStar)const;
	int operator<(const String &someString)const;
	int operator>(const String &someString)const;
	String &operator=(const String &someString);
	int operator=(const char *someCharStar);
	int operator+=(const String &someString);
	int operator+=(const char *someStr);
	void operator+=(char someChar);
  char &operator[](DWORD itemIndex);
	char charAt(DWORD itemIndex)const;
	String &setAt(DWORD itemIndex,char ch);
	friend istream &operator>>(istream &stream,String &someString);
	friend ostream &operator<<(ostream &stream,const String &someString);
	operator char *(void)const;
	String operator+(const String &someString)const;
	int reserve(unsigned nBytes,WORD setZero=TRUE);
	int token(const char *token);
	int isNull(void)const;
	void upper(void);
	void lower(void);
	int length(void)const;
	void length(short newLength);
	DWORD lengthBytes(void)const;
	void removeTokens(String someTokens);
  void replaceToken(BYTE tokenFind,BYTE tokenReplace);
	int hex(void)const;
  void expand(void);
	void convert(double doubleValue,const char *formatString);
	void convert(int integerValue,const char *formatString);
	void convert(long longValue,const char *formatString);
	int strstr(const char *string)const;
	int strpos(const char *string)const;
	int strchr(char someChar)const;
	int strncmp(const char *string)const;
	String &trimRight(void);
  String &trimLeft(void);
	void spaceTerm(void);
	String betweenString(char beginToken,char endToken)const;
	String substr(WORD startPosition,WORD endPosition)const;
	String substr(WORD startPosition)const;
	String extractDigits(void)const;
	String extractAlpha(void)const;
	WORD makeBlock(Block<String> &receiveStrings,const String &tokenString)const;
	WORD insert(const String &insertString,WORD insertPosition=0);
	WORD insert(char *lpInsertString,WORD insertPosition=0);
	WORD remove(WORD removePosition=0);
  int toInt(void)const;
	short toShort(void)const;
	float toFloat(void)const;
	double toDouble(void)const;
	long toLong(void)const;
	String &fromInt(int value);
	String &fromShort(short value);
	String &fromUShort(unsigned short value);
	String &fromFloat(float value);
	String &fromLong(long value);
	String &fromBool(bool value);
	String &fromDouble(double value);
	bool equals(const String &string)const;
	const char *str(void)const;
	char *str(void);
	String quotes(void)const;
private:
	enum{Blank=' '};
	void shiftRight(String &shiftString,WORD startPos,WORD endPos,WORD insertLength,WORD originalLength);
	void removeData(void);
	HINSTANCE instanceData(void);

	char FAR *mnpStr;
  DWORD mLengthBytes;
};

inline
String::String(void)
: mnpStr(0), mLengthBytes(0L)
{
	reserve(MaxString);
}

inline
String::String(int resourceStringID)
: mnpStr(0), mLengthBytes(0L)
{
	reserve(MaxString);
	if(!::LoadString(instanceData(),resourceStringID,mnpStr,MaxString-1))::strcpy(mnpStr,"UNSET");
}

inline
String::String(int resourceStringID,HINSTANCE hInstance)
: mnpStr(0), mLengthBytes(0L)
{
	reserve(MaxString);
	if(!::LoadString(hInstance,resourceStringID,mnpStr,MaxString-1))::strcpy(mnpStr,"UNSET");
}

inline
String::String(char characterItem)
: mnpStr(0), mLengthBytes(0)
{
	reserve(sizeof(characterItem)+1);
	*mnpStr=characterItem;
}

inline
String::~String()
{
  removeData();
}

inline
String::operator char *(void)const
{
	return mnpStr;
}

inline
char &String::operator[](DWORD itemIndex)
{
  return *(mnpStr+itemIndex);
}

inline
String &String::setAt(DWORD itemIndex,char ch)
{
  *(mnpStr+itemIndex)=ch;
	return *this;
}

inline
char String::charAt(DWORD itemIndex)const
{
  return *(mnpStr+itemIndex);
}

inline
int String::reserve(unsigned nBytes,WORD setZero)
{
	if(!nBytes)return 0;
	if(nBytes>mLengthBytes)
	{
		removeData();
		mnpStr=::new char[nBytes];
		mLengthBytes=nBytes;
	}
	if(setZero)::memset(mnpStr,0,mLengthBytes);
	return 1;
}

inline
HINSTANCE String::instanceData(void)
{
#ifdef __FLAT__
	return ::GetModuleHandle(0);
#else
	return((HINSTANCE)(_DS-1));
#endif
}

inline
String String::substr(WORD startPosition)const
{
  return substr(startPosition,length());
}

inline
int String::length(void)const
{
	return (mnpStr?::strlen(mnpStr):0);
}

inline
void String::removeData(void)
{
	if(!mnpStr)return;
	::delete[] mnpStr;
	mnpStr=0;
  mLengthBytes=0;
}

inline
int String::isNull(void)const
{
	if(!mnpStr||!(*mnpStr))return 1;
	return 0;
}

inline
DWORD String::lengthBytes(void)const
{
  return mLengthBytes;
}

inline
int String::operator==(const String &someString)const
{
	if(!mnpStr&&!someString.mnpStr)return 1;
	if(!mnpStr||!someString.mnpStr)return 0;
	return (!::strcmp(mnpStr,someString.mnpStr));
}

inline
int String::operator!=(const String &someString)const
{
	if(!mnpStr&&!someString.mnpStr)return 0;
	if(!mnpStr||!someString.mnpStr)return 1;
	return (::strcmp(mnpStr,someString.mnpStr));
}

inline
int String::operator!=(const char *someCharStar)const
{
	if(!mnpStr&&!someCharStar)return 0;
	if(!mnpStr||!someCharStar)return 1;
	return (::strcmp(mnpStr,someCharStar));
}

inline
int String::operator==(const char *someCharStar)const
{
	if(!mnpStr&&!someCharStar)return 1;
	if(!mnpStr||!someCharStar)return 0;
  return (!::strcmp(mnpStr,someCharStar));
}

inline
int String::operator<(const String &someString)const
{
	if(isNull()&&someString.isNull())return FALSE;
	if(isNull())return TRUE;
	return (::strcmp(mnpStr,someString.mnpStr)<0?TRUE:FALSE);
}

inline
int String::operator>(const String &someString)const
{
	if(isNull()&&someString.isNull())return FALSE;
	if(isNull())return FALSE;
	return (::strcmp(mnpStr,someString.mnpStr)>0?TRUE:FALSE);
}

inline
int String::strstr(const char *string)const
{
	if(!mnpStr)return 0;
	return (int)::strstr(mnpStr,string);
}

inline
bool String::equals(const String &string)const
{
  return *this==string?true:false;
}

inline
const char *String::str(void)const
{
  return mnpStr;
}

inline
char *String::str(void)
{
  return mnpStr;
}

inline
String String::quotes(void)const
{
  return String("\"")+*this+String("\"");
}

typedef String string;

#endif
