//----------------------------------------------------------------------------
//	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_Port2.cpp

	\author Ralf Gerstenberger

	\date created at 2003/07/28

	\brief Port2 example from ODEM

	Port2 example from ODEM transferred to ODEMx.
*/

/** \example Example_Port2.cpp
	This example demonstrates a migration from ODEM to ODEMx.
	The original Port2 simulation was taken from ODEM and adjusted
	to run with ODEMx. Port2 simulates a port with tides. The
	original source-code is preserved in this file to show the
	differences.
*/

/*
#include "odem.h"

	ODEMx requires different include files than ODEM. The
	most simple solution is to include odemx.h. This file
	in turn includes other header from ODEMx. All classes
	of ODEMx are placed in the namespace ODEMx. In this simple
	example it is safe to use the whole namespace.
*/
#include <odemx/odemx.h>
using namespace odemx::base;
using namespace odemx::random;
using namespace odemx::synchronization;

#include <vector>
using namespace std;


/*
#ifdef _USE_GL
#include "grtrace.h"
#endif

	ODEMx does not support the GrTrace from ODEM.

	In ODEMx all model components require a pointer to the
	simulation. In general a user would provide a class for
	its special simulation which would inherit the ODEMx
	Simulation class. But for convenience ODEMx also contains
	a default simulation class. The function getDefaultSimulation()
	returns a pointer to an object of this class.
*/

Simulation* sim = &odemx::getDefaultSimulation();

/*
	The names of the following classes have not been changed between
	ODEM and ODEMx.
*/
Res*   tugs;				// Schlepper
Res*   jetties;				// Anlegeplaetze
CondQ* dockq;
ContinuousDist* next;
ContinuousDist* discharge;

/*
class Boat : public Discrete {
public:
	int main ();
	Boat() : Discrete("boat"){}
};

	The ODEM base class Discrete for active model components
	has been replaced by the class Process in ODEMx. As in ODEM
	a user has to provide an implementation of the function
	virtual int main(). The constructor of Process requires,
	in addition to a name, a pointer to the simulation class.
	Another difference between ODEM and ODEMx is, that call-backs
	used for coding conditions or selections are member-functions
	(bool cond1()).
*/
class Boat : public Process {
public:
	int main ();
	Boat() : Process( *sim, "boat"){}

	bool cond1();
};

/*
bool cond1();
*/

int Boat::main() {
// im Dock
	jetties->acquire(1);

	/*
	dockq->waituntil(cond1);

	The interface of CondQ has changed. In this example
	we have to use wait(...) instead of waituntil(...).
	The cast is required because of the decision to use
	member functions for call-backs. We think the advantages
	outweigh the disadvantages of this cast.
	*/
	dockq->wait((odemx::base::Condition)&Boat::cond1);

	tugs->acquire(2);

	/*
	hold(2.0);

	Most scheduling functions have been changed between ODEM and ODEMx.
	hold() for instance is now replaced by a holdFor().
	*/
	holdFor(2);

	tugs->release(2);
	dockq->signal();

// Loeschen der Ladung
	/*
	hold(discharge->sample());
	*/
	holdFor(static_cast< SimTime >( discharge->sample() ));

// ablegen
	tugs->acquire(1);

	/*
	hold (2.0);
	*/
	holdFor(2);

	tugs->release(1);
	jetties->release(1);
	dockq->signal();

	return 0;
}

/*
class Tide : public Discrete {
public:
	static bool low;
	Tide(): Discrete("tide") {}
	int main ();

	(see the comments for Boat)
};
*/
class Tide : public Process {
public:
	static bool low;
	Tide(): Process( *sim, "tide") {}
	int main ();
};

bool Tide::low = false;

/*
bool cond1() {

	(see the comments for Boat)
*/
bool Boat::cond1() {
	/*
	return (tugs->avail() >=2) && !Tide::low;

	The function avail() is replaced by getTokenNumber()
	in ODEMx.
	*/
	return (tugs->getTokenNumber() >=2) && !Tide::low;
}

int Tide::main() {
	for (;;) {
		// low
		low = true;

		/*
		hold(4.0);
		*/
		holdFor(4);

		low = false;
		dockq->signal();

		// high
		/*
		hold(9.0);
		*/
		holdFor(9);
	}
	return 0;
}

