#ifndef INCLUDED_BOBCAT_TABLE_
#define INCLUDED_BOBCAT_TABLE_

#include <sstream>

#include <bobcat/tablebase>

namespace FBB
{

class Table: public TableBase, public std::ostringstream
{
    template <typename Type>
    friend Table &operator<<(Table &table, Type const &ref);

    public:
                                        // required for push_back()
        using value_type =  std::string;
        using const_reference  =  Element const &;

        Table(size_t nColumns, FillDirection direction,             // 0
                                WidthType widthType = COLUMNWIDTH);

        Table(TableSupport &tableSupport,                           // 1
                size_t nColumns, FillDirection direction,
                WidthType widthType = COLUMNWIDTH);

        Table(Table const &other) = delete;
        Table &operator=(Table const &other) = delete;

        Table &append(std::string const &str, char const *sep = " \t",
                            bool addEmpty = false);

        template <typename InputIterator>
        void fill(InputIterator begin, InputIterator end);              // .f

        void push_back(Element const &element); // add an element to       .f
                                                // the table, using the
                                                // default alignment.

        Table &setAlign(Align const &align);    // set an alignment        .f

        Table &def();                   // fillup an incomplete table      .f
                                        // automatically at insertions

        using TableBase::clear;
        void clearStr();                // clear the ostringstream part    .f

    private:
        Table &flush();                     // insert the text currently
                                            // inserted into the Table object
                                            // as ostringstream into the table
};

inline void Table::clearStr()
{
    std::ostringstream::clear();
}
inline Table &Table::def()
{
    TableBase::def();
    return *this;
}
template <typename Iter>
void Table::fill(Iter it, Iter end)
{
    TableBase::clear();

    while (it != end)
    {
        std::ostringstream str;
        str << *it++;
        push_back(str.str());
    }
}
inline void Table::push_back(Element const &element)
{
    d_tabulated = false;
    d_string.push_back(element);
}
inline Table &Table::setAlign(Align const &align)
{
    TableBase::setAlign(align);
    return *this;
}

    // Free Functions

                        // Insert column or element alignments
inline Table &operator<<(Table &tab, Align const &align)
{
    return tab.setAlign(align);
}

inline Table &def(Table &table)
{
    return table.def();
}

                        // For def
inline Table &operator<<(Table &table, Table &(*fun)(Table &))
{
    return (*fun)(table);
}

                        // Insert any other insertable type into a Table
template <typename Type>    // Insert any other insertable type into a Table
Table &operator<<(Table &table, Type const &ref)
{
    reinterpret_cast<std::ostringstream &>(table) << ref;
    return table.flush();
}

} // FBB



#endif
