
//

#include "XString.h"
#include <Shlwapi.h>
#include <stdio.h>
#include <stdlib.h>

#pragma warning(disable:4996)

extern void wlog(char* str, ...);

XString::XString(const char*txt)
{
	
	if(txt)
	{
		len = (int)strlen(txt);
		if(len)
		{
			bufferlen = STRBASEBUFFERLEN*(len/STRBASEBUFFERLEN) + STRBASEBUFFERLEN;
			buffer=new char [bufferlen];
			strcpy(buffer,txt);
			return;
		}	
	}
	else
		len = 0;

	buffer=NULL;
	bufferlen = 0;
}

XString::XString(WCHAR*txt)
{
//	wlog("chreate char* %S",txt);
//	wlog("orig      %S",txt);
	len = (int)wcslen(txt);
	if(len)
	{
		bufferlen = STRBASEBUFFERLEN*(len/STRBASEBUFFERLEN) + STRBASEBUFFERLEN;
		buffer=new char [bufferlen];
		wcstombs(buffer,txt,len+1);
	}
	else
	{
		buffer=NULL;
		bufferlen = 0;
	}
	//	wlog("chreated  %s",buffer);
}

XString::XString(void)
{
	bufferlen = 0;
	len=0;
	buffer = NULL;
}

XString::XString(const XString &str) //der copykonstruktor wenn ich den nicht so schreiben würde würdde er einfach
//len=str.len buffer=str.buffer wenn ich einen der beiden lösche wird der text deleted und ein sting zeigt ins nichts
{
	len = str.len;
		
	if(len)
	{
		bufferlen = STRBASEBUFFERLEN*(len/STRBASEBUFFERLEN) + STRBASEBUFFERLEN;
		buffer=new char [bufferlen];
		strcpy(buffer,str.buffer);
	}
	else
	{
		buffer=NULL;
		bufferlen = 0;
	}
}

XString::XString(int val)
{
	bufferlen = STRBASEBUFFERLEN;
	buffer = new char [STRBASEBUFFERLEN];
	itoa(val, buffer, 10);
	len = (int)strlen(buffer);
}

XString::XString(float val)
{
	bufferlen = STRBASEBUFFERLEN;
	buffer=new char [STRBASEBUFFERLEN];
	sprintf(buffer,"%f",val); 
	//_gcvt(val,10,buffer);
	int i;
	len = (int)strlen(buffer);
	for(i=len-1;i>0;i--)
		if(buffer[i] != '0')
			break;
	if(buffer[i] == '.')
		buffer[++i] = '0';
	buffer[i+1] = '\0';
	len = (int)strlen(buffer);
}

XString::~XString(void)
{
	//wlog("destruct sting %s",buffer);
	if(buffer)
		delete [] buffer;
}

void XString::SetLength(const unsigned nchars)
{
	if (bufferlen + 1 >= nchars)
	{
		buffer[nchars] = '\0';
	}
	else
	{
		bufferlen = STRBASEBUFFERLEN*(nchars/STRBASEBUFFERLEN) + STRBASEBUFFERLEN;
		char* btemp = new char[bufferlen];
		if (len > 0 && buffer)
		{
			memcpy(btemp, buffer, len+1);
			delete [] buffer;
		}
		buffer = btemp;
		buffer[nchars] = '\0';
	}
	len = nchars;
}

void XString::operator =(const XString &str)
{
	//wlog("cpy XString %s %d",str.getbuffer(),str.getlen());
	//wlog("orig %s %d",getbuffer(),getlen());
	
	len=str.len;
	if(len >= bufferlen)
	{
		bufferlen = STRBASEBUFFERLEN*(len/STRBASEBUFFERLEN) + STRBASEBUFFERLEN;
		if(buffer)
			delete [] buffer;
		buffer=new char[bufferlen];
	}
	
	if(str.buffer)
		strcpy(buffer,str.buffer);
	else
		buffer[0]='\0';
	//wlog("cpy  %s",buffer);
}

void XString::operator =(char*txt)
{
	//wlog("cpy char* %s",txt);
	//wlog("orig %s",txt);
	if(txt)
	{
		len=(int)strlen(txt);
		if(len >= bufferlen)
		{
			bufferlen = STRBASEBUFFERLEN*(len/STRBASEBUFFERLEN) + STRBASEBUFFERLEN;
			if(buffer)
				delete [] buffer;
			buffer=new char[bufferlen];
		}
		if(len)
			strcpy(buffer,txt);
		else
			buffer[0] = '\0';
	}
	else
	{
		len = 0;
		buffer[0] = '\0';
	}
	//wlog("cpy  %s",buffer);
}

