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

#include <z_evtmgr.hpp>
#include <z_string.hpp>
#include <z_sysevt.hpp>

#if defined(ZAF_MOTIF)
#include <z_scrdsp.hpp>
#include <z_win.hpp>
#endif

#if !defined(ZAF_LOCAL_FILE_STATICS)
#include <z_app.hpp>
#include <z_devall.hpp>
#define ZAF_LOCAL_FILE_STATICS
#define ZAF_APPLICATION_INFO
#define ZAF_REGION_INFO
#define ZAF_LIST_INFO
#define ZAF_FILE_INFO
#define ZAF_CURSOR_INFO
#define ZAF_DEVICE_INFO
#define ZAF_KEYBOARD_INFO
#define ZAF_MOUSE_INFO
#define ZAF_DISPLAY_INFO
#define ZAF_TIMER_INFO
#define ZAF_HELP_TIPS_INFO
#define ZAF_UTILS_INFO
#include "gbl_def.cpp"
#endif

// ----- ZafEventManager ----------------------------------------------------

ZafEventManager::ZafEventManager(int _noOfQueueEvents) :
	ZafList((ZafCompareFunction)ZafDevice::CompareDevices),
	queueBlock(_noOfQueueEvents)
{
	// Set the static variables.
	if (!ZafDevice::display)
		ZafDevice::display = zafDisplay;
	if (!ZafDevice::eventManager)
		ZafDevice::eventManager = this;

#if defined(ZAF_MACINTOSH)
	blocking = false;
	mouseMovedRgn = NewRgn();
	SetRectRgn(mouseMovedRgn, -32001, -32001, -32000, -32000);
#elif defined(ZAF_MOTIF)
	blocking = false;
#elif defined(ZAF_RTOS)
	blockingSemaphore = new ZafSemaphore(ZAF_BINARY_SEMAPHORE, ZAF_FIFO_SEMAPHORE, ZAF_TAKEN_SEMAPHORE);
	exclusionSemaphore = new ZafSemaphore(ZAF_BINARY_SEMAPHORE, ZAF_FIFO_SEMAPHORE, ZAF_AVAILABLE_SEMAPHORE);
#endif
}

ZafEventManager::~ZafEventManager(void)
{
	for (ZafDevice *device = First(); device; device = device->Next())
		device->Event(D_DEINITIALIZE);

#if defined(ZAF_MACINTOSH)
	if (mouseMovedRgn)
		DisposeRgn(mouseMovedRgn);
#elif defined(ZAF_RTOS)
	if (blockingSemaphore)
	{
		delete (blockingSemaphore);
		blockingSemaphore = ZAF_NULLP(ZafSemaphore);
	}
	if (exclusionSemaphore)
	{
		delete (exclusionSemaphore);
		blockingSemaphore = ZAF_NULLP(ZafSemaphore);
	}
#endif

	// Clear the static variables.
	ZafDevice::display = ZAF_NULLP(ZafDisplay);
	ZafDevice::eventManager = ZAF_NULLP(ZafEventManager);
}

ZafDevice *ZafEventManager::Add(ZafDevice *object, ZafDevice *position)
{
	// Add the device to the object list.
	if (object && ZafList::Index(object) == -1)
	{
		if (position)
			ZafList::Add(object, position);	// position insert.
		else
			ZafList::Add(object);			// compareFunction insert.
		object->Event(D_INITIALIZE);
	}
	return (object);
}

ZafEventType ZafEventManager::Event(const ZafEventStruct &event, ZafDeviceType deviceType)
{
	// Process the event.
	ZafEventType ccode = S_UNKNOWN;
	for (ZafDevice *device = First(); device; device = device->Next())
		if (deviceType == device->DeviceType() || deviceType == E_DEVICE)
		 	ccode = device->Event(event);

	// Return the associated response code.
	return (ccode);
}

ZafDevice *ZafEventManager::GetObject(ZafNumberID matchID)
{
	// Try to find a matching device.
	for (ZafDevice *device = First(); device; device = device->Next())
		if (device->NumberID() == matchID)
			return (device);
	return (ZAF_NULLP(ZafDevice));
}

ZafDevice *ZafEventManager::GetObject(const ZafIChar *matchID)
{
	// Try to find a matching device.
	for (ZafDevice *device = First(); device; device = device->Next())
		if (!streq(device->StringID(), matchID))
			return (device);
	return (ZAF_NULLP(ZafDevice));
}

#if defined(ZAF_UNICODE)
#include <z_str.hpp>
ZafDevice *ZafEventManager::GetObject(const char *matchID)
{
	// Setting text at window object level is invalid.
	ZafStringData stringData(matchID);
	return (GetObject(stringData.Text()));
}
#endif

ZafEventType ZafEventManager::SetDeviceImage(ZafDeviceType deviceType, ZafDeviceImage deviceImage)
{
	// Send the image information to the affected device.
	ZafEventStruct event(deviceImage);
	for (ZafDevice *device = First(); device; device = device->Next())
		if (deviceType == device->DeviceType())
		 	return (device->Event(event));
	return (event.type);
}

ZafEventType ZafEventManager::SetDevicePosition(ZafDeviceType deviceType, int column, int line)
{
	// Send the position information to the affected device.
	ZafEventStruct event(D_POSITION);
	event.position.Assign(column, line, ZAF_PIXEL);
	for (ZafDevice *device = First(); device; device = device->Next())
		if (deviceType == device->DeviceType())
		 	return (device->Event(event));
	return (event.type);
}

ZafEventType ZafEventManager::SetDeviceState(ZafDeviceType deviceType, ZafDeviceState deviceState)
{
	// Send the state information to the affected device.
	ZafEventType state = D_OFF;
	ZafEventStruct event(deviceState);
	for (ZafDevice *device = First(); device; device = device->Next())
		if (deviceType == device->DeviceType())
		{
		 	device->Event(event);
			event.type = D_STATE;
		 	state = device->Event(event);
		}
	return (state);
}

ZafDevice *ZafEventManager::Subtract(ZafDevice *object)
{
	// Remove the device from the object list.
	if (ZafList::Index(object) != -1)
	{
		object->Event(D_DEINITIALIZE);
		return ((ZafDevice *)ZafList::Subtract(object));
	}
	return (ZAF_NULLP(ZafDevice));
}

// ----- ZafQueueElement ---------------------------------------------------

ZafQueueElement::ZafQueueElement(void) :
	ZafElement()
{
}

ZafQueueElement::~ZafQueueElement(void)
{
}

ZafQueueBlock::ZafQueueBlock(int _noOfElements) :
	ZafListBlock(_noOfElements)
{
	// Initialize the queue block.
	ZafQueueElement *queueBlock = new ZafQueueElement[_noOfElements];
	elementArray = queueBlock;
	for (int i = 0; i < _noOfElements; i++)
		freeList.Add(&queueBlock[i], ZAF_NULLP(ZafElement));
}

ZafQueueBlock::~ZafQueueBlock(void)
{
	// Free the queue block.
	ZafQueueElement *queueBlock = (ZafQueueElement *)elementArray;

	// Early C++ versions require explicit number of elements.
	delete [] queueBlock;
}

