/*! @file

    @id $Id$
*/
//       1         2         3         4         5         6         7         8
// 45678901234567890123456789012345678901234567890123456789012345678901234567890

#ifndef __MRW__IOMANIP__
#define __MRW__IOMANIP__

#include <stdexcept>
#include <sstream>
#include <string>
#include <iomanip>

// check if code is compiled with a new C++11 compiler
// otherwise there is a fallback wich makes everything much more compliacted
#ifndef MRW__OLD_PRE11_COMPILER
#if __cplusplus < 201103L
/// Code is compiled with an old non C++11 standard compliant compiler
/** There are workarounds for old non C++11 compatible
    compilers. These workarounds are deprecated, but will remain until
    most compilers fully support C++11. So this workaround will be
    removed in future releases, when support for C++11 is more
    common. Only rely on this workaround, if you really have to.
    @see oldcompiler for details on usage */
#define MRW__OLD_PRE11_COMPILER
#warning You need a C++11 compliant compiler, on gcc use option -std=c++11
#warning emulating C++11 - this changes the way you use the library
#warning this is deprecated and will be removed in future releases
#warning refere to the library documentation for more details
#endif
#endif


namespace mrw {
  //! IO-Manipulator to split long lines into several shorter lines.
  template <class _CharT = char, class _Traits = std::char_traits<_CharT> >
      class basic_split /*: public std::basic_ostream<_CharT, _Traits>*/ {
    public:
      basic_split(const basic_split& o):
          _width(o._width),
          _indent(o._indent),
          _fill(o._fill),
          _buffer(o._buffer.str()),
          _os(o._os) {
      }
      basic_split(int width=80, int indent=0, char fill=' '):
          _width(width), _indent(indent), _fill(fill), _os(0) {
        if (_width<_indent)
#ifdef MRW__OLD_PRE11_COMPILER
          throw std::runtime_error(((std::stringstream&)
                                    (std::stringstream()
                                     <<"wrong use of split: width is "<<_width
                                     <<" but should be larger than indent,"
                                     <<" which is "<<_indent)).str());
#else
        throw std::runtime_error("wrong use of split: width is "+
                                 std::to_string(_width)+
                                 " but should be larger than indent,"
                                 " which is "+std::to_string(_indent));
#endif
      }
      virtual ~basic_split() {
        flush();
      }
      friend basic_split& operator<<(std::basic_ostream<_CharT, _Traits>& os,
                                     const basic_split& s) {
        if (s._os!=&os) {
          const_cast<basic_split&>(s).flush();
          const_cast<basic_split&>(s)._os = &os;
        }
        return const_cast<basic_split&>(s);
      }
      template <typename T> basic_split& operator<<(const T& t) {
        if (!_os)
          throw std::runtime_error("wrong use of split, it is an io"
                                   " manipulator and must be used within"
                                   " a stream");
        _buffer<<t;
        while (_buffer.str().size()>=_width-_indent) {
          if (_indent) *_os<<std::setw(_indent)<<std::setfill(_fill)<<_fill;
          std::string::size_type pos
            (_buffer.str().find_last_of(' ', _width-_indent));
          std::string::size_type next(pos+1);
          if (pos==std::string::npos) {
            pos=_width-_indent;
            next=pos;
          }
          *_os<<_buffer.str().substr(0, pos)<<std::endl;
          _buffer.str(_buffer.str().substr(next));
        }
        return *this;
      }
    private:
      void flush() {
        if (_os) {
          if (_indent) *_os<<std::setw(_indent)<<std::setfill(_fill)<<_fill;
          *_os<<_buffer.str();
          _buffer.clear();
        }
      }
    private:
      int _width;
      int _indent;
      char _fill;
      std::stringstream _buffer;
      std::basic_ostream<_CharT, _Traits>* _os;
  };
  typedef basic_split<char> ssplit;
}
#endif
