/*	Author: Magdin Stoica
	Supervisor: Dr. Ryan Leduc
	
	Project created in conformity with the requirements for the Degree of Master of Engineering in Software Engineering, 
	Computing and Software Department, 
	McMaster University
	2003 - 2007
*/

#pragma once

#include <vector>
#include <memory>
#include "CommonDefinitions.h"
#include "DesEvent.h"

namespace DESpot
{
	class DesEventIterator;

	class EventPool
	{
		//Types
		public:
			typedef std::auto_ptr<DesEventIterator> EventIteratorPtr;
	
		public:
			EventPool(void);
			~EventPool(void);

		//Event access
		public:
			//Returns a event that must exist in the pool. Throws exception if the eventId is not found in the pool
			DesEvent* getEvent(const DesEvent::ID& eventId) const;
			
			//Attempts to find an event with the given ID
			bool findEvent(const DesEvent::ID& eventId, DesEvent** ppFoundEvent = null) const;

			//Attempts to find an event with the given name
			bool findEvent(const std::wstring& eventName, DesEvent** ppFoundEvent = null) const;

			//Attempts to find an event 
			bool findEvent(const DesEvent& event, DesEvent** ppFoundEvent = null) const;

		//Pool operations
		public:
			//Adds a new event to the pool with the properties of the event template. A new ID will be assigned to the new
			//event (not that one in the template even if has any)
			const DesEvent& addNewEvent(const DesEvent& eventTemplate);
			
			//Adds the given event as is. The ID is preserved but it is required not to be used by any existing even in the pool
			void addEvent(DesEvent* pEventToAdd);

			//Change an event from the pool. Returns true when the change is done and false if no change
			//was necessary. In case a change was applied it returns the event that was changed in the out parameter
			//if it was requested by teh caller
			bool changeEvent(const DesEvent::ID& eventId, const DesEvent& newEvent, const DesEvent** out_event = null);
			bool changeEventName(const DesEvent::ID& eventId, const std::wstring& newName, const DesEvent** out_event = null);
			bool changeEventAlias(const DesEvent::ID& eventId, const std::wstring& newAlias, const DesEvent** out_event = null);
			bool changeEventType(const DesEvent::ID& eventId, EventType newType, const DesEvent** out_event = null);
			bool changeEventCtrl(const DesEvent::ID& eventId, bool isControllable, const DesEvent** out_event = null);

			//Removes the event with given ID from the pool. It doesn't detroy the event
			DesEvent* removeEvent(DesEvent::ID eventId);

			//Removes the given event from the pool. It doesn't detroy the event
			void removeEvent(DesEvent* pEventToRemove);

			//deletes all the events, reverting the event pool back to initial state after construction
			void clear();

			//Returns the number of events in the pool
			DesEvent::Count getEventCount() const;
			DesEvent::Count getEventCountByCtrl(bool isControllable) const;
			DesEvent::Count getEventCountByType(EventType type) const;

			//Iterator
			DesEventIterator* createIterator() const;

			//returns the last used event ID 
			DesEvent::ID getLastUsedId() const;

		//Implementation types
		private:
			typedef std::vector<DesEvent*> EventPoolSet;
			typedef EventPoolSet::const_iterator EventIterator;

		//Implementations methods
		private:
			//Returns an unused ID to be used for a new event before being added to the pool. Once this is called
			//the returned ID will not be used again so it is important to only call this when adding a new event to
			//be used within the automaton
			DesEvent::ID reserveNewEventID();

			DesEvent::Count& getEventTypeCounter(EventType type);
			const DesEvent::Count& getEventTypeCounter(EventType type) const;
		//Data
		private:
			//The set of events in the pool. Note that the set may contain null events that occurred when events were removed from the pool
			EventPoolSet m_eventPool;
			
			//The number of events in the pool. Note that we cannot rely on the size of the pool set as the set
			//may contains nulls
			DesEvent::Count m_eventCount;
			DesEvent::Count m_eventCtrlCount;
			DesEvent::Count m_eventDefCount;
			DesEvent::Count m_eventReqCount;
			DesEvent::Count m_eventAnsCount;
			DesEvent::Count m_eventLdCount;

			//Event ID management
			DesEvent::Index m_nextFreeID;
	};

} //end of namespace DESpot
