//------------------------------------------------------------------------------
//	Copyright (C) 2009 Humboldt-Universitaet zu Berlin
//
//	This library is free software; you can redistribute it and/or
//	modify it under the terms of the GNU Lesser General Public
//	License as published by the Free Software Foundation; either
//	version 2.1 of the License, or (at your option) any later version.
//
//	This library is distributed in the hope that it will be useful,
//	but WITHOUT ANY WARRANTY; without even the implied warranty of
//	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
//	Lesser General Public License for more details.
//
//	You should have received a copy of the GNU Lesser General Public
//	License along with this library; if not, write to the Free Software
//	Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
//------------------------------------------------------------------------------

/**
 * @file Example_Connection.cpp
 * @author Ronald Kluth
 * @date created at 2010/03/16
 * @brief Example displaying the basic usage of a user-defined coroutine class
 * @since 3.0
 */

/**
 * @example Example_Connection.cpp
 * The basic usage of a coroutine implementation is demonstrated
 *
 * This example demonstrates how protocol connections can be modeled
 * in ODEMx as separate coroutines. For this example, we use a very simple
 * message class that can only report its type.
 *
 * Next, a user-defined coroutine class is defined. Its @c run method keeps
 * it active for as long as the connection has not been closed. Each time
 * the coroutine resumes, it checks whether there is a new message and
 * simply prints the type. After that, it yields to return control to its
 * caller.
 *
 * The main program uses this behavior to resume the coroutine several times,
 * setting new messages whenever the coroutine yields control.
 */

#include <odemx/odemx.h>

using namespace odemx;
//
// Simple message class that only has a type and no data
//
class Message
{
public:
	enum Type { T1, T2 };

	Message( Type t ): type_( t ) {}
	Type getType() const { return type_; }
private:
	Type type_;
};
//
// User-defined coroutine subclass that implements a simple protocol
// connection which can maintain an internal state and yield control
// to a caller.
//
class Connection: public coroutine::Coroutine
{
public:
	Connection( base::Simulation& sim )
	:	Coroutine( &sim )
	,	msg_( 0 )
	,	closed_( false )
	{}

	virtual void run()
	{
		//
		// Run until connection gets closed
		//
		while( ! closed_ )
		{
			if( msg_ )
			{
				//
				// If a message was set for this connection, display the type
				//
				switch( msg_->getType() )
				{
					case Message::T1:
						std::cout << "T1" << std::endl;
						break;
					case Message::T2:
						std::cout << "T2" << std::endl;
						break;
				}
			}
			//
			// Return control to the caller of the coroutine
			//
			yield();
		}
		//
		// The connection was closed
		//
		std::cout << "Connection closed" << std::endl;
	}
	void setMessage( Message* msg )
	{
		msg_ = msg;
	}
	void close()
	{
		closed_ = true;
	}
private:
	Message* msg_;
	bool closed_;
};

int main()
{
	//
	// Create two message objects to pass to the connection object
	//
	Message m1( Message::T1 );
	Message m2( Message::T2 );
	base::Simulation& sim = getDefaultSimulation();
	//
	// Create one coroutine-based connection object and resume it
	// several times.
	//
	Connection c( sim );
	c();
	c.setMessage( &m1 );
	c();
	c.setMessage( &m2 );
	c();
	c.close();
	c();
	return 0;
}
