#ifndef INCLUDED_BOBCAT_READLINEBUF_
#define INCLUDED_BOBCAT_READLINEBUF_

#include <string>
#include <streambuf>
#include <memory>

namespace FBB
{

struct HistoryExpansion
{
    enum Type
    {
        DONT_EXPAND_HISTORY,
        EXPAND_HISTORY
    };
    enum Expansion
    {
        ERROR,
        NO_EXPANSION,
        EXPANDED,
        DONT_EXEC,
    };
};


class ReadLineBuf: public HistoryExpansion, public std::streambuf
{
    bool d_history;
    std::string d_prompt;
    std::string d_buffer;

    size_t (ReadLineBuf::*d_readline)();// calls readLine() or expandLine()
    std::string (*d_timestamp)();       // return a timestamp

    Expansion d_expansion;
    std::string d_expansionError;

    static std::unique_ptr<ReadLineBuf> s_readLineBuf;

    public:
        static ReadLineBuf &initialize(std::string const &prompt,
                                       Type type = DONT_EXPAND_HISTORY);
        static ReadLineBuf &initialize(std::string const &prompt,
                             size_t historySize,
                             Type type = DONT_EXPAND_HISTORY);
        static ReadLineBuf &instance();


        ~ReadLineBuf() override;

        void setPrompt(std::string const &prompt = "");             // .f
        bool setExpansion(Type type);

        Expansion expansion() const;                                // .f
        std::string const &expansionError() const;                  // .f

        bool useTimestamps(std::string (*timestamp)() = 0);

        size_t readLine();          // reads a line, adds it to the history

    private:
        explicit ReadLineBuf(std::string const &prompt,
                             Type type = DONT_EXPAND_HISTORY);
        explicit ReadLineBuf(std::string const &prompt,
                             size_t historySize,
                             Type type = DONT_EXPAND_HISTORY);

        int underflow() override;

//        size_t readLine();          // reads a line, adds it to the history
        size_t expandLine();        // reads a line, expands it if necessary,
                                    // then adds it to the history
        size_t nextLine(char *buf);
};

inline void ReadLineBuf::setPrompt(std::string const &prompt)
{
    d_prompt = prompt;
}
inline ReadLineBuf::Expansion ReadLineBuf::expansion() const
{
    return d_expansion;
}
inline std::string const &ReadLineBuf::expansionError() const
{
    return d_expansionError;
}

} // FBB
#endif
