#pragma once

#include "ConcurrentQueue.h"
#include <string>
#include <boost/thread.hpp>

template<class T>
class BackgroundWorker
{
public:
  typedef T task_type;
private:
  ConcurrentQueue<T> m_queue;
  volatile bool m_running;
  boost::thread m_thread;

  void run()
  {
    onStart();
    bool lastWasSuccessful = true;
    task_type val;
    while(m_running || lastWasSuccessful)
    {
      lastWasSuccessful = m_queue.try_pop(val);
      if(lastWasSuccessful)
        handle(val);
      Sleep(0);
    }
    onEnd();
  }
protected:
  BackgroundWorker() : m_running(true) {}
  
  void push(const task_type &val) 
  { 
    if(m_running)
      m_queue.push(val); 
  }
  virtual void onStart() {}
  virtual void onEnd() {}
  virtual void handle(const T &val) const = 0;
  bool isRunning() const { return m_running; }

  void start(const std::string &threadName)
  {
    if(!m_thread.joinable())
    {
      m_thread = boost::thread(&BackgroundWorker::run, this);
      HANDLE handle = m_thread.native_handle();
      SetThreadName(GetThreadId(handle), threadName);
    }
  }

  void stop()
  {
    m_running = false;
    if(m_thread.joinable())
    {
      m_thread.join();
    }
  }

  void clearQueue()
  {
    task_type val;
    while(m_queue.try_pop(val))
      handle(val);
  }
public:
  virtual ~BackgroundWorker()
  {
    stop();
  }
};