//	GameCounter.h - Class which can be used to count all sorts of things.
//	----------------------------------------------------------------------------
//	This file is part of 'NiallsAVLib', base code for any kind of audiovisual
//	apps.
//	Copyright (C) 2012  Niall Moody
//
//	This program is free software: you can redistribute it and/or modify
//	it under the terms of the GNU General Public License as published by
//	the Free Software Foundation, either version 3 of the License, or
//	(at your option) any later version.
//
//	This program 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 General Public License for more details.
//
//	You should have received a copy of the GNU General Public License
//	along with this program.  If not, see <http://www.gnu.org/licenses/>.
//	----------------------------------------------------------------------------

#ifndef GAMECOUNTER_H_
#define GAMECOUNTER_H_

#include "c0xHeaders.h"

#include <string>
#include <vector>
#include <map>

//------------------------------------------------------------------------------
///	Virtual base class for entities which need notified of particular counter values.
class CounterNotification
{
  public:
	///	Destructor.
	virtual ~CounterNotification() {};

	///	Called when the related counter reaches the specified value.
	virtual void countReached(const std::wstring& counter, int value) = 0;
};

//------------------------------------------------------------------------------
///	Class which can be used to count all sorts of things.
/*!
	Individual counters are referred to by strings.  New counters are created by
	just calling incrementCount or registerNotification.  To be informed when a
	counter reaches a particular value, inherit from CounterNotification and
	call registerNotification with a pointer to your subclass.  Individual
	counters can have multiple CounterNotifications attached to them.
 */
class GameCounter
{
  public:
	///	Constructor.
	GameCounter();
	///	Destructor.
	~GameCounter();

	///	Increments the named count.
	void incrementCount(const std::wstring& counter,
						int val = 1,
						bool addsToScore = true);
	///	Returns the current value of the named count.
	int getCount(const std::wstring& counter) const;
	///	Returns the player's score.
	/*!
		(the player's score is the sum of every active counter)
	 */
	int getScore() const;
	///	Resets all the counters to 0.
	void reset();
	///	Resets the named counter to 0.
	void resetCount(const std::wstring& counter);

	///	Returns the number of active counters.
	int getNumCounters() const {return counters.size();};

	///	Registers a CounterNotification for the named counter.
	/*!
		\param counter The counter we're interested in.
		\param value When we want to get notified.  This is a modulo deal, so
		every time the counter reaches a multiple of <value>, notification will
		be called.
		\param notification The object to be notified when the counter reaches
		value.
	 */
	void registerNotification(const std::wstring& counter,
							  int value,
							  CounterNotification *notification);
	///	Unregisters a CounterNotification for the named counter.
	void unregisterNotification(const std::wstring& counter,
								int value,
								CounterNotification *notification);
  private:
	///	Struct representing a single counter.
	struct Counter
	{
		///	Constructor.  Just initialises things to 0.
		Counter():
		value(0),
		contributesToScore(true)
		{};

		///	The current value.
		int value;
		///	The values at which a notification should be sent...
		std::vector<int> noteCounts;
		///	...and their destinations.
		std::vector<CounterNotification *> noteDests;
		///	Whether or not this counter contributes to the score.
		bool contributesToScore;
	};
	typedef shared_ptr<Counter> CounterPtr;

	///	Helper method to create a new counter.
	void createCounter(const std::wstring& name, bool addsToScore);

	///	All the counters used in the game.
	std::map<std::wstring, CounterPtr> counters;
};

#endif
