//	Zinc Application Framework - Z_LANG.CPP
//	COPYRIGHT (C) 1990-1999.  All Rights Reserved.
//	Zinc Software Incorporated.  Pleasant Grove, Utah  USA

#include <z_ctype.hpp>
#include <z_idata.hpp>
#include <z_lang.hpp>
#include <z_string.hpp>
#define ZAF_LANGUAGE_DATA_INFO
#include "gbl_def.cpp"

// ----- ZafMessageData -----------------------------------------------------

ZafMessageData::ZafMessageData(const ZafIChar *tValue, ZafIChar setHotKeyChar, int setHotKeyIndex) :
	ZafStringData(tValue, -1, false), hotKeyChar(ToUpper(setHotKeyChar)),
	hotKeyIndex(setHotKeyIndex)
{
}

ZafIChar ZafMessageData::SetHotKey(ZafIChar setHotKeyChar, int setHotKeyIndex)
{
	if (hotKeyChar != setHotKeyChar || hotKeyIndex != setHotKeyIndex)
		SetUpdate(Update() | ZAF_UPDATE_HOT_KEY);
	hotKeyChar = ToUpper(setHotKeyChar);
	hotKeyIndex = setHotKeyIndex;
	return (hotKeyChar);
}

bool ZafMessageData::IsA(ZafClassID compareID) const
{
	return ((compareID == classID) ? true : ZafStringData::IsA(compareID));
}

bool ZafMessageData::IsA(ZafClassName compareName) const
{
	return (!strcmp(compareName, className) ? true : ZafStringData::IsA(compareName));
}

// ----- ZafLanguageData ----------------------------------------------------

ZafLanguageData::ZafLanguageData(bool tStaticData) :
	ZafDataRecord(), lockCount(0),
	staticData(tStaticData), data(ZAF_NULLP(ZafMessageStruct))
{
}

ZafLanguageData::ZafLanguageData(ZafMessageStruct *tData, bool tStaticData) :
	ZafDataRecord(), lockCount(0),
	staticData(tStaticData), data(ZAF_NULLP(ZafMessageStruct))
{
	SetMessages(tData);
}

ZafLanguageData::ZafLanguageData(const ZafLanguageData &copy) :
	ZafDataRecord(copy), lockCount(0),
	staticData(copy.staticData), data(ZAF_NULLP(ZafMessageStruct))
{
	// Copy the data contents.
	SetMessages(copy.data);
}

ZafLanguageData::~ZafLanguageData(void)
{
	// Delete the language data.
	Clear();
}

void ZafLanguageData::Lock(void)
{
	lockCount++;
}

bool ZafLanguageData::Locked(void)
{
	return (lockCount == 0) ? false : true;
}

void ZafLanguageData::UnLock(void)
{
	if (lockCount > 0)
		lockCount--;
}

void ZafLanguageData::Clear(void)
{
	// Clear the data.
	PushLevel();
	if (data && !StaticData())
	{
		// Delete the table contents
		for (int i = 0; data[i].numberID || data[i].stringID; i++)
		{
			delete [](ZafIChar *)data[i].stringID;
			delete []data[i].text;
		}
		delete []data;
	}
	data = ZAF_NULLP(ZafMessageStruct);
	PopLevel();
}

ZafData *ZafLanguageData::Duplicate(void)
{
	return (new ZafLanguageData(*this));
}

ZafIChar *ZafLanguageData::GetMessage(ZafStringID matchID, bool useDefault,
	ZafIChar *hotKeyChar, int *hotKeyIndex) const
{
	if (!data)
		return (ZAF_NULLP(ZafIChar));

	// Try to find a matching entry.
	for (int i = 0; data[i].numberID || data[i].stringID; i++)
		if (strcmp(data[i].stringID, matchID) == 0)
		{
			if (hotKeyChar)
				*hotKeyChar = data[i].hotKeyChar;
			if (hotKeyIndex)
				*hotKeyIndex = data[i].hotKeyIndex;
			return (data[i].text);
		}
	return (useDefault ? data[0].text : ZAF_NULLP(ZafIChar));
}

ZafIChar *ZafLanguageData::GetMessage(ZafNumberID matchID, bool useDefault,
	ZafIChar *hotKeyChar, int *hotKeyIndex) const
{
	if (!data)
		return (ZAF_NULLP(ZafIChar));

	// Try to find a matching entry.
	for (int i = 0; data[i].numberID || data[i].stringID; i++)
		if (data[i].numberID == matchID)
		{
			if (hotKeyChar)
				*hotKeyChar = data[i].hotKeyChar;
			if (hotKeyIndex)
				*hotKeyIndex = data[i].hotKeyIndex;
			return (data[i].text);
		}
	return (useDefault ? data[0].text : ZAF_NULLP(ZafIChar));
}

