#ifndef __JROOT__JTREEWRITEROBJECTOUTPUT__
#define __JROOT__JTREEWRITEROBJECTOUTPUT__

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


/**
 * \author mdejong
 */

namespace JROOT {}
namespace JPP { using namespace JROOT; }

namespace JROOT {

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


  /**
   * JTreeWriter object output.
   *
   * This class implements the JLANG::JObjectOutput interface.
   */
  template<class T>
  class JTreeWriterObjectOutput :
    public virtual JObjectOutput<T>
  {
  protected:
    /**
     * Default constructor.
     */
    JTreeWriterObjectOutput() :
      out(new JTreeWriter<T>(getTreeParameters<T>())),
      del(true)
    {}


    /**
     * Destructor.
     */
    ~JTreeWriterObjectOutput()
    {
      if (del) {
	delete out;
      }
    }


    /**
     * Set directory.
     *
     * \param  dir        pointer to directory
     */
    void SetDirectory(TDirectory* dir)
    {
      out->SetDirectory(dir);

      del = (dir == NULL);
    }


    JTreeWriter<T>* out;
    bool            del;  // delete TTree on destruction 

  public:
    /**
     * Get TreeWriter.
     *
     * \return            TreeWriter
     */
    JTreeWriter<T>& getTreeWriter() 
    {
      return *out;
    }


    /**
     * Object output.
     *
     * \param  object     object
     * \return            true if OK; else false
     */
    virtual bool put(const T& object) override 
    {
      return (out->Write(object) > 0);
    }


    /**
     * Set circular buffer size.
     *
     * \param  size       number of entries
     */
    void SetCircular(Long64_t size)
    {
      out->SetCircular(size);
    }


    /**
     * Reset TTree.
     */
    void Reset()
    {
      out->Reset();
    }

  private:
    JTreeWriterObjectOutput(const JTreeWriterObjectOutput&);
    JTreeWriterObjectOutput(JTreeWriterObjectOutput&&);
    JTreeWriterObjectOutput& operator=(const JTreeWriterObjectOutput&);
    JTreeWriterObjectOutput& operator=(JTreeWriterObjectOutput&&);
  };


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

  {
  protected:
    /**
     * Set directory.
     *
     * \param  dir        pointer to directory
     */
    void SetDirectory(TDirectory* dir)
    {
      JTreeWriterObjectOutput<JHead_t>::SetDirectory(dir);
      JTreeWriterObjectOutput<JTail_t>::SetDirectory(dir);
    }

  public:
    using JTreeWriterObjectOutput<JHead_t>::put;
    using JTreeWriterObjectOutput<JTail_t>::put;    

    /**
     * Set circular buffer size.
     *
     * \param  size       number of entries
     */
    void SetCircular(Long64_t size)
    {
      JTreeWriterObjectOutput<JHead_t>::SetCircular(size);
      JTreeWriterObjectOutput<JTail_t>::SetCircular(size);
    }


    /**
     * Reset TTree.
     */
    void Reset()
    {
      JTreeWriterObjectOutput<JHead_t>::Reset();
      JTreeWriterObjectOutput<JTail_t>::Reset();
    }
  };


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

#endif