//===========================================================================//
// File:	receiver.cc                                                         //
// Project: MUNGA           Brick: Dynamic Dispatch                          //
// Contents: Implementation Details of Dynamic Dispatch Processing           //
//---------------------------------------------------------------------------//
//   Date    Who  Modification                                               //
// --------  ---  ---------------------------------------------------------- //
// 10/19/94  JMA  Initial coding.                                            //
// 10/28/94  JMA  Made compatible with SGI CC                                //
// 11/03/94  ECH  Made compatible with BC4.0                                 //
// 11/05/94  JMA  Made compatible with GNU C++                               //
// 11/30/94  JMA  Adapted to new style conventions                           //
// 12/01/94  JMA  Made compatible with SGI CC                                //
// 12/04/94  JMA  Moved Message under Receiver, merged with message.hh       //
//---------------------------------------------------------------------------//
// Copyright (C) 1994-1995, Virtual World Entertainment, Inc.                //
//                      PROPRIETARY AND CONFIDENTIAL                         //
//===========================================================================//

#include "AdeptHeaders.hpp"

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

const Receiver::MessageHandler
	Receiver::NullMessageHandler=NULL;

const Receiver::MessageEntry
	Receiver::MessageEntries[]=
{
	MESSAGE_ENTRY(Receiver, Default)
};

