#ifndef INCLUDED_BOBCAT_MEMORYBUF_
#define INCLUDED_BOBCAT_MEMORYBUF_

#include <ios>
#include <iosfwd>
#include <streambuf>

#include <bobcat/memorybridge>

namespace FBB
{
                                        // in memorybridge/memorybridge
class MemoryBuf: public std::streambuf
{
    enum Last
    {
        SEEK,
        READ,
        WRITE
    };

    Last d_last;                    // last requested action

    std::ios::openmode d_mode;

    MemoryBridge d_bridge;

    public:
        MemoryBuf();                                                    // 1

        MemoryBuf(MemoryBuf &&tmp);                                     // 2


        MemoryBuf(std::string const &bufSize, bool erase,              // 3
                std::ios::openmode openMode = std::ios::in | std::ios::out,
                size_t access = 0600);

        MemoryBuf(std::string const &bufSize,                           // .f
                std::ios::openmode openMode = std::ios::in | std::ios::out,
                size_t access = 0600);

        MemoryBuf(int id, bool erase,                                  // 4
                std::ios::openmode openMode = std::ios::in | std::ios::out);

        MemoryBuf(int id,                                               // .f
                std::ios::openmode openMode = std::ios::in | std::ios::out);

        ~MemoryBuf() override;

        MemoryBuf &operator=(MemoryBuf &&tmp);

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

        void info(std::ostream &out) const;                             // .f

        std::streamsize maxEnd() const;                                 // .f

        void setErase(bool erase);                                    // .f

        void swap(MemoryBuf &other);                                    // .f

        void truncate(std::streamsize size);                            // .f
        std::streamsize writtenUntil() const;                           // .f


    private:
        void noBuffers();
        std::streamsize getOffset();

        // all remaining members override

        int pbackfail(int ch)       override;
        std::streamsize showmanyc() override;

        int underflow()             override;
        int overflow(int ch)        override;

        std::streamsize xsgetn(char *buf, std::streamsize n)        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 MemoryBuf::MemoryBuf(std::string const &bufSize,
                            std::ios::openmode openMode, size_t access)
:
    MemoryBuf(bufSize, false, openMode, access)
{}


inline MemoryBuf::MemoryBuf(int id, std::ios::openmode openMode)
:
    MemoryBuf(id, false, openMode)
{}

inline int MemoryBuf::id() const
{
    return d_bridge.id();
}

inline void MemoryBuf::info(std::ostream &out) const
{
    d_bridge.info(out);
}

    // by X
inline std::streamsize MemoryBuf::maxEnd() const
{
    return d_bridge.maxEnd();
}

    // by memorystream/memorystream.f (setErase)
inline void MemoryBuf::setErase(bool erase)
{
    d_bridge.setErase(erase);
}

inline void MemoryBuf::truncate(std::streamsize size)
{
    d_bridge.truncate(size);
}

    // by sharedstream/writtenuntil.f
inline std::streamsize MemoryBuf::writtenUntil() const
{
    return d_bridge.writtenUntil();
}

} // FBB

#endif