/*
class Arrival : public Discrete {
public:
	Boat *b;
	Arrival(): Discrete("arrival") {}
	int main ();
};

	(see the comments for Boat)
*/
class Arrival : public Process {
	vector<Boat*> generatedBoats;
public:
	Boat *b;
	Arrival(): Process( *sim, "arrival") {}
	~Arrival() {
		vector<Boat*>::iterator i;
		for ( i = generatedBoats.begin(); i != generatedBoats.end(); ++i )
			delete *i;
	}
	int main ();
};


int Arrival::main() {
	for (;;) {
		b = new Boat;
		generatedBoats.push_back(b);
		/*
		b->start(NOW);
		hold(next->sample());

		The function start() is not available in
		ODEMx. In ODEMx any hold* or activate* function
		can be used to start a new process.
		*/
		b->hold();
		holdFor(static_cast< SimTime >( next->sample() ));
	}
	return 0;
}

int main(int argc, const char* argv[]) {
/*
	InitializeOdemLib(argc, argv);

#ifdef _USE_GL
	trace().addClient(new GrTrace);
#endif
	trace().start();

	It is not necessary to initialise ODEMx.

	The trace system has changed between ODEM and ODEMx.
	The trace management is done by the simulation class.
	A new trace is added with the function addConsumer(...).
	The trace is controlled with startTrace(), stopTrace(),
	pauseTrace() and continueTrace(). HtmlTrace logs the
	simulation events in a html file. It also provides a simple
	filter to reduce the output. Without a filter the ODEMx trace
	logs much more events than its predecessor in ODEM. In
	this example the filter is set to produce an ODEM-like output.

	In ODEMx several reports are available in one simulation to the
	cost of explicitly creating report objects (the class
	HtmlReport is provided by ODEMx) and registering
	model components to the different reports.

	The results of this simulation can be found in the files
	'Port2_Trace.html' and 'Port2_Report.html'. Trace and report
	of the original ODEM version have been added to the ODEMx package
	for you to compare output and results. They can be found
	along with the Port2.cpp file ('Port2_Trace.txt' and
	'Port2_Report.txt').
*/
//	HtmlTrace trace(sim, "Port2_Trace.html");
//	HtmlReport report(sim, "Port2_Report.html");

//	trace.setFilter("all; mtn:changeState, changeExTime, create, time,"
//					"execute process, init, execute, changeTokenNumber,"
//					"current process, run until, sleep");
//	sim->addConsumer(&trace);
//	sim->startTrace();

	Arrival *a = new Arrival;
	Tide *t = new Tide;

/*
	next = new NegativeExponential("next boat", 0.1);
	discharge = new Normal("discharge", 14.0, 3.0);
	tugs = new Res("tugs", 3);
	jetties = new Res("jetties", 2);
	dockq = new CondQ("dockq");

	As already mentioned, in ODEMx most model components require
	a pointer to an object of the simulation class. Res in
	addition does need a maximum token number which can be larger
	than the initial number of available token.
*/
	next = new NegativeExponential(*sim, "next boat", 0.1);
	discharge = new Normal(*sim, "discharge", 14.0, 3.0);
	tugs = new Res(*sim, "tugs", 3, 3);
	jetties = new Res(*sim, "jetties", 2, 2);
	dockq = new CondQ(*sim, "dockq");

//	report.addProducer(next);
//	report.addProducer(discharge);
//	report.addProducer(tugs);
//	report.addProducer(jetties);
//	report.addProducer(dockq);

	/*
	a->start(NOW);
	t->start(DELAY,1);
	main_Discrete()->hold(50.0);

	(see Arrival::main comments as well)

	In ODEMx the global main function is not integrated as a
	process. The simulation control is instead realised by the
	functions run(), runUntil(...) and step().
	*/
	a->activate();
	t->activateIn(1);
	sim->runUntil(50);

	/*
	trace().pause();
	*/
//	sim->pauseTrace();

	/*
	main_Discrete()->hold(28.0*24.0-50.0);
	*/
	sim->runUntil(28*24);

	/*
	report();

	The function generateReport() has to be called for every report.
	Registered model components mustn't be deleted because
	generateReport() gathers data from them.
	*/
//	report.generateReport();

//	sim->stopTrace();
	sim->exitSimulation();

	delete a;
	delete t;
	delete next;
	delete discharge;
	delete tugs;
	delete jetties;
	delete dockq;

	return 0;
}

