/*  $Id: keep_alive_generic.cpp,v 1.12 2003/09/29 08:38:46 mbn Exp $
**
**  ClanLib Game SDK
**  Copyright (C) 2003  The ClanLib Team
**  For a total list of contributers see the file CREDITS.
**
**  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
**
*/

#include "Core/precomp.h"
#include <list>
#include <map>

#include "API/Core/System/keep_alive.h"
#include "API/Core/System/system.h"
#include "API/Core/System/event_listener.h"
#include "API/Core/System/thread.h"
#include "API/Core/System/mutex.h"

unsigned int CL_System::susp_start;
unsigned int CL_System::susp_cnt = 0;
unsigned int CL_System::susp_accum = 0;

void CL_System::suspend_time()
{
	++susp_cnt;
	if (susp_cnt == 1)
		susp_start = sys_time();
}

void CL_System::resume_time()
{
	if (susp_cnt != 0) {
		--susp_cnt;
		if (susp_cnt == 0) {
			susp_accum += sys_time() - susp_start;
		}
	}
}

unsigned int CL_System::get_time()
{
	if (susp_cnt == 0)
		return sys_time() - susp_accum;
	else
		return susp_start - susp_accum;
}

CL_Mutex mutex_keep_alive;
std::map<int, std::list<CL_KeepAlive*>* > keep_alives;

CL_KeepAlive::CL_KeepAlive()
{
	create_thread_id = CL_Thread::get_current_id();
	CL_MutexSection mutex_lock(&mutex_keep_alive);
	std::map<int, std::list<CL_KeepAlive*>* >::iterator it;
	it = keep_alives.find(create_thread_id);
	if (it == keep_alives.end())
	{
		keep_alives[create_thread_id] = new std::list<CL_KeepAlive*>;
	}
	
	keep_alives[create_thread_id]->push_back(this);
}

CL_KeepAlive::~CL_KeepAlive()
{
	CL_MutexSection mutex_lock(&mutex_keep_alive);
	std::list<CL_KeepAlive*> *list = keep_alives[create_thread_id];
	list->remove(this);
	if (list->empty())
	{
		delete list;
		keep_alives.erase(keep_alives.find(create_thread_id));
	}
}

void CL_System::keep_alive()
{
	int cur_thread_id = CL_Thread::get_current_id();
	CL_MutexSection mutex_lock(&mutex_keep_alive);
	std::map<int, std::list<CL_KeepAlive*>* >::iterator it_map;
	it_map = keep_alives.find(cur_thread_id);
	if (it_map == keep_alives.end()) return;

	std::list<CL_KeepAlive*> *list = it_map->second;

	for (
		std::list<CL_KeepAlive*>::iterator it = list->begin();
		it != list->end();
		it++)
	{
		(*it)->keep_alive();
	}
}

void CL_System::keep_alive(int millis)
{
	CL_EventListener events;
	keep_alive(events, millis);
}

bool CL_System::keep_alive(CL_EventListener &events, int timeout)
{
	// TODO: Add triggers for keep alive objects.

	if (timeout == -1)
	{
		do CL_System::keep_alive(); while (!events.wait(10));

		return true;
	}
	else
	{
		while (timeout > 0)
		{
			CL_System::keep_alive();
			if (events.wait(timeout > 10 ? 10 : timeout)) return true;
			timeout -= 10;
		}

		return false;
	}
}


