//------------------------------------------------------------------------------
//	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_DiningPhilosophers.cpp
 * @author Ronald Kluth
 * @date created at 2010/04/24
 * @brief Example showing a variation of the dining philosophers problem
 * @since 3.0
 */

/**
 * @example Example_DiningPhilosophers.cpp
 *
 * There are 800 seats and as many philosophers and forks on one table.
 * Philosophers either spend time thinking or eating. But the latter is only
 * possible if two forks are available. As this Simulation is fairly time
 * consuming, it was used to measure ODEMx performance.
 */

#include <odemx/odemx.h>
#include <deque>

class Philosopher: public odemx::base::Process {
public:
	Philosopher( bool& fork1, bool& fork2, odemx::base::SimTime timePeriod )
	:	Process( odemx::getDefaultSimulation(), "Philosopher" )
	,	fork1( fork1 ), fork2( fork2 ), timePeriod( timePeriod )
	{}
private:
	virtual int main() {
		while( true ) {
			do { // thinking
				spendTime();
			} while( ! takeForks() );
			// forks acquired, start eating
			spendTime();
			returnForks();
		}
		return 0;
	}
private:
	bool& fork1;
	bool& fork2;
	int timePeriod;
private:
	bool takeForks() {
		if( fork1 && fork2 ) {
			fork1 = fork2 = false;
			return true;
		}
		return false;
	}
	void returnForks() { fork1 = fork2 = true; }
	void spendTime(){ holdFor( timePeriod ); }
};

int main() {
	std::deque< Philosopher* > phils;
	std::deque< bool > forks;
	int seats = 800;
	for( int i = 0; i < seats; ++i ) { forks.push_back( true ); }
	for( int i = 0; i < seats - 1; ++i ) {
		phils.push_back( new Philosopher( forks[ i ],  forks[ i + 1 ], 10 ) );
	}
	phils.push_back( new Philosopher( forks[ forks.size() - 1 ],  forks[ 0 ], 10 ) );

	for( int i = 0; i < phils.size(); ++i ) { phils[ i ]->activate(); }
	odemx::getDefaultSimulation().runUntil( 10000 );
	std::for_each( phils.begin(), phils.end(), odemx::DeletePtr< Philosopher >() );
}
