#ifndef INCLUDED_BOBCAT_IFDBUF_
#define INCLUDED_BOBCAT_IFDBUF_

#include <bobcat/eoibuf>

namespace FBB
{

class IFdBuf: public EoiBuf
{
    public:
            // Mode defines what to do with the file descriptor at
            // destruction-time or when the default open is
            // called. CLOSE_FD will close the fd, KEEP_FD will leave the
            // fd as-is. When open is called with a Mode argument, then
            // the provided argument is used for the actual fd. The Mode
            // specified at the constructor is therefore only used for the
            // mode-less open() call and for the destructor.
        enum Mode
        {
            CLOSE_FD,   // 0
            KEEP_FD,    // 1
        };

    private:
        Mode        d_mode;
        int         d_fd = -1;

    public:
        IFdBuf();                                     // 1
        IFdBuf(IFdBuf const &other) = delete;

        explicit IFdBuf(Mode mode);                   // 2
        explicit IFdBuf(int fd, size_t size = 1);     // 3
        IFdBuf(int fd, Mode mode, size_t size = 1);   // 4

        ~IFdBuf() override;

        IFdBuf &operator=(IFdBuf const &other) = delete;

        void reset(int xfd, Mode mode, size_t size = 1);        // .cc
        void reset(int xfd, size_t size = 1);                   // .f
        void close();                                           // .f
        int fd() const;                                         // .f
        Mode mode() const;                                      // .f

    protected:
        void cleanup(Mode mode);
        void setFd(int fd);                                     // .f
        int p_underflow();                                      // .f
        std::streamsize p_xsgetn(char *dest, std::streamsize n);   // .f

    private:
        int underflow() override;
        std::streamsize xsgetn(char *dest, std::streamsize n) override;
};

inline void IFdBuf::reset(int fd, size_t size)
{
    reset(fd, d_mode, size);
}
inline void IFdBuf::close()
{
    cleanup(CLOSE_FD);
}
inline int IFdBuf::fd() const
{
    return d_fd;
}
inline IFdBuf::Mode IFdBuf::mode() const
{
    return d_mode;
}
inline void IFdBuf::setFd(int fd)
{
    d_fd = fd;
}
inline int IFdBuf::p_underflow()
{
    return IFdBuf::underflow();
}
inline std::streamsize IFdBuf::p_xsgetn(char *dest, std::streamsize size)
{
    return IFdBuf::xsgetn(dest, size);
}

} // FBB

#endif
