/*	XGStringList.cpp
 *
 *		This manages a handle full of strings
 */

/*  YAAF - Yet another application framework
 *  Copyright (C) 1997, 1998 William Edward Woody
 *  
 *  This library is free software; you can redistribute it
 *  and/or modify it under the terms of the GNU Library
 *  General Public License as published by the Free Software
 *  Foundation; either version 2 of the License, or any
 *  later version.
 *  
 *  This library is distributed in the hope that it will be
 *  useful, but WITHOUT ANY WARRANTY; without even the implied
 *  warranty of MERCHANTABIILITY or FITNESS FOR A PARTICULAR
 *  PURPOSE. See the GNU Library General Public License for
 *  more details.
 *  
 *  You should have received a copy of the GNU Library General
 *  Public License along with this library; if not, write to the
 *  Free Software Foundation, Inc., 59 Temple Place - Suite 330,
 *  Boston, MA 02111-1307, USA.
 *  
 *  To contact the author, either e-mail me at woody@pandawave.com, 
 *	or write to
 *  
 *          William Edward Woody
 *          In Phase Consulting
 *          1545 Ard Eevin Avenue
 *          Glendale, CA 91202
 *
 *	Or visit us on the web at http://www.pandawave.com
 */

#include <XConfig.h>			// must be first to optimize compile on MSVC++
#include <XHandle.h>
#include <XDataUtil.h>
#include <string.h>
#include <XError.h>

/************************************************************************/
/*																		*/
/*	Construction/Destruction											*/
/*																		*/
/************************************************************************/

//  @G"Construction/Destruction"

/*	@F"XGStringList::XGStringList" @I
 *
 *		Initialize my handle. This creates an empty string list.
 */

XGStringList::XGStringList(short extraData)
{
	fNumber = 0;
	fExtra = extraData;
}

/*	@F"XGStringList::~XGStringList" @I
 *
 *		Delete the string list and release resources.
 */

XGStringList::~XGStringList()
{
}

/************************************************************************/
/*																		*/
/*	String Interface													*/
/*																		*/
/************************************************************************/

// @G"String List Interface"

/*	@F"XGStringList::GetString" @I
 *
 *		Get the specified string. This is a zero-based index.
 */

void XGStringList::GetString(long x, char *str) const
{
	unsigned char *ptr = (unsigned char *)**this;
	
	if ((x < 0) || (x >= fNumber)) {
		throw XGPostError(KXGStringListError);
	}
	while (x-- > 0) ptr += fExtra + 1 + *ptr;
	cvtp2c(str,ptr);
}

/*	@F"XGStringList::GetExtra" @I
 *
 *		Get the extra data. This is the data that is associated with my
 *	string
 */

void XGStringList::GetExtra(long x, void *data) const
{
	unsigned char *ptr = (unsigned char *)**this;
	
	if (fExtra == 0) {
		throw XGPostError(KXGStringListExtra);
	}
	if ((x < 0) || (x >= fNumber)) {
		throw XGPostError(KXGStringListError);
	}
	while (x-- > 0) ptr += fExtra + 1 + *ptr;
	::memmove((char *)data,ptr + *ptr + 1,fExtra);
}

/*	@F"XGStringList::SetString" @I
 *
 *		Set to the specified string
 */

void XGStringList::SetString(long x, const char *str)
{
	long delta;
	long index;
	unsigned char *ptr = (unsigned char *)**this;
	
	if ((x < 0) || (x >= fNumber)) {
		throw XGPostError(KXGStringListError);
	}
	index = 0;
	while (x-- > 0) index += fExtra + 1 + ptr[index];
	delta = strlen(str) - ptr[index];
	if (delta > 0) {
		XGHandle::Insert(index,delta);
	} else if (delta < 0) {
		XGHandle::Delete(index,-delta);
	}
	ptr = (unsigned char *)**this;
	cvtc2p(ptr+index,str);
}

/*	@F"XGStringList::SetExtra" @I
 *
 *		Set the extra data. This is the data that is associated with my
 *	string
 */

void XGStringList::SetExtra(long x, const void *data)
{
	unsigned char *ptr = (unsigned char *)**this;
	
	if (fExtra == 0) {
		throw XGPostError(KXGStringListExtra);
	}
	if ((x < 0) || (x >= fNumber)) {
		throw XGPostError(KXGStringListError);
	}
	while (x-- > 0) ptr += fExtra + 1 + *ptr;
	::memmove(ptr + *ptr + 1,(const char *)data,fExtra);
}

/*	@F"XGStringList::Insert" @I
 *
 *		Insert a string into the offset specified. If index is set
 *	to zero, this puts the string at the start. If the index is
 *	set to the length of this thing, the string is appended to the end.
 */

void XGStringList::Insert(long x, const char *str)
{
	long delta;
	long index;
	unsigned char *ptr = (unsigned char *)**this;
	
	if (str == NULL) str = "";						// insert blank string
	if ((x < 0) || (x > fNumber)) {
		throw XGPostError(KXGStringListError);
	}
	index = 0;
	while (x-- > 0) index += fExtra + 1 + ptr[index];
	delta = strlen(str) + 1 + fExtra;
	XGHandle::Insert(index,delta);
	ptr = (unsigned char *)**this;
	cvtc2p(ptr+index,str);							// copy string in
	memset(ptr+index+ptr[index]+1,0,fExtra);		// zero extra memory
	fNumber++;
}

/*	@F"XGStringList::Delete" @I
 *
 *		Delete the specified string
 */

void XGStringList::Delete(long x)
{
	long index;
	unsigned char *ptr = (unsigned char *)**this;
	
	if ((x < 0) || (x >= fNumber)) {
		throw XGPostError(KXGStringListError);
	}
	index = 0;
	while (x-- > 0) index += fExtra + 1 + ptr[index];
	XGHandle::Delete(index,fExtra+1+ptr[index]);
	fNumber--;
}

/*	@F"XGStringList::DeleteAll" @I
 *
 *		Delete all the strings
 */

void XGStringList::DeleteAll()
{
	SetSize(0);
	fNumber = 0;
}
