/***************************************************************************
 *   Copyright (C) 2010 by Joris Guisson                                   *
 *   joris.guisson@gmail.com                                               *
 *                                                                         *
 *   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 2 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, write to the                         *
 *   Free Software Foundation, Inc.,                                       *
 *   51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.          *
 ***************************************************************************/


#include "resourcemanager.h"

namespace bt
{
	Resource::Resource(bt::ResourceManager* rman, const QString& group) : rman(rman),group(group)
	{
	}
	
	Resource::~Resource()
	{
		if (rman)
			rman->remove(this);
	}
	
	void Resource::release()
	{
		if (rman)
		{
			rman->remove(this);
			rman = 0;
		}
	}


	ResourceManager::ResourceManager(Uint32 max_active_resources) : max_active_resources(max_active_resources)
	{
	}

	ResourceManager::~ResourceManager()
	{
	}
		
	void ResourceManager::add(Resource* r)
	{
		QMap<QString,Resource::List>::iterator i = pending.find(r->groupName());
		if (i == pending.end())
			i = pending.insert(r->groupName(),Resource::List());
		
		i.value().append(r);
		if (current.isEmpty())
			current = r->groupName();
		update();
	}
	
	bool ResourceManager::acquire(Resource* r)
	{
		if (active.size() < max_active_resources && pending.isEmpty())
		{
			add(r);
			return true;
		}
		else
			return false;
	}

	
	void ResourceManager::remove(Resource* r)
	{
		if (active.remove(r))
		{
			update();
		}
		else
		{
			QMap<QString,Resource::List>::iterator i = pending.find(r->groupName());
			if (i != pending.end())
				i.value().removeAll(r);
		}
	}
	
	void ResourceManager::update()
	{
		if ((Uint32)active.size() >= max_active_resources)
			return;
		
		QMap<QString,Resource::List>::iterator i = pending.find(current);
		if (i == pending.end())
			i = pending.begin();
		
		QMap<QString,Resource::List>::iterator start = i;
		Uint32 activated = 0;
		while ((Uint32)active.size() < max_active_resources)
		{
			if (!i.value().isEmpty())
			{
				Resource* r = i.value().takeFirst();
				active.insert(r);
				r->acquired();
				activated++;
			}
			i++;
			if (i == pending.end()) // Loop around
				i = pending.begin();
			
			if (i == start) // we have completed an antire cycle
			{
				if (activated == 0) // Nothing was activated, so exit the loop
					break;
				else
					activated = 0;
			}
		}
		
		current = i.key();
	}

	void ResourceManager::shutdown()
	{
		max_active_resources = 0;
	}

}
