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

#include <z_pal1.hpp>
#include <z_string.hpp>
#define ZAF_PALETTE_DATA_INFO
#include "gbl_def.cpp"

// ----- ZafPaletteData -----------------------------------------------------

ZafPaletteData::ZafPaletteData(bool setStaticData) :
	ZafData(),
	staticData(setStaticData), mapTableSize(0),
	mapTable(ZAF_NULLP(ZafPaletteMap))
{
	SetMapTable(ZAF_NULLP(ZafPaletteMap));
}

ZafPaletteData::ZafPaletteData(ZafPaletteMap *setMapTable, bool setStaticData) :
	ZafData(),
	staticData(setStaticData), mapTableSize(0),
	mapTable(ZAF_NULLP(ZafPaletteMap))
{
	SetMapTable(setMapTable);
}

ZafPaletteData::ZafPaletteData(const ZafPaletteData &copy) :
	ZafData(copy),
	staticData(copy.staticData), mapTableSize(0),
	mapTable(ZAF_NULLP(ZafPaletteMap))
{
	SetMapTable(copy.mapTable);
}

ZafPaletteData::~ZafPaletteData(void)
{
	if (!staticData)
		delete []mapTable;
}

ZafError ZafPaletteData::AddPalette(ZafPaletteType type, ZafPaletteState state, ZafPaletteStruct &palette)
{
	PushLevel();

	// Determine the insertion index.
	// "index" is the index for the new entry in the map table.
	// "insert" indicates whether the new entry will be inserted at
	// the index point or will overwrite the entry at the index point.
	int index = 0;
	bool insert = true;
	while (mapTable[index].type != ZAF_PM_NONE)
	{
		if (mapTable[index].type == type)
		{
			// Search for matching entries or insert at the end of the group.
			while (mapTable[index].type == type)
			{
				if (mapTable[index].state == state)
				{
					insert = false; // Replace the entry.
					break;
				}
				else if (mapTable[index].state == ZAF_PM_ANY_STATE)
					break; // Insert above any-state entries.
				index++;
			}
			break;
		}
		else if (mapTable[index].type == ZAF_PM_ANY_TYPE)
			break; // Insert above the "any-type" entries.
		index++;
	}

	// Re-allocate the pallete to allow space for the new inserted palette. 
	if (insert || staticData)
	{
		// Allocate the new palette.
		mapTableSize++;
		ZafPaletteMap *tempMapTable = mapTable;
		mapTable = new ZafPaletteMap[mapTableSize];

		// Copy the old palette.
		memcpy(mapTable, tempMapTable, index * sizeof(ZafPaletteMap));
		memcpy(&mapTable[index + 1], &tempMapTable[index], (mapTableSize - index - 1) * sizeof(ZafPaletteMap));

		// Free the old palette.
		if (!staticData)
			delete []tempMapTable;

		// Make sure mapTable gets cleaned up.
		staticData = false;

		// Initialize the new entry.
		mapTable[index].type = type;
		mapTable[index].state = state;
		mapTable[index].palette.lineStyle = ZAF_LINE_NULL;
		mapTable[index].palette.fillPattern = ZAF_PTN_NULL;
		mapTable[index].palette.colorForeground = mapTable[index].palette.colorBackground = ZAF_CLR_NULL;
		mapTable[index].palette.monoForeground = mapTable[index].palette.monoBackground = ZAF_MONO_NULL;
		mapTable[index].palette.font = ZAF_FNT_NULL;
#		if defined(ZAF_MSWINDOWS)
		mapTable[index].palette.osPalette.colorForeground = mapTable[index].palette.osPalette.colorBackground = 0xFFFFFFFFL;
#		elif defined(ZAF_MOTIF)
		mapTable[index].palette.osPalette = 0;
#		elif defined(ZAF_MACINTOSH)
		mapTable[index].palette.osPalette = 0;
#		elif defined(ZAF_INDEPENDENT)
		mapTable[index].palette.osPalette = 0;
#		endif
	}

	// Check the palette, removing null entries and adding new entries.
	if (palette.fillPattern == ZAF_PTN_NULL &&
		palette.colorForeground == ZAF_CLR_NULL &&
		palette.colorBackground == ZAF_CLR_NULL &&
		palette.monoForeground == ZAF_MONO_NULL &&
		palette.monoBackground == ZAF_MONO_NULL &&
		palette.font == ZAF_FNT_NULL)
		memmove(&mapTable[index], &mapTable[index + 1], (mapTableSize - index - 1) * sizeof(ZafPaletteMap));
	else
		mapTable[index].palette = palette;

	PopLevel();

	// Return success.
	return (ZAF_ERROR_NONE);
}

