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

#include <ctype.h>
#include <string.h>
#include "Exception.h"
#include "StringBuffer.h"

off_t StringBuffer::no = 0;
int StringBuffer::existing = 0;
int StringBuffer::existingTop = 100;

StringBuffer::StringBuffer(int size, int inc) {
	init();
	this->size = size;
	this->inc = inc;
	buf = new int[size];
	len = 0;
}

StringBuffer::StringBuffer(const StringBuffer &buffer) {
	init();
	size = buffer.size;
	inc = buffer.inc;
	buf = new int[size];
//	len = 0;

//	for (int i = 0; i < buffer.len; i++)
//		append((char)buffer.buf[i]);

	len = buffer.len;
	memcpy(buf, buffer.buf, len * sizeof buf[0]);
}

StringBuffer::StringBuffer(StringBuffer *buffer) {
	init();
	buf = buffer->buf;
	buffer->buf = NULL;

	len = buffer->len;
	size = buffer->size;
	inc = buffer->inc;

	delete buffer;
}

StringBuffer::StringBuffer(const char *str) {
	init();
	this->size = strlen(str);
	buf = new int[size];
	len = 0;

	append(str);
}

StringBuffer::StringBuffer(String &str, int remove) {
	init();
	size = str.length();
	buf = new int[size];
	len = 0;

	for (int i = 0; i < size; i++)
		append((char)str.charAt(i));

	if (remove)
		delete &str;
}

StringBuffer::LogProxy StringBuffer::log;

StringBuffer::~StringBuffer() {
	if (buf != NULL)
		delete[] buf;
	existing--;
}

StringBuffer &StringBuffer::operator=(StringBuffer *buffer) {
	int *oldBuf = buf;
	buf = buffer->buf;
	buffer->buf = oldBuf;

	len = buffer->len;
	size = buffer->size;
	inc = buffer->inc;

	delete buffer;
	return *this;
}

int StringBuffer::charAt(int index) const {
	if (index < 0 || index >= len)
		throw new Exception(S.e + "StringBuffer::charAt:"
			+ " index = " + index + ", len = " + len);
	return buf[index];
}

StringBuffer &StringBuffer::delete_(int start, int end) {
	for (int i = 0; i < len - end; i++)
		buf[start + i] = buf[end + i];

	if (end > len)
		len = start;
	else
		len -= end - start;

	return *this;
}

int StringBuffer::endsWith(const char *suffix) const {
	int offset = len - strlen(suffix);
	if (offset < 0)
		return 0;

	for (int i = offset; i < len; i++)
		if (suffix[i - offset] != buf[i])
			return 0;

	return 1;
}

void StringBuffer::ensureCapacity(int minimumCapacity) {
	if (capacity() >= minimumCapacity)
		return;

	while (capacity() < minimumCapacity)
		size += inc;
	int *oldBuf = buf;
	buf = new int[size];
//	for (int i = 0; i < len; i++)
//		buf[i] = oldBuf[i];
	memcpy(buf, oldBuf, len * sizeof buf[0]);
	delete[] oldBuf;
}

int StringBuffer::equals(const char *str) const {
	int i;
	for (i = 0; i < len; i++)
		if (str[i] == 0)
			return 0;
		else if (str[i] != buf[i])
			return 0;

	return str[i] == 0;
}

int StringBuffer::equalsIgnoreCase(const char *str) const {
	int i;
	for (i = 0; i < len; i++)
		if (str[i] == 0)
			return 0;
		else if (toupper(str[i]) != toupper(buf[i]))
			return 0;

	return str[i] == 0;
}

int StringBuffer::indexOf(const char *str, int fromIndex) const {
	for (int i = fromIndex; i < len; i++)
		for (int j = i; ; j++)
			if (str[j - i] == 0)
				return i;
			else if (j == len)
				break;
			else if (buf[j] != str[j - i])
				break;

	return -1;
}

void StringBuffer::init() {
	inc = 16;
	no++;
	existing++;
	if (existing > existingTop) {
		existingTop += 100;
		log.put(1, S.e + "StringBuffer: no = " + no
			+ " existing = " + existing);
	}
}

StringBuffer &StringBuffer::insert(int offset, char c) {
	ensureCapacity(1);

	for (int i = len; i > offset; i--)
		buf[i] = buf[i - 1];

	buf[offset] = c;
	len++;
	return *this;
}

StringBuffer &StringBuffer::insert(int offset, int i) {
	if (i == 0)
		insert(offset, '0');
	else if (i < 0) {
		insert(offset++, '-');
		i = -i;
	}

	for (; i > 0; i /= 10)
		insert(offset, (char)('0' + i % 10));

	return *this;
}

StringBuffer &StringBuffer::insert(int offset, off_t n) {
	if (n == 0)
		insert(offset, '0');
	else if (n < 0) {
		insert(offset++, '-');
		n = -n;
	}

	for (; n > 0; n /= 10)
		insert(offset, (char)('0' + n % 10));

	return *this;
}

StringBuffer &StringBuffer::insert(int offset, const char *str) {
	int n = strlen(str);
	ensureCapacity(n);

//	for (int i = 0; str[i] != 0; i++)
//		insert(offset + i, str[i]);

	memmove(&buf[offset + n], &buf[offset],
		(len - offset) * sizeof buf[0]);
	for (int i = 0; i < n; i++)
		buf[offset + i] = str[i];
	len += n;

	return *this;
}

StringBuffer &StringBuffer::insert(
		int index, const char *str, int offset, int len) {
	for (int i = 0; i < len; i++)
		insert(index + i, str[offset + i]);

	return *this;
}

int StringBuffer::lastIndexOf(const char *str) const {
	int len2 = strlen(str);
	for (int i = len - len2; i >= 0; i--)
		for (int j = 0; j <= len2; j++)
			if (j == len2)
				return i;
			else if (buf[i + j] != str[j])
				break;

	return -1;
}

void StringBuffer::setCharAt(int index, char ch) {
	if (index < 0 || index >= len)
		throw new Exception(S.e + "StringBuffer::setCharAt:"
			+ " index = " + index + ", len = " + len);
	buf[index] = ch;
}

void StringBuffer::setLog(class Log *aLogPtr) {
	log.setLog(aLogPtr);
}

int StringBuffer::startsWith(const char *prefix) const {
	for (int i = 0; i < len; i++)
		if (prefix[i] == 0)
			return 1;
		else if (prefix[i] != buf[i])
			return 0;

	return prefix[len] == 0;
}

StringBuffer *StringBuffer::substring(int beginIndex, int endIndex) const {
	if (beginIndex < 0 || beginIndex > endIndex || endIndex > len)
		throw new Exception(S.e + "StringBuffer::substring:"
			+ " beginIndex = " + beginIndex
			+ ", endIndex = " + endIndex
			+ ", len = " + len);

	StringBuffer *buf2 = new StringBuffer(endIndex - beginIndex);
	for (int i = beginIndex; i < endIndex; i++)
		buf2->buf[i - beginIndex] = buf[i];
	buf2->len = endIndex - beginIndex;

	return buf2;
}

StringBuffer *StringBuffer::toUpperCase() {
	StringBuffer *buf2 = new StringBuffer(len);
	for (int i = 0; i < len; i++)
		buf2->buf[i] = toupper(buf[i]);
	buf2->len = len;

	return buf2;
}


#include "Log.h"

void StringBuffer::LogProxy::put(int level, String &message) {
	if (logPtr != NULL)
		logPtr->put(level, message);
}
