/**
 * @file TestProtocol.h
 * @date Jul 16, 2008
 * @author Ronald Kluth
 *
 * @brief Contains all helper classes required for testing ODEMx module \b %Protocol.
 */

#ifndef TESTPROTOCOL_H_
#define TESTPROTOCOL_H_

#include <UnitTest++.h>
#include "../Main/Globals.h"

#include <odemx/data/SimRecordFilter.h>

#include <odemx/protocol/Device.h>
#include <odemx/protocol/Entity.h>
#include <odemx/protocol/ErrorModel.h>
#include <odemx/protocol/ErrorModelDraw.h>
#include <odemx/protocol/Layer.h>
#include <odemx/protocol/Medium.h>
#include <odemx/protocol/Pdu.h>
#include <odemx/protocol/Sap.h>
#include <odemx/protocol/Service.h>
#include <odemx/protocol/ServiceProvider.h>
#include <odemx/protocol/Stack.h>

/**
 * @namespace Protocol
 *
 * @brief Contains helpers and tests for module ODEMx %Protocol
 *
 * The UnitTest++ macro SUITE( Protocol ) declares namespace Protocol.
 * Consequently, all helpers for this test suite should be placed in
 * the same namespace.
 */

namespace SuiteProtocol {

	using namespace odemx;
	using namespace odemx::protocol;

	struct PduTest: public Pdu
	{
		PduTest() {}
		PduTest( int value ): value( value ) {}

		virtual std::size_t getSize() const
		{
			return 100;
		}
		virtual PduPtr clone() const
		{
			return PduPtr( new PduTest( value ) );
		}
		int value;
	};

	struct ServiceProviderTest: public ServiceProvider
	{
		ServiceProviderTest( base::Simulation& sim, const data::Label& label )
		:	ServiceProvider( sim, label )
		,	handledInput( false )
		{}

		virtual void handleInput( const std::string& sap, odemx::protocol::PduPtr )
		{
			inputSap = sap;
			handledInput = true;
		}

		bool handledInput;
		std::string inputSap;
	};

	struct ServiceTest: public Service
	{
		ServiceTest( base::Simulation& sim, const data::Label& label )
		:	Service( sim, label )
		,	handledSend( false )
		,	handledReceive( false )
		{}

		virtual void handleSend( const std::string& sap, odemx::protocol::PduPtr )
		{
			inputSap = sap;
			handledSend = true;
		}
		virtual void handleReceive( PduPtr )
		{
			handledReceive = true;
		}
		using Service::receive;

		bool handledSend, handledReceive;
		std::string inputSap;
	};

	struct ErrorModelTestSuccess: public ErrorModel
	{
		static ErrorModelPtr create()
		{
			return ErrorModelPtr( new ErrorModelTestSuccess() );
		}
		virtual bool apply( PduPtr )
		{
			return true;
		}
	};

	struct ErrorModelTestFailure: public ErrorModel
	{
		static ErrorModelPtr create()
		{
			return ErrorModelPtr( new ErrorModelTestFailure() );
		}
		virtual bool apply( PduPtr )
		{
			return false;
		}
	};

	struct MediumTest: public Medium
	{
		MediumTest( base::Simulation& sim, const data::Label& label )
		:	Medium( sim, label )
		{}

		typedef Medium::LinkInfo LinkInfo;
		typedef Medium::TransmissionStart TransmissionStart;
		typedef Medium::TransmissionEnd TransmissionEnd;
	};

	struct EntityTest: public Entity
	{
		EntityTest( base::Simulation& sim, const data::Label& label )
		:	Entity( sim, label )
		,	handledInput( false )
		{}

		virtual void handleInput( const std::string& sap, odemx::protocol::PduPtr )
		{
			inputSap = sap;
			handledInput = true;
		}

		bool handledInput;
		std::string inputSap;
	};

	struct DeviceTest: public Device
	{
		using Device::send;
		using Device::pass;
		using Device::startTransmission;
		using Device::endTransmission;

		DeviceTest( base::Simulation& sim, const data::Label& label )
		:	Device( sim, label )
		,	handledSend( false )
		,	handledReceive( false )
		,	doSend( false )
		{}