void ZafPaletteData::Clear(void)
{
	// Clear the data.
	PushLevel();
	SetMapTable(ZAF_NULLP(ZafPaletteMap));
	PopLevel();
}

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

ZafPaletteStruct ZafPaletteData::GetPalette(ZafPaletteType type, ZafPaletteState state)
{
	// Try to find the palette entry.
	ZafPaletteMap *entry = mapTable;
	while (entry->type != ZAF_PM_NONE)
	{
		if (entry->type == type && entry->state == state)
			return (entry->palette);
		entry++;
	}

	// Entry not found, return an empty palette.
	ZafPaletteStruct palette;
	palette.lineStyle = ZAF_LINE_NULL;
	palette.fillPattern = ZAF_PTN_NULL;
	palette.colorForeground = palette.colorBackground = ZAF_CLR_NULL;
	palette.monoForeground = palette.monoBackground = ZAF_MONO_NULL;
	palette.font = ZAF_FNT_NULL;
#	if defined(ZAF_MSWINDOWS)
	palette.osPalette.colorForeground = palette.osPalette.colorBackground = 0xFFFFFFFFL;
#	elif defined(ZAF_MOTIF)
	palette.osPalette = 0;
#	elif defined(ZAF_MACINTOSH)
	palette.osPalette = 0;
#	elif defined(ZAF_INDEPENDENT)
	palette.osPalette = 0;
#	endif
	return (palette);
}

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

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

ZafError ZafPaletteData::SetMapTable(ZafPaletteMap *setMapTable)
{
	PushLevel();
	if (staticData && setMapTable)
	{
		mapTable = setMapTable;
		mapTableSize = 0;
		while (mapTable[mapTableSize].type != ZAF_PM_NONE &&
			!(mapTable[mapTableSize].type == ZAF_PM_ANY_TYPE &&
			mapTable[mapTableSize].state == ZAF_PM_ANY_STATE))
				mapTableSize++;
		mapTableSize++;
	}
	else if (setMapTable)
	{
		mapTableSize = 0;
		while (setMapTable[mapTableSize].type != ZAF_PM_NONE &&
			!(setMapTable[mapTableSize].type == ZAF_PM_ANY_TYPE &&
			setMapTable[mapTableSize].state == ZAF_PM_ANY_STATE))
				mapTableSize++;
		mapTableSize++;

		mapTable = new ZafPaletteMap[mapTableSize];
		memcpy(mapTable, setMapTable, mapTableSize * sizeof(ZafPaletteMap));
	}
	else if (mapTable)
	{
		mapTable[0].type = ZAF_PM_NONE;
		mapTable[0].state = ZAF_PM_ANY_STATE;
	}
	else
	{
		staticData = false;
		mapTableSize = 1;
		mapTable = new ZafPaletteMap[mapTableSize];
		mapTable[0].type = ZAF_PM_NONE;
		mapTable[0].state = ZAF_PM_ANY_STATE;
		mapTable[0].palette.lineStyle = ZAF_LINE_NULL;
		mapTable[0].palette.fillPattern = ZAF_PTN_NULL;
		mapTable[0].palette.colorForeground = mapTable[0].palette.colorBackground = ZAF_CLR_NULL;
		mapTable[0].palette.monoForeground = mapTable[0].palette.monoBackground = ZAF_MONO_NULL;
		mapTable[0].palette.font = ZAF_FNT_NULL;
#		if defined(ZAF_MSWINDOWS)
		mapTable[0].palette.osPalette.colorForeground = mapTable[0].palette.osPalette.colorBackground = 0xFFFFFFFFL;
#		elif defined(ZAF_MOTIF)
		mapTable[0].palette.osPalette = 0;
#		elif defined(ZAF_MACINTOSH)
		mapTable[0].palette.osPalette = 0;
#		elif defined(ZAF_INDEPENDENT)
		mapTable[0].palette.osPalette = 0;
#		endif
	}
	PopLevel();

	// Return success.
	return (ZAF_ERROR_NONE);
}

