// File: crn_threading_null.h
// See Copyright Notice and license at the end of include/crnlib.h
#pragma once

#include "crn_atomics.h"

namespace crnlib
{
   const uint g_number_of_processors = 1;
   
   inline void crn_threading_init()
   {
   }

   typedef uint64 crn_thread_id_t;
   inline crn_thread_id_t crn_get_current_thread_id()
   {
      return 0;
   }

   inline void crn_sleep(unsigned int milliseconds)
   {
      milliseconds;
   }

   inline uint crn_get_max_helper_threads()
   {
      return 0;
   }

   class mutex
   {
      CRNLIB_NO_COPY_OR_ASSIGNMENT_OP(mutex);

   public:
      inline mutex(unsigned int spin_count = 0)
      {
         spin_count;
      }

      inline ~mutex()
      {
      }

      inline void lock()
      {
      }

      inline void unlock()
      {
      }

      inline void set_spin_count(unsigned int count)
      {
         count;
      }
   };

   class scoped_mutex
   {
      scoped_mutex(const scoped_mutex&);
      scoped_mutex& operator= (const scoped_mutex&);

   public:
      inline scoped_mutex(mutex& lock) : m_lock(lock) { m_lock.lock(); }
      inline ~scoped_mutex() { m_lock.unlock(); }

   private:
      mutex& m_lock;
   };

    // Simple non-recursive spinlock.
   class spinlock
   {
   public:
      inline spinlock()
      {
      }

      inline void lock(uint32 max_spins = 4096, bool yielding = true, bool memoryBarrier = true)
      {
         max_spins, yielding, memoryBarrier;
      }

      inline void lock_no_barrier(uint32 max_spins = 4096, bool yielding = true)
      {
         max_spins, yielding;
      }

      inline void unlock()
      {
      }

      inline void unlock_no_barrier()
      {
      }
   };

   class scoped_spinlock
   {
      scoped_spinlock(const scoped_spinlock&);
      scoped_spinlock& operator= (const scoped_spinlock&);

   public:
      inline scoped_spinlock(spinlock& lock) : m_lock(lock) { m_lock.lock(); }
      inline ~scoped_spinlock() { m_lock.unlock(); }

   private:
      spinlock& m_lock;
   };

   class semaphore
   {
      CRNLIB_NO_COPY_OR_ASSIGNMENT_OP(semaphore);

   public:
      inline semaphore(long initialCount = 0, long maximumCount = 1, const char* pName = NULL)
      {
         initialCount, maximumCount, pName;
      }

      inline ~semaphore()
      {
      }

      inline void release(long releaseCount = 1, long *pPreviousCount = NULL)
      {
         releaseCount, pPreviousCount;
      }

      inline bool wait(uint32 milliseconds = cUINT32_MAX)
      {
         milliseconds;
         return true;
      }
   };

   class task_pool
   {
   public:
      inline task_pool() { }
      inline task_pool(uint num_threads) { num_threads; }
      inline ~task_pool() { }

      inline bool init(uint num_threads) { num_threads; return true; }
      inline void deinit() { }

      inline uint get_num_threads() const { return 0; }
      inline uint get_num_outstanding_tasks() const { return 0; }

      // C-style task callback
      typedef void (*task_callback_func)(uint64 data, void* pData_ptr);
      inline bool queue_task(task_callback_func pFunc, uint64 data = 0, void* pData_ptr = NULL)
      {
         pFunc(data, pData_ptr);
         return true;
      }

      class executable_task
      {
      public:
         virtual void execute_task(uint64 data, void* pData_ptr) = 0;
      };

      // It's the caller's responsibility to delete pObj within the execute_task() method, if needed!
      inline bool queue_task(executable_task* pObj, uint64 data = 0, void* pData_ptr = NULL)
      {
         pObj->execute_task(data, pData_ptr);
         return true;
      }

      template<typename S, typename T>
      inline bool queue_object_task(S* pObject, T pObject_method, uint64 data = 0, void* pData_ptr = NULL)
      {
         (pObject->*pObject_method)(data, pData_ptr);
         return true;
      }

      template<typename S, typename T>
      inline bool queue_multiple_object_tasks(S* pObject, T pObject_method, uint64 first_data, uint num_tasks, void* pData_ptr = NULL)
      {
         for (uint i = 0; i < num_tasks; i++)
         {
            (pObject->*pObject_method)(first_data + i, pData_ptr);
         }
         return true;
      }

      inline void join() { }
   };

} // namespace crnlib