#ifndef INCLUDED_BOBCAT_OMUTEXSTREAM_
#define INCLUDED_BOBCAT_OMUTEXSTREAM_

#include <ostream>
#include <mutex>

namespace FBB
{

class OMutexStream
{
    std::ostream &d_out;

    public:
        class Out;

        explicit OMutexStream(std::ostream &out);

        Out ostream() const;
};

class OMutexStream::Out: public std::ostream
{
    friend Out OMutexStream::ostream() const;

    template <typename Tp>
    friend Out operator<<(OMutexStream const &mstr, Tp &&tp);           // 1.f

    template <typename Ret>
    friend Out operator<<(OMutexStream const &mstr,                     // 2.f
                          Ret &(*manip)(Ret &os));

    static std::recursive_mutex s_mutex;

    public:
        ~Out();

    private:
        Out(OMutexStream const &mstr);              // 1.cc
        Out(Out &&tmp);                         // 2.f
};

inline OMutexStream::OMutexStream(std::ostream &out)
:
    d_out(out)
{}
inline OMutexStream::Out OMutexStream::ostream() const
{
    return OMutexStream::Out{ *this };
}
inline OMutexStream::Out::Out(Out &&tmp)
:
    std::ostream(tmp.rdbuf())
{}
template <typename Tp>
OMutexStream::Out operator<<(OMutexStream const &mstr, Tp &&tp)
{
    OMutexStream::Out out{ mstr };
    out << std::forward<Tp>(tp);
    return out;
}
template <typename Ret>
OMutexStream::Out operator<<(OMutexStream const &mstr, Ret &(*manip)(Ret &os))
{
    OMutexStream::Out out{ mstr };
    out << manip;
    return out;
}

}   // FBB

#endif
