#ifndef LM_MUTEX
#define LM_MUTEX

#ifdef WIN32
#include <winsock2.h>
#include <windows.h>
#else
#include <pthread.h>
#endif

/**
 * Simple crossplatform mutex implementation
 */
class Mutex
{
public:
    Mutex(bool autolock = false) : autolock_(autolock)
    {
        init();
        if (autolock_) lock();
    }
   
    virtual ~Mutex()
    {
        if (autolock_) unlock();
        destroy();
    }
    
   
protected:
#ifdef WIN32
    PCRITICAL_SECTION mutex;
#else
    pthread_mutex_t *mutex;
#endif
    
private:
    /**
     * Asignment operator and copy constructur are deprecated. Therefore it is in private section
     */
    Mutex& operator=(const Mutex& m){return *this;}
    Mutex(const Mutex& m){}
    
    void init()
    {
#ifdef WIN32
        mutex = new CRITICAL_SECTION;
        InitializeCriticalSection(mutex); 
#else
        mutex = new pthread_mutex_t;
        pthread_mutexattr_t attr;
        pthread_mutexattr_init(&attr);
        pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
        pthread_mutex_init(mutex, &attr);
#endif
    }
    
    void destroy()
    {
#ifdef WIN32
        DeleteCriticalSection(mutex); 
        delete mutex;
#else
        pthread_mutex_destroy(mutex);
        delete mutex;
#endif
    }
    
    bool autolock_;
    
public:
    void lock()
    { 
#ifdef WIN32
        EnterCriticalSection(mutex);
#else
        pthread_mutex_lock(mutex);
#endif
    }
    
    void unlock()
    {
#ifdef WIN32
        LeaveCriticalSection(mutex);
#else
        pthread_mutex_unlock(mutex);
#endif
    }
    
};


class Cond: public Mutex
{
public:
    Cond() :Mutex() 
    {
#ifdef WIN32
       // Create an auto-reset event.
       event = CreateEvent (NULL,  // no security
                            FALSE, // auto-reset event
                            FALSE, // non-signaled initially
                            NULL); // unnamed
#else
        pthread_cond_init(&cond, NULL);
#endif
    }
    
    virtual ~Cond()
    {
#ifdef WIN32
        CloseHandle(event);
#else
        pthread_cond_destroy(&cond);
#endif
    }
    
    void signal()
    {
#ifdef WIN32
       PulseEvent(event);
#else
       pthread_cond_signal(&cond);
#endif
    }
    
    void wait()
    {
#ifdef WIN32
       LeaveCriticalSection(mutex);
       WaitForSingleObject(event,
                           INFINITE); // Wait "forever"

       // Reacquire the mutex before returning.
       EnterCriticalSection (mutex);
#else
        pthread_cond_wait(&cond, mutex);
#endif
     
    }
    
private:
#ifdef WIN32
      HANDLE event;
#else
      pthread_cond_t cond;
#endif    
};


class MutexGuard
{
public:
   MutexGuard(Mutex &mutex) : mutex_(mutex), locked_(false)
   {
      acquire();
   }

   ~MutexGuard()
   {
      release();
   }


   void acquire()
   {
      locked_ = true;
      mutex_.lock();
   }

   void release()
   {
      if (locked_)
      {
         locked_ = false;
         mutex_.unlock();
      }
   }

private:
    Mutex &mutex_;
    bool locked_;
};


#endif /* MUTEX */


