#include "c4d_string.h"
#include "c4d_memory.h"

void* String::operator new(size_t,int line,const CHAR *file)
{
	return C4DOS.St->Alloc();
}

void String::operator delete(void* del,int line, const CHAR *file)
{
	C4DOS.St->Free((String*)del);
}

void String::operator delete(void* del)
{
	C4DOS.St->Free((String*)del);
}

String::String(void)
{
	C4DOS.St->Init(this);
}

String::String(const String &cs)
{
	C4DOS.St->Init(this);
	C4DOS.St->CopyTo(&cs,this);
}

String::String(const CHAR *cstr,StringEncoding type)
{
	C4DOS.St->Init(this);
	C4DOS.St->InitCString(this,cstr,-1,type);
}

String::String(LONG count,UWORD fillch)
{
	C4DOS.St->Init(this);
	C4DOS.St->InitArray(this,count,fillch);
}

String::~String(void)
{
	C4DOS.St->Flush(this);
}

void String::CopyTo(String *str) const
{
	C4DOS.St->CopyTo(this,str);
}

String *String::GetClone(void) const
{
 	return C4DOS.St->GetClone(this);
}

const String& String::operator = (const String &cs)
{
	C4DOS.St->CopyTo(&cs,this);
	return *this;
}

void FreeString(String *&str)
{
	if (str) C4DOS.St->Free(str);
	str=NULL;
}

LONG String::GetLength(void) const
{
	return C4DOS.St->GetLength(this);
}

const String operator + (const String &Str1,const String &Str2)
{
	return String(Str1)+=Str2;
}

const String& String::operator += (const String &Str)
{
	Insert(GetLength(),Str);
	return *this;
}

Bool String::operator < (const String &Str) const
{
	return (Compare(Str) < 0);
}

Bool String::operator > (const String &Str) const
{
	return (Compare(Str) > 0);
}

Bool String::operator <= (const String &Str) const
{
	return (Compare(Str) <= 0);
}

Bool String::operator >= (const String &Str) const
{
	return (Compare(Str) >= 0);
}

Bool String::operator == (const String &Str) const
{
	return (Compare(Str) == 0);
}

Bool String::operator != (const String &Str) const
{
	return (Compare(Str) != 0);
}

LONG String::Compare(const String &cs) const
{
	return C4DOS.St->Compare(this,&cs,0);
}

LONG String::ComparePart(const String &Str, LONG cnt, LONG pos) const
{
	return (this->*C4DOS.St->ComparePart)(Str,cnt,pos);
}

LONG String::LexCompare(const String &cs) const
{
	return C4DOS.St->Compare(this,&cs,1);
}

LONG String::RelCompare(const String &cs) const
{
	return C4DOS.St->Compare(this,&cs,2);
}

Bool String::FindFirst(const String &cs,LONG *pos,LONG start) const
{
	return C4DOS.St->FindFirst(this,&cs,pos,start);
}

Bool String::FindLast(const String &cs,LONG *pos,LONG start) const
{
	return C4DOS.St->FindLast(this,&cs,pos,start);
}

Bool String::FindFirstUpper(const String &findupper, LONG *pos, LONG start) const
{
	return (this->*C4DOS.St->FindFirstUpper)(findupper,pos,start);
}

Bool String::FindLastUpper(const String &findupper, LONG *pos, LONG start) const
{
	return (this->*C4DOS.St->FindLastUpper)(findupper,pos,start);
}

Bool String::FindFirst(UWORD ch,LONG *pos,LONG start) const
{
	return (this->*C4DOS.St->FindFirstCh)(ch,pos,start);
}

Bool String::FindLast(UWORD ch,LONG *pos,LONG start) const
{
	return (this->*C4DOS.St->FindLastCh)(ch,pos,start);
}

void String::Delete(LONG pos,LONG count)
{
	C4DOS.St->Delete(this,pos,count);
}

void String::Insert(LONG pos,UWORD ch)
{
	String tmp = String(1,ch);
	C4DOS.St->Insert(this,pos,&tmp);
}

void String::Insert(LONG pos,const String &cs)
{
	C4DOS.St->Insert(this,pos,&cs);
}

const String String::SubStr(LONG start,LONG count) const
{
	String str,*s=C4DOS.St->SubStr(this,start,count);
	if (s) str=*s;
	FreeString(s);
	return str;
}

Real String::StringToReal(LONG *error, LONG unit, LONG angletype, LONG base) const
{
	return C4DOS.St->ToReal(this,error,unit,angletype,base);
}

LONG String::StringToLong(LONG *error) const
{
	return C4DOS.St->ToLong(this,error);
}

const String String::ToUpper() const
{
	String str,*s=C4DOS.St->ToUpper(this);
	if (s) str=*s;
	FreeString(s);
	return str;
}

const String String::ToLower() const
{
	String str,*s=C4DOS.St->ToLower(this);
	if (s) str=*s;
	FreeString(s);
	return str;
}