ZafMessageData *ZafLanguageData::GetMessageData(const ZafIChar *tStringID, bool useDefault)
{
	ZafMessageData *messageData = DynamicPtrCast(GetObject(tStringID), ZafMessageData);

	if (!messageData && data)
	{
		ZafIChar *message = ZAF_NULLP(ZafIChar);
		int i;
		for (i = 0; data[i].numberID || data[i].stringID; i++)
			if (strcmp(data[i].stringID, tStringID) == 0)
			{
				message = data[i].text;
				break;
			}

		if (useDefault && !message)
		{
			i = 0;
			message = data[i].text;
		}

		if (message)
		{
			messageData = new ZafMessageData(message, data[i].hotKeyChar,
				data[i].hotKeyIndex);
			messageData->SetStringID(data[i].stringID);
			messageData->SetNumberID(data[i].numberID);
			messageData->AddNotification(this);
			Add(messageData);
		}
	}

	return (messageData);
}

ZafMessageData *ZafLanguageData::GetMessageData(ZafNumberID tNumberID, bool useDefault)
{
	ZafMessageData *messageData = DynamicPtrCast(GetObject(tNumberID), ZafMessageData);

	if (!messageData)
	{
		ZafIChar *message = ZAF_NULLP(ZafIChar);
		int i;
		for (i = 0; data[i].numberID || data[i].stringID; i++)
			if (data[i].numberID == tNumberID)
			{
				message = data[i].text;
				break;
			}

		if (useDefault && !message)
		{
			i = 0;
			message = data[i].text;
		}

		if (message)
		{
			messageData = new ZafMessageData(message, data[i].hotKeyChar,
				data[i].hotKeyIndex);
			messageData->SetStringID(data[i].stringID);
			messageData->SetNumberID(data[i].numberID);
			messageData->AddNotification(this);
			Add(messageData);
		}
	}

	return (messageData);
}

int ZafLanguageData::Messages(void)
{
	int messages = 0;
	if (data)
		while (data[messages].numberID || data[messages].stringID)
			messages++;
	return (messages);
}

bool ZafLanguageData::IsA(ZafClassID compareID) const
{
	return ((compareID == classID) ? true : ZafDataRecord::IsA(compareID));
}

bool ZafLanguageData::IsA(ZafClassName compareName) const
{
	return (!strcmp(compareName, className) ? true : ZafDataRecord::IsA(compareName));
}

ZafError ZafLanguageData::SetMessage(ZafNumberID matchID, ZafIChar *text,
	ZafIChar hotKeyChar, int hotKeyIndex)
{
	if (!data)
		return (ZAF_ERROR_INVALID_SOURCE);

	// Try to find a matching entry.
	PushLevel();
	for (int i = 0; data[i].numberID || data[i].stringID; i++)
		if (data[i].numberID == matchID)
		{
			delete data[i].text;
			data[i].text = text ? strdup(text) : strdup(ZafLanguageManager::blankString);
			data[i].hotKeyChar = hotKeyChar;
			data[i].hotKeyIndex = hotKeyIndex;
			PopLevel();
			return (ZAF_ERROR_NONE);
		}
	PopLevel();
	return (ZAF_ERROR_INVALID_ID);
}

ZafError ZafLanguageData::SetMessages(ZafMessageStruct *srcTable)
{
	// Set the new information.
	if (StaticData())
		data = srcTable;
	else if (srcTable)
	{
		// Clear the old information.
		Clear();

		// Count the number of table objects.
		int tCount = 0;
		while (srcTable[tCount].numberID || srcTable[tCount].stringID)
			tCount++;

		// Copy the table contents.
		data = new ZafMessageStruct[tCount+1];
		for (int i = 0; i < tCount; i++)
		{
			data[i].text = srcTable[i].text ? strdup(srcTable[i].text) : strdup(ZafLanguageManager::blankString);
			data[i].numberID = srcTable[i].numberID;
			data[i].stringID = srcTable[i].stringID ? strdup(srcTable[i].stringID) : ZAF_NULLP(ZafIChar);
			data[i].hotKeyChar = srcTable[i].hotKeyChar;
			data[i].hotKeyIndex = srcTable[i].hotKeyIndex;
		}

		// Mark the end of the array.
		data[tCount].text = ZAF_NULLP(ZafIChar);
		data[tCount].numberID = ZAF_NUMID_NULL;
		data[tCount].stringID = ZAF_NULLP(ZafIChar);
		data[tCount].hotKeyChar = '\0';
		data[tCount].hotKeyIndex = 0;
	}

	for (ZafMessageData *messageData = First(); messageData; messageData = (ZafMessageData *)messageData->Next())
	{
		int hotKeyIndex;
		ZafIChar hotKeyChar;
		ZafIChar *message;
		if (messageData->StringID())
			message = GetMessage(messageData->StringID(), true,
				&hotKeyChar, &hotKeyIndex);
		else
			message = GetMessage(messageData->NumberID(), true,
				&hotKeyChar, &hotKeyIndex);
		messageData->SetHotKey(hotKeyChar, hotKeyIndex);
		messageData->SetText(message);
	}

	// Return success.
	return (ZAF_ERROR_NONE);
}

ZafError ZafLanguageData::SetMessages(const ZafLanguageData &copy)
{
	// Reset the language information.
	if (copy.staticData)
	{
		Clear();
		staticData = true;
		data = copy.data;
	}
	else
		SetMessages(copy.data);
	return (ZAF_ERROR_NONE);
}

bool ZafLanguageData::SetStaticData(bool tStaticData)
{
	// If the data is marked static, the user is in charge of protecting 
	// the data.  Otherwise, we must copy the contents to a new array.
	// This is done by re-setting the variables and data pointer, then
	// by resetting the array.
	if (staticData != tStaticData)
	{
		if (tStaticData)
			staticData = tStaticData;
		else
		{
			staticData = tStaticData;
			ZafMessageStruct *newData = data;
			data = ZAF_NULLP(ZafMessageStruct);
			SetMessages(newData);
		}
	}
	return (staticData);
}

// ----- Persistent functions -----------------------------------------------
#if defined(USE_ZAF_PERSISTENCE)
ZafLanguageData::ZafLanguageData(const ZafIChar *name, ZafDataPersistence &persist, const ZafIChar *languageName) :
	ZafDataRecord(name, (persist.PushLanguage(languageName ? languageName : ZafLanguageManager::LanguageName()),
	persist.PushLevel(className, classID, ZAF_PERSIST_ROOT_DIRECTORY))),
	lockCount(0), staticData(false), data(ZAF_NULLP(ZafMessageStruct))
{
	// Read the object.
	if (persist.Error() == ZAF_ERROR_NONE)
		ZafLanguageData::ReadData(persist);

	persist.PopLevel();
	persist.PopLanguage();
	if (persist.Error() != ZAF_ERROR_NONE)
	{
		SetError(persist.Error());
		persist.SetError(ZAF_ERROR_NONE);
	}
}

ZafElement *ZafLanguageData::Read(const ZafIChar *name, ZafDataPersistence &persist)
{
	return (new ZafLanguageData(name, persist));
}

void ZafLanguageData::ReadData(ZafDataPersistence &persist)
{
	// Read the data.
	int noOfElements;
	ZafFile *file = persist.CurrentFile();
	*file >> noOfElements;
	data = new ZafMessageStruct[noOfElements+1];
	for (int i = 0; i < noOfElements; i++)
	{
		data[i].text = ZAF_NULLP(ZafIChar);
		ZafUInt16 hotKeyChar;
		*file >> data[i].numberID >> (ZafIChar **)&data[i].stringID >> &data[i].text >> hotKeyChar >> data[i].hotKeyIndex;
		data[i].hotKeyChar = (ZafIChar)hotKeyChar;
		if (!data[i].text)
			data[i].text = strdup(ZafLanguageManager::blankString);
	}

	// Stub out the last entry.
	data[noOfElements].numberID = ZAF_NUMID_NULL;
	data[noOfElements].stringID = ZAF_NULLP(ZafIChar);
	data[noOfElements].text = ZAF_NULLP(ZafIChar);
	data[noOfElements].hotKeyChar = '\0';
	data[noOfElements].hotKeyIndex = 0;
}

void ZafLanguageData::Write(ZafDataPersistence &persist)
{
	// Write the object.
	ZafData::Write(persist.PushLevel(className, classID, ZAF_PERSIST_ROOT_DIRECTORY));
	if (persist.Error() == ZAF_ERROR_NONE)
		ZafLanguageData::WriteData(persist);
	persist.PopLevel();
	if (persist.Error() != ZAF_ERROR_NONE)
		SetError(persist.Error());
}

void ZafLanguageData::WriteData(ZafDataPersistence &persist)
{
	// Write the data.
	int noOfElements = 0;

	if (data)
		while (data[noOfElements].numberID || data[noOfElements].stringID)
			noOfElements++;

	ZafFile *file = persist.CurrentFile();
	*file << noOfElements;
	for (int i = 0; i < noOfElements; i++)
	{
		ZafUInt16 hotKeyChar = (ZafUInt16)data[i].hotKeyChar;
		*file << data[i].numberID << data[i].stringID << data[i].text << hotKeyChar << data[i].hotKeyIndex;
	}
}
#endif
