//	Thread.h - Simple thread base class.
//  ----------------------------------------------------------------------------
//	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 THREAD_H_
#define THREAD_H_

#include "c0xHeaders.h"

#include <string>

class BackendThread;
typedef int (*ThreadMethod)(void *);
typedef shared_ptr<BackendThread> BackendThreadPtr;

//------------------------------------------------------------------------------
///	Base class for backend thread implementations.
class BackendThread
{
  public:
	///	Constructor.
	BackendThread() {};
	///	Destructor.
	virtual ~BackendThread() {};

	///	Creates and starts a thread.
	/*!
		\param threadMethod The thread function to call.
		\param name The name of the thread.
		\param data Any data to pass to the thread.
		\return True if thread creation was successful.
	 */
	virtual bool createThread(ThreadMethod threadMethod,
							  const std::string& name,
							  void *data) = 0;
	///	Waits for the thread to finish.
	virtual void waitToFinish() = 0;

	///	Simple class used to construct an instance of a BackendThread subclass.
	class Creator
	{
	  public:
		///	Constructor.
		Creator() {};
		///	Destructor.
		virtual ~Creator() {};

		///	Returns a new instance of a BackendThread subclass.
		virtual BackendThreadPtr createBackendThread() const = 0;

		///	Tells the current thread to wait the passed-in number of milliseconds.
		virtual void wait(int milliseconds) const = 0;
	};
};

//------------------------------------------------------------------------------
///	Simple thread base class.
/*!
	To use it, you should create a subclass that implements the run() method.
 */
class Thread
{
  public:
	///	Constructor.
	Thread(const std::string& threadName);
	///	Destructor.
	/*!
		This will wait for the thread to terminate.  Do not delete a Thread
		object from it's own thread.  It is assumed that your subclass will
		implement some kind of way to tell the running thread that it must
		terminate, and exit the run() method, otherwise you may find your
		program hangs forever.
	 */
	virtual ~Thread();

	///	Call this to start the thread.
	/*!
		\param threadPointer Pointer to the subclass calling it (since it needs
		to be passed to SDL_CreateThread, and we can't just use this in Thread
		(because that would be a base class pointer, not a subclass...).
	 */
	void startThread(Thread *threadPointer);

	///	Where any processing for the thread occurs.
	/*!
		\return Set this to true if the thread completed successfully, false
		otherwise.

		To use this class, you want to create a subclass, and put all your
		processing stuff in this method.
	 */
	virtual bool run() = 0;

	///	Static method passed to SDL_CreateThread, to ensure run() is always called.
	/*!
		In the Thread constructor, we pass in a pointer to the instance of
		Thread for this method, so it can call Thread::run().
	 */
	static int threadMethod(void *data);

	///	Tells the current thread to wait the passed-in number of milliseconds.
	static void wait(int milliseconds);

	///	Used to set the BackendThread creator.
	/*!
		This *MUST* be called on startup, or Thread will refuse to work.

		This method is necessary because different backends may have different
		thread implementations.

		This method may only be called *once*; multiple calls constitutes an
		error.
	 */
	static void setBackendThreadCreator(BackendThread::Creator *creator);
  private:
	///	The name of the thread.
	std::string name;

	///	Pointer to the backend's thread implementation.
	BackendThreadPtr thread;

	///	Used to create the correct BackendThread for the current backend.
	static BackendThread::Creator *backendThreadCreator;
};

#endif
