#ifndef _INCLUDED_BOBCAT_MULTISTREAMBUF_
#define _INCLUDED_BOBCAT_MULTISTREAMBUF_

#include <streambuf>
#include <vector>
#include <ostream>
#include <string>

namespace FBB
{

class MultiStreambuf: public std::streambuf
{
    public:
        enum Mode
        {
            OFF,                // stream not used
            ON,                 // stream always used
            ONCE,               // stream used until flushed
            RESET,              // stream once used. Set to ONCE to re-use
        };

        class stream            // holds a pointer to a stream and a indicator
        {                       // telling us whether or not to use the stream
            friend class MultiStreambuf;

            std::ostream *d_os;
            Mode          d_mode;

            public:
                stream(std::ostream &os, Mode mode = ON)
                :
                    d_os(&os),
                    d_mode(mode)
                {}
                void setMode(Mode mode)
                {
                    d_mode = mode;
                }
                Mode mode() const
                {
                    return d_mode;
                }
                std::ostream &ostream()
                {
                    return *d_os;
                }
            private:
                static void setOnce(stream &os)
                {
                    if (os.d_mode == RESET)
                        os.d_mode = ONCE;
                }
        };

        typedef std::vector<stream>::iterator iterator;
        typedef std::vector<stream>::const_iterator const_iterator;

    private:
        std::string d_buffer;
        std::vector<stream> d_os;

    public:
        MultiStreambuf()
        {}
        MultiStreambuf(std::ostream &os, Mode mode = ON)
        {
            insert(os, mode);
        }
        MultiStreambuf(std::vector<stream> const &osvector)
        {
            insert(osvector);
        }

        void insert(std::ostream &os, Mode mode = ON)
        {
            d_os.push_back(stream(os, mode));
        }
        void insert(std::vector<stream> const &os)
        {
            d_os.insert(d_os.end(), os.begin(), os.end());
        }
        iterator begin()
        {
            return d_os.begin();
        }
        iterator end()
        {
            return d_os.end();
        }
        const_iterator begin() const
        {
            return d_os.begin();
        }
        const_iterator end() const
        {
            return d_os.end();
        }

        void setOnce();             // reset all `RESET' modes to `ONCE'
        
    protected:
        virtual int overflow(int c)
        {
            if (c == EOF)
                sync();
            else 
                d_buffer += c;

            return c;
        }

        virtual std::streamsize xsputn(char const *buffer, std::streamsize n)
        {
            d_buffer.append(buffer, n);
            return n;
        }

        virtual int sync();

    private:
        struct Insert
        {
            std::string &buffer;
            bool ok;
        };

        static void insert(stream &os, Insert &insert); 
};


} // namespace FBB
        
#endif
