#include "String.h"
#include <string.h>
#include <stdio.h>
#include <assert.h>
#include <stdlib.h>
#include <memory.h>

String::~String()	{ if(name)	free(name);}

BOOL String::compare_text(C char * p) C
{ return memcmp(name, p, l)==0; }

BOOL String::operator==(C char *p) C
{ return name ? (p && strcmp(name, p)==0) : (!p || !*p); }

inline char * smalloc(int x) { return (char *)malloc(x);}

String::String(C String& a)
: name(a.name&&a.l ? smalloc(a.l+1) : 0), l(a.l)
{
 if(name)	memcpy(name, a.name, l+1);
 else l=0;
}

String::String(C char *n, int lng)
: l(lng<0&&n ? strlen(n): lng), name(n&&l>0 ? smalloc(l+1) : 0)
{if(name)	{memcpy(name, n, l); name[l]='\0';}  else l=0;}

String& String::operator=(C String& a)
{
 if(name && name!=a.name) {free(name); name=0; l=0;}
 if(a.name && a.name!=name)	{
 	name = smalloc(a.l+1);
 	if(name)	{ l=a.l; memcpy(name, a.name, l+1); }
	else	l = 0;
	}
 return *this;
}


String& String::operator=(C char *s)
{
 if(name && name!=s)	{	free(name); name=0; l=0;}
 if(s && *s && name!=s)	{
 	l = strlen(s);
 	name = smalloc(l+1);
 	if(name)	memcpy(name, s, l+1);
	else l=0;
	}
 return *this;
}

String& String::operator+=(C String& s)
{
 if(s.l > 0)	{
 	char *tmp = name;
	int oldsize = l;
	l = oldsize + s.l;
 	name = smalloc(l+1);
 	if(name)	{
		if(tmp)	memcpy(name, tmp, oldsize+1);
		if(s.name)	memcpy(&name[oldsize], s.name, s.l+1);
		}
	else	l = 0;
 	free(tmp);
	}
 return *this;
}

String& String::operator+=(C char * s)
{
 C int l2 = s ? strlen(s) : 0;
 if(l2 > 0)	{
 	char *tmp = name;
	int oldsize = l;
	l = oldsize + l2;
 	name = smalloc(l+1);
 	if(name)	{
		if(tmp)	memcpy(name, tmp, oldsize+1);
		if(s)	memcpy(&name[oldsize], s, l2+1);
		}
	else	l = 0;
 	free(tmp);
	}
 return *this;
}

BOOL String::begins_with(C String& ps) C
{
 C char *s = name;
 C char *p = ps.name;
 while(s<name+l && p<ps.name+ps.l && *s==*p)
	{s++; p++;}
 return p>=ps.name+ps.l;
}

BOOL String::begins_with(C char *p) C
{
 if(!p)	return TRUE;
 assert(!name || name[l]=='\0');
 C char *s = name;
 while(s<name+l && *p && *s==*p)
	{s++; p++;}
 return !*p;
}

String operator+(C String& a, C String& b)
{
 if(a.length() == 0)	return b;
 else if(b.length() == 0)	return a;

 char *p = smalloc(a.length() + b.length() + 1);
 if(!p)	return String();

 memcpy(p, a.name, a.length());
 memcpy(&p[a.length()], b.name, b.length()+1);
 return String(p, a.length()+b.length());
}

String operator+(C String& a, C char * b)
{
 C int l2 = b ? strlen(b) : 0;
 if(l2 == 0)	return a;
 if(a.length() == 0)	return String(b);

 char *p = smalloc(a.length() + l2 + 1);
 if(!p)	return String();

 memcpy(p, a.name, a.length());
 memcpy(&p[a.length()], b, l2+1);
 return String(p, a.length()+l2);
}

String operator+(C char *b, C String& a)
{
 C int l2 = b ? strlen(b) : 0;
 if(l2 == 0)	return a;
 if(a.length() == 0)	return String(b);

 char *p = smalloc(a.length() + l2 + 1);
 if(!p)	return String();

 memcpy(p, b, l2);
 memcpy(&p[l2], a.name, a.length()+1);
 return String(p, a.length()+l2);
}

/* Can produce random numbers nicely for "no" almost as large as 2^31: */
int String::hash(int no) C
{
 unsigned x = l*7141U+54773U;
 C char *p;
 for(p=name;p<name+l;p++)
	x = 7141U*((unsigned)*p + x%259200U) + 54773U;
 x %= no;
 assert((int)x >= 0);
 return (int)x;
}

char *String::array() C
{
 return strdup((C char *)(*this));
}
