#ifndef __JLANG__JSTREAMOBJECTOUTPUT__
#define __JLANG__JSTREAMOBJECTOUTPUT__

#include <string>
#include <ostream>

#include "JLang/JObjectOutput.hh"
#include "JLang/JTypeList.hh"
#include "JLang/JNullType.hh"


/**
 * \author mdejong
 */

namespace JLANG {}
namespace JPP { using namespace JLANG; }

namespace JLANG {


  /**
   * Template implementation of stream output for single data type.
   *
   * This class implements the JLANG::JObjectOutput interface.
   */
  template<class T>
  class JStreamObjectOutput :
    public virtual JObjectOutput<T>
  {
  public:
    /**
     * Constructor.
     *
     * \param  out        output stream
     * \param  sep        token separator
     */
    JStreamObjectOutput(std::ostream&      out,
			const std::string& sep = "") :
      __out(out),
      __sep(sep)
    {}


    /**
     * Object output.
     *
     * \param  object     object
     * \return            true if OK; else false
     */
    virtual bool put(const T& object) override 
    {
      __out << object << __sep;

      return (bool) __out;
    }


    /**
     * Get token separator.
     *
     * \return            separator
     */
    const std::string& getSeparator() const
    {
      return this->__sep;
    }


    /**
     * Set token separator.
     *
     * \param sep         separator
     */
    void setSeparator(const std::string& sep)
    {
      this->__sep = sep;
    }

  private:
    std::ostream& __out;
    std::string   __sep;
  };


  /**
   * Template specialisationimplementation of stream object output for multiple data types.
   *
   * This class recursively implements the JLANG::JObjectOutput interface
   * for all data types by deriving from:
   *  - JStreamObjectOutput<JHead_t>; and 
   *  - JStreamObjectOutput<JTail_t>.
   */
  template<class JHead_t, class JTail_t>
  class JStreamObjectOutput< JTypeList<JHead_t, JTail_t> > :
    public virtual JObjectOutput< JTypeList<JHead_t, JTail_t> >,
    public JStreamObjectOutput<JHead_t>,
    public JStreamObjectOutput<JTail_t>

  {
  public:

    using JStreamObjectOutput<JHead_t>::put;
    using JStreamObjectOutput<JTail_t>::put;


    /**
     * Constructor.
     *
     * \param  out        output stream
     * \param  sep        token separator
     */
    JStreamObjectOutput(std::ostream&      out,
			const std::string& sep = "") :
      JStreamObjectOutput<JHead_t>(out, sep),
      JStreamObjectOutput<JTail_t>(out, sep)
    {}


    /**
     * Set token separator.
     *
     * \param sep         separator
     */
    void setSeparator(const std::string& sep)
    {
      JStreamObjectOutput<JHead_t>::setSeparator(sep);
      JStreamObjectOutput<JTail_t>::setSeparator(sep);
    }
  };


  /**
   * Terminator class of recursive JStreamObjectOutput class.
   */
  template<class JHead_t>
  class JStreamObjectOutput< JTypeList<JHead_t, JNullType> > :
    public JStreamObjectOutput<JHead_t>
  {
  public:

    using JStreamObjectOutput<JHead_t>::put;


    /**
     * Constructor.
     *
     * \param  out        output stream
     * \param  sep        token separator
     */
    JStreamObjectOutput(std::ostream&      out,
			const std::string& sep = "") :
      JStreamObjectOutput<JHead_t>(out, sep)
    {}
  };
}

#endif