/*-*-c++-*-
 * $Id: ctextring.cpp,v 1.1 2002/01/28 15:38:32 holzheu Exp $
 *
 * This file is part of qlcrash, a GUI for the dump-analysis tool lcrash.
 *
 * Copyright (C) 2001 IBM Deutschland Entwicklung GmbH, IBM Corporation
 *
 * Authors:
 * Michael Geselbracht (let@users.sourceforge.net)
 * Fritz Elfert (elfert@de.ibm.com)
 * Michael Holzheu (holzheu@de.ibm.com)
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU Lesser Public License as published by
 * the Free Software Foundation; either version 2.1 of the License, or
 * (at your option) any later version. See the file COPYING for more
 * information.
 */
#include "ctextring.h"

#include <qstringlist.h>
#include <assert.h>

#define DEFAULT_RINGSIZE 5000

CTextRing::CTextRing() : oRing(0), oRingSize(0)
{
}

CTextRing::CTextRing(unsigned int size) : oRing(0), oRingSize(0)
{
	setSize(size);
}

CTextRing::~CTextRing()
{
	clear();
	delete oRing;
}

void
CTextRing::clear()
{
	for (int i = 0; i < oRingSize; i++) {
		if (oRing[i] != 0) {
			delete oRing[i];
			oRing[i] = 0;
		}
	}
	oHead = 0;
	oTail = 0;
}

void
CTextRing::setSize(unsigned int size)
{
	assert(size > 1);
	clear();
	if (size != (unsigned int) oRingSize) {
		delete oRing;
		oRing = new CString*[size];
		assert(oRing != 0);
		oRingSize = size;
		
		for (int i = 0; i < oRingSize; i++) {
			oRing[i] = 0;
		}
	}
}

void
CTextRing::add(const QString& str, QColor color)
{
	int pos = 0;
	
	if (str.length() == 0) {
		return;
	}
	
	if (oTail == oHead) {
		pos = oTail;
		if (oRing[pos] == 0) {
			if (oRingSize < 2) {
				setSize(DEFAULT_RINGSIZE);
			}
			oRing[pos] = new CString;
			oRing[pos]->setColor(color);
			oTail++;
			if (oTail == oRingSize) {
				oTail = 0;
			}
		}
		else { // buffer is full
			pos = oTail - 1;
			if (pos == -1) {
				pos = oRingSize - 1;
			}
		}
	}
	else {
		pos = oTail - 1;
		if (pos < 0) {
			pos = oRingSize - 1;
		}
	}
	
	oRing[pos]->append(str);
	oRing[pos]->setColor(color);
}

void
CTextRing::appendLine(const QString& str, QColor color)
{
	int pos = 0;
	
	if (oRingSize < 2) {
		setSize(DEFAULT_RINGSIZE);
	}
	
	if (oTail == oHead) {
		if (oRing[oHead] == 0) { // buffer is empty
			oTail++;
			if (oTail == oRingSize) {
				oTail = 0;
			}
			pos = oHead;
		}
		else { // buffer is full
			pos = oHead;
			delete oRing[pos];
			oTail++;
			oHead++;
			if (oTail == oRingSize) {
				oHead = 0;
				oTail = 0;
			}
		}
	}
	else {
		pos = oTail;
		oTail++;
		if (oTail == oRingSize) {
			oTail = 0;
		}
	}
	
	oRing[pos] = new CString(str);
	oRing[pos]->setColor(color);
}

void
CTextRing::append(const QString& str, QColor color, int pos)
{
	QStringList list = QStringList::split('\n', str, true);
	QStringList::Iterator it = list.begin();
	
	if (it != list.end()) {
		QString appendix = "";
		if (pos >= 0) {
			// save text from 'pos' to line end
			CString* str = lastLine();
			if (str != 0) {
				appendix = str->mid(pos);
				str->truncate(str->length() - appendix.length());
			}
		}
		add(*it, color);
		while (++it != list.end()) {
			appendLine(*it, color);
		}
		
		add(appendix);
	}
}

unsigned int
CTextRing::numLines() const
{
	int lines = oTail - oHead;
	
	if (lines == 0) { // empty ?
		if (oRing[oHead] != 0) { // ring is full
			lines = oRingSize;
		}
	}
	else if (lines < 0) {
		lines = oRingSize - oHead + oTail;
	}
	
	return lines;
}

CString*
CTextRing::line(unsigned int n)
{
	int pos = oHead + n;
	if (pos >= oRingSize) {
		pos -= oRingSize;
	}
	
	if (pos >= oRingSize) {
		return 0;
	}
	
	if (pos == 0 && oRing[pos] == 0) {
		oRing[0] = new CString;
		oTail++;
	}
	
	return oRing[pos];
}

CString*
CTextRing::lastLine()
{
	return ((numLines() > 0) ? line(numLines() - 1) : line(0));
}
