// Copyright (C) 2010, Guy Barrand. All rights reserved.
// See the file tools.license for terms.

#ifndef tools_rroot_base_leaf
#define tools_rroot_base_leaf

#ifdef TOOLS_MEM
#include "../mem"
#endif

#include "named"

namespace tools {
namespace rroot {

class base_leaf : public virtual iro {
public:
  static const std::string& s_class() {
    static const std::string s_v("tools::rroot::base_leaf");
    return s_v;
  }
public: //iro
  virtual void* cast(const std::string& a_class) const {
    if(void* p = cmp_cast<base_leaf>(this,a_class)) return p;
    return 0;
  }
  virtual const std::string& s_cls() const {return s_class();}
public:
  static cid id_class() {return base_leaf_cid();}
  virtual void* cast(cid a_class) const {
    if(void* p = cmp_cast<base_leaf>(this,a_class)) {return p;}
    else return 0;
  }
public:
  virtual bool stream(buffer& a_buffer) {
    if(m_own_leaf_count) {
      if(a_buffer.map_objs()) a_buffer.remove_in_map(m_leaf_count);
      delete m_leaf_count;
    }
    m_leaf_count = 0;
    m_own_leaf_count = false;

    int fOffset;
    bool fIsUnsigned;

    short v;
    unsigned int s,c;
    if(!a_buffer.read_version(v,s,c)) return false;
    //FIXME if (v > 1) {
    //TLeaf::Class()->ReadBuffer(b, this, R__v, R__s, R__c);
    //FIXME } else {
    //====process old versions before automatic schema evolution
    if(!Named_stream(a_buffer,m_name,m_title)) return false;

    // Ok with v 1 & 2
    if(!a_buffer.read(m_length)) return false;
    if(!a_buffer.read(m_length_type)) return false;
    if(!a_buffer.read(fOffset)) return false;
    if(!a_buffer.read(m_is_range)) return false;
    if(!a_buffer.read(fIsUnsigned)) return false;

   {ifac::args args;
    iro* obj;
    bool created;
    if(!a_buffer.read_object(m_fac,args,obj,created)) {
      m_out << "tools::rroot::base_leaf::stream :"
            << " can't read object." 
            << std::endl;
      return false;
    }
    if(!obj) {
      //m_out << "tools::rroot::base_leaf::stream :"
      //      << " null leaf count object." 
      //      << std::endl;
    } else {
      m_leaf_count = safe_cast<iro,base_leaf>(*obj);
      if(!m_leaf_count) {
        m_out << "tools::rroot::base_leaf::stream :"
              << " can't cast base_leaf." 
              << std::endl;
        m_leaf_count = 0;
        if(created) {
          if(a_buffer.map_objs()) a_buffer.remove_in_map(obj);
          delete obj;
        }
        return false;
      }
      if(created) m_own_leaf_count = true;
    }}

    if(!a_buffer.check_byte_count(s,c,"TLeaf")) return false;

    if(!m_length) m_length = 1;
/*
    fNewValue = false;
    if(!setAddress(0)) return false;
*/
    return true;
  }
public:
  virtual bool read_buffer(buffer&) = 0;
  virtual bool print_value(std::ostream&,uint32) const = 0;
  virtual uint32 num_elem() const = 0;
public:
  base_leaf(std::ostream& a_out,ifac& a_fac)
  :m_out(a_out)
  ,m_fac(a_fac)
  ,m_name("")
  ,m_title("")

  //,fIndirectAddress(false)
  //,fNewValue(false)
  //,m_ndata(0)
  ,m_length(0)
  ,m_length_type(0)
//,fOffset(0)
  ,m_is_range(false)
//,fIsUnsigned(false)
  ,m_leaf_count(0)
  ,m_own_leaf_count(false)
  {
#ifdef TOOLS_MEM
    mem::increment(s_class().c_str());
#endif
  }
  virtual ~base_leaf(){
    if(m_own_leaf_count) delete m_leaf_count;
#ifdef TOOLS_MEM
    mem::decrement(s_class().c_str());
#endif
  }
protected:
  base_leaf(const base_leaf& a_from)
  :iro(a_from)
  ,m_out(a_from.m_out)
  ,m_fac(a_from.m_fac)
  //,m_ndata(0)
  ,m_length(0)
  ,m_length_type(0)
  ,m_is_range(false)
  ,m_leaf_count(0)
  ,m_own_leaf_count(false)
  {}
  base_leaf& operator=(const base_leaf&){return *this;}
public:
  const std::string& name() const {return m_name;}
  const std::string& title() const {return m_title;}
  const base_leaf* leaf_count() const {return m_leaf_count;}
/*
  uint32 length() const {
    // Return the number of effective elements of this leaf.
    if(m_leaf_count) {
      m_out << "tools::rroot::base_leaf::length :"
            << " m_leaf_count not null. Case not yet handled." 
            << std::endl;
      return m_length;

      //uint32 len = m_leaf_count->number();
      //if (len > fLeafCount->maximum()) {
      //  m_out << "tools::rroot::base_leaf::length :"
      //        << fName << ", len=" << len << " and max=" 
      //        << fLeafCount->maximum()
      //        << std::endl;
      //  len = fLeafCount->maximum();
      //}
      //return len * fLength;

    } else {
      return m_length;
    }
  }
*/
protected:
  std::ostream& m_out;
  ifac& m_fac;
protected: //Named
  std::string m_name;
  std::string m_title;
  //bool fIndirectAddress;
  //bool fNewValue;
//uint32 m_ndata;           //! Number of elements in fAddress data buffer
  uint32 m_length;          //  Number of fixed length elements
  uint32 m_length_type;     //  Number of bytes for this data type
//int fOffset;              //  Offset in ClonesArray object (if one)
  bool m_is_range;          //  (=true if leaf has a range, false otherwise)
//bool fIsUnsigned;         //  (=kTRUE if unsigned, kFALSE otherwise)
  base_leaf* m_leaf_count;  //  Pointer to Leaf count if variable length
  bool m_own_leaf_count;
};

}}

#endif
