#ifndef SYNC_H
#define SYNC_H

#include <basic/queue.h>
#include <boost/thread.hpp>

namespace af {
namespace sync {

template<typename T>
struct queue
{
    // for convenient
    typedef typename af::basic::queue<T> container;

    struct monitor_t
    {
        monitor_t() : q_(0) {};
        monitor_t(monitor_t& m) : q_(m.q_) {}
        ~monitor_t() {}

        template<typename F>
        void operator()(F& f) const
        {
            boost::lock_guard<boost::mutex> lock(q_->m_);
            q_->c_.notify_one();
            f(q_->q_);
        }

    private:
        queue* q_;
        // for setting reference
        friend monitor_t queue::monitor();

    };

    queue() : q_() {}

    bool empty() const
    {
        boost::lock_guard<boost::mutex> lock(m_);
        return q_.empty();
    }

    size_t size() const
    {
        boost::lock_guard<boost::mutex> lock(m_);
        return q_.size();
    }

    bool pop(T& msg, unsigned int ms)
    {
        boost::system_time const timeout
            = boost::get_system_time()
            + boost::posix_time::milliseconds(ms);
        boost::unique_lock<boost::mutex> lock(m_);
        while( q_.empty())
        {
            if (!c_.timed_wait(lock, timeout))
                return false;
        }

        q_.pop(msg);
        return true;
    }

    // consumes msg and moves it into the queue
    void push(T& msg)
    {
        boost::lock_guard<boost::mutex> lock(m_);
        q_.push(msg);
        c_.notify_one();
    }

    void clear()
    {
        boost::lock_guard<boost::mutex> lock(m_);
        q_.clear();
    }

    monitor_t monitor()
    {
        monitor_t tmp;
        tmp.q_ = this;
        return tmp;
    }

    ~queue()
    {
        clear();
    }

private:

    // do not copy
    queue(queue const&);
    queue& operator=(queue const&);

    af::basic::queue<T> q_;
    mutable boost::mutex m_;
    boost::condition_variable c_;
};

}
}
