//	GameCounter.cpp - Singleton 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/>.
//	----------------------------------------------------------------------------

#include "GameCounter.h"

#include <algorithm>

using std::wstring;
using std::map;

//------------------------------------------------------------------------------
GameCounter::GameCounter()
{
	
}

//------------------------------------------------------------------------------
GameCounter::~GameCounter()
{
	
}

//------------------------------------------------------------------------------
void GameCounter::incrementCount(const wstring& counter,
								 int val,
								 bool addsToScore)
{
	unsigned int i;
	map<wstring, CounterPtr>::iterator it = counters.find(counter);

	if(it == counters.end())
		createCounter(counter, addsToScore);

	counters[counter]->value += val;
	for(i=0;i<counters[counter]->noteCounts.size();++i)
	{
		CounterPtr& c = counters[counter];

		if((c->value % c->noteCounts[i]) == 0)
			c->noteDests[i]->countReached(counter, c->value);
	}
}

//------------------------------------------------------------------------------
int GameCounter::getCount(const wstring& counter) const
{
	int retval = 0;
	map<wstring, CounterPtr>::const_iterator it = counters.find(counter);

	if(it != counters.end())
		retval = it->second->value;

	return retval;
}

//------------------------------------------------------------------------------
int GameCounter::getScore() const
{
	int retval = 0;
	map<wstring, CounterPtr>::const_iterator it;

	for(it=counters.begin();it!=counters.end();++it)
	{
		if(it->second->contributesToScore)
			retval += it->second->value;
	}

	return retval;
}

//------------------------------------------------------------------------------
void GameCounter::reset()
{
	map<wstring, CounterPtr>::const_iterator it;

	for(it=counters.begin();it!=counters.end();++it)
		it->second->value = 0;
}

//------------------------------------------------------------------------------
void GameCounter::resetCount(const wstring& counter)
{
	map<wstring, CounterPtr>::const_iterator it;

	it = counters.find(counter);
	if(it!=counters.end())
		it->second->value = 0;
}

//------------------------------------------------------------------------------
void GameCounter::registerNotification(const wstring& counter,
									   int value,
									   CounterNotification *notification)
{
	map<wstring, CounterPtr>::iterator it = counters.find(counter);

	if(it == counters.end())
		createCounter(counter, true);

	counters[counter]->noteCounts.push_back(value);
	counters[counter]->noteDests.push_back(notification);
}

//------------------------------------------------------------------------------
void GameCounter::unregisterNotification(const std::wstring& counter,
										 int value,
										 CounterNotification *notification)
{
	map<wstring, CounterPtr>::iterator it = counters.find(counter);

	if(it != counters.end())
	{
		std::vector<int>::iterator countIt = find(counters[counter]->noteCounts.begin(),
												  counters[counter]->noteCounts.end(),
												  value);
		std::vector<CounterNotification *>::iterator destIt = find(counters[counter]->noteDests.begin(),
																   counters[counter]->noteDests.end(),
																   notification);

		//Because there's a chance there will be multiple identical counters.
		while(countIt != counters[counter]->noteCounts.end())
		{
			counters[counter]->noteCounts.erase(countIt);

			countIt = find(counters[counter]->noteCounts.begin(),
						   counters[counter]->noteCounts.end(),
						   value);
		}
		while(destIt != counters[counter]->noteDests.end())
		{
			counters[counter]->noteDests.erase(destIt);

			destIt = find(counters[counter]->noteDests.begin(),
						  counters[counter]->noteDests.end(),
						  notification);
		}
		//Possible bug: could you wind up with noteCounts & noteDests having
		//different sizes? (don't *think* so?)
	}
}

//------------------------------------------------------------------------------
void GameCounter::createCounter(const wstring& name, bool addsToScore)
{
	counters.insert(make_pair(name, CounterPtr(new Counter)));
	counters[name]->contributesToScore = addsToScore;
}