void XString::operator =(int val)
{	
	if(bufferlen < STRBASEBUFFERLEN)
	{
		bufferlen = STRBASEBUFFERLEN;
		if(buffer)
			delete [] buffer;
		buffer=new char [STRBASEBUFFERLEN];
	}
	itoa(val,buffer,10);
	len=(int)strlen(buffer);
	//wlog("cpy  %s",buffer);
}

void XString::operator =(float val)
{
	if(bufferlen < STRBASEBUFFERLEN)
	{
		bufferlen = STRBASEBUFFERLEN;
		if(buffer)
			delete [] buffer;
		buffer=new char [STRBASEBUFFERLEN];
	}
	sprintf(buffer,"%f",val); 
	//_gcvt(val,10,buffer);
	int i;
	len=(int)strlen(buffer);
	for(i=len-1;i>0;i--)
		if(buffer[i] != '0')
			break;
	if(buffer[i] == '.')
		buffer[++i] = '0';
	buffer[i+1] = '\0';
	len=(int)strlen(buffer);
}

void XString::operator =(WCHAR*txt)
{
	//wlog("cpy wchar* %S",txt);
	//wlog("orig %S",txt);
	if(txt)
	{
		len=(int)wcslen(txt);
		if(len >= bufferlen)
		{
			bufferlen = STRBASEBUFFERLEN*(len/STRBASEBUFFERLEN) + STRBASEBUFFERLEN;
			if(buffer)
				delete [] buffer;
			buffer=new char[bufferlen];
		}
		if(len)
			wcstombs(buffer,txt,len+1);
		else
			buffer[0] = '\0';
	}
	else
	{
		len = 0;
		buffer[0] = '\0';
	}
	//wlog("cpy  %s",buffer);
}

bool XString::isnumber(void) const
{
	int i;
	char	c;

	if(!buffer)
		return FALSE;

	for(i=0;i<len;i++)
	{
		c=buffer[i];
		if(c>'9'||c<'0')
			return FALSE;
	}
	return TRUE;
}

int XString::toint(void) const
{
	if(buffer)
		return atoi(buffer);
	else 
		return 0;
}

float XString::tofloat(void) const
{
	if(buffer)
		return (float)atof(buffer);
	else
		return 0.f;
}

int XString::instr(const XString& str, const int offset) const
{
	if(len > 0 && buffer != NULL)
	{
		int i,ret,j;

		for(i=offset;i<=len-str.getlen();i++)
		{
			ret=i;
			for(j=0;j<=str.getlen();j++)
			{
				if(j==str.getlen())
				{	
					return ret+1;
				}

				if(str.getbuffer()[j]!=buffer[i])
				{
					j=str.getlen()+2;
				}
				i++;
			}
			i=ret;
		}
	}

	return -1;
}

int XString::instrrev(const XString& str, const int offset) const 
{
	if(len > 0 && buffer != NULL)
	{
		int i,ret,j;

		for(i=len-offset-str.getlen();i;i--)
		{
			ret=i;
			for(j=0;j<=str.getlen();j++)
			{
				if(j==str.getlen())
				{	
					return ret+1;
				}

				if(str.getbuffer()[j]!=buffer[i])
				{
					j=str.getlen()+2;
				}
				i++;
			}
			i=ret;
		}
	}

	return -1;
}

void XString::appand(const XString&str)
{
	if (!str.len)
		return ;

	if(len + str.len >= bufferlen)
	{
		bufferlen = STRBASEBUFFERLEN*((len + str.len)/STRBASEBUFFERLEN) + STRBASEBUFFERLEN;
		char *tempbuffer = new char[bufferlen];
		if(buffer)
		{
			strcpy(tempbuffer,buffer);
			delete [] buffer;
		}
		buffer = tempbuffer;
	}
	
	strcpy(buffer+len,str.buffer);
	len += str.len;
}

void XString::appand(char*str)
{
	if(!str)
		return;

	int nlen = (int)strlen(str);
	if(len + nlen >= bufferlen)
	{
		bufferlen = STRBASEBUFFERLEN*((len + nlen)/STRBASEBUFFERLEN) + STRBASEBUFFERLEN;
		char *tempbuffer = new char[bufferlen];
		if(buffer)
		{
			strcpy(tempbuffer,buffer);
			delete [] buffer;
		}
		buffer = tempbuffer;
	}
	strcpy(buffer+len,str);
	len += nlen;
}

