#ifndef INCLUDED_BOBCAT_MULTIBUF_
#define INCLUDED_BOBCAT_MULTIBUF_

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

namespace FBB
{

struct MultiBuf: public std::streambuf
{
    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
        ALL,                // with remove: remove all ostreams matching os
    };

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

        std::ostream *d_os;
        Mode          d_mode;

        public:
            stream(std::ostream &os, Mode mode = ON);   // 1.f
            void setMode(Mode mode);                    // .f
            Mode mode() const;                          // .f
            std::ostream &ostream();                    // .f
        private:
            static void setOnce(stream &os);            // .f
    };

    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:
        MultiBuf()    = default;
        explicit MultiBuf(std::ostream &os, Mode mode = ON);      // 1.f
        explicit MultiBuf(std::vector<stream> const &osvector);   // 2.f

        void insert(std::ostream &os, Mode mode = ON);                  // 1.f
        void insert(std::vector<stream> const &os);                     // 2.f

        bool remove(std::ostream &os, Mode mode = ONCE);

        iterator begin();                                               // 1.f
        iterator end();                                                 // 1.f
        const_iterator begin() const;                                   // 2.f
        const_iterator end() const;                                     // 2.f
        size_t size() const;                                            //  .f
        void setOnce();             // reset all `RESET' modes to `ONCE'
        
    private:
        int overflow(int c) override;
        std::streamsize xsputn(char const *buffer, std::streamsize n) 
                                                                override;
        int sync() override;

        struct Insert;

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

#include "mode.f"
#include "ostream.f"
#include "setmode.f"
#include "setonce.f"
#include "stream1.f"

#include "multibuf1.f"
#include "multibuf2.f"

#include "begin1.f"
#include "begin2.f"
#include "end1.f"
#include "end2.f"
#include "insert1.f"
#include "insert2.f"

} // namespace FBB
        
#endif
