#ifndef INCLUDED_BOBCAT_SHAREDPOS_
#define INCLUDED_BOBCAT_SHAREDPOS_

#include <iosfwd>
#include <ios>

#include <bobcat/sharedsegment>
#include <bobcat/exception>

namespace FBB
{

class SharedPos
{
    friend std::ostream &operator<<(std::ostream &out, SharedPos const &pos);

    SharedSegment *d_sharedData = 0;       // setup must have been called to
                                        // initialize data members

    std::streamsize d_maxOffset = 0;    // max. possible offset, given nBlocks

    std::streamsize d_offset = 0;       // next location to write

    size_t d_blockIdx = 0;
    size_t d_blockOffset = 0;

    public:
        bool atMaxOffset() const;

        size_t blockIdx() const;

        size_t blockOffset() const;

        bool eof() const;               // true if no char can be read
                                        // because offset >= writeoffset

        std::streamsize eos() const;        // abs. offset just past
                                            // block[blockIdx()]

        std::streamsize maxOffset() const;  // abs. max. possible offset

        std::streamsize offset() const;     // current abs. offset

        void reset(SharedSegment *sharedData);

                                                // returns -1 if inaccessible
        std::ios::pos_type seek(std::ios::off_type offset,
                                std::ios::seekdir way = std::ios::beg);

        std::streamsize showmanyc() const;

        void operator++();              // caller must have locked the shared
                                        // data
        void operator+=(size_t len);    // caller must have locked the shared
                                        // data
    private:
        std::ostream &insert(std::ostream &out) const;

        size_t segmentSize() const;

        void update();
        std::streamsize nReadable() const;
};

inline bool SharedPos::atMaxOffset() const
{
    return d_offset == d_maxOffset;
}
inline size_t SharedPos::blockIdx() const
{
    return d_blockIdx;
}
inline size_t SharedPos::blockOffset() const
{
    return d_blockOffset;
}
inline bool SharedPos::eof() const
{
    return d_offset >= d_sharedData->nReadable();
}
inline std::streamsize SharedPos::eos() const
{
    return static_cast<std::streamsize>(blockIdx() + 1) * segmentSize();
}
inline std::streamsize SharedPos::maxOffset() const
{
    return d_maxOffset;
}
inline std::streamsize SharedPos::nReadable() const
{
    return d_sharedData->nReadable();
}
inline std::streamsize SharedPos::offset() const
{
    return d_offset;
}
inline std::ostream &operator<<(std::ostream &out, SharedPos const &sharedPos)
{
    return sharedPos.insert(out);
}
inline size_t SharedPos::segmentSize() const
{
    return d_sharedData->segmentSize();
}

} // FBB
#endif
