/*
 * @(#)String.cpp
 *
 * This file is part of webCDwriter - Network CD Writing.
 *
 * Copyright (C) 2002 Jörg P. M. Haeger
 *
 * webCDwriter is free software. See CDWserver.cpp for details.
 *
 * Jörg Haeger, 22.04.2002
 */

#include <stdlib.h>
#include <string.h>
#include "Exception.h"
#include "Log.h"
#include "String.h"
#include "StringBuffer.h"

EmptyString S;

String::String() {
	buf = new StringBuffer(0);
	bytes = NULL;
	tmp = false;
	validityMark = originalValidityMark;
}

String::String(const String &str) {
	buf = new StringBuffer(*str.buf);
	bytes = NULL;
	tmp = false;
	validityMark = originalValidityMark;
}

String::String(String *str) {
	buf = str->buf;
	str->buf = NULL;

	bytes = str->bytes;
	str->bytes = NULL;

	tmp = false;
	validityMark = originalValidityMark;

	delete str;
}

String::String(const char *str) {
	if (str == NULL)
		str = "<null>";
	buf = new StringBuffer(str);
	bytes = NULL;
	tmp = false;
	validityMark = originalValidityMark;
}

String::String(StringBuffer &buffer) {
	buf = new StringBuffer(buffer);
	bytes = NULL;
	tmp = false;
	validityMark = originalValidityMark;
}

String::String(StringBuffer *buffer) {
	buf = buffer;
	bytes = NULL;
	tmp = false;
	validityMark = originalValidityMark;
}

const int String::originalValidityMark = 0x12488421;

String::~String() {
	if (validityMark != originalValidityMark) {
		log.put(1, "tried to free invalid String");
		return;
	}
	if (buf != NULL)
		delete buf;
	if (bytes != NULL)
		delete[] bytes;
	validityMark = 0;
}

String &String::operator=(String &str) {
	log.debug("String", "%x::operator=(%s)", this, str.getBytes());
	if (&str == this)
		return str;

	if (bytes != NULL) {
		delete[] bytes;
		bytes = NULL;
	}
	delete buf;
	buf = new StringBuffer(*str.buf);
	log.debug("String", "duplicated String %x", &str);
	return *this;
}

String &String::operator=(String *str) {
	StringBuffer *oldBuf = buf;
	buf = str->buf;
	str->buf = oldBuf;

	char *oldBytes = bytes;
	bytes = str->bytes;
	str->bytes = oldBytes;

	delete str;
	return *this;
}

String &String::operator=(const char *str) {
	return this->operator=(new String(str));
}

String &String::operator+(char c) {
	if (this == &S.e) {
		char str0[2];
		str0[0] = c;
		str0[1] = 0;
		String *str = new String(str0);
		str->tmp = 1;
		return *str;
	}
	buf->append(c);
	return *this;
}

String &String::operator+(int i) {
	if (this == &S.e) {
		String *str = String::valueOf(i);
		str->tmp = 1;
		return *str;
	}
	buf->append(i);
	return *this;
}

String &String::operator+(long l) {
	if (this == &S.e) {
		String *str = String::valueOf(l);
		str->tmp = 1;
		return *str;
	}
	buf->append(l);
	return *this;
}

String &String::operator+(String &str) {
	if (this == &S.e) {
		String *str2 = new String(str);
		str2->tmp = 1;
		return *str2;
	}
	buf->append(str.getBytes());
	return *this;
}

String &String::operator+(const char *str) {
	if (str == NULL)
		str = "<null>";
	if (this == &S.e) {
		String *str2 = new String(str);
		str2->tmp = 1;
		return *str2;
	}
	buf->append(str);
	return *this;
}

int String::charAt(int index) {
	return buf->charAt(index);
}

int String::compareToIgnoreCase(const char *str) {
	return strcasecmp(getBytes(), str);
}

int String::endsWith(const char *suffix) {
	return buf->endsWith(suffix);
}

int String::equals(const char *str) {
	return buf->equals(str);
}

int String::equals(String &str) {
	return buf->equals(str.getBytes());
}

int String::equalsIgnoreCase(const char *str) {
	return buf->equalsIgnoreCase(str);
}

void String::free(String *str) {
	if (str == NULL)
		return;

	if (str->tmp)
		delete str;
	else
		log.put(1, S.e + "String::free: non-tmp string:"
			+ " <" + *str + ">");
}

const char *String::getBytes() {
	if (bytes != NULL)
		delete[] bytes;

	int len = buf->length();
	bytes = new char[len + 1];
	for (int i = 0; i < len; i++)
		bytes[i] = buf->charAt(i);
	bytes[len] = 0;

	return bytes;
}

int String::indexOf(const char *str) {
	return buf->indexOf(str);
}

int String::lastIndexOf(const char *str) {
	return buf->lastIndexOf(str);
}

int String::length() {
	return buf->length();
}

int String::startsWith(const char *prefix) {
	return buf->startsWith(prefix);
}

String *String::substring(int beginIndex) {
	return substring(beginIndex, length());
}

String *String::substring(int beginIndex, int endIndex) {
	return new String(buf->substring(beginIndex, endIndex));
}

String *String::valueOf(int i) {
	StringBuffer buf;
	buf.append(i);
	return new String(buf);
}

String *String::valueOf(long l) {
	StringBuffer buf;
	buf.append(l);
	return new String(buf);
}
