#ifndef _LuceneThreads_h
#define  _LuceneThreads_h
#if defined(_LUCENE_PRAGMA_ONCE)
# pragma once
#endif

CL_NS_DEF(util)
#if defined(_CL_DISABLE_MULTITHREADING)
  #define SCOPED_LOCK_MUTEX(theMutex)
  #define SCOPED_LOCK_MUTEX_EX(theMutex,mutexname,dummy)

  #define DEFINE_MUTEX(x)
  #define STATIC_DEFINE_MUTEX(x)
#else //_CL_DISABLE_MULTITHREADING

#if defined(_LUCENE_THREADMUTEX)
   //do nothing

#elif defined(LUCENE_THREAD_HACK) //LUCENE_THREAD_HACK
   ///a lock mutex hack
   class mutex_default{
	private:
		int locked;
		_LUCENE_THREADID_TYPE threadId;
	public:
	  mutex_default(const mutex_default& clone){
         locked=0; 
		 threadId=0;
	  }
      mutex_default(){	
         locked=0; 
		 threadId=0;
      }
      ~mutex_default(){
      }
      void lock(){
		  _LUCENE_THREADID_TYPE id = _LUCENE_CURRTHREADID;
		  if ( this->threadId == id ){
			locked++;
		  }else{
			while ( locked>0 )
				_sleep(1);
			this->threadId = id;
			locked=1; //wait till unlocked, then lock
		  }
      }
      void unlock(){
#if defined(_DEBUG)
         if ( locked > 0 ){
			if ( locked == 1 )
				this->threadId = 0;
            locked--;
         } else
            _CLTHROWA(CL_ERR_Runtime, "Mutex wasn't locked");
# else
			if ( locked == 1 )
				this->threadId = 0;
            locked--;
# endif // _DEBUG
      }
   };
   #define _LUCENE_THREADMUTEX CL_NS(util)::mutex_default
   #define _LUCENE_THREADMUTEX_USINGDEFAULT
   
#elif defined(_CLCOMPILER_MSVC) || defined(__MINGW32__)
   #if !defined(LUCENE_USE_WINDOWS_H) && !defined(_WINDOWS_)
      //we have not explicity included windows.h and windows.h has
      //not been included (check _WINDOWS_), then we must define
      //our own definitions to the thread locking functions:
      struct CRITICAL_SECTION
      {
         struct critical_section_debug * DebugInfo;
         long LockCount;
         long RecursionCount;
         void * OwningThread;
         void * LockSemaphore;
      #if defined(_WIN64)
         unsigned __int64 SpinCount;
      #else
         unsigned long SpinCount;
      #endif
      };

      extern "C" __declspec(dllimport) void __stdcall InitializeCriticalSection(CRITICAL_SECTION *);
      extern "C" __declspec(dllimport) void __stdcall EnterCriticalSection(CRITICAL_SECTION *);
      extern "C" __declspec(dllimport) void __stdcall LeaveCriticalSection(CRITICAL_SECTION *);
      extern "C" __declspec(dllimport) void __stdcall DeleteCriticalSection(CRITICAL_SECTION *);
	  extern "C" __declspec(dllimport) unsigned long __stdcall GetCurrentThreadId();
   #endif

   ///a windows implementation of the lock mutex
   ///todo: boost has a InterlockedExchange way of locking too. More backwards compatible/faster???
   class mutex_win32
   {
   private:
      CRITICAL_SECTION mtx;
   public:
	  mutex_win32(const mutex_win32& clone){
		  InitializeCriticalSection(&mtx); 
	  }
      mutex_win32()
      { InitializeCriticalSection(&mtx); }

      ~mutex_win32()
      { DeleteCriticalSection(&mtx); }

      void lock()
      { EnterCriticalSection(&mtx); }

      void unlock()
      { LeaveCriticalSection(&mtx); }
   };
   #define _LUCENE_THREADMUTEX CL_NS(util)::mutex_win32

#elif defined(_CL_HAVE_PTHREAD) && defined(_POSIX_THREADS) && (_POSIX_THREADS+0 >= 0)
   #include <pthread.h>
   ///a posix implementation of the lock mutex
   ///todo: boost also has a 'spinlock' mutex which uses atomic_t
   ///might this be faster, or more x-platform?
   class mutex_pthread
   {
   private:
      pthread_mutex_t mtx;
   public:
	  mutex_pthread(const mutex_pthread& clone){
      	#if defined(__hpux) && defined(_DECTHREADS_)
			pthread_mutex_init(&mtx, pthread_mutexattr_default);
		#else
			pthread_mutex_init(&mtx, 0); 
		#endif
	  }
      mutex_pthread()
      { 
      	#if defined(__hpux) && defined(_DECTHREADS_)
			pthread_mutex_init(&mtx, pthread_mutexattr_default);
		#else
			pthread_mutex_init(&mtx, 0); 
		#endif	
	  }

      ~mutex_pthread()
      { pthread_mutex_destroy(&mtx); }

      void lock()
      { pthread_mutex_lock(&mtx); }

      void unlock()
      { pthread_mutex_unlock(&mtx); }
   };
   #define _LUCENE_THREADMUTEX CL_NS(util)::mutex_pthread

#else
	Cannot implements threads... cannot continue
#endif //mutex types

class mutexGuard
{
private:
    _LUCENE_THREADMUTEX& mrMutex;
	bool dummy;
public:
  mutexGuard( _LUCENE_THREADMUTEX& rMutex, bool dummy=false ) :
    mrMutex(rMutex)
  {
	  this->dummy = dummy;
	  if ( !dummy )
		mrMutex.lock();
  }
  ~mutexGuard()
  {
    if ( !dummy )
		mrMutex.unlock();
  }
};

# define SCOPED_LOCK_MUTEX(theMutex) CL_NS(util)::mutexGuard theMutexGuard(theMutex);
# define SCOPED_LOCK_MUTEX_EX(theMutex,mutexname,dummy) CL_NS(util)::mutexGuard mutexname(theMutex,dummy);

# define DEFINE_MUTEX(theMutex) _LUCENE_THREADMUTEX theMutex;
# define STATIC_DEFINE_MUTEX(theMutex) static _LUCENE_THREADMUTEX theMutex;

#endif //_CL_DISABLE_MULTITHREADING


CL_NS_END

#endif
