#ifndef _INCLUDED_BOBCAT_IFDSTREAMBUF_
#define _INCLUDED_BOBCAT_IFDSTREAMBUF_

#include <streambuf>

namespace FBB
{    
    class IFdStreambuf: public std::streambuf
    {
        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,
                KEEP_FD,
            };

        private:
            Mode        d_mode;
            int         d_fd;
            size_t    d_n;
            char*       d_buffer;

        public:
            IFdStreambuf();
            IFdStreambuf(Mode mode);
            IFdStreambuf(int fd, size_t n = 1);
            IFdStreambuf(int fd, Mode mode, size_t n = 1);

            ~IFdStreambuf();

            void open(int xfd, Mode mode, size_t n = 1);
            void open(int xfd, size_t n = 1);
            virtual int underflow();
            virtual std::streamsize xsgetn(char *dest, std::streamsize n);

        private:
            IFdStreambuf(IFdStreambuf const &other);              // NI
            IFdStreambuf &operator=(IFdStreambuf const &other);   // NI

            void cleanup(Mode mode);
    };

inline IFdStreambuf::IFdStreambuf()
:
    d_mode(KEEP_FD),         // comply with old default
    d_n(0),
    d_buffer(0)
{}

inline IFdStreambuf::IFdStreambuf(Mode mode)
:
    d_mode(mode),
    d_n(0),
    d_buffer(0)
{}

inline IFdStreambuf::IFdStreambuf(int fd, size_t n)
:
    d_mode(KEEP_FD),        // comply with old default
    d_buffer(0)
{
    open(fd, KEEP_FD, n);
}

inline IFdStreambuf::IFdStreambuf(int fd, Mode mode, size_t n)
:
    d_mode(mode),
    d_buffer(0)
{
    open(fd, KEEP_FD, n);
}

inline IFdStreambuf::~IFdStreambuf()
{
    cleanup(d_mode);
}

inline void IFdStreambuf::open(int xfd, size_t n)
{
    open(xfd, d_mode, n);
}

} // FBB

#endif
