/*
 * thread_safe_queue.h
 *
 *  Created on: 13 Oct 2014
 *      Author: stephan
 */

#ifndef THREAD_SAFE_QUEUE_H_
#define THREAD_SAFE_QUEUE_H_

#include <queue>
#include <mutex>
#include <condition_variable>

/**
 * Class provides a queue object which can be used by multiple threads at once,
 * mutexes will ensure that only one thread can access the queue at a time.
 *
 * Queue supplies access to 2 queues
 *
 * 1) unsigned char data
 * 2) length of the data packet in queue (1)
 */
class ThreadSafeQueue
{
  public:
    ThreadSafeQueue() :
        m_data_queue(), m_length_queue(), m_mutex(), m_conditional() {
    }

    void push(unsigned char* _msg, int _len) {
      std::lock_guard<std::mutex> lock(m_mutex);
      m_data_queue.push(_msg);
      m_length_queue.push(_len);
      m_conditional.notify_one();
    }

    unsigned char* front(int* len_) {
      std::unique_lock<std::mutex> lock(m_mutex);
      while (m_data_queue.empty()) {
        m_conditional.wait(lock);
      }
      *len_ = m_length_queue.front();
      return m_data_queue.front();
    }

    void pop() {
      std::unique_lock<std::mutex> lock(m_mutex);
      while (m_data_queue.empty()) {
        m_conditional.wait(lock);
      }
      unsigned char* data = m_data_queue.front();
      m_data_queue.pop();
      delete[] data;
      m_length_queue.pop();
    }

    void unlock() {
      this->push(new unsigned char[10] { { 0x00 } }, -1);
    }

    ~ThreadSafeQueue() {
      while (!m_data_queue.empty()) {
        this->pop();
      }
    }

  private:
    std::queue<unsigned char*> m_data_queue;
    std::queue<int> m_length_queue;
    std::mutex m_mutex;
    std::condition_variable m_conditional;
};
#endif

/* THREAD_SAFE_QUEUE_H_ */
