#ifndef __JIO__JWRITEROBJECTITERATOR__
#define __JIO__JWRITEROBJECTITERATOR__

#include "JLang/JObjectOutput.hh"
#include "JLang/JTypeList.hh"
#include "JLang/JNullType.hh"
#include "JLang/JConversion.hh"
#include "JLang/JBool.hh"
#include "JIO/JSerialisable.hh"


/**
 * \author mdejong
 */

namespace JIO {}
namespace JPP { using namespace JIO; }

namespace JIO {

  using JLANG::JObjectOutput;
  using JLANG::JTypeList;
  using JLANG::JNullType;


  /**
   * Implementation of object output using JIO::JWriter for single data type.
   *
   * This class implements the JLANG::JObjectOutput interface.
   */
  template<class T>
  class JWriterObjectOutput :
    public virtual JObjectOutput<T>
  {
  public:
    /**
     * Constructor.
     *
     * \param  writer     writer output
     */
    JWriterObjectOutput(JWriter& writer) :
      out(writer)
    {}


    /**
     * Object output.
     *
     * \param  object     object
     * \return            true if OK; else false
     */
    virtual bool put(const T& object) override 
    {
      return put(object, JLANG::JBool<JLANG::JConversion<T,JSerialisable>::is_derived>());
    }

  private:
    bool put(const T& object, JLANG::JBool<true>)  { return (bool) object.write(out); }
    bool put(const T& object, JLANG::JBool<false>) { return (bool) (out << object); }

    JWriter& out;
  };


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

  {
  public:
    /**
     * Constructor.
     *
     * \param  writer     writer output
     */
    JWriterObjectOutput(JWriter& writer) :
      JWriterObjectOutput<JHead_t>(writer),
      JWriterObjectOutput<JTail_t>(writer)
    {}
  };


  /**
   * Terminator class of recursive JWriterObjectOutput class.
   */
  template<class JHead_t>
  class JWriterObjectOutput< JTypeList<JHead_t, JNullType> > :
    public JWriterObjectOutput<JHead_t>
  {
  public:
    /**
     * Constructor.
     *
     * \param  writer     writer output
     */
    JWriterObjectOutput(JWriter& writer) :
      JWriterObjectOutput<JHead_t>(writer)
    {}
  };
}

#endif