//===========================================================================//
// File:	event.hh                                                            //
// Project: MUNGA           Brick: Event Manager                             //
// Contents: interface specification of event manager                        //
//---------------------------------------------------------------------------//
//   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                           //
//---------------------------------------------------------------------------//
// Copyright (C) 1994-1995, Virtual World Entertainment, Inc.                //
//                      PROPRIETARY AND CONFIDENTIAL                         //
//===========================================================================//

#if !defined(EVENT_HPP)
#	define EVENT_HPP

#	if !defined(TIME_HPP)
#		include <time.hpp>
#	endif

#	if !defined(SLOT_HPP)
#		include <slot.hpp>
#	endif

#	if !defined(NETWORK_HPP)
#		include <network.hpp>
#	endif

	class GeneralEventQueue;
	class EventQueue;
	class DeferredEventQueue;
	class Entity;

	//##########################################################################
	//########################    AbstractEvent    #############################
	//##########################################################################

	class AbstractEvent:
		public Node
	{
		friend class GeneralEventQueue;
		friend class EventStatisticsManager;

	//##########################################################################
	// Event Functionality
	//
	protected:
		AbstractEvent(
			Receiver::Message *message,
			Time time,
			ClassID class_id
		);
		~AbstractEvent();

	public:
		virtual void
			Process();
		virtual void
			DumpData();

	protected:
		Time						alarmTime;
		Receiver::Message*	messageToSend;
	};

	//##########################################################################
	//############################    Event    #################################
	//##########################################################################

	class Event:
		public AbstractEvent
	{
		friend class GeneralEventQueue;
      friend class EventQueue;
		friend class Receiver;
		friend class DeferredEventQueue;
      friend class Entity;
		friend class EventStatisticsManager;

	//##########################################################################
	// Node Support
	//
	private:
		void
			ReleaseLinkHandler(
				Socket *socket,
				Plug *plug
			);

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

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


	//##########################################################################
	// Event Functionality
	//
	private:
		Event(
			Receiver *target,
			Receiver::Message *message,
			Time time
		);
		~Event();

	public:
		void
			Repost(
				EventQueue *queue,
				int priority,
				Time new_time=Time::Null
			);

		void
			Defer();

		void
			Process();
		void
			DumpData();

	private:
		SlotOf<Receiver*>		targetReceiver;
	};

	//##########################################################################
	//########################    NetworkEvent    ##############################
	//##########################################################################

	class NetworkEvent:
		public AbstractEvent
	{
		friend class GeneralEventQueue;

	//##########################################################################
	// Event Functionality
	//
	private:
		enum EventStyle
		{
			SendStyle,
			BroadcastStyle,
			ExclusiveBroadcastStyle
		};

		NetworkEvent(
			HostID hostID,
			NetworkManager::ClientID client_ID,
			EventStyle event_style,
			Receiver::Message *message,
			Time time
		);
		~NetworkEvent();

	public:
		void
			Process();

	private:
		HostID
			hostID;
		NetworkManager::ClientID
			clientID;
		EventStyle
			eventStyle;
	};

	//##########################################################################
	//####################    GeneralEventQueue    ############################
	//##########################################################################
	//
	// NOTE: Do not create any static event queues!  new must be used to allocate
	//       all event queue objects
	//
	class GeneralEventQueue:
		public Node
	{
		friend class Event;

	//##########################################################################
	// EventQueue Allocation
	//
	public:
		GeneralEventQueue(ClassID class_ID);
		GeneralEventQueue();
		~GeneralEventQueue();

		static GeneralEventQueue*
			Make(
				int priorities,
				const char* trace_name=NULL
			);

	protected:
		int
			priorityLevels;
		ChainOf<AbstractEvent*>
			pendingEvents;
		ChainOf<AbstractEvent*>
			timedEvents;
		int
			eventCount;
		#if defined(TRACE_EVENT_COUNT)
			TraceOf<int>
				*eventCountTrace;
		#endif

	//##########################################################################
	// EventQueue Functionality
	//
	public:
		void
			Post(
				int priority,
				Receiver *target,
				Receiver::Message *message,
				Time when=Time::Null
			);
		void
			SendEvent(
				int priority,
				HostID host_ID,
				NetworkManager::ClientID client_id,
				Receiver::Message *message,
				Time when=Time::Null
			);
		void
			BroadcastEvent(
				int priority,
				NetworkManager::ClientID client_id,
				Receiver::Message *message,
				Time when=Time::Null
			);
		void
			ExclusiveBroadcastEvent(
				int priority,
				NetworkManager::ClientID client_id,
				Receiver::Message *message,
				Time when=Time::Null
			);
		int
			GetEventCount()
				{return eventCount;}

		AbstractEvent*
			PeekAtNextEvent(int min_priority=0);
		Logical
			IsPriorityEmpty(int priority);

		Logical
			ProcessOneEvent(int min_priority=0);
		void
			ProcessAllEvents(int min_priority=0);

		void
			FlushAllEvents(int max_priority=-1);
		void
			FlushMatchingEvents(
				Receiver::MessageID target_message,
				int max_priority=-1
			);

		void
			Enqueue(
				int priority,
				AbstractEvent *event
			);

	//##########################################################################
	// Testing Support
	//
	public:
		void
			DumpEventQueue();
	};

	//##########################################################################
	//#########################    EventQueue    ###############################
	//##########################################################################

	class EventQueue:
		public GeneralEventQueue
	{
	//##########################################################################
	// EventQueue Allocation
	//
	public:
		EventQueue();
		static EventQueue*
			Make(
				int priorities,
            const char* trace_name=NULL
			);
		~EventQueue();

	//##########################################################################
	// EventQueue Posting & Processing
	//
	public:
		Event*
			PeekAtNextEvent(int min_priority=0)
				{
					return
						(Event*)GeneralEventQueue::PeekAtNextEvent(min_priority);
				}

		void
			ProcessMatchingEvents(
				Receiver *receiver,
				Receiver::MessageID message_ID=Receiver::AnyMessageID
			);

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

	//##########################################################################
	//#####################    DeferredEventQueue    ###########################
	//##########################################################################
	//
	// NOTE: Do not create any static event queues!  new must be used to allocate
	//       all event queue objects
	//
	class DeferredEventQueue:
		public Node
	{
		friend class Event;

	//##########################################################################
	// Node Support
	//
	private:
		void
			ReleaseLinkHandler(
				Socket *socket,
				Plug *plug
			);

	//##########################################################################
	// Deferred Queue Functionality
	//
	public:
		DeferredEventQueue(Receiver *target);
		~DeferredEventQueue();

		void
			ProcessAllEvents()
				{Check(this); deferredEvents->ProcessAllEvents();}

	private:
		EventQueue
			*deferredEvents;
		SlotOf<Receiver*>
			waitingReceiver;
	};

#endif

