#ifndef __TCThread_h__
#define __TCThread_h__

#include "AutoHandle.h"

/////////////////////////////////////////////////////////////////////////////
// TCThread.h | Declaration of the TCThread class
// 


/////////////////////////////////////////////////////////////////////////////
// Forward Declarations

/////////////////////////////////////////////////////////////////////////////
// Type definition/prototype for a user-defined callback function that
// represents a thread, specified as the /pfnThreadProc/ parameters of the
// TCThread::BeginThread method.
//
// See Also: TCThread, TCThread::BeginThread
typedef unsigned (__stdcall* TC_THREADPROC)(void*);


/////////////////////////////////////////////////////////////////////////////
// Remarks: This class is like CWinThread with all that Thread State and
// m_pMainWnd stuff removed from it.  It came about because many COM objects
// won't be able to use CWinThread because there won't be a MainWnd for the
// thread to be associated with.  This class does not use MFC.
//
// The Usage is almost identical to CWinThread.  Call the static function 
// TCThread::BeginThread() to create and start the thread.  When the
// controlling function returns, the thread is automatically cleaned up, just
// like CWinThread.  The following function may also be used on the thread:
//
//       int GetThreadPriority()
//       BOOL SetThreadPriority(int nPriority)
//       DWORD SuspendThread()
//       DWORD ResumeThread()
//       bool PostThreadMessage(UINT message, WPARAM wParam, LPARAM lParam)
class TCThread
{
// Construction / Destruction
public:
  TCThread();
  TCThread(TC_THREADPROC pfnThreadProc, LPVOID pParam);
  virtual ~TCThread();
  
  // Static functions to create and return a TCThread 
  static TCThread* BeginThread(TC_THREADPROC pfnThreadProc, LPVOID pParam,
    int nPriority = THREAD_PRIORITY_NORMAL, UINT nStackSize = 0,
    DWORD dwCreateFlags = 0, LPSECURITY_ATTRIBUTES pSecurityAttrs = NULL);
  static TCThread* BeginMsgThread(TC_THREADPROC pfnThreadProc, LPVOID pParam,
    int nPriority = THREAD_PRIORITY_NORMAL, UINT nStackSize = 0,
    DWORD dwCreateFlags = 0, LPSECURITY_ATTRIBUTES pSecurityAttrs = NULL);

  // Called by TCBeginThread
  bool CreateThread(bool bMsgQueue = false, DWORD dwCreateFlags = 0,
    UINT nStackSize = 0, LPSECURITY_ATTRIBUTES pSecurityAttrs = NULL);

  void EndThread(UINT nExitCode, bool bDelete = true);

  // 'delete this' only if m_bAutoDelete == true
  void Delete();

// Group=Attributes
public:
  HANDLE    m_hThread;       // This thread's HANDLE
  DWORD     m_nThreadID;     // This thread's ID
  bool      m_bAutoDelete:1; // Enables 'delete this' after thread termination
  TCHandle  m_hEventExit;    // Thread proc can wait for this

  int GetThreadPriority();
  bool SetThreadPriority(int nPriority);

// Operations
public:
  DWORD SuspendThread();
  DWORD ResumeThread();
  bool PostThreadMessage(UINT message, WPARAM wParam = 0, LPARAM lParam = 0);
  DWORD SignalExitAndWait(DWORD dwWait = INFINITE);

// Operators
public:
  operator HANDLE() const;

// Implementation
public:
  // These items aren't for user consumption.
  void CommonConstruct();

  // Actual entry point for all threads of this type.
  static UINT __stdcall TCThreadEntry(void* pParam);
  static UINT __stdcall TCMsgThreadEntry(void* pParam);

// Group=Data Members
public:
  // Parameters passed to starting function.  Used internally.
  LPVOID        m_pThreadParams; 
  TC_THREADPROC m_pfnThreadProc;
  DWORD         m_dwCreateFlags;
  
  // Events to coordinate thread startup. Used internally.
  TCHandle      m_hEvent, m_hEvent2;

  // Error checking. Used internally.
  bool          m_bError:1, m_bMsgQueue:1;
};


/////////////////////////////////////////////////////////////////////////////
// Group=Attributes