Receiver::ClassData*
	Receiver::DefaultData = NULL;

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	Receiver::InitializeClass()
{
	Verify(!DefaultData);
	DefaultData =
		new ClassData(
			ReceiverClassID,
			"Adept::Receiver",
			Plug::DefaultData,
			ELEMENTS(MessageEntries), MessageEntries
		);
	Register_Object(DefaultData);
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	Receiver::TerminateClass()
{
	Unregister_Object(DefaultData);
	delete DefaultData;
	DefaultData = NULL;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
Receiver::Receiver(ClassData *class_data):
	Plug(class_data)
{
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	Receiver::DefaultMessageHandler(const Message* message)
{
	SPEW((0, "Default Handler activated on message ID %d", message->messageID));
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	Receiver::Receive(const Message *what)
{
	Check_Object(this);
	Check_Object(what);

	//
	//--------------------------------------------------------------------------
	// Now, see if the receiver can handle this type of message, and if so, send
	// the message to the returned method handler
	//--------------------------------------------------------------------------
	//
	ClassData *class_data = GetClassData();
	Check_Object(class_data);
	MessageHandler handler = class_data->GetMessageHandler(what->messageID);
	Verify(handler != Receiver::NullMessageHandler);
#if defined(_DEBUG) && 0 // jcem - for MR test
  {
	char Buffer[128];
	sprintf(Buffer, "Receiver:: %s\n", class_data->messageHandlers[what->messageID-1].messageName);
	OutputDebugString(Buffer);
  }
#endif // _DEBUG && ...
	(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_Object(this);
	STOP(("Not implemented"));
#if 0
	PlugIteratorOf<Event*> i(this);
	Event *event;
	while ((event = i.ReadAndNext()) != NULL)
	{
		if (event->GetClassID() == EventClassID)
		{
			Unregister_Object(event);
			delete event;
		}
	}
#endif
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	Receiver::FlushMatchingEvents(
		Receiver::MessageID target_message,
		int 							// max_priority doesn't work yet!!!!
	)
{
	Check_Object(this);
	STOP(("Not implemented"));
#if 0
	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;
		}
	}
#endif
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	Receiver::TestInstance()
{
	Verify(IsDerivedFrom(DefaultData));
}

//#############################################################################
//#############################    ClassData    ##############################
//#############################################################################

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
Receiver__ClassData::Receiver__ClassData(
	RegisteredClass::ClassID class_id,
	const char *class_name,
	Plug::ClassData *parent,
	Receiver::MessageID count,
	const Receiver::MessageEntry *handler_table
):
	Plug__ClassData(class_id, class_name, parent)
{
	Check_Pointer(this);

	//
	//----------------------------
	// Look for our parent's table
	//----------------------------
	//
	Receiver__ClassData *inheritance;
	if (class_id != ReceiverClassID)
	{
		inheritance = Cast_Pointer(Receiver__ClassData*, parent);
		Check_Object(inheritance);
	}
	else
	{
		Verify(parent->GetClassID() == PlugClassID);
		inheritance = NULL;
	}

	//
	//---------------------------------------------------------------
	// If we have not supplied a message table, use our parents table
	//---------------------------------------------------------------
	//
	if (count == 0 && inheritance != NULL)
	{
		Check_Object(inheritance);
		deleteMessages = false;
		messageHandlers = inheritance->messageHandlers;
		messageCount = inheritance->messageCount;
		return;
	}

	//
	//---------------------------------
	// We will have to make a new table
	//---------------------------------
	//
	deleteMessages = true;
	Check_Pointer(handler_table);
	Verify(count > 0);

	//
	//-------------------------------------------------------
	// Find out the highest message type we have to deal with
	//-------------------------------------------------------
	//
	messageCount = 0;
	Receiver::MessageID i;
	for (i=0; i<count; ++i)
	{
		if (handler_table[i].messageID > messageCount)
		{
			messageCount = handler_table[i].messageID;
		}
	}

	//
	//--------------------------------------------------
	// Adjust the table size to include our parent stuff
	//--------------------------------------------------
	//
	if (inheritance)
	{
		Verify(messageCount <= inheritance->messageCount + count);
		if (messageCount < inheritance->messageCount)
		{
			messageCount = inheritance->messageCount;
		}
		#if defined(_ARMOR)
		else if (messageCount > inheritance->messageCount)
		{
			i = inheritance->messageCount+1;
			goto Check_Table;
		}
		#endif
	}

	//
	//-----------------------------------------------
	// Make sure that there are no holes in the table
	//-----------------------------------------------
	//
	else
	{
		Verify(messageCount == count);
		#if defined(_ARMOR)
		i = 1;
Check_Table:
			while (i <= messageCount)
			{
				int j;
				for (j=0; j<count; ++j)
				{
					if (handler_table[j].messageID == 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::MessageEntry[messageCount];
	Register_Pointer(messageHandlers);
	i = 0;
	if (inheritance)
	{
		for (; i<inheritance->messageCount; ++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].messageID - 1;
		Verify(index >= 0 && index < messageCount);
		messageHandlers[index] = handler_table[i];
	}
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
Receiver__ClassData::~Receiver__ClassData()
{
	if (deleteMessages)
	{
		Unregister_Pointer(messageHandlers);
		delete[] messageHandlers;
	}
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
size_t
	Receiver__ClassData::WriteClassBlock(
		MemoryStream* stream,
		bool write_it
	)
{
	Check_Object(this);
	int size = 0;

	//
	//----------------------------------------------------------------
	// If we are just finding out the size of the class, figure it out
	//----------------------------------------------------------------
	//
	if (!write_it)
	{
		size += 2*sizeof(int);
		size += strlen(GetClassName())+1;
		int messages = GetMessageCount();
		for (int i=1; i<=messages; ++i)
		{
			const Receiver::MessageEntry *entry = GetMessageEntry(i);
			Check_Pointer(entry);
			const char* name = entry->messageName;
			Check_Pointer(name);
			size += strlen(name) + 1;
		}
		size = (size+3)&~3;
	}

	//
	//------------------------
	// Otherwise, write it out
	//------------------------
	//
	else
	{
		int messages = GetMessageCount();
		*stream << GetClassID() << messages;
		size_t str_len = strlen(GetClassName()) + 1;
		stream->WriteBytes(className, str_len);
		size = str_len;
		for (int i=1; i<=messages; ++i)
		{
			const Receiver::MessageEntry *entry = GetMessageEntry(i);
			Check_Pointer(entry);
			const char* name = entry->messageName;
			Check_Pointer(name);
			str_len = strlen(name) + 1;
			stream->WriteBytes(name, str_len);
			size += str_len;
		}
		while (size&3)
		{
			*stream << '\0';
			++size;
		}
		size = 0;
	}

	//
	//---------------------------------------------------------------------
	// Now call all of our derived classes and add their sizes to the total
	//---------------------------------------------------------------------
	//
	RegisteredClass__ClassData *class_data = firstChildClass;
	while (class_data)
	{
		Receiver__ClassData *receiver_class =
			Cast_Pointer(Receiver__ClassData*, class_data);
		Check_Object(receiver_class);
		size += receiver_class->WriteClassBlock(stream, write_it);
		class_data = receiver_class->nextSiblingClass;
	}
	return size;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
const Receiver::MessageEntry*
	Receiver__ClassData::FindMessageEntry(const char* name)
{
	Check_Object(this);
	Check_Pointer(name);

	for (int i=0; i<messageCount; ++i)
	{
		if (!_stricmp(name, messageHandlers[i].messageName))
		{
			return &messageHandlers[i];
		}
	}
   return NULL;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	Receiver__ClassData::TestInstance()
{
	Verify(IsDerivedFrom(Receiver::DefaultData));
}