XString XString::Left(int n) const
{
	if(!buffer || !n)
		return XString((char*)NULL);

	if(n > len)
		n = len;

	char	temp = buffer[n];
	buffer[n] = '\0';
	XString	ret(buffer);
	buffer[n] = temp;

	return ret;
}

XString XString::Right(int n) const
{
	if(!buffer || !n)
		return XString((char*)NULL);

	if(n > len)
		n = len;
	XString	ret(buffer+len-n);

	return ret;
}

XString XString::SubStr(int start,int n) const
{
	if(!buffer || start >= len)
		return XString((char*)NULL);

	if(!n)
		return XString(buffer + start);

	if(start + n > len)
		n = len - start;

	//at start + len the subXString ends, we store this char and temporay set it to 0
	char h = buffer[start+n]; 

	buffer[start+n] = '\0';
	XString ret(buffer+start);
	buffer[start+n] = h;

	return ret;
}

XString XString::Filter(char c) const
{
	XString tmp;
	tmp.bufferlen = bufferlen;
	tmp.buffer = new char[bufferlen];

	char* src = buffer;
	char* dst = tmp.buffer;

	for(int i=0;i<=len;i++,src++)
	{
		if(*src != c)
			*dst++ = *src;
	}

	tmp.len = (int)(dst - tmp.buffer - 1);

	return tmp;
}

void XString::appand(WCHAR*str)
{
	if (!str)
		return; 

	XString tempstr=str;
	//ich machs mir leicht, ist aber nicht optimal	
	appand(tempstr);
}

void XString::appand(char c)
{
	if(len + 1 >= bufferlen)
	{
		bufferlen += STRBASEBUFFERLEN;
		char *tempbuffer = new char[bufferlen];
		if(buffer)
		{
			strcpy(tempbuffer,buffer);
			delete [] buffer;
		}
		buffer = tempbuffer;
	}

	buffer[len++] = c;
	buffer[len] = '\0';
}

void XString::appand(int val)
{
	if(len+11 > bufferlen)
	{
		bufferlen += STRBASEBUFFERLEN;
		char *tempbuffer = new char[bufferlen];
		if(buffer)
		{
			strcpy(tempbuffer,buffer);
			delete [] buffer;
		}
		buffer = tempbuffer;
	}
	itoa(val,buffer+len,10);
	len += (int)strlen(buffer+len);
}

void XString::appand(float val)
{
	if(len+20 > bufferlen)
	{
		bufferlen += STRBASEBUFFERLEN;
		char *tempbuffer = new char[bufferlen];
		if(buffer)
		{
			strcpy(tempbuffer,buffer);
			delete [] buffer;
		}
		buffer = tempbuffer;
	}

	sprintf(buffer+len,"%f",val); 
    len += (int)strlen(buffer+len);

	int i;
	for(i=1;i<20;i++)
		if(buffer[len-i] != '0')
			break;
	if(buffer[len-i] == '.')
	{
		i--;
		buffer[len-i] = '0';
	}
	buffer[len-i+1] = '\0';
	len-=i-1;
}

int XString::cmp(const XString& str) const
{
	if(buffer && str.buffer)
	{
		if(buffer == str.buffer && len == str.len)
			return 0;
		else
			return strcmp(buffer, str.buffer);
	}
	else //no compare possible
	{
		return -1;
	}
}

bool XString::operator ==(const XString &str) const
{
	if(buffer && str.buffer && len == str.len) //can only be equal when have the same length
	{
		if(buffer == str.buffer)
			return true;
		else
			return !strcmp(buffer,str.buffer);
	}
	else
	{
		return false;
	}
}

bool XString::operator ==(char*txt) const
{
	if (!txt || !buffer)
	{
		if (len==0 && txt && txt[0] == '\0')
			return true;
		else
			return false;
	}
	else
		return !strcmp(buffer,txt);
}

bool XString::operator ==(WCHAR*txt) const
{
	//asdfasdf
	return 0;
}

XString XString::operator +(const XString&str) const
{
	XString h;
	if(len)
		h=buffer;
	h.appand(str);
	return h;
}

XString XString::operator +(char*str)
{
	XString h;
	if(len)
		h=buffer;
	h.appand(str);
	return h;
}

