//----------------------------------------------------------------------------
//	Copyright (C) 2002, 2003, 2004 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_Matryoshka_Simulation.cpp

	\author Ralf Gerstenberger

	\date created at 2002/12/14

	\brief Example for recursive simulations

	This example shows the techniques for
	realising a recursive simulation with ODEMx.

	\since 1.0
*/
/** \example Example_Matryoshka_Simulation.cpp
	Recursive simulations are
	introduced.

	One of the unique features of ODEMx is the possibility to run a simulation inside
	another simulation without unwanted side-effects. This could come in handy if you
	want to simulate an agent network for instance. Agents have an internal model of
	their environment, which they use to make their decisions. With ODEMx such an
	agent could be modelled with an internal (simplified) simulation. Another example
	could be a very complex simulation task. With ODEMx you could split the model into
	several blocks, develop	each one as a simulation on its own, and plug them together
	at the end.
*/

#include <odemx/base/Process.h>
#include <odemx/base/Simulation.h>
using odemx::base::Process;
using odemx::base::Simulation;

#include <iostream>
using std::cout;
using std::endl;

//
// In this example we demonstrate the possibility to cascade simulations in a recursive
// simulation called Matryoshka. Like the Russian puppet inside a puppet inside a puppet
// inside ...
//
// A user defined simulation is a class derived from Simulation. Every process or model
// component requires a pointer to its simulation. The user defined simulation can provide
// its processes with additional data. Furthermore, a user defined simulation must implement
// the 'initSimulation()' function to start its processes and to do specific initialisations.
//
class Matryoshka
:	public Simulation
{
	//
	// The simulation contains only the process Proc.
	// This process expects a Matryoshka-simulation as
	// environment. Defining the process as an inside
	// class of Matryoshka is of course not required.
	//
	class Proc
	:	public Process
	{
	public:
		Proc( Matryoshka& sim )
		:	Process( sim, "Proc" )
		{}

	protected:
		//
		// In its 'main()' function the process gets a pointer to
		// its simulation. After a cast (the dynanmic_cast could
		// be spared) the process can access the data provided by
		// its simulation.
		//
		virtual int main()
		{
			int i;
			Matryoshka& sim = dynamic_cast< Matryoshka& >( this->getSimulation() );
			int level = sim.getLevel();

			for( i = level; i > 0; --i )
			{
				cout << ' ';
			}

			if( level % 2 > 0 )
			{
				cout << "Di " << level << endl;
			}
			else
			{
				cout << "Da " << level << endl;
			}

			//
			// After some outputs the process starts the recursion.
			//
			if( level > 0 )
			{
				Matryoshka m( level - 1 );
				m.run();
			}

			for( i = level; i > 0; --i )
			{
				cout << ' ';
			}

			if( level % 2 > 0 )
			{
				cout << "Di " << level << endl;
			}
			else
			{
				cout << "Da " << level << endl;
			}
			return 0;
		}
	};

	Proc p;
	unsigned int mLevel;

public:
	//
	// Because of the recursion Matryoshka needs the additional
	// parameter 'level'.
	//
	Matryoshka( unsigned int level )
	:	Simulation( "Matryoshka" )
	,	p( *this )
	,	mLevel( level )
	{}

	~Matryoshka()
	{
		//delete p;
	}

	//
	// 'level' is the recursion parameter of the Matryoshka simulation.
	//
	unsigned int getLevel() { return mLevel; }

protected:
	//
	// If you are defining your own simulation class you have to provide 'initSimulation'
	// to initialise the simulation. This function is called when the simulation is started
	// for the first time.
	//
	virtual void initSimulation()
	{
		p.activate();
	}
};

//
// The 'main' function looks a bit deserted in this example. Almost everything
// is done in the simulation. The advantage is, you can 'reuse' the simulation
// as it is.
//
int main(int argc, char* argv[])
{
	// Start the first simulation to kick off the recursion
	Matryoshka m( 10 );
	m.run();

	return 0;
}

