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

#include <z_notify.hpp>

ZafNotification::ZafNotification(void) :
	updateType(ZAF_UPDATE_ALL), notifyArray(ZAF_NULLP(NotifyObject))
{
}

ZafNotification::~ZafNotification(void)
{
	// Check for an active array.
	if (notifyArray)
		delete []notifyArray;
}

ZafNotifyObject *ZafNotification::AddNotification(ZafNotifyObject *object, ZafUpdateFunction function, ZafUpdateType type)
{
	// Check the notification array.
	int offset = 0;
	if (notifyArray)
	{
		// Find the last item.
		for ( ; notifyArray[offset].object; offset++)
			if (notifyArray[offset].object == object &&
				notifyArray[offset].function == function)
				return (object);

		// Reallocate the array.
		if (((offset + 1) % ZAF_DYNAMIC_ARRAY_INCREMENT) == 0)
		{
			NotifyObject *tempArray = notifyArray;
			notifyArray = new NotifyObject[offset + ZAF_DYNAMIC_ARRAY_INCREMENT + 1];
			for (int i = 0; tempArray[i].object; i++)
				notifyArray[i] = tempArray[i];
			delete []tempArray;
		}
	}
	else
		notifyArray = new NotifyObject[ZAF_DYNAMIC_ARRAY_INCREMENT];

	// Reset the notification object.
	notifyArray[offset+1].object = 0;
	notifyArray[offset+1].function = 0;
	notifyArray[offset+1].updateType = ZAF_UPDATE_NONE;
	notifyArray[offset].object = object;
	notifyArray[offset].function = function;
	notifyArray[offset].updateType = type;

	return (object);
}

void ZafNotification::ClearNotifications(void)
{
	// Clear the notification object.
	if (notifyArray)
		delete []notifyArray;
	notifyArray = 0;
}

ZafUpdateType ZafNotification::SetUpdate(ZafUpdateType setUpdateType) 
{ 
	updateType = setUpdateType; 
	return (updateType); 
}

ZafUpdateType ZafNotification::SetUpdate(ZafNotifyObject *object, ZafUpdateType type)
{
	// Find the notification object.
	for (int i = 0; notifyArray[i].object; i++)
		if (notifyArray[i].object == object)
		{
			notifyArray[i].updateType = type;
			return (type);
		}
	return (ZAF_UPDATE_NONE);
}

ZafNotifyObject *ZafNotification::SubtractNotification(ZafNotifyObject *notifyObject, ZafUpdateFunction notifyFunction)
{
	// Check for a valid array.
	if (!notifyArray)
		return (0);

	// Try to find a matching entry.
	for (int i = 0; notifyArray[i].object; i++)
		if (notifyArray[i].object == notifyObject &&
			(!notifyFunction || notifyArray[i].function == notifyFunction))
		{
			// Check for an empty array.
			if (i == 0 && !notifyArray[i+1].object)
			{
				delete []notifyArray;
				notifyArray = 0;
				return (0);
			}

			// Remove the object from the notification array.
			for (int j = i; notifyArray[j].object; j++)
				notifyArray[j] = notifyArray[j+1];

			// Return the next object.
			return (notifyArray[i].object);
		}
	return (0);
}

int ZafNotification::NotifyCount(void) const
{
	// Check for a valid array.
	if (!notifyArray)
		return (0);

	// Count the data notifications.
	int count = 0;
	while (notifyArray[count].object)
		count++;
	return (count);
}

ZafUpdateType ZafNotification::Update(ZafNotifyObject *object) const
{
	// Find the notification object.
	for (int i = 0; notifyArray[i].object; i++)
		if (notifyArray[i].object == object)
			return (notifyArray[i].updateType);
	return (ZAF_UPDATE_NONE);
}

ZafError ZafNotification::UpdateData(ZafNotifyObject *dataSource)
{
	// Prevent recursion.
	if (!notifyArray || (updateType & ZAF_UPDATE_DATA) == 0)
		return (ZAF_ERROR_INVALID);
	updateType &= ~ZAF_UPDATE_DATA; // prevent recursion.

	// Notify all objects of object changes.
	if (dataSource)
	{
		for (int i = 0; notifyArray[i].object; i++)
			if (dataSource == notifyArray[i].object &&
				notifyArray[i].function && (notifyArray[i].updateType & ZAF_UPDATE_DATA))
				(*notifyArray[i].function)(notifyArray[i].object, ZAF_UPDATE_DATA);
	}
	else
	{
		for (int i = 0; notifyArray[i].object; i++)
			if (notifyArray[i].function && (notifyArray[i].updateType & ZAF_UPDATE_DATA))
				(*notifyArray[i].function)(notifyArray[i].object, ZAF_UPDATE_DATA);
	}

	updateType |= ZAF_UPDATE_DATA;
	return (ZAF_ERROR_NONE);
}

ZafError ZafNotification::UpdateObjects(ZafNotifyObject *objectMatch)
{
	// Prevent recursion.
//	if (!notifyArray || (updateType & ZAF_UPDATE_OBJECT) == 0)
	if (!notifyArray || (updateType & ~ZAF_UPDATE_DATA) == 0)
		return (ZAF_ERROR_INVALID);
//	updateType &= ~ZAF_UPDATE_OBJECT; // prevent recursion.
	ZafUpdateType tUpdate = updateType;
	ZafUpdateType sendUpdate = updateType & ~ZAF_UPDATE_DATA;
	updateType = ZAF_UPDATE_NONE; // prevent recursion.

	// Notify all objects of data changes.
	if (objectMatch)
	{
		for (int i = 0; notifyArray[i].object; i++)
			if (objectMatch == notifyArray[i].object &&
				notifyArray[i].function && (notifyArray[i].updateType & sendUpdate))
				(*notifyArray[i].function)(notifyArray[i].object, 
					tUpdate & ~ZAF_UPDATE_DATA);
//				(*notifyArray[i].function)(notifyArray[i].object,
//					notifyArray[i].updateType & sendUpdate);
	}
	else
	{
		for (int i = 0; notifyArray[i].object; i++)
			if (notifyArray[i].function && (notifyArray[i].updateType & sendUpdate))
				(*notifyArray[i].function)(notifyArray[i].object, 
					tUpdate & ~ZAF_UPDATE_DATA);
//				(*notifyArray[i].function)(notifyArray[i].object,
//					notifyArray[i].updateType & sendUpdate);
	}

	updateType = tUpdate & ~ZAF_UPDATE_HOT_KEY;
	return (ZAF_ERROR_NONE);
}