XString XString::operator +(WCHAR*str)
{
	XString h;
	if(len)
		h=buffer;
	h.appand(str);
	return h;
}

XString XString::operator +(int val)
{
	XString h;
	if(len)
		h=buffer;
	h.appand(val);
	return h;
}

XString XString::operator +(float val)
{
	XString h;
	if(len)
		h=buffer;
	h.appand(val);
	return h;
}

void XString::replace(XString torplc,XString rplc)
{
	if(torplc.getlen() == 0)
		return;

	//XString tmp;
	//for(int i=0;i<=len-rplc.getlen();i++)
	//{
	//	int rlpcpos=i;
	//	for(int j=0;j<=torplc.getlen();j++)
	//	{
	//		if(j==torplc.getlen())
	//		{	
	//			return ret+1;
	//		}

	//		if(torplc.getbuffer()[j]!=buffer[i])
	//		{
	//			break;
	//		}
	//	}
	//	i=rlpcpos;
	//}
}

void XString::Read(FILE* const f)
{
    fread(&len,sizeof(int),1,f);
	int bl = STRBASEBUFFERLEN*(len/STRBASEBUFFERLEN) + STRBASEBUFFERLEN;
	if(bufferlen < bl)
	{
		bufferlen = bl;
		if(buffer)
			delete buffer;
		buffer = new char[bufferlen];
	}
	if(len)
		fread(buffer,sizeof(char),len,f);
	if(buffer)
		buffer[len] = '\0';
}

void XString::Write(FILE* const f) const
{
	fwrite(&len,sizeof(int),1,f);
	if(len)
		fwrite(buffer,sizeof(char),len,f);
}

void XString::insertat(unsigned pos,XString str)
{
	if(len)
	{
		if(str.len)
		{
			if((int)pos >= len)
			{
				appand(str);
			}
			else
			{
				int newlen = len+str.len;
				
				char *newbuffer;

				if(newlen > bufferlen)//new bigger buffer
				{
					bufferlen = STRBASEBUFFERLEN*((newlen)/STRBASEBUFFERLEN) + STRBASEBUFFERLEN;
					newbuffer = new char[bufferlen];
					if(buffer)
						strncpy(newbuffer,buffer,pos);//fill first part of new buffer
				}
				else
				{
					newbuffer = buffer; //old buffer is big enough, so it becomes the new one. first part already alright
				}

				if(pos-len)
				{
					if(buffer) //copy end of the new XString (second part of old XString) to its position
						strncpy(newbuffer,buffer+pos,len-pos+1); //(+1 for 'binary null')
				}
				else //if there was no end, we have to set the new XString end
				{
					newbuffer[newlen] = '\0';
				}
							
				//insert mid part
				strncpy(newbuffer+pos,str.buffer,str.len);

				if(newlen > bufferlen)
				{
					delete [] buffer;
					buffer = newbuffer;
				}
				
				len = newlen;
			}
		}
	}
	else//current XString empty
	{
		*this = str;//just copy from part to be inserted
	}
}

void XString::ToLower(void)
{
	for(char*b=buffer;b<buffer+len;++b)
		*b = tolower(*b);
}

void XString::ToUpper(void)
{
	for(char*b=buffer;b<buffer+len;++b)
		*b = toupper(*b);
}

XString XString::BuildRelativePath(const XString &to, const XString &from)
{
	int sameIndex = -1;
	int minlen = to.getlen() < from.getlen() ? to.getlen() : from.getlen();
	for (int i = 0; i < minlen; i++)
	{
		if (tolower(to.getbuffer()[i]) != tolower(from.getbuffer()[i]))
			break;
		if (to.getbuffer()[i] == '\\')
			sameIndex = i;
	}
	if (sameIndex == 0)
		return to; //return absolute path of traget if they have nothing in common (other drive)

	XString relPath;

	//appand "..\\" for every directory 
	for (int i = sameIndex + 1; i < from.getlen(); i++)
    {
		//if (i == sameIndex)
		//	relPath.appand("..");
		//else
			if (from.getbuffer()[i] == '\\')
			{
				if (relPath.getlen() == 0)
					relPath.appand("..");
				else
					relPath.appand("\\..");
			}
    }

    if (relPath.getlen() == 0)
        relPath = ".";
    
	//add last part of target path
	relPath.appand(to.getbuffer() + sameIndex);

	return relPath;
}