#pragma once

#include <boost/atomic.hpp>

//TODO: Revise the locking mechanism to allow push and pop concurently

template<class T>
class ConcurrentQueue
{
public:
  typedef T value_type;
private:
  struct Node
  {
    Node(const value_type& val) : value(val), next(0) {}
    const value_type value;
    boost::atomic<Node *> next;
  };
  Node * m_first;
  Node * m_last;
  //boost::atomic<bool> m_readLock;
  boost::atomic<bool> m_writeLock;
public:
  ConcurrentQueue()
    : m_first(NULL), m_last(NULL), /*m_readLock(false),*/ m_writeLock(false)
  {
  }
  ~ConcurrentQueue()
  {
    while(m_first)
    {
      Node * tmp = m_first;
      m_first = tmp->next;
      delete tmp;
    }
  }

  void push(const value_type &val)
  {
    Node * tmp = new Node(val);
    while(m_writeLock.exchange(true)) {}
    if (m_last == NULL)
    {
      assert(m_first == NULL);
      m_first = m_last = tmp;
    }
    else
    {
      m_last->next = tmp;
      m_last = tmp;
    }
    m_writeLock = false;
  }
  bool try_pop(value_type &result)
  {
    //while(m_readLock.exchange(true)) {}
    while(m_writeLock.exchange(true)) {}

    if (m_first)
    {
      result = m_first->value;
      Node * next = m_first->next;
      delete m_first;
      m_first = next;
      if (m_first == NULL)
        m_last = NULL;
      //m_readLock = false;
      m_writeLock = false;
      return true;
    }
    else
    {
      //m_readLock = false;
      m_writeLock = false;
      return false;
    }

    //Node * first = m_first;
    //Node * next = m_first->next;
    //if(next)
    //{
    //  value_type val = next->value;
    //  next->value = 0;
    //  m_first = next;
    //  m_readLock = false;

    //  result = *val;
    //  delete val;
    //  delete first;
    //  return true;
    //}
    //m_readLock = false;
    //return false;
  }
};