#include "munga.h"
#pragma hdrstop

#include "receiver.h"
#include "event.h"

//#############################################################################
//#############################    Receiver    ################################
//#############################################################################

const Receiver::Handler
	Receiver::NullHandler=NULL;

Receiver::SharedData
	Receiver::DefaultData(
		Receiver::GetClassDerivations(),
		Receiver::GetMessageHandlers()
	);

Derivation* Receiver::GetClassDerivations()
{
	static Derivation classDerivations("Receiver");
	return &classDerivations;
}

const Receiver::HandlerEntry
	Receiver::MessageHandlerEntries[]=
{
	{
		Receiver::WatcherChangedMessageID,
		"WatcherChanged",
		(Receiver::Handler)&Receiver::DefaultMessageHandler
	},
	{
		Receiver::LoadResourceFinishedMessageID,
		"LoadResourceFinished",
		(Receiver::Handler)&Receiver::DefaultMessageHandler
	}
};

Receiver::MessageHandlerSet& Receiver::GetMessageHandlers()
{
	static Receiver::MessageHandlerSet messageHandlers(ELEMENTS(Receiver::MessageHandlerEntries), Receiver::MessageHandlerEntries);
	return messageHandlers;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
#if defined(USE_SIGNATURE)
	int
		Is_Signature_Bad(const volatile Receiver__Message *)
	{
		return False;
	}
#endif

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
#if DEBUG_LEVEL>0
	Receiver::DefaultMessageHandler(Message* message)
#else
	Receiver::DefaultMessageHandler(Message*)
#endif
{
	Tell(
		"Default Handler activated on message ID " << message->messageID << endl
	);
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	Receiver::Receive(Message *what)
{
	//
	//-------------------------------------------------------------------------
	// Service the message taps by creating an iterator to step through all the
	// MessageTaps registered with the Derivation object for the receiver's
	// class.  Each tap will do whatever it thinks best about this receiver
	// having received this message
	//-------------------------------------------------------------------------
	//
	Check(this);
	Check_Pointer(what);
	ChainIteratorOf<MessageTap*> i(GetDerivation()->activeTaps);
	MessageTap *tap;
	while ((tap = i.ReadAndNext()) != NULL)
	{
		tap->Scan(this,what);
	}

	//
	//--------------------------------------------------------------------------
	// Now, see if the receiver can handle this type of message, and if so, send
	// the message to the returned method handler
	//--------------------------------------------------------------------------
	//
	Receiver::SharedData *sharedData = GetSharedData();
	Handler handler = sharedData->activeMessageHandlers->Find(what->messageID);
	if (handler != Receiver::NullHandler)
	{
		(this->*handler)(what);
	}
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	Receiver::Receive(Event *event)
{
	Receive(event->messageToSend);
	Unregister_Object(event);
	delete event;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	Receiver::FlushEvents(int)		// max_priority doesn't work yet!!!!
{
	Check(this);
	PlugIteratorOf<Event*> i(this);
	Event *event;
	while ((event = i.ReadAndNext()) != NULL)
	{
		if (event->GetClassID() == EventClassID)
		{
			Unregister_Object(event);
			delete event;
		}
	}
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	Receiver::FlushMatchingEvents(
		Receiver::MessageID target_message,
		int 							// max_priority doesn't work yet!!!!
	)
{
	Check(this);
	PlugIteratorOf<Event*>
		i(this);
	Event* event;
	while ((event = i.ReadAndNext()) != NULL)
	{
		if (
			event->GetClassID() == EventClassID && (
				target_message == Receiver::AnyMessageID
				 || event->messageToSend->messageID == target_message
			)
		)
		{
			Unregister_Object(event);
			delete event;
		}
	}
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	Receiver::ProcessDeferredQueue()
{
	//
	//------------------------------------------------
	// Find a delay queue, and return if there is none
	//------------------------------------------------
	//
	Check(this);
	PlugIteratorOf<DeferredEventQueue*> i(this);
	DeferredEventQueue *deferred_queue;
	while ((deferred_queue = i.ReadAndNext()) != NULL)
	{
		if (deferred_queue->GetClassID() == DeferredEventQueueClassID)
		{
			break;
		}
	}
	if (!deferred_queue)
	{
		return;
	}

	//
	//--------------------------------------------------------------
	// Now, tell the queue to process all its events, then delete it
	//--------------------------------------------------------------
	//
	deferred_queue->ProcessAllEvents();
	Unregister_Object(deferred_queue);
	delete deferred_queue;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
Logical
	Receiver::TestInstance() const
{
	return IsDerivedFrom(*GetClassDerivations());
}

//#############################################################################
//#########################    Receiver::Message    ###########################
//#############################################################################

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
Logical
	Receiver::Message::TestInstance() const
{
	return True;
}

//#############################################################################
//######################### Receiver::DynamicMessage ##########################
//#############################################################################

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
Receiver__DynamicMessage::Receiver__DynamicMessage(
	Receiver::MessageID message_ID,
	size_t message_size
)
{
	Receiver::Message new_message(message_ID, message_size);
	WriteBytes(&new_message, message_size);
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
MemoryStream&
	Receiver::DynamicMessage::WriteBytes(
		const void *ptr,
		size_t number_of_bytes
	)
{
	DynamicMemoryStream::WriteBytes(ptr, number_of_bytes);

	Receiver::Message *message = GetMessagePointer();
	size_t new_size = GetBytesUsed();
	message->messageLength = new_size;
   return *this;
}

//#############################################################################
//############################    MessageTap    ###############################
//#############################################################################

MemoryBlock *MessageTap::GetAllocatedMemory()
{
	static MemoryBlock allocatedMemory(sizeof(MessageTap), 30, 30, "Message Taps");
	return &allocatedMemory;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
MessageTap::MessageTap(
	Derivation *derivation,
	Receiver *client,
	Receiver::ScanCallback call_back
):
	Plug(MessageTapClassID)
{
	//
	//---------------------------
	// Initialize the message tap
	//---------------------------
	//
	Check(client);
	clientReceiver = client;
	scanCallback = call_back;
	matchingReceiver = NULL;
	matchingMessageID = Receiver::AnyMessageID;

	//
	//--------------------------------------------
	// Hook the tap up to the specified derivation
	//--------------------------------------------
	//
	Check(derivation);
	derivation->AppendMessageTap(this);
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
MessageTap::MessageTap(
	Derivation *derivation,
	Receiver *client,
	Receiver::ScanCallback call_back,
	Receiver::MessageID messageID,
	Receiver *receiver
):
	Plug(MessageTapClassID)
{
	//
	//---------------------------
	// Initialize the message tap
	//---------------------------
	//
	Check(client);
	clientReceiver = client;
	scanCallback = call_back;

	matchingReceiver = receiver;
	matchingMessageID = messageID;

	//
	//--------------------------------------------
	// Hook the tap up to the specified derivation
	//--------------------------------------------
	//
	Check(derivation);
	derivation->AppendMessageTap(this);
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	MessageTap::Scan(
		Receiver *receiver,
		Receiver::Message *message
	)
{
	Check(this);
	Check(message);

	if (
		(!matchingReceiver || matchingReceiver == receiver)
		 && (
			matchingMessageID == Receiver::AnyMessageID
			 || matchingMessageID == message->messageID
		 )
	)
	{
		(clientReceiver->*scanCallback)(message,receiver);
	}
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
Logical
	MessageTap::TestInstance() const
{
	return True;
}

//#############################################################################
//#####################    Receiver::InheritanceSet    ########################
//#############################################################################

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
Logical
	Receiver::InheritanceSet::TestInstance() const
{
	return True;
}

//#############################################################################
//####################    Receiver::MessageHandlerSet    ######################
//#############################################################################

const Receiver::MessageHandlerSet
	Receiver::MessageHandlerSet::NullSet;

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
Receiver__MessageHandlerSet::~Receiver__MessageHandlerSet()
{
	if (messageHandlers)
	{
		Unregister_Pointer(messageHandlers);
		delete[] messageHandlers;
		messageHandlers = NULL;
	}
};

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	Receiver::MessageHandlerSet::Build(
		Receiver::MessageID count,
		const Receiver::HandlerEntry handler_table[],
		const Receiver::MessageHandlerSet *inheritance
	)
{
	//
	//-------------------------------------------------------
	// Find out the highest message type we have to deal with
	//-------------------------------------------------------
	//
	Check(this);
	Check_Pointer(handler_table);
	entryCount = 0;
	Receiver::MessageID i;
	for (i=0; i<count; ++i)
	{
		if (handler_table[i].entryID > entryCount)
		{
			entryCount = handler_table[i].entryID;
		}
	}
	if (inheritance)
	{
		Check(inheritance);
		if (entryCount < inheritance->entryCount)
		{
			entryCount = inheritance->entryCount;
		}
		#if DEBUG_LEVEL>0
		else if (entryCount > inheritance->entryCount)
		{
			i = inheritance->entryCount+1;
			goto Check_Table;
		}
		#endif
	}
	else
	{
		Verify(entryCount == count);
		#if DEBUG_LEVEL>0
		i = 1;
Check_Table:
			while (i <= entryCount)
			{
				int j;
				for (j=0; j<count; ++j)
				{
					if (handler_table[j].entryID == i)
					{
						break;
					}
				}
				if (j == count)
				{
					break;
				}
            ++i;
			}
			Verify(i > count);
		#endif
	}

	//
	//-----------------------------------------------------------------------
	// Allocate the memory for the new handler set, and copy the inherited
	// handlers to the new table.  We are guaranteed to have enough space for
	// the inherited table
	//-----------------------------------------------------------------------
	//
	messageHandlers = new Receiver::HandlerEntry[entryCount];
	Check_Pointer(messageHandlers);
	Register_Pointer(messageHandlers);
	i = 0;
	if (inheritance)
	{
		for (; i<inheritance->entryCount; ++i)
		{
			messageHandlers[i] = inheritance->messageHandlers[i];
		}
	}

	//
	//----------------------------------------------------------------------
	// Step through the new table supplied, placing each handler in the slot
	// determined by the message type
	//----------------------------------------------------------------------
	//
	for (i=0; i<count; ++i)
	{
		Receiver::MessageID index = handler_table[i].entryID - 1;
		Verify(index >= 0 && index < entryCount);
		messageHandlers[index] = handler_table[i];
	}
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
const Receiver::HandlerEntry*
	Receiver::MessageHandlerSet::Find(const char* name) const
{
	Check(this);
	Check_Pointer(name);

	for (int i=0; i<entryCount; ++i)
	{
		if (!strcmp(name, messageHandlers[i].entryName))
		{
			return &messageHandlers[i];
		}
	}
   return NULL;
}

//#############################################################################
//#############################    Derivation    ##############################
//#############################################################################

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
Derivation::Derivation(char *name):
	Node(DerivationClassID),
	classDerivations(this),
	activeTaps(this)
{
	Dump(name);
	className = name;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
Derivation::Derivation(
	Derivation *derivation,
	char *name
):
	Node(DerivationClassID),
	classDerivations(this),
	activeTaps(this)
{
	//
	//----------------------------------------------------------
	// Add this derivation as a child of the parent's derivation
	//----------------------------------------------------------
	//
	Dump(name);
	className = name;
	Check(derivation);
	if (derivation)
		derivation->AppendDerivation(this);
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	Derivation::AppendMessageTap(MessageTap* tap)
{
	Check(this);
	Check(tap);

	//
	//----------------------------------------------------------------------
	// Add the tap to the taps chain, then step through all our derivations,
	// sending each of them this same method
	//----------------------------------------------------------------------
	//
	activeTaps.Add(tap);
	ChainIteratorOf<Derivation*>
		i(classDerivations);
	Derivation *derivation;
	while ((derivation = i.ReadAndNext()) != NULL)
	{
		derivation->AppendMessageTap(tap);
	}
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
Logical
	Derivation::IsDescendedFrom(Derivation& parent)
{
	Check(this);
	Check(&parent);

	//
	//------------------------------
	// We are descended from ourself
	//------------------------------
	//
	if (&parent == this)
	{
		return True;
	}

	//
	//----------------------------------------------------------------------
	// Find our parent derivation, and ask him
	// sending each of them this same method
	//----------------------------------------------------------------------
	//
	PlugIteratorOf<Derivation*> i(this);
	Derivation *derivation;
	while ((derivation = i.ReadAndNext()) != NULL)
	{
		if (derivation->GetClassID() == DerivationClassID)
		{
			return derivation->IsDescendedFrom(parent);
		}
	}
	return False;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
Logical
	Derivation::IsDescendedFrom(const char* parent)
{
	Check(this);
	Check_Pointer(parent);

	//
	//------------------------------
	// We are descended from ourself
	//------------------------------
	//
	Check_Pointer(className);
	if (!strcmp(className, parent))
	{
		return True;
	}

	//
	//----------------------------------------------------------------------
	// Find our parent derivation, and ask him
	// sending each of them this same method
	//----------------------------------------------------------------------
	//
	PlugIteratorOf<Derivation*> i(this);
	Derivation *derivation;
	while ((derivation = i.ReadAndNext()) != NULL)
	{
		Check(derivation);
		if (derivation->GetClassID() == DerivationClassID)
		{
			return derivation->IsDescendedFrom(parent);
		}
	}
	return False;
}

//#############################################################################
//######################    Receiver::SharedData    ##########################
//#############################################################################

Logical
	Receiver::SharedData::TestInstance() const
{
	return True;
}

#if defined(TEST_CLASS)
#	include "receiver.tcp"
#endif
