/*
	Lan Wars.
	Copyright (c) 2009, Darragh Coy.
	All rights reserved.
	Original work(s), source code & author(s) details available at: http://www.darraghcoy.com

	Redistribution and use in source and binary forms, with or without modification, are permitted 
	provided that the following conditions are met:

		* 	Redistributions of source code must retain the above copyright notice, this list of 
			conditions and the following disclaimer.
		* 	Redistributions in binary form must reproduce the above copyright notice, this list of 
			conditions and the following disclaimer in the documentation.
		* 	Neither the name of the author nor the names of contributors may be used to endorse or 
			promote products derived from this software without specific prior written permission.
		* 	The use of any third party libraries, modules or data files provided with the source 
			form of the program must follow and respect the individual licensing terms of these 
			components. You do not have permission to modify or circumvent the licensing terms for 
			provided third party components unless the third party licenses specifically allow this. 
			If you do not agree to the terms of provided third party components then you do not have 
			permission to use them in your derived work(s).
		* 	The terms of this license do not apply to separate (but related) distributions if supplied 
			by the author(s), only to the contents of this source distribution, derived works, and the 
			binaries produced by either modified or unmodified versions of the source code. The terms 
			of this license do not also apply to any third party libraries or components provided with 
			the source distribution. Such third party elements are licensed under their own separate 
			agreements.

	THIS SOFTWARE IS PROVIDED BY DARRAGH COY ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, 
	BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 
	ARE DISCLAIMED. IN NO EVENT SHALL DARRAGH COY BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 
	EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 
	OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY 
	OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 
	IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

#ifndef GAME_THREAD_H
#define GAME_THREAD_H

//=====================================================================================================================
//=====================================================================================================================

namespace Game
{
	//=================================================================================================================
	//=================================================================================================================
	
	class Condition;

	//=================================================================================================================
	/// @brief		This class represents a thread. This particular thread object takes a static thread entry function
	///				as a parameter for where it should begin execution. Also, unlike windows threads this thread 
	///				object can be re-executed once it has finished one execution of the thread_main function. This 
	///				allows the thread to be used as a worker thread, that can be assigned different tasks at will.
	/// @remarks	To ease complexity and to prevent muddle ups with synchronisation, this thread is only allowed to
	///				be manipulated or read from the thread it is created from. This is typically the main thread, 
	///				but that need not be the case. If any of the thread functions is called from another thread then an 
	///				assertion fails in debug mode.
	//=================================================================================================================

	class Thread
	{
		public:

			//=========================================================================================================
			// Typedefs
			//=========================================================================================================

				/// Represents the format for a thread entry point function. It takes a pointer to the thread as a parameter.

				typedef void ( * ThreadEntryFunction )( void * user_data ); 
			
			//=========================================================================================================
			// Functions
			//=========================================================================================================
					    
				/// Creates the thread. The thread is initially suspended until a call to Run() is made.

				Thread
				( 
					ThreadEntryFunction		thread_main					,
					unsigned				stack_size		= 0xffff	,
					bool					exit_on_failure	= true		
				);

				/// Destroys the thread

				~Thread();

				/// Begins running the thread: if the thread has exited this can be used to re-run the thread

				void Run( void * user_data = 0);
				
				/// Waits until the thread has finished excecution
				
				inline void WaitTillFinished() const;
				
				//=====================================================================================================
				/// @brief		Tells if the thread is valid:
				/// @pre		The caller must be the thread that made this thread
				//=====================================================================================================				

				inline bool IsValid() const 
				{ 
					// Make sure ok:
					
					ENSURE( GetCurrentThreadId() == m_creator_id , "The caller must be the thread that made this thread" )						
				
					// Return the value
				
					return m_thread_handle != 0;
				}

				//=====================================================================================================
				/// @brief		Gets the id of the thread.
				/// @pre		The thread must be valid
				/// @pre		The caller must be the thread that made this thread
				//=====================================================================================================

				inline unsigned GetID() const 
				{ 
					// Make sure ok:
					
					ENSURE( GetCurrentThreadId() == m_creator_id , "The caller must be the thread that made this thread" )				
				
					// Return the value
				
					return m_thread_id; 
				}

				/// Tells if the thread is currently running
				
				bool IsRunning() const;
				
				//=====================================================================================================
				/// @brief		Tells if the thread is currently stopped
				/// @pre		The caller must be the thread that made this thread
				//=====================================================================================================
				
				inline bool IsStopped() const 
				{ 
					// Make sure ok:
					
					ENSURE( GetCurrentThreadId() == m_creator_id , "The caller must be the thread that made this thread" )						
				
					// Return if we are not running
				
					return ! IsRunning();
				}

				//=====================================================================================================
				/// @brief		Returns the entry function for this thread
				/// @pre		The caller must be the thread that made this thread
				//=====================================================================================================
				
				inline ThreadEntryFunction GetEntryFunction() const 
				{ 
					// Make sure ok:
					
					ENSURE( GetCurrentThreadId() == m_creator_id , "The caller must be the thread that made this thread" )
					
					// Return the value
									
					return m_entry_function; 
				}
			
		private:
		
			//=========================================================================================================
			// Functions
			//=========================================================================================================	
			
				/// This is the initial thread entry function used for all threads the void * parameter points to a thread object
				
				static DWORD WINAPI CommonThreadEntryPoint( void * param );
			
				/// Cannot be copied
				
				Thread( const Thread & other );
				
				/// Cannot be copied
				
				Thread & operator = ( const Thread & other );				
		
			//=========================================================================================================
			// Variables
			//=========================================================================================================							
		
				/// Handle to the Win32 thread for this object

				HANDLE m_thread_handle;
				
				/// The entry function for this thread
				
				ThreadEntryFunction m_entry_function;

				/// Id for this thread

				DWORD m_thread_id;
				
				/// A condition that must be true for the thread to execute or consider executing it's thread_main function
				
				Condition * m_begin_thread_condition;
				
				/// A condition that is set to true when the thread has finished one execution
				
				Condition * m_thread_ended_condition;
				
				/// A simple boolean condition that is set to true if the thread should exit CommonThreadEntryPoint() and execute no more
				
				bool m_exit_common_entry_function;
				
				/// Current user data for the thread: this is passed to the thread_main function before an interation of the thread begins
				
				void * m_user_data;
				
				/// A condition 
				
				#ifdef DEBUG
				
					/// Debug only: id of the thread that made this particular thread 	
				
					DWORD m_creator_id;
					
				#endif
	};
};

#endif 
