/* (c) 1999-2000 Tino Schwarze, see COPYING for details */
/**@pkg events.cEvent */
/**
 * an abstract event
 *
 * #include "cEvent.hh"
 *
 * This is an abstract base class for an event.
 *
 *@pkgdoc events.cEvent
 */
// now follows documentation for the event system
/**
 * Here are the packages which make up my event handling system.
 *
 * It is based on the Register/Dispatch Idiom as described in the
 * C++ Coding Standard.
 *
 * Although it is pretty simple, it is very powerful. The center of the
 * event system is an event dispatcher. It does not need to be a centralized
 * solution but can be distributed as well (several event dispatchers
 * connected via appropiate routing protocols). The best of it is, that
 * one can later derive from cEventDispatcher to implement more 
 * sophisticated methods of event routing. The current implementation only
 * passes events withing the same program.
 *
 * To make the system work, event consumers subscribe for specified events
 * at the event dispatcher. Event producers send their events to the
 * event dispatcher which in turn figures out which consumer is interested
 * in that particular event. It then calls every subscriber at first come -
 * first serve basis and passes the event to the subscriber. The
 * subscriber may or may not accept the event. If it was not accepted,
 * it is passed to the next subscriber, else it is considered to have
 * been delivered successfully.
 *
 * That's all.
 *
 *@pkgdoc events
 */

#ifndef cEvent_hh
#define cEvent_hh

// aquire STL strings
#include <string>

// forward declaration
class cStorableEvent;

/**
 * an event class
 	*
 	*/
class cEvent
{
	friend ostream& operator << (ostream &os, const cEvent &ev);

//LIFETIME
public:
	/**
	 * default constructor
	 	* @param type const string reference to type/name of event
		* The type is used to identify an event.
	 	*/
	cEvent (const string &type = "cEvent");

	/**
	 * default destructor
	 	*/
	virtual ~cEvent ();

	/**
	 * clone this object (allocate a new one)
		*/
	virtual cEvent *Clone () const
	{
		return new cEvent(mName);
	}

	/**
	 * operator == for cEvents - it returns true if they're of the
	 * same type(name)
		*/
	const bool operator == (const cEvent &e) const
	{
		return (mName == e.mName);
	}

	/**
	 * operator < for cEvents - it compares the name strings
		*/
	const bool operator < (const cEvent &e) const
	{
		return (mName < e.mName);
	}

	virtual const string &GetName () const
	{
		return mName;
	}

protected:
	string mName;
};

/**
 * a class which provides a way to store cEvent objects and derived
 * objects
 */
class cStorableEvent
{
	/**
	 * mainly for debugging purposes: a way to output an event
	 */
	friend ostream &operator << (ostream &, const cStorableEvent &);

//LIFETIME
public:
	/**
	 * default constructor - gets the event to store
	 	*
	 	* (Note: It does not store the event provided but a clone of it,
	 	* therefore cEvent::Clone() is called.)
		* @param e const reference to cEvent object to store
	 	*/
	cStorableEvent (const cEvent &e)
	{
		mEvent = e.Clone ();
	};

	/**
	 * the copy constructor
	 	*
		* This is important as we have a dynamically allocated member.
		*
	 	* @param const reference to cStorableEvent to copy
		*/
	cStorableEvent (const cStorableEvent &cse)
	{
		mEvent = cse.mEvent->Clone ();
	}

	/**
	 * destructor
	 	*/
	~cStorableEvent ()
	{
		delete mEvent;
	};

	/**
	 * operator for casting to cEvent
	 	* @return const reference to cEvent
		*/
	operator const cEvent &()
	{
		return *mEvent;
	}

	/**
	 * operator == to compare cStorableEvents
	 	*
	 	* This is just delegated to the stored cEvents.
		*
		* @param se const reference to cStorableEvent to compare with
		* @return true if the stored event's types match
		*/
	const bool operator == (const cStorableEvent &se) const
	{
		return ((*mEvent) == (*se.mEvent));
	};

	/**
	 * operator < to compare cStorableEvents
	 	*
	 	* This is just delegated to the stored cEvents.
		*
		* This operator is a bit odd but needed by STL to store
		* cStorableEvents in Sorted Containers.
		*
		* @param se const reference to cStorableEvent to compare with
		* @return true if this event's type is lower than se's type in
		* terms of string comparison
		*/
	const bool operator < (const cStorableEvent &se) const
	{
		return ((*mEvent) < (*se.mEvent));
	};

	/**
	 * operator == for comparing cStorableEvents with cEvents
	 	*/
	const bool operator == (const cEvent &e) const
	{
		return ((*mEvent) == e);
	};

	/**
	 * operator < for comparing cStorableEvents with cEvents
	 	*/
	const bool operator < (const cEvent &e) const
	{
		return ((*mEvent) < e);
	};

	/**
	 * return name/type of event
	 	* @return const reference to string with name/type of event
	 	*/
	const string &GetName () const
	{
		return mEvent->GetName ();
	}

private:
	/**
	 * The cEvent object which is stored by cStorableEvent
	 	*/
	cEvent *mEvent;
};

#endif	// ifndef cEvent_hh
