#include <classes/DataStructures/String.h>

#include <string.h>
#include <iostream.h>

StringC::StringC(const STRPTR s)
	: len(s ? strlen(s) : 0),
	  buffer(s ? len+1 : 64)
{
	if (s)
		memcpy(buffer.buffer(),s,len+1)
	else
		*((UBYTE *) buffer.buffer()) = 0;
}

StringC::StringC(ULONG l, STRPTR s)
	: len(s ? l : 0),
	  buffer(s ? len+1 : 64)
{
	if (s)
	{
		memcpy(buffer.buffer(),s,len);
		*((UBYTE *) buffer.buffer() + len) = 0;
	}
	else
		*((UBYTE *) buffer.buffer()) = 0;
}

StringC::StringC(const StringC &s)
	: len(s.len),
	  buffer(s.buffer)
{
}

StringC::StringC(UBYTE c)
	: len(c ? 1 : 0 ),
	  buffer(64)
{
	*((UBYTE *) buffer.buffer()) = c;
	*((UBYTE *) buffer.buffer() + 1) = 0;
}

StringC::~StringC()
{
}

StringC::operator STRPTR() const
{
	return (STRPTR) buffer.buffer();
}

StringC &StringC::operator= (const StringC &s)
{
	if (this != &s)
	{
		len = s.len;
		buffer = s.buffer;
	};
	return *this;
}

StringC &StringC::operator= (const STRPTR s)
{
	if (s)
	{
		len = strlen(s);
		buffer.setBufferSize(len+1);
		memcpy(buffer.buffer(),s,len+1);
	}
	else {
		buffer.setBufferSize(64);
		*((UBYTE *) buffer.buffer()) = 0;
	};
	return *this;
}

StringC &StringC::operator+= (const StringC &s)
{
	if (s)
	{
		buffer.setBufferSize(len+s.len+1);
		memcpy(((UBYTE *) buffer.buffer()) + len,s.buffer.buffer(),s.len+1);
		len += s.len;
	};
	return *this;
}

StringC &StringC::operator+= (const STRPTR s)
{
	if (s)
	{
		ULONG l = strlen(s);
		buffer.setBufferSize(len+l+1);
		memcpy(((UBYTE *) buffer.buffer()) + len,s,l+1);
		len += l;
	};
	return *this;
}

UBYTE &StringC::operator[] (ULONG i)
{
	while (i >= buffer.size())
		buffer.doubleBuffer();
	return (UBYTE &) *((UBYTE *) buffer.buffer() + i);
}

ULONG StringC::length() const
{
	return len;
}

ULONG StringC::bufsize() const
{
	return buffer.size();
}

StringC StringC::left(ULONG i) const
{
	if (i > len)
		i = len;
	return StringC(i,(STRPTR) buffer.buffer());
}

StringC StringC::right(ULONG i) const
{
	if (i > len)
		i = len;
	return StringC(i,(STRPTR) buffer.buffer()+len-i);
}

StringC StringC::mid(ULONG i, ULONG j) const
{
	if (i > len)
		i = len;
	if (i + j > len)
		j = len - i;
	return StringC(i,(STRPTR) buffer.buffer()+j);
}

VOID StringC::doubleBuffer()
{
	buffer.doubleBuffer();
}

VOID StringC::shrinkBuffer()
{
	len = strlen((STRPTR) buffer.buffer());
	buffer.setBufferSize(len+1);
}

VOID StringC::setBufferSize(ULONG i)
{
	buffer.setBufferSize(i);
	if (i <= len)
	{
		len = i - 1;
		*((UBYTE *) buffer.buffer() + len) = 0;
	};
}

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

StringC operator+ (const StringC &s1, const StringC &s2)
{
	StringC s = s1;
	s += s2;
	return s;
}

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

BOOL operator== (const StringC &s1, const StringC &s2)
{
	return strcmp((STRPTR) s1,(STRPTR) s2) == 0;
}

BOOL operator!= (const StringC &s1, const StringC &s2)
{
	return strcmp((STRPTR) s1,(STRPTR) s2) != 0;
}

BOOL operator< (const StringC &s1, const StringC &s2)
{
	return strcmp((STRPTR) s1,(STRPTR) s2) < 0;
}

BOOL operator> (const StringC &s1, const StringC &s2)
{
	return strcmp((STRPTR) s1,(STRPTR) s2) > 0;
}

BOOL operator<= (const StringC &s1, const StringC &s2)
{
	return strcmp((STRPTR) s1,(STRPTR) s2) <= 0;
}

BOOL operator>= (const StringC &s1, const StringC &s2)
{
	return strcmp((STRPTR) s1,(STRPTR) s2) >= 0;
}

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

class ostream &operator<< (ostream &o, const StringC &s)
{
	o << (char *) (STRPTR) s;
	return o;
}

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

class istream &operator>> (istream &i, StringC &s)
{
	char c[STREAM_MAXSTRING];
	i >> c;
	s = (STRPTR) c;
	return i;
}
