#ifndef INCLUDED_BOBCAT_MULTIBUF_
#define INCLUDED_BOBCAT_MULTIBUF_

#include <streambuf>
#include <iosfwd>
#include <string>
#include <vector>

namespace FBB
{

struct MultiBuf: public std::streambuf
{
    enum Mode
    {
        OFF,                // Stream removed
        ON,                 // Stream used
        ONCE,               // Stream used until flushed, then Mode = RESET
        RESET,              // Stream not used. Set to ONCE to re-use once
        ALL,                // obsolete (since version 6.12.00)
    };

    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_ostrPtr;
        Mode          d_mode;

        public:
            std::ostream &ostream() const;
            Mode mode() const;                                      // 2.f

        private:
            Stream(std::ostream &os, Mode mode);                    // .f
    };

    using StreamVect = std::vector<Stream>;
    using const_iterator =  StreamVect::const_iterator;

    private:
        using iterator =  StreamVect::iterator;
        std::vector<Stream> d_os;

    public:
        // default seek_off/seek_pos are used, returning -1

        MultiBuf() = default;       // CC, MC, op=(C), op=(M): default

//        explicit MultiBuf(std::ostream &os, Mode mode = ON);        // 2.cc

        template <typename ...Ostreams>
        MultiBuf(std::ostream &ostr1,                               // 3.f
                 Ostreams &&...ostreams);

        template <typename ...Pairs>
        MultiBuf(std::ostream &ostr1, Mode mode,                    // 4.f
                 Pairs &&...pairs);

        virtual ~MultiBuf() override;           // only the vtable store

        const_iterator begin() const;                               // .f
        const_iterator end() const;                                 // .f

        void clear();

        void insert(std::ostream &os, Mode mode = ON);              // .cc

        Mode mode(std::ostream &str) const;                         // 1.cc

        bool remove(std::ostream &os);                              // 1.cc
        bool remove(size_t idx);                                    // 2.cc

        void reset(Mode mode);      // all streams' modes to 'mode'     1.cc 
        bool reset(std::ostream &out, Mode mode); // out's mode: 'mode' 2.cc

        void setOnce();                 // all `RESET' modes to `ONCE'  1.f
        bool setOnce(std::ostream &out);  // out's mode set to `ONCE'   2.f 
        bool setOnce(size_t idx);       // d_os[idx].mode = ONCE        3.cc 

        size_t size() const;                                        // .f
        StreamVect const &streamVect() const;                       // .f

    private:
        void addOstreams() const;                                   // 1.f

        template <typename ...Ostreams>                             // 2.f
        void addOstreams(std::ostream &os, Ostreams &&...ostreams);

        void addPairs() const;                                      // 1.f

        template <typename ...Pairs>                                // 2.f
        void addPairs(std::ostream &os, Mode modee, Pairs &&...pairs);

        Stream *find(std::ostream &out) const;

        std::streamsize write(char const *buffer, std::streamsize nChars);

        int overflow(int ch) override;
        std::streamsize xsputn(char const *buffer, 
                               std::streamsize nChars) override;
        int sync() override;
};

#include "multibuf3.f"
#include "addostreams1.f"
#include "addostreams2.f"

#include "multibuf4.f"
#include "addpairs1.f"
#include "addpairs2.f"

#include "clear.f"

#include "begin.f"
#include "end.f"
#include "streamvect.f"
#include "size.f"

#include "setonce1.f"
#include "setonce2.f"

#include "ostream.f"
#include "mode2.f"

} // namespace FBB

#endif