bool ZafPaletteData::SetStaticData(bool setStaticData)
{
	// 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 != setStaticData)
	{
		staticData = setStaticData;
		if (!staticData)
		{
			ZafPaletteMap *newMapTable = mapTable;
			mapTable = ZAF_NULLP(ZafPaletteMap);
			SetMapTable(newMapTable);
		}
	}

	return (staticData);
}

// ----- Persistent functions -----------------------------------------------
#if defined(USE_ZAF_PERSISTENCE)
ZafPaletteData::ZafPaletteData(const ZafIChar *name, ZafDataPersistence &persist) :
	ZafData(name, persist.PushLevel(className, classID, ZAF_PERSIST_FILE)),
	staticData(false)
{
	// Read the object.
	if (persist.Error() == ZAF_ERROR_NONE)
		ZafPaletteData::ReadData(persist);
	persist.PopLevel();
	if (persist.Error() != ZAF_ERROR_NONE)
		SetError(persist.Error());
}

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

void ZafPaletteData::ReadData(ZafDataPersistence &persist)
{
	ZafFile *file = persist.CurrentFile();

	*file >> mapTableSize;

	mapTable = new ZafPaletteMap[mapTableSize];
	for (int i = 0; i < mapTableSize; i++)
	{
		*file >> mapTable[i].type;
		*file >> mapTable[i].state;
		*file >> mapTable[i].palette.lineStyle;
		*file >> mapTable[i].palette.fillPattern;
		*file >> mapTable[i].palette.colorForeground;
		*file >> mapTable[i].palette.colorBackground;
		*file >> mapTable[i].palette.monoForeground;
		*file >> mapTable[i].palette.monoBackground;
		*file >> mapTable[i].palette.font;
#		if defined(ZAF_MSWINDOWS)
		mapTable[i].palette.osPalette.colorForeground = mapTable[i].palette.osPalette.colorBackground = 0xFFFFFFFFL;
#		elif defined(ZAF_MOTIF)
		mapTable[i].palette.osPalette = 0;
#		elif defined(ZAF_MACINTOSH)
		mapTable[i].palette.osPalette = 0;
#		elif defined(ZAF_INDEPENDENT)
		mapTable[i].palette.osPalette = 0;
#		endif
	}
}

void ZafPaletteData::Write(ZafDataPersistence &persist)
{
	ZafData::Write(persist.PushLevel(className, classID, ZAF_PERSIST_FILE));
	if (persist.Error() == ZAF_ERROR_NONE)
		ZafPaletteData::WriteData(persist);
	persist.PopLevel();
	if (persist.Error() != ZAF_ERROR_NONE)
		SetError(persist.Error());
}

void ZafPaletteData::WriteData(ZafDataPersistence &persist)
{
	ZafFile *file = persist.CurrentFile();

	*file << mapTableSize;

	for (int i = 0; i < mapTableSize; i++)
	{
		*file << mapTable[i].type;
		*file << mapTable[i].state;
		*file << mapTable[i].palette.lineStyle;
		*file << mapTable[i].palette.fillPattern;
		*file << mapTable[i].palette.colorForeground;
		*file << mapTable[i].palette.colorBackground;
		*file << mapTable[i].palette.monoForeground;
		*file << mapTable[i].palette.monoBackground;
		*file << mapTable[i].palette.font;
	}
}
#endif