		virtual void handleSend( const std::string& sap, PduPtr p )
		{
			inputSap = sap;
			handledSend = true;
			if( doSend )
			{
				send( p );
			}
		}
		virtual void handleReceive( PduPtr p )
		{
			receivedPdu = std::tr1::static_pointer_cast< PduTest >( p );
			handledReceive = true;
		}
		virtual base::SimTime computeTransmissionDuration( std::size_t pduSize )
		{
			return static_cast< base::SimTime >( pduSize );
		}
		virtual bool hasCollisionDetection()
		{
			return true;
		}
		bool handledSend, handledReceive;
		std::string inputSap;
		std::tr1::shared_ptr< PduTest > receivedPdu;
		bool doSend;
	};

//	/********************* NETTOPOLOGY ****************************************/
//
//	/**
//	 * @class NetTopologyTest
//	 * @brief Helper class to test NetTopology, implements getTrace()
//	 */
//	class NetTopologyTest:
//		public NetTopology,
//		public DefLabeledObject
//	{
//	public:
//		/// Constructor
//		NetTopologyTest( ProtocolSimulation* s, Label l, NetTopologyObserver* o )
//		:	NetTopology( s, o ),
//			DefLabeledObject( s, l )
//		{}
//		/// required implementation of pure virtual function
//		virtual Trace* getTrace() const { return getSimulation(); }
//	};
//
//	/**
//	 * @class NetTopologyTestObserver
//	 * @brief Implements NetTopologyObserver to validate execution of
//	 * NetTopology methods
//	 */
//	class NetTopologyTestObserver:
//		public NetTopologyObserver,
//		public ObserverBase
//	{
//	public:
//		/**
//		 * @brief Constructor
//		 * @param output determines whether Observations are sent to stdout
//		 */
//		NetTopologyTestObserver( bool output ):
//			ObserverBase( output )
//			{}
//
//		/**
//		 * @name Implementation of virtual Observer functions
//		 *
//		 * Most ODEMx classes define an Observer interface with empty
//		 * implementation. These virtual functions are re-implemented here in
//		 * order to observe the behavior of test objects. All of them call
//		 * ObserverBase::saw() to store events with parameters in the
//		 * observation history which can then be used to verify expected
//		 * behavior of objects.
//		 *
//		 * @{
//		 */
//		virtual void onRegisterNode( NetTopology* sender, ProtocolStack* n, double x, double y )
//		{ ObserverBase::saw( "onRegisterNode", sender, n->getLabel(), "("+toString(x)+", "+toString(y)+")" ); }
//		virtual void onRemoveNode( NetTopology* sender, ProtocolStack* n )
//		{ ObserverBase::saw( "onRemoveNode", sender, n ); }
//		virtual void onMakeLink( NetTopology* sender, ProtocolStack* n1, ProtocolStack* n2, double p )
//		{ ObserverBase::saw( "onMakeLink", sender, n1->getLabel() + "->" + n2->getLabel(), toString( p ) ); }
//		virtual void onChangeLink( NetTopology* sender, ProtocolStack* n1, ProtocolStack* n2, double p )
//		{ ObserverBase::saw( "onChangeLink", sender, n1->getLabel() + "->" + n2->getLabel(), toString( p ) ); }
//		virtual void onRemoveLink( NetTopology* sender, ProtocolStack* n1, ProtocolStack* n2 )
//		{ ObserverBase::saw( "onRemoveLink", sender, n1->getLabel(), n2->getLabel() ); }
//		//@}
//	};
//
//	/*************************** PROTOCOL MESSAGE *****************************/
//
//	/**
//	 * @class ProtocolMessageTest
//	 * @brief Helper class to test interface ProtcolMessage and various other
//	 * classes
//	 */
//	class ProtocolMessageTest:
//		public odemx::ProtocolMessage
//	{
//	public:
//		std::string content; ///< message content as string
//		odemx::ProtocolStack* sender; ///< the origin of the message
//		odemx::ProtocolStack* receiver; ///< the destination of the message
//		SimTime duration; ///< the time it takes to send the message
//
//		/// Constructor
//		ProtocolMessageTest( std::string s, odemx::ProtocolStack* from,
//							 odemx::ProtocolStack* to, SimTime duration )
//		:	content( s ),
//			sender( from ),
//			receiver( to ),
//			duration( duration )
//			{}
//
//		/// Destructor
//		virtual ~ProtocolMessageTest() {}
//
//		/**
//		 * @name Simple implementations of pure virtual functions
//		 * @{
//		 */
//		virtual bool isUnicast() const
//			{ return receiver != 0; }
//		virtual odemx::ProtocolStack* getSource() const
//			{ return sender; }
//		virtual odemx::ProtocolStack* getDestination() const
//			{ return receiver; }
//		virtual odemx::ProtocolStack* getSendNode() const
//			{ return sender; }
//		virtual odemx::ProtocolStack* getReceiveNode() const
//			{ return receiver; }
//		virtual odemx::SimTime getTransmissionDuration() const
//			{ return duration; }
//		virtual ProtocolMessageTest* deepCopy()
//			{ return new ProtocolMessageTest( *this ); }
//		virtual std::string toString()
//		{
//			ostringstream stream;
//			stream << "Message '" << content
//				   << "' from " << sender->getLabel()
//				   << " to " << (receiver ? receiver->getLabel() : "ALL" );
//			return stream.str();
//		}
//		//@}
//	};
//
//	/**************************** PROTOCOL ENTITY *****************************/
//
//	/**
//	 * @class ProtocolEntityTestData
//	 * @brief Used as simple port data object in ProtocolEntity tests
//	 */
//	class ProtocolEntityTestData:
//		public PortData
//	{
//	public:
//		std::string contents; ///< the data as string
//
//		/// Constructor
//		ProtocolEntityTestData( const std::string& str )
//		:	contents( str )
//		{}
//
//		/// allows to test PortData* with string comparison
//		std::string toString() { return contents; }
//	};
//
//	/**
//	 * @class ProtocolEntityTest
//	 * @brief Subclass that implements pure virtual functions for testing
//	 * ProtocolEntity methods
//	 */
//	class ProtocolEntityTest:
//		public odemx::ProtocolEntity
//	{
//	public:
//		bool handledTopInput; ///< monitors if top layer input was handled
//		bool handledBottomInput; ///< monitors if bottom layer input was handled
//
//		/// Constructor
//		ProtocolEntityTest( ProtocolSimulation* s, ProtocolLayer* layer,
//				ProtocolStack* owner, ProtocolEntityObserver* o = 0 )
//		:	ProtocolEntity( s, layer, owner, o ),
//			handledTopInput( false ),
//			handledBottomInput( false )
//			{}
//
//		/// required implementation of pure virtual function
//		virtual void handleUpperLayerInput( PortData* topInput )
//		{
//			handledTopInput = true;
//		}
//		/// required implementation of pure virtual function
//		virtual void handleLowerLayerInput( PortData* bottomInput )
//		{
//			handledBottomInput = true;
//		}
//		/// put data into the entity's top port
//		void putTop( ProtocolEntityTestData* d )
//		{
//			ProtocolEntity::putTop( d );
//		}
//		/// put data into the entity's bottom port
//		void putBottom( ProtocolEntityTestData* d )
//		{
//			ProtocolEntity::putBottom( d );
//		}
//	};
//
//	/**
//	 * @class ProtocolEntityTestObserver
//	 * @brief Implements ProtocolEntityObserver to validate execution of
//	 * ProtocolEntity methods
//	 */
//	class ProtocolEntityTestObserver:
//		public ObserverBase,
//		public ProtocolEntityObserver
//	{
//	public:
//		/**
//		 * @brief Constructor
//		 * @param output determines whether Observations are sent to stdout
//		 */
//		ProtocolEntityTestObserver( bool output ):
//			ObserverBase( output )
//			{}
//
//		/**
//		 * @name Implementation of virtual Observer functions
//		 *
//		 * Most ODEMx classes define an Observer interface with empty
//		 * implementation. These virtual functions are re-implemented here in
//		 * order to observe the behavior of test objects. All of them call
//		 * ObserverBase::saw() to store events with parameters in the
//		 * observation history which can then be used to verify expected
//		 * behavior of objects.
//		 *
//		 * @{
//		 */
//		/// relevant re-implementation of ProcessObserver interface
//		virtual void onWait(Process* sender, MemoryVector* memvec)
//		{
//			ostringstream memos;
//			for( MemoryVector::iterator i = memvec->begin(); i != memvec->end(); ++i )
//			{
//				if( i != memvec->begin() ) memos << "+";
//				memos << (*i)->getLabel();
//			}
//			ObserverBase::saw( "onWait", sender, memos.str() );
//		}
//		virtual void onReadTop( ProtocolEntity* sender, PortData* e )
//		{ ObserverBase::saw( "onReadTop", sender, (dynamic_cast< ProtocolEntityTestData* >( e ))->toString() ); }
//		virtual void onReadBottom( ProtocolEntity* sender, PortData* e )
//		{ ObserverBase::saw( "onReadBottom", sender, (dynamic_cast< ProtocolEntityTestData* >( e ))->toString() ); }
//		virtual void onTransmit( ProtocolEntity* sender, PortData* e )
//		{ ObserverBase::saw( "onTransmit", sender, (dynamic_cast< ProtocolEntityTestData* >( e ))->toString() ); }
//		virtual void onPassUpward( ProtocolEntity* sender, PortData* e )
//		{ ObserverBase::saw( "onPassUpward", sender, (dynamic_cast< ProtocolEntityTestData* >( e ))->toString() ); }
//		//@}
//	};
//
//	/*************************** PROTOCOL LAYER *******************************/
//
//	/**
//	 * @class ProtocolLayerTestObserver
//	 * @brief Implements ProtocolLayerObserver to validate execution of
//	 * ProtocolLayer methods
//	 */
//	class ProtocolLayerTestObserver:
//		public ProtocolLayerObserver,
//		public ObserverBase
//	{
//	public:
//		/**
//		 * @brief Constructor
//		 * @param output determines whether Observations are sent to stdout
//		 */
//		ProtocolLayerTestObserver( bool output ):
//			ObserverBase( output )
//			{}
//
//		/**
//		 * @name Implementation of virtual Observer functions
//		 *
//		 * Most ODEMx classes define an Observer interface with empty
//		 * implementation. These virtual functions are re-implemented here in
//		 * order to observe the behavior of test objects. All of them call
//		 * ObserverBase::saw() to store events with parameters in the
//		 * observation history which can then be used to verify expected
//		 * behavior of objects.
//		 *
//		 * @{
//		 */
//		virtual void onCreate( ProtocolLayer* sender ) { ObserverBase::saw( "onCreate", sender ); }
//		virtual void onDestroy( ProtocolLayer* sender ) { ObserverBase::saw( "onDestroy", sender ); }
//		virtual void onAddEntity( ProtocolLayer* sender, ProtocolEntity* e ) { ObserverBase::saw( "onAddEntity", sender ); }
//		virtual void onRemoveEntity( ProtocolLayer* sender, ProtocolEntity* e ) { ObserverBase::saw( "onRemoveEntity", sender ); }
//		//@}
//	};
//
//	/**************************** PROTOCOL STACK ******************************/
//
//	/**
//	 * @class ProtocolStackTest
//	 * @brief Subclass that implements a pure virtual function for testing
//	 * ProtocolEntity methods
//	 */
//	class ProtocolStackTest:
//		public ProtocolStack
//	{
//	public:
//		bool receivedDataFromTopEntity; ///< monitors whether new data has been received
//		PortData* receivedMessage; ///< pointer to the last received message
//
//		/// Constructor
//		ProtocolStackTest( ProtocolSimulation* s, Label l, ProtocolStackObserver* o = 0 )
//		:	ProtocolStack( s, l, o ),
//		receivedDataFromTopEntity( false ),
//		receivedMessage( 0 )
//		{}
//
//		/// required implementation of pure virtual function
//		virtual void receivedData( PortData* msg )
//		{
//			receivedDataFromTopEntity = true;
//			receivedMessage = msg;
//		};
//	};
//
//	/**
//	 * @class ProtocolStackTestObserver
//	 * @brief Implements ProtocolStackObserver to validate execution of
//	 * ProtocolStack methods
//	 */
//	class ProtocolStackTestObserver:
//		public ProtocolStackObserver,
//		public ObserverBase
//	{
//	public:
//		/**
//		 * @brief Constructor
//		 * @param output determines whether Observations are sent to stdout
//		 */
//		ProtocolStackTestObserver( bool output ):
//			ObserverBase( output )
//			{}
//
//		/**
//		 * @name Implementation of virtual Observer functions
//		 *
//		 * Most ODEMx classes define an Observer interface with empty
//		 * implementation. These virtual functions are re-implemented here in
//		 * order to observe the behavior of test objects. All of them call
//		 * ObserverBase::saw() to store events with parameters in the
//		 * observation history which can then be used to verify expected
//		 * behavior of objects.
//		 *
//		 * @{
//		 */
//		virtual void onCreate( ProtocolStack* sender )
//		{ ObserverBase::saw( "onCreate", sender ); }
//		virtual void onDestroy( ProtocolStack* sender )
//		{ ObserverBase::saw( "onDestroy", sender ); }
//		virtual void onInputData( ProtocolStack* sender, PortData* message )
//		{ ObserverBase::saw( "onInputData", sender, ( dynamic_cast< ProtocolEntityTestData* >( message ) )->toString() ); }
//		virtual void onReceivedData( ProtocolStack* sender, PortData* message )
//		{ ObserverBase::saw( "onReceivedData", sender, ( dynamic_cast< ProtocolEntityTestData* >( message ) )->toString() ); }
//		virtual void onReceiveTransmission( ProtocolStack* sender, ProtocolMessage* message )
//		{ ObserverBase::saw( "onReceiveTransmission", sender, message->toString() ); }
//		//@}
//	};
//
//	/************************** TRANSMISSION MEDIUM ***************************/
//
//	/**
//	 * @class TransmissionMediumTest
//	 * @brief Simplified transmission medium to be used as helper for testing
//	 * other protocol classes
//	 */
//	class TransmissionMediumTest:
//		public TransmissionMedium
//	{
//	public:
//		bool transmitCalled; ///< monitors whether transmit() was called
//
//		/// Constructor
//		TransmissionMediumTest( ProtocolSimulation* s, Label l, TransmissionMediumObserver* o = 0 )
//		:	TransmissionMedium( s, l, o ),
//			transmitCalled( false )
//		{}
//
//		/// simple implementation of virtual function that sets a boolean \c true
//		virtual bool transmit( ProtocolMessage* msg )
//		{
//			transmitCalled = true;
//			return true;
//		};
//	};
//
//	/**
//	 * @class TransmissionMediumTestObserver
//	 * @brief Implements TransmissionMediumObserver to validate execution of
//	 * TransmissionMedium methods
//	 */
//	class TransmissionMediumTestObserver:
//		public TransmissionMediumObserver,
//		public ObserverBase
//	{
//	public:
//		/**
//		 * @brief Constructor
//		 * @param output determines whether Observations are sent to stdout
//		 */
//		TransmissionMediumTestObserver( bool output ):
//			ObserverBase( output )
//			{}
//
//		/**
//		 * @name Implementation of virtual Observer functions
//		 *
//		 * Most ODEMx classes define an Observer interface with empty
//		 * implementation. These virtual functions are re-implemented here in
//		 * order to observe the behavior of test objects. All of them call
//		 * ObserverBase::saw() to store events with parameters in the
//		 * observation history which can then be used to verify expected
//		 * behavior of objects.
//		 *
//		 * @{
//		 */
//		virtual void onCreate( TransmissionMedium* sender )
//		{ ObserverBase::saw( "onCreate", sender ); }
//		virtual void onDestroy( TransmissionMedium* sender )
//		{ ObserverBase::saw( "onDestroy", sender ); }
//		virtual void onTransmit( TransmissionMedium* sender, ProtocolMessage* m )
//		{ ObserverBase::saw( "onTransmit", sender, m->toString() ); }
//		virtual void onScheduleUnicast( TransmissionMedium* sender, ProtocolMessage* m, SimTime t )
//		{ ObserverBase::saw( "onScheduleUnicast", sender, m->toString(), toString( t ) ); }
//		virtual void onScheduleBroadcast( TransmissionMedium* sender, ProtocolMessage* m, SimTime t )
//		{ ObserverBase::saw( "onScheduleBroadcast", sender, m->toString(), toString( t ) ); }
//		//@}
//	};
//
//	/************************** TRANSMISSION EVENTS ***************************/
//
//	/**
//	 * @class UnicastTransmissionTestObserver
//	 * @brief Implements UnicastTransmissionObserver to validate execution of
//	 * UnicastTransmission methods
//	 */
//	class UnicastTransmissionTestObserver:
//		public UnicastTransmissionObserver,
//		public ObserverBase
//	{
//	public:
//		/**
//		 * @brief Constructor
//		 * @param output determines whether Observations are sent to stdout
//		 */
//		UnicastTransmissionTestObserver( bool output ):
//			ObserverBase( output )
//			{}
//
//		/**
//		 * @name Implementation of virtual Observer functions
//		 *
//		 * Most ODEMx classes define an Observer interface with empty
//		 * implementation. These virtual functions are re-implemented here in
//		 * order to observe the behavior of test objects. All of them call
//		 * ObserverBase::saw() to store events with parameters in the
//		 * observation history which can then be used to verify expected
//		 * behavior of objects.
//		 *
//		 * @{
//		 */
//		virtual void onSuccess( UnicastTransmission* sender, ProtocolMessage* m,
//								ProtocolStack* n1, ProtocolStack* n2 )
//		{
//			ObserverBase::saw( "onSuccess", sender, n1->getLabel() + "->" + n2->getLabel(), m->toString() );
//		}
//		virtual void onFailure( UnicastTransmission* sender, ProtocolMessage* m,
//								ProtocolStack* n1, ProtocolStack* n2 )
//		{
//			ObserverBase::saw( "onFailure", sender, n1->getLabel() + "->" + n2->getLabel(), m->toString() );
//		}
//		//@}
//	};
//
//	/**
//	 * @class BroadcastTransmissionTestObserver
//	 * @brief Implements BroadcastTransmissionObserver to validate execution of
//	 * BroadcastTransmission methods
//	 */
//	class BroadcastTransmissionTestObserver:
//		public BroadcastTransmissionObserver,
//		public ObserverBase
//	{
//	public:
//		/**
//		 * @brief Constructor
//		 * @param output determines whether Observations are sent to stdout
//		 */
//		BroadcastTransmissionTestObserver( bool output ):
//			ObserverBase( output )
//			{}
//
//		/**
//		 * @name Implementation of virtual Observer functions
//		 *
//		 * Most ODEMx classes define an Observer interface with empty
//		 * implementation. These virtual functions are re-implemented here in
//		 * order to observe the behavior of test objects. All of them call
//		 * ObserverBase::saw() to store events with parameters in the
//		 * observation history which can then be used to verify expected
//		 * behavior of objects.
//		 *
//		 * @{
//		 */
//		virtual void onSuccess( BroadcastTransmission* sender, ProtocolMessage* m,
//								ProtocolStack* n1, ProtocolStack* n2 )
//		{
//			ObserverBase::saw( "onSuccess", sender, n1->getLabel() + "->" + n2->getLabel(), m->toString() );
//		}
//		virtual void onFailure( BroadcastTransmission* sender, ProtocolMessage* m,
//								ProtocolStack* n1, ProtocolStack* n2 )
//		{
//			ObserverBase::saw( "onFailure", sender, n1->getLabel() + "->" + n2->getLabel(), m->toString() );
//		}
//		//@}
//	};


} // namespace SuiteProtocol

#endif /* TESTPROTOCOL_H_ */
