//------------------------------------------------------------------------------
//	Copyright (C) 2008, 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_Event.cpp
 * @author Ronald Kluth
 * @date created at 2008/12/08
 * @brief Example displaying the basic techniques for realizing an event-based
 * simulation with ODEMx.
 * @since 2.1
*/

/**
 * @example Example_Event.cpp
 * Further basic simulation techniques of ODEMx are introduced.
 *
 * An event-based simulation contains a number of event objects that describe
 * certain event occurrences in a model. An event represents one atomic
 * action. These actions are timeless. In this example, several scheduling
 * operations are presented together with an example event class.
 */

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

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

//--------------------------------------------------------------------------Tick
//
// This example Event represents simple SimTime ticks. It outputs a '*' every
// full tick in SimTime.
//
class Tick: public Event
{
public:
	//
	// Every event object needs a reference to the simulation context it belongs
	// to. However, ODEMx provides a default simulation context, to enable use
	// of processes and events without having to define a customized simulation
	// class. Events, like all simulation elements, require a label for
	// identification. ODEMx ensures that labels are unique within the same
	// simulation context by appending numbers to duplicate labels.
	//
	Tick(): Event( odemx::getDefaultSimulation(), "Tick" ) {}
	//
	// This method overrides the pure virtual method of the base class Event.
	// It describes the corresponding action in a model if this event occurs.
	// Here, we simply output a '*' and reschedule the event to model the
	// recurring ticks of a clock.
	//
	virtual void eventAction()
	{
		scheduleIn( 1 );
		cout << " * ";
	}
};

//--------------------------------------------------------------------------main

int main( int argc, char* argv[] )
{
	//
	// For this example, the default simulation context is used. In more complex
	// applications it is recommended to provide a customized simulation class.
	//
	Simulation& sim = odemx::getDefaultSimulation();
	//
	// Using the default constructor, our Tick event will use the default
	// simulation context that is also referenced by 'sim'.
	//
	Tick ticker;
	//
	// The event object is just created at this point. It will not be executed
	// because it is not scheduled. An event can be scheduled by any of these
	// methods:
	//
	// 'schedule()'
	// 'scheduleIn()'
	// 'scheduleAt()'
	// 'scheduleAppend()'
	// 'scheduleAppendIn()'
	// 'scheduleAppendAt()'
	//
	// 'schedule()' and 'scheduleAppend()' are equal to
	// 'scheduleIn( 0 )' and scheduleAppendIn( 0 ), respectively.
	// 'scheduleAt( t )' and 'scheduleAppendAt( t )' are equal to
	// 'scheduleIn( t - now )' and 'scheduleAppendIn( t - now )'.
	//
	ticker.scheduleAt( 1 );
	//
	// There are three ways to compute a simulation. Firstly, you can 'run()'
	// the simulation until it is finished. A simulation is finished if there
	// is no active process or event scheduled, or if it is stopped with
	// 'exitSimulation()'. Secondly, you can compute a simulation 'step()' by
	// step. Thirdly, you can run a simulation until a given SimTime is
	// reached with 'runUntil()'.
	//
	// Because Tick events will reschedule themselves forever, we should not use
	// 'run()'. Instead we try both 'step()' and 'runUntil()'.
	//
	cout << "Basic Event Simulation Example\n";
	cout << "==============================\n";

	for( int i = 1; i < 5; ++i )
	{
		sim.step();
		cout << "\n" << "Step " << i << ": time = " << sim.getTime() << "\n";
	}

	cout << "\n" << "continue until SimTime 6 is reached:";
	sim.runUntil( 6 );
	cout << "\n" << "time = " << sim.getTime() << "\n";

	cout << "==============================" << endl;
	return 0;
}

//----------------------------------------------------------------program output
//
// Basic Event Simulation Example
// ==============================
//  *
// Step 1: time = 1
//  *
// Step 2: time = 2
//  *
// Step 3: time = 3
//  *
// Step 4: time = 4
//
// continue until SimTime 6 is reached: *  *
// time = 6
// ===============================
//
// In contrast to the basicProcess example there is a '*' at step 1 because
// event actions are atomic. Keep in mind that always all of the statements
// in eventAction() are executed, even if there are scheduling calls. In this
// case, the same Event object is rescheduled, but it still outputs the '*'.
// Once an Event's action is started, it cannot be stopped or postponed.
//