/////////////////////////////////////////////////////////////////////////////
// Description: Gets the priority of the current thread.
//
// Return Value: The current thread priority level within its priority class.
// The value returned will be one of the following, listed from highest
// priority to lowest:
//
// + THREAD_PRIORITY_TIME_CRITICAL
// + THREAD_PRIORITY_HIGHEST
// + THREAD_PRIORITY_ABOVE_NORMAL
// + THREAD_PRIORITY_NORMAL
// + THREAD_PRIORITY_BELOW_NORMAL
// + THREAD_PRIORITY_LOWEST
// + THREAD_PRIORITY_IDLE 
//
// Sets the priority of the current thread.
//
// See Also: TCThread::SetThreadPriority
inline int TCThread::GetThreadPriority()                 
{
  assert(NULL != m_hThread);
  return ::GetThreadPriority(m_hThread);
}

/////////////////////////////////////////////////////////////////////////////
// Description: Sets the priority of the current thread.
//
// Return Value: Nonzero if function was successful; otherwise 0.
//
// Parameters:
//   nPriority - Specifies the new thread priority level within its priority
//   class. This parameter must be one of the following values, listed from
//   highest priority to lowest:
//
// THREAD_PRIORITY_TIME_CRITICAL
//
// THREAD_PRIORITY_HIGHEST
//
// THREAD_PRIORITY_ABOVE_NORMAL
//
// THREAD_PRIORITY_NORMAL
//
// THREAD_PRIORITY_BELOW_NORMAL
//
// THREAD_PRIORITY_LOWEST
//
// THREAD_PRIORITY_IDLE
//
// This function sets the priority level of the current thread within its
// priority class. It can only be called after CreateThread successfully
// returns.
//
// See Also: TCThread::GetThreadPriority
inline bool TCThread::SetThreadPriority(int nPriority)
{
  assert(NULL != m_hThread);
  return !!::SetThreadPriority(m_hThread, nPriority);
}


/////////////////////////////////////////////////////////////////////////////
// Group=Operations

/////////////////////////////////////////////////////////////////////////////
// Description: Increments a thread's suspend count.
//
// Increments the current thread's suspend count. If any thread has a suspend
// count above zero, that thread does not execute. The thread can be resumed
// by calling the ResumeThread member function.
//
// Return Value: The thread's previous suspend count if successful;
// 0xFFFFFFFF otherwise.
//
// See Also: TCThread::ResumeThread
inline DWORD TCThread::SuspendThread()
{
  assert(NULL != m_hThread);
  return ::SuspendThread(m_hThread);
}

/////////////////////////////////////////////////////////////////////////////
// Description: Decrements a thread's suspend count.
//
// Called to resume execution of a thread that was suspended by the
// SuspendThread member function, or a thread created with the
// CREATE_SUSPENDED flag. The suspend count of the current thread is reduced
// by one. If the suspend count is reduced to zero, the thread resumes
// execution; otherwise the thread remains suspended.
//
// Return Value: The thread's previous suspend count if successful;
// 0xFFFFFFFF otherwise. If the return value is zero, the current thread was
// not suspended. If the return value is one, the thread was suspended, but
// is now restarted. Any return value greater than one means the thread
// remains suspended.
inline DWORD TCThread::ResumeThread()
{
  assert(NULL != m_hThread);
  return ::ResumeThread(m_hThread);
}

/////////////////////////////////////////////////////////////////////////////
// Description: Posts a message to the message queue of this thread.
//
// Return Value: Nonzero if successful; otherwise 0.
//
// Parameters:
//   message - ID of the user-defined message.
//   wParam - First message parameter.
//   lParam - Second message parameter.
//
// Called to post a message to the message queue of this object. 
inline bool TCThread::PostThreadMessage(UINT message, WPARAM wParam,
  LPARAM lParam)
{
  assert(NULL != m_hThread);
  assert(0 != m_nThreadID);
  return !!::PostThreadMessage(m_nThreadID, message, wParam, lParam);
}


inline DWORD TCThread::SignalExitAndWait(DWORD dwWait)
{
  HANDLE hth = m_hThread;
  ::SetEvent(m_hEventExit);
  if (m_bMsgQueue)
    PostThreadMessage(WM_QUIT, 0, 0);
  return WaitForSingleObject(hth, dwWait);
}


/////////////////////////////////////////////////////////////////////////////
// Group=Operators

inline TCThread::operator HANDLE() const
{
  return (NULL == this) ? NULL : m_hThread;
}


/////////////////////////////////////////////////////////////////////////////

#endif // __TCThread_h__