/*
** This program is free software; you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation; either version 1, or (at your option)
** any later version.

** This program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
** GNU General Public License for more details.

** You should have received a copy of the GNU General Public License
** along with this program; if not, write to the Free Software
** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/

/*
 * Author : Alexandre Parenteau <aubonbeurre@hotmail.com> --- August 1998
 */

/*
 * MultiString.cpp --- remember several unique persistents strings
 */

#include "stdafx.h"

#include "MultiString.h"

#if qUnix
#	include "uwidget.h"
#endif

#ifdef WIN32
#	ifdef _DEBUG
#	define new DEBUG_NEW
#	undef THIS_FILE
	static char THIS_FILE[] = __FILE__;
#	endif
#	pragma warning (disable : 4660)
#endif /* WIN32 */

template<class T>
TMString<T>::TMString(unsigned int maxstr, const char *uniqueName, char * const *defaultStr, 
	kClassPersistent pclass) : CPersistent(uniqueName, pclass), fMaxStr(maxstr)
{
	if(defaultStr != 0L)
	{
		int i = 0;
		while(defaultStr[i] != 0L)
		{
			Insert(defaultStr[i++]);
		}
	}
}

template<class T>
TMString<T>::~TMString()
{
}

template<class T>
unsigned int TMString<T>::SizeOf(void) const
{
	typename NAMESPACE(std) vector<T>::const_iterator i;
	unsigned int thesize = sizeof(int);
	
	for(i = fAllStrs.begin(); i != fAllStrs.end(); ++i)
	{
		thesize += (*i).length() + 1;
	}
	return thesize;
}

template<class T>
const void *TMString<T>::GetData(void) const
{
	unsigned int thesize = SizeOf(), tmpsize;
	((TMString *)this)->fBuf.AdjustSize(thesize);
	char *tmp = ((TMString *)this)->fBuf;
	*(int *)tmp = fAllStrs.size();
	tmp += sizeof(int) / sizeof(char);
	
	typename NAMESPACE(std) vector<T>::const_iterator i;
	for(i = fAllStrs.begin(); i != fAllStrs.end(); ++i)
	{
		tmpsize = (*i).length() + 1;
		memcpy(tmp, (const char *)(*i), tmpsize * sizeof(char));
		tmp += tmpsize;
	}
	
	return (char *)fBuf;
}

template<class T>
void TMString<T>::SetData(const void *ptr, unsigned int size)
{
	const char *tmp = (char *)ptr;
	unsigned int thesize;
	fAllStrs.erase(fAllStrs.begin(), fAllStrs.end());
	thesize = *(int *)tmp;
	tmp += sizeof(int) / sizeof(char);
	for(unsigned int i = 0; i < thesize && i < fMaxStr; i++)
	{
		fAllStrs.push_back(T(tmp));
		tmp += strlen(tmp) + 1;
	}
}

//	The string classes have too many operators to use std::find.
template<class T>
typename TMString<T>::list_t::const_iterator TMString<T>::Find(const char *instr) const
{
#if (__GNUC__ > 2)
	// prevent compiler warnings if gcc 3.x is used
	typename TMString<T>::list_t::const_iterator i;
#else
	TMString<T>::list_t::const_iterator i;
#endif
	for(i = fAllStrs.begin(); i != fAllStrs.end(); ++i)
		if(Compare(*i, instr) == 0) break;
		
	return i;
}

template<class T>
void TMString<T>::Insert(const char *newstr)
{
	TouchTimeStamp();

	typename NAMESPACE(std) vector<T>::iterator i;
	for(i = fAllStrs.begin(); i != fAllStrs.end(); ++i)
	{
		if(Compare(*i, newstr) == 0)
		{
			fAllStrs.erase(i);
			fAllStrs.insert(fAllStrs.begin(), T(newstr));
			return;
		}
	}
	fAllStrs.insert(fAllStrs.begin(), T(newstr));
	if(fAllStrs.size() > fMaxStr)
	{
		fAllStrs.erase(fAllStrs.begin() + fMaxStr, fAllStrs.end());
	}
}

template<class T>
bool TMString<T>::Remove(const char *newstr)
{

	typename NAMESPACE(std) vector<T>::iterator i;
	for(i = fAllStrs.begin(); i != fAllStrs.end(); ++i)
	{
		if(Compare(*i, newstr) == 0)
		{
			TouchTimeStamp();
			fAllStrs.erase(i);
			return true;
		}
	}
	
	return false;
}

template <class T>
void TMString<T>::RemoveAll()
{
	TouchTimeStamp();
	fAllStrs.clear();
}

template class TMString<CStr>;
template class TMString<CPStr>;

UIMPLEMENT_DYNAMIC(CMString, CPersistent)
UIMPLEMENT_DYNAMIC(CMPString, CPersistent)

void CKeyString::Concatenate(UStr & res, const char *key, const char *value)
{
	char c;
	while((c = *key++) != '\0')
	{
		if(c == '@' || c == '\\')
			res << '\\';
		res << c;
	}
	res << '@';
	while((c = *value++) != '\0')
	{
		if(c == '@' || c == '\\')
			res << '\\';
		res << c;
	}
}

void CKeyString::Split(const char *str, UStr & key, UStr & value)
{
	key = "";
	value = "";
	char c;
	bool inKey = true;
	while((c = *str++) != 0)
	{
		if(c == '\\')
			c = *str++;
		else if(c == '@')
		{
			inKey = false;
			continue;
		}
		
		if(inKey)
			key << c;
		else
			value << c;
	}
}

int CKeyString::Compare(const char *s1, const char *s2) const
{
	UStr key1, key2, val1, val2;
	Split(s1, key1, val1);
	Split(s2, key2, val2);
	return strcmp(key1, key2);
}

#if qUnix
void DoDataExchange(bool fill, int widid, int cmdid, CMString & mstr)
{
	if(fill)
	{
		UEventSendMessage(widid, EV_COMBO_RESETALL, cmdid, 0L);
		const NAMESPACE(std) vector<CStr> & list = mstr.GetList();
                NAMESPACE(std) vector<CStr>::const_iterator i;
		for(i = list.begin(); i != list.end(); ++i)
		{
			UEventSendMessage(widid, EV_COMBO_APPEND, cmdid, (void *)(const char *)*i);
		}
	}
	else
	{
		UStr value;
		UEventSendMessage(widid, EV_GETTEXT, cmdid, &value);
		if(!value.empty())
		{
			mstr.Insert(value);
		}
	}
}
#endif // qUnix
