
/* ****************************************************************************

 * eID Middleware Project.
 * Copyright (C) 2008-2010 FedICT.
 *
 * This is free software; you can redistribute it and/or modify it
 * under the terms of the GNU Lesser General Public License version
 * 3.0 as published by the Free Software Foundation.
 *
 * This software 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 software; if not, see
 * http://www.gnu.org/licenses/.

**************************************************************************** */
#include "thread.h"
#include <stdlib.h>

namespace eIDMW
{

/** run_internal() function, has different
 * return code etc. on different platform */
	THREAD_INITFUNCTION(run_internal, arg)
	{
		CThread *pThread = (CThread *) arg;

		        pThread->Run();

		// Fixme: this should be done after THREAD_END(),
		// but we can't do anything after this; therefore
		// we add a little delay in IsRunning()
		        pThread->m_isRunning = false;

		        THREAD_END(pThread->m_SyncHandle);
	}

	CThread:: CThread()
	{
		m_isRunning = false;
		m_bStopRequest = false;
#ifdef WIN32
		m_SyncHandle = NULL;
#else
		m_SyncHandle = 0;
#endif
	}
	CThread::~CThread()
	{
		THREAD_CLEANUP(m_SyncHandle);
	}

	int CThread::Start()
	{
		int status;
		THREAD_OBJ threadHandle;

		m_isRunning = true;

		// Here we start the thread. The entry point is the
		// run_internal() function, which on it's turn calls this->Run()
		THREAD_START(run_internal, this, threadHandle, m_SyncHandle,
			     status);

		if (status != 0)
			m_isRunning = false;

		return status;
	}

	bool CThread::IsRunning()
	{
		// To make 'sure' THREAD_END() is called 
		if (!m_isRunning)
			SleepMillisecs(1);

		return m_isRunning;
	}

	void CThread::SleepMillisecs(int millisecs)
	{
#ifdef WIN32
		Sleep(millisecs);
#else
		usleep(millisecs * 1000);
#endif
	}

	void CThread::RequestStop()
	{
		//Ask the thread to stop
		m_bStopRequest = true;
	}

	void CThread::ForceStop()
	{
		//The thread must be killed
		//TODO (Now, we just ask the thread to stop)
		RequestStop();
	}

	void CThread::Stop(unsigned long ulSleepFrequency)
	{
		//Ask the thread to stop
		RequestStop();

		//Wait until the end of the thread
		WaitTillStopped(ulSleepFrequency);
	}

	void CThread::WaitTillStopped(unsigned long ulSleepFrequency)
	{
		//Wait until the end of the thread
		while (IsRunning())
		{
			SleepMillisecs(ulSleepFrequency);
		}
	}

	bool CThread::WaitTimeout(unsigned long ulTimeout, int iStopMode)
	{
		unsigned long ulCount = ulTimeout;

		//Wait until the end of the thread or the timeout
		while (IsRunning() && ulCount > 0)
		{
			SleepMillisecs(1000);
			ulCount--;
		}

		/*
		   iStopMode : 0 = do not stop the thread after timeout
		   1 = request the thread o stop after timeout
		   2 = force the thread to stop
		 */
		if (IsRunning())
		{
			switch (iStopMode)
			{
				case 1:
					RequestStop();
					break;
				case 2:
					ForceStop();
					break;
				default:
					break;
			}
			return false;
		} else
		{
			return true;
		}
	}

	int CThread::getCurrentPid()
	{
#ifdef WIN32
		return _getpid();
#else
		return getpid();
#endif
	}

	beid_thread_id CThread::getCurrentThreadId()
	{
#ifdef WIN32
		return GetCurrentThreadId();
#else
		return pthread_self();
#endif

	}

}
