//===========================================================================//
// File:	receiver.hpp                                                         //
// Project: MUNGA           Brick: Dynamic Dispatch                          //
// Contents: Dynamic Dispatch Interface                                      //
//---------------------------------------------------------------------------//
//   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/04/94  JMA  Made compatible with GNU C++                               //
// 11/04/94  ECH  Added null handler set		                                //
// 11/29/94  JMA  Changed ClassIdentity to ClassID                           //
// 11/30/94  JMA  Adapted to new style conventions                           //
// 12/04/94  JMA  Moved Message under Receiver, merged with message.hpp       //
// 12/06/94  JMA  Made DefaultData publicly visible                          //
//---------------------------------------------------------------------------//
// Copyright (C) 1994, Virtual World Entertainment, Inc. All Rights reserved //
//                      PROPRIETARY AND CONFIDENTIAL                         //
//===========================================================================//

#if !defined(RECEIVER_HPP)
#	define RECEIVER_HPP

#	if !defined(NODE_HPP)
#		include <node.hpp>
#	endif

#	if !defined(CHAIN_HPP)
#		include <chain.hpp>
#	endif

#	if !defined(MEMBLOCK_HPP)
#		include <memblock.hpp>
#	endif

#	if !defined(MEMSTRM_HPP)
#		include <memstrm.hpp>
#	endif

	class Receiver__SharedData;
	class Receiver__InheritanceSet;
	struct Receiver__HandlerEntry;
	class Receiver__MessageHandlerSet;
	class Receiver__Message;
	class Receiver__DynamicMessage;
	class Derivation;
	class Event;
	class DynamicMemoryStream;
	class MessageTap;

	//##########################################################################
	//##########################    Receiver    ################################
	//##########################################################################
	//
	// It is suggested that calls to methods meant to be serviced by a receiver
	// be built through inline functions in the derived class, rather than
	// having to build the parameter block in the scope of the caller.  Letting
	// the inline code build the parameter block is much cleaner, and allows the
	// message code numbers to be held inside the derived class, further
	// protecting against calling methods for objects not in a proper derivation
	// chain.
	//
	class Receiver:
		public Node
	{
	//##########################################################################
	// Shared Data Support
	//
	public:
		typedef Receiver__SharedData SharedData;
		SharedData*
			GetSharedData() const;

		static Derivation ClassDerivations;
		Derivation*
			GetDerivation() const;

		static SharedData DefaultData;

		Logical
			IsDerivedFrom(Derivation& parent) const;
		Logical
			IsDerivedFrom(const char* parent) const;

	protected:
		const SharedData* sharedData;

	//##########################################################################
	// Construction and Destruction Support
	//
	protected:
		Receiver(
			ClassID class_ID,
			SharedData &shared_data
		):
			Node(class_ID),
			sharedData(&shared_data)
				{}

		Receiver(
			PlugStream *stream,
			SharedData &shared_data
		):
			Node(stream),
			sharedData(&shared_data)
				{}

	//##########################################################################
	// Messaging Support
	//
	public:
		typedef Receiver__Message Message;
		typedef Receiver__DynamicMessage DynamicMessage;
		typedef Receiver__InheritanceSet InheritanceSet;
		typedef Receiver__HandlerEntry HandlerEntry;
		typedef Receiver__MessageHandlerSet MessageHandlerSet;
		typedef void (Receiver::*Handler)(const Message*);
		typedef Enumeration MessageID;

		enum {
			AnyMessageID=0,
			WatcherChangedMessageID,
			LoadResourceFinishedMessageID,
			NextMessageID
		};

		static const Handler NullHandler;

		void
			Receive(Message *What);

		virtual	void
			Dispatch(Message *What)
				{Receive(What);}

		void
			DefaultMessageHandler(Message*);

		typedef void (Receiver::*ScanCallback)(
			Receiver::Message *message,
			Receiver *receiver
		);

		MessageTap*
			MakeMessageTap(
				Derivation *derivation,
				ScanCallback callback
			);
		MessageTap*
			MakeMessageTap(
				Derivation *derivation,
				ScanCallback callback,
				Receiver::MessageID matching_message,
				Receiver *match_receiver
			);

	protected:
		static const HandlerEntry
			MessageHandlerEntries[];
		static MessageHandlerSet
			MessageHandlers;

	//##########################################################################
	// Event Support
	//
	public:
		virtual void
			Receive(Event *event);

		void
			FlushEvents(int max_priority=-1);
		void
			FlushMatchingEvents(
				MessageID target_message,
				int max_priority=-1
			);

		void
			ProcessDeferredQueue();

	//##########################################################################
	// Test Support
	//
	public:
		static Logical
			TestClass();
		Logical
			TestInstance() const;
	};

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

	class Receiver__Message
	{
	public:
		#if defined(USE_SIGNATURE)
			friend int
				Is_Signature_Bad(const volatile Receiver__Message *);
		#endif

		size_t
			messageLength;
		Receiver::MessageID
			messageID;

		enum {
			ReliableBit,
			NextBit
		};

		enum {
			ReliableFlag = 1 << ReliableBit
		};

		LWord
			messageFlags;

		Receiver__Message(
			Receiver::MessageID id,
			size_t message_length
		):
			messageID(id),
			messageLength(message_length),
			messageFlags(ReliableFlag)			// HACK
				{}

		Logical
			TestInstance() const;
	};

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

	class Receiver__DynamicMessage:
		public DynamicMemoryStream
	{
	public:
		Receiver__DynamicMessage()
			{}
		Receiver__DynamicMessage(
			void *stream_start,
			size_t stream_size,
			size_t initial_offset=0
		):
			DynamicMemoryStream(stream_start, stream_size, initial_offset)
				{}
		Receiver__DynamicMessage(
			Receiver::MessageID message_ID,
			size_t size = sizeof(Receiver::Message)
		);

		Receiver::Message*
			GetMessagePointer()
				{Check(this); return Cast_Object(Receiver::Message*, streamStart);}

	protected:
		MemoryStream&
			WriteBytes(
				const void *ptr,
				size_t number_of_bytes
			);
	};

	//##########################################################################
	//####################    ReceiverDataMessageOf    #########################
	//##########################################################################

	template <class T> class ReceiverDataMessageOf:
		public Receiver::Message
	{
	public:
		T
			dataContents;

		ReceiverDataMessageOf(
			Receiver::MessageID id,
			size_t message_length,
			const T& data
		):
			Receiver::Message(id, message_length),
			dataContents(data)
				{}
	};

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

	class MessageTap:
		public Plug
	{
	//##########################################################################
	// MessageTap Functionality
	//
	public:
		MessageTap(
			Derivation *derivation,
			Receiver *client,
			Receiver::ScanCallback callback
		);
		MessageTap(
			Derivation *derivation,
			Receiver *client,
			Receiver::ScanCallback callback,
			Receiver::MessageID matching_message,
			Receiver *match_receiver
		);

	private:
		Receiver::ScanCallback	scanCallback;
		Receiver*					clientReceiver;
		Receiver*					matchingReceiver;
		Receiver::MessageID		matchingMessageID;

	public:
		void
			Scan(
				Receiver *receiver,
				Receiver::Message *message
			);

	//##########################################################################
	// Memory Allocation
	//
	private:
		static MemoryBlock AllocatedMemory;

	public:
		void*
			operator new(size_t)
				{return AllocatedMemory.New();}
		void
			operator delete(void *where)
				{AllocatedMemory.Delete(where);}

	//##########################################################################
	// Test support
	//
	public:
		Logical
			TestInstance() const;
		static Logical
			TestClass();
	};

	//##########################################################################
	//##################    Receiver::InheritanceSet    ########################
	//##########################################################################
	//
	// NOTE: An InheritanceSet generated for a class should only be inherited by
	//       other classes derived from that base class.  If this is not done,
	//       SEVERE run-time weirdness will happen
	//
	class Receiver__InheritanceSet SIGNATURED
	{
	public:
		Logical
			TestInstance() const;
		Enumeration
			GetEntryCount()
				{Check(this); return entryCount;}

	protected:
		Enumeration
			entryCount;

		Receiver__InheritanceSet()
			{}
		~Receiver__InheritanceSet()
			{}
	};

	//##########################################################################
	//###################    Receiver::HandlerEntry    #########################
	//##########################################################################

	struct Receiver__HandlerEntry
	{
		Enumeration
			entryID;
		const char*
			entryName;
		Receiver::Handler
			entryHandler;
	};

	#define MESSAGE_ENTRY(class,message)\
		{\
			class::message##MessageID,\
			#message,\
			(Receiver::Handler)&class::message##MessageHandler\
		}

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

	class Receiver__MessageHandlerSet:
		public Receiver__InheritanceSet
	{
	//##########################################################################
	// Constructors and Destructors
	//
	public:
		Receiver__MessageHandlerSet(
			Receiver::MessageID count,
			const Receiver::HandlerEntry handler_table[],
			const Receiver::MessageHandlerSet &inheritance
		)
			{Build(count, handler_table, &inheritance);}
		Receiver__MessageHandlerSet(
			Receiver::MessageID count,
			const Receiver::HandlerEntry handler_table[]
		)
			{Build(count, handler_table, NULL);}
		Receiver__MessageHandlerSet()
			{messageHandlers = NULL; entryCount = 0;}
		~Receiver__MessageHandlerSet();

	protected:
		void
			Build(
				Receiver::MessageID count,
				const Receiver::HandlerEntry handler_table[],
				const Receiver::MessageHandlerSet *inheritance
			);

	//##########################################################################
	// HandlerSet Functionality
	//
	public:
		static const Receiver::MessageHandlerSet
			NullSet;

		Receiver::Handler
			Find(Receiver::MessageID message) const
				{
					Check(this);
					Verify(message > 0);
					return (message<=entryCount)
						? messageHandlers[message-1].entryHandler
						: Receiver::NullHandler;
				}
		const Receiver::HandlerEntry*
			Find(const char* name) const;

		const char *
			GetName(Receiver::MessageID message) const
				{
					Check(this);
					return (message<=entryCount)
						? messageHandlers[message-1].entryName
						: NULL;
				}

	protected:
		Receiver::HandlerEntry* messageHandlers;

	//##########################################################################
	// Test Support
	//
	public:
		static Logical
			TestClass();
	};

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

	class Derivation:
		public Node
	{
		friend class Receiver;

	//##########################################################################
	// Construction and Destruction
	//
	public:
		Derivation(char *who);
		Derivation(Derivation& parent,char *who);

		char *className;

	//##########################################################################
	// Messagetap support
	//
	private:
		Derivation(Derivation& copy);
		ChainOf<MessageTap*>
			activeTaps;

	public:
		void
			AppendMessageTap(MessageTap* tap);
		Logical
			IsDescendedFrom(Derivation& parent);
		Logical
			IsDescendedFrom(const char* parent);

	//##########################################################################
	// Inheritance Registration Support
	//
	private:
		ChainOf<Derivation*>
			classDerivations;

		void
			AppendDerivation(Derivation* child)
				{Check(this); classDerivations.Add(child);}

	//##########################################################################
	// Test Support
	//
	public:
		static Logical
			TestClass();
	};

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

	class Receiver__SharedData SIGNATURED
	{
	public:
		Receiver__SharedData(
			Derivation& derivation,
			Receiver::MessageHandlerSet &handler
		):
			derivedClasses(&derivation),
			activeMessageHandlers(&handler)
				{}

		Derivation
			*derivedClasses;
		Receiver::MessageHandlerSet
			*activeMessageHandlers;

		Logical
      	TestInstance() const;
	};

	inline Receiver::SharedData*
		Receiver::GetSharedData() const
			{Check(this); return Cast_Object(SharedData*,sharedData);}

	inline Derivation*
		Receiver::GetDerivation() const
			{Check(this); return GetSharedData()->derivedClasses;}

	inline Logical
		Receiver::IsDerivedFrom(Derivation& parent) const
			{return sharedData->derivedClasses->IsDescendedFrom(parent);}

	inline Logical
		Receiver::IsDerivedFrom(const char* parent) const
			{Check(this); return GetDerivation()->IsDescendedFrom(parent);}

	inline MessageTap*
		Receiver::MakeMessageTap(
			Derivation *derivation,
			ScanCallback callback
		)
			{Check(this); return new MessageTap(derivation, this, callback);}

	inline MessageTap*
		Receiver::MakeMessageTap(
			Derivation *derivation,
			ScanCallback callback,
			Receiver::MessageID matching_message,
			Receiver *match_receiver
		)
			{
				Check(this);
				return new MessageTap(
					derivation,
					this,
					callback,
					matching_message,
					match_receiver
				);
			}
#endif

