import game;
import util;

interface GameObserver
{
	// this(in Game g);
	void on_game_changed(char c, in Game g, bool finished);
}

class Driver
{
	this(Game g) { this.game = g; }
	this(File game_data) { this(Game.load(game_data)); }

	void command(char c)
	{
		if( finished )
			return;
		if( c == 'A' )
			aborted = true;
		else
			game.command(c);
		foreach(ob; observers)
			ob.on_game_changed(c, game, finished);
	}

	T addObserver(T)()
	{
		T t = new T(game);
		observers ~= t;
		return t;
	}

	@property bool finished()
	{
		return game.cleared || game.dead || aborted;
	}

private:
	Game           game;
	GameObserver[] observers;
	bool           aborted = false;
}

unittest
{
	static class MockGame : Game {
		this() { super(null,null,null); }
		string log;
		void command(char c) { log ~= c; }
	}
	static class MockObserver : GameObserver {
		string log;
		this(in Game g) {}
		void on_game_changed(char c, in Game g, bool fin) { log~=c; if(fin)log~="$"; }
	}

	auto g = new MockGame;
	auto d = new Driver(g);
	auto o = d.addObserver!MockObserver();
	foreach(char c; "UDLRSAUDLRSA")
		d.command(c);
	assert(g.log == "UDLRS");
	assert(o.log == "UDLRSA$");
}
