//===========================================================================//
// 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                         //
//===========================================================================//

#pragma once

#include "Adept.hpp"
#include "Receiver.hpp"

namespace Adept {

	class GeneralEventQueue;
	class EventQueue;
	class Entity;
	class EventTrace;
	class Connection;
	class InBox;

	enum EventPriorities
	{
		MinEventPriority = 0,
		LowEventPriority,
		DefaultEventPriority,
		HighEventPriority,
		MaxEventPriority,
		EventPrioritiesCount
	};

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

	class AbstractEvent:
		public Stuff::Plug
	{
		friend class GeneralEventQueue;
		friend class EventQueue;
		friend class EventStatisticsManager;

	//##########################################################################
	// Event Functionality
	//
	protected:
		AbstractEvent(
			ClassData *class_data,
			const Receiver::Message *message,
			Stuff::Time time
		);

	public:
		~AbstractEvent();

		virtual void
			Process();
		virtual void
			DumpData();

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

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

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

		static void
			InitializeClass(
				size_t block_count = 20,
				size_t block_delta = 10
			);
		static void
			TerminateClass();

		void
			TestInstance();

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

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


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

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// Class Data Support
	//
	public:
		static ClassData
			*DefaultData;

	public:
		void
			Repost(
				EventQueue *queue,
				Stuff::Time new_time=-1.0
			);

		void
			Process();
		void
			DumpData();

	private:
		Stuff::SlotOf<Receiver*>		targetReceiver;
	};

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

	class NetworkEvent:
		public AbstractEvent
	{
		friend class GeneralEventQueue;

	public:
		static void
			InitializeClass();
		static void
			TerminateClass();

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

		NetworkEvent(
			Connection *connection,
			InBox *box,
			EventStyle event_style,
			const Receiver::Message *message,
			Stuff::Time time
		);
		~NetworkEvent();

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// Class Data Support
	//
	public:
		static ClassData
			*DefaultData;

	public:
		void
			Process();

		void
			TestInstance();

	private:
		InBox
			*eventBox;
		Connection
			*eventConnection;
		EventStyle
			eventStyle;
	};

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

	public:
		static void
			InitializeClass();
		static void
			TerminateClass();

	//##########################################################################
	// EventQueue Allocation
	//
	public:
		GeneralEventQueue(ClassData *class_data = DefaultData);
		~GeneralEventQueue();

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

		void
			TestInstance();

		static GeneralEventQueue
			*Instance;

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// Class Data Support
	//
	public:
		static ClassData
			*DefaultData;

	protected:
		int
			priorityLevels;
		Stuff::ChainOf<AbstractEvent*>
			pendingEvents;
		Stuff::ChainOf<AbstractEvent*>
			timedEvents;
		int
			eventCount;

	//##########################################################################
	// EventQueue Functionality
	//
	public:
		AbstractEvent*
			Post(
				Receiver *target,
				const Receiver::Message *message,
				Stuff::Time when=-1.0
			);
		AbstractEvent*
			SendEvent(
				Connection *connection,
				InBox *box,
				const Receiver::Message *message,
				Stuff::Time when=-1.0
			);
		AbstractEvent*
			BroadcastEvent(
				InBox *box,
				const Receiver::Message *message,
				Stuff::Time when=-1.0
			);
		AbstractEvent*
			ExclusiveBroadcastEvent(
				InBox *box,
				const Receiver::Message *message,
				Stuff::Time when=-1.0
			);
		int
			GetEventCount()
				{return eventCount;}

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

		bool
			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(AbstractEvent *event);

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

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

	class EventQueue:
		public GeneralEventQueue
	{
		friend class Event;

	public:
		static void
			InitializeClass();
		static void
			TerminateClass();

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

		void
			TestInstance();

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// Class Data Support
	//
	public:
		static ClassData
			*DefaultData;

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

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

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

}


