#ifndef INCLUDED_BOBCAT_SHAREDBUF_
#define INCLUDED_BOBCAT_SHAREDBUF_

#include <ios>
#include <streambuf>

#include <bobcat/sharedmemory>
#include <bobcat/sharedcondition>

namespace FBB
{

class SharedBuf: public std::streambuf, public virtual SharedEnum__
{
    std::ios::openmode d_openMode;
    std::ios::openmode d_currentMode;       // initially openMode, thereafter
                                            // either ::in or ::out
    SharedMemory d_memory;

    public:
        SharedBuf();                                      // 1

        SharedBuf(
                size_t maxSize, SizeUnit sizeUnit,              // 2
                std::ios::openmode openMode = std::ios::in | std::ios::out,
                size_t access = 0600);

        SharedBuf(                                        // 3
                int id,
                std::ios::openmode openMode = std::ios::in | std::ios::out);

        void clear();                   // clear all existing data and reduce
                                        // until only the segment at
                                        // d_sharedData

        int id() const;                 // id of the shared Memory segment

        void kill();                    // kill all shared segments w/o locks
                                        // the object is unusable hereafter

        void memInfo(std::ostream &out) const;

        void remove();                  // remove all shared segments.
                                        // the object is unusable hereafter

        void setMemory(SharedMemory &&tmp);

    protected:
        SharedCondition attachSharedCondition(std::ios::off_type offset = 0,
                        std::ios::seekdir way = std::ios::beg);
        SharedCondition createSharedCondition();
        void setOpenMode(std::ios::openmode openMode);
        SharedMemory &sharedMemory();

    private:
        bool mode(std::ios::openmode flag);

        int pbackfail(int ch) override;
        std::streamsize showmanyc() override;
        int underflow() override;
        std::streamsize xsgetn(char *buf, std::streamsize n) override;

        int overflow(int c) override;
        std::streamsize xsputn(char const *buf, std::streamsize n) override;

        std::ios::pos_type seekoff(
            std::ios::off_type offset,
            std::ios::seekdir way = std::ios::beg,
            std::ios::openmode mode = std::ios::in | std::ios::out) override;

        std::ios::pos_type seekpos(
            std::ios::pos_type offset,
            std::ios::openmode mode = std::ios::in | std::ios::out) override;
};

inline void SharedBuf::clear()
{
    d_memory.clear();
}
inline int SharedBuf::id() const
{
    return d_memory.id();
}
inline void SharedBuf::kill()
{
    d_memory.kill();
}
inline void SharedBuf::memInfo(std::ostream &out) const
{
    out << d_memory;
}
inline void SharedBuf::remove()
{
    d_memory.remove();
}
inline void SharedBuf::setMemory(SharedMemory &&tmp)
{
    d_memory = std::move(tmp);
}
inline void SharedBuf::setOpenMode(std::ios::openmode openMode)
{
    d_openMode = openMode;
    d_currentMode = openMode;
}
inline SharedMemory &SharedBuf::sharedMemory()
{
    return d_memory;
}

} // FBB
#endif