void String::GetUcBlock(UWORD *Ubc, LONG Max) const
{
	C4DOS.St->GetUcBlock((String*)this,Ubc,Max,FALSE);
}

void String::GetUcBlockNull(UWORD *Ubc, LONG Max) const
{
	C4DOS.St->GetUcBlock((String*)this,Ubc,Max,TRUE);
}

void String::SetUcBlock(UWORD *Ubc, LONG Count)
{
	C4DOS.St->SetUcBlock(this,Ubc,Count);
}

LONG String::GetCStringLen(StringEncoding type) const
{
	return C4DOS.St->GetCStringLen(this,type);
}

LONG String::GetCString(CHAR *scstr, LONG max, StringEncoding type) const
{
	return C4DOS.St->GetCString(this,scstr,max,type);
}

CHAR* String::GetCStringCopy(StringEncoding type) const
{
	LONG len = C4DOS.St->GetCStringLen(this,type);
	if (!len) return 0;

	CHAR *txt = (CHAR*)GeAlloc(len+2);
	if (!txt) return NULL;

	C4DOS.St->GetCString(this,txt,len+2,type);
	txt[len] = 0;

	return txt;
}

LONG String::SetCString(const CHAR *cstr, LONG count, StringEncoding type)
{
	String *s=C4DOS.St->AllocCString((CHAR*)cstr,count,type);
	if (s) *this=*s;
	FreeString(s);
	return GetLength();
}

const String LongToString(LONG l)
{
	String str,*s=C4DOS.St->LongToString(l);
	if (s) str=*s;
	FreeString(s);
	return str;
}

const String LLongToString(LLONG l)
{
	String str;
	C4DOS.St->LLongToString(l,&str);
	return str;
}

const String RealToString(Real v, LONG vvk, LONG nnk, Bool e, UWORD xchar)
{
	String str,*s=C4DOS.St->RealToString(v,vvk,nnk,e,xchar);
	if (s) str=*s;
	FreeString(s);
	return str;
}

const String::PChar String::operator[] (LONG Pos) const
{
	if (Pos >= GetLength() || Pos < 0) Pos = -1;
	return PChar((String *)(this),Pos);
}

String::PChar String::operator[] (LONG Pos)
{
	if (Pos >= GetLength() || Pos < 0) Pos = -1;
	return PChar(this,Pos);
}

String::PChar::PChar(String *str,LONG pos)
{
	Str = str;
	Pos = pos;
}

String::PChar& String::PChar::operator = (const PChar& rhs)
{
	if (!Str) return *this;
	if (Pos < 0 || Pos >= Str->GetLength()) return *this;
	
	C4DOS.St->SetChr(Str,Pos,C4DOS.St->GetChr(rhs.Str,rhs.Pos));
	return *this;
}

String::PChar& String::PChar::operator = (UWORD c)
{
	if (!Str) return *this;
	if (Pos < 0 || Pos >= Str->GetLength()) return *this;
	C4DOS.St->SetChr(Str,Pos,c);
	return *this;
}

String::PChar::operator UWORD(void) const
{
	if (!Str) return 0;
	if (Pos < 0 || Pos >= Str->GetLength()) return 0;
	else return C4DOS.St->GetChr(Str,Pos);
}

#if (defined _DEBUG) && (defined WIN32)
static CHAR array[1000];

CHAR *cstr(String &str)
{
	str.GetCString(array,1000);
	return array;
}

CHAR *cstr(const String &str)
{
	str.GetCString(array,1000);
	return array;
}

#include "c4d_file.h"

CHAR *cstr(Filename &fn)
{
	fn.GetString().GetCString(array,1000);
	return array;
}

CHAR *cstr(const Filename &fn)
{
	fn.GetString().GetCString(array,1000);
	return array;
}

#endif


String PtrToString(void *t_hex)
{
	VLONG hex = (VLONG)t_hex;
	CHAR hexstring[sizeof(VULONG)*2+4];
	LONG t,i;

	t = 0;
	hexstring[t++] = '0';
	hexstring[t++] = 'x';

	for (i=sizeof(VULONG)*8-4; i>=0; i-=4)
	{
		VULONG x = ((hex>>i)&0xF);
		if (x<10) hexstring[t++] = x+'0';
		else hexstring[t++] = x-10+'A';
	}
	hexstring[t]=0;
	return String(hexstring);
}

String MemoryToString(LLONG mem)
{
	if (mem>1024*1024*1024)
		return RealToString(Real(mem >> 20)/1024,0,2)+String(" GB");
	else if (mem>1024*1024)
		return RealToString(Real(mem >> 10)/1024,0,2)+String(" MB");
	else if (mem>1024)
		return RealToString(Real(mem)/(1024),0,2)+String(" KB");

	return LongToString(mem)+String(" B");
}
