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

#ifndef tools_rroot_branch_element
#define tools_rroot_branch_element

#include "branch"

namespace tools {
namespace rroot {

class branch_element : public branch {
  typedef branch parent;
public:
  static const std::string& s_class() {
    static const std::string s_v("tools::rroot::branch_element");
    return s_v;
  }
public: //iro
  virtual void* cast(const std::string& a_class) const {
    if(void* p = cmp_cast<branch_element>(this,a_class)) return p;
    return parent::cast(a_class);
  }
  virtual const std::string& s_cls() const {return s_class();}
public:
  static cid id_class() {return branch_element_cid();}
  virtual void* cast(cid a_class) const {
    if(void* p = cmp_cast<branch_element>(this,a_class)) {return p;}
    return parent::cast(a_class);
  }
public:
  virtual bool stream(buffer& a_buffer) {
    short v;
    unsigned int s, c;
    if(!a_buffer.read_version(v,s,c)) return false;
    if(!parent::stream(a_buffer)) return false;

    if(v<=7) {
      if(!a_buffer.read(fClassName)) return false;
      if(!a_buffer.read(fClassVersion)) return false;
      if(!a_buffer.read(fID)) return false;
      if(!a_buffer.read(fType)) return false;
      if(!a_buffer.read(fStreamerType)) return false;
    } else { //v>=8
      if(!a_buffer.read(fClassName)) return false;
      std::string fParentName;
      if(!a_buffer.read(fParentName)) return false;
      std::string fCloneName;
      if(!a_buffer.read(fCloneName)) return false;
      int dummy_int;
      if(!a_buffer.read(dummy_int)) return false; //fCheckSum
      if(!a_buffer.read(dummy_int)) return false; //fClassVersion

      if(!a_buffer.read(fID)) return false;
      if(!a_buffer.read(fType)) return false;
      if(!a_buffer.read(fStreamerType)) return false;

      if(!a_buffer.read(dummy_int)) return false; //fMaximum

      //TBranchElement* fBranchCount;
      if(!dummy_TXxx_pointer_stream(a_buffer,m_fac)) {
        m_out << "tools::rroot::base_element::stream : "
              << "can't read fBranchCount."
              << std::endl;
        return false;
      }

      //TBranchElement* fBranchCount2;
      if(!dummy_TXxx_pointer_stream(a_buffer,m_fac)) {
        m_out << "tools::rroot::base_element::stream : "
              << "can't read fBranchCount2."
              << std::endl;
        return false;
      }

    }

    if(!a_buffer.check_byte_count(s,c,"TBranchElement")) return false;
    return true;
  }
public: //branch

  virtual bool read_leaves(buffer& a_buffer){

    // read object ?
    if(!m_obj) {
      ifac::args args;
      m_obj = m_fac.create(fClassName,args);
      if(!m_obj) return false;
    }

    if(!m_obj->stream(a_buffer)){
      m_out << "tools::rroot::branch_element::read_leaves :"
            << " name " << m_name << " ref_cls " << fClassName << " :"
            << " obj stream failed."
            << std::endl;          
      return false;
    }

    return true;

/*
    ///////////////////////////////////////////////////////
    /// STL container /////////////////////////////////////
    ///////////////////////////////////////////////////////
    if(fType==4) {
      // STL container master branch (has only the number of elements).
      //from v4-00-01
      int n;
      if(!a_buffer.read(n)) return false;
      //fNdata = n;

      m_out << "tools::rroot::branch_element::read_leaves :"
            << " name " << m_name << " ref_cls " << fClassName
            << " : type " << fType << " not treated."
            << std::endl;  
      return false;

    } else if(fType==41) {
      // STL container sub-branch (contains the elements).
      m_out << "tools::rroot::branch_element::read_leaves :"
            << " name " << m_name << " ref_cls " << fClassName
            << " : type " << fType << " not treated."
            << std::endl;
      return false;

    ///////////////////////////////////////////////////////
    /// TClonesArray container ////////////////////////////
    ///////////////////////////////////////////////////////
    } else if(fType==3) {
      // TClonesArray master branch (has only the number of elements).
      //from v4-00-01
      int n;
      if(!a_buffer.read(n)) return false;

      //fNdata = n;
      //TClonesArray *clones = (TClonesArray*)fObject;
      //if (!clones) return;
      //if (clones->IsZombie()) return;
      //clones->Clear();
      //clones->ExpandCreateFast(fNdata);

      m_out << "tools::rroot::branch_element::read_leaves :"
            << " name " << m_name << " ref_cls " << fClassName
            << " : type " << fType << " not treated."
            << std::endl;
      return false;

    } else if(fType==31) {
      // TClonesArray sub-branch (contains the elements).
      m_out << "tools::rroot::branch_element::read_leaves :"
            << " name " << m_name << " ref_cls " << fClassName
            << " : type " << fType << " not treated."
            << std::endl;
      return false;

    ///////////////////////////////////////////////////////
    ///////////////////////////////////////////////////////
    ///////////////////////////////////////////////////////
    } else if(fType<=2) {
      // branch in split mode

      //from v4-00-01
      //if (fBranchCount) fNdata = (Int_t)fBranchCount->GetValue(0,0);
      //else fNdata = 1;
      //if (!fInfo) return;
      //fInfo->ReadBuffer(b,fObject,fID);
      //if (fStreamerType == 6) fNdata = (Int_t)GetValue(0,0);

      //from 3.0.06
      //if (fID >= 0) {
      //  fInfo->ReadBuffer(b,fAddress,fID);
      //} else if (fID == -1) {   // top level branch in non split mode
      //  char **ppointer = (char**)fAddress;
      //  fInfo->ReadBuffer(b,*ppointer,fID);
      //}

      //m_out << "tools::rroot::branch_element::read_leaves :"
      //      << " name " << m_name << " ref_cls " << fClassName << " :"
      //      << " type " << fType << " with ID " << fID << "."
      //      << " and then ?"
      //      << std::endl;

      // read object ?
      if(!m_obj) {
        ifac::args args;
        m_obj = m_fac.create(fClassName,args);
        if(!m_obj) return false;
      }

      if(!m_obj->stream(a_buffer)){
        m_out << "tools::rroot::branch_element::read_leaves :"
              << " name " << m_name << " ref_cls " << fClassName << " :"
              << " obj stream failed."
              << std::endl;          
        return false;
      }

      //m_out << "tools::rroot::branch_element::read_leaves :"
      //      << " name " << m_name << " ref_cls " << fClassName << " :"
      //      << " obj streamed."
      //      << std::endl;          

      return true;

//  } else if(fType==0) {
//     if(fID>=0) {
//       // branch in split mode
//       m_out << "tools::rroot::branch_element::read_leaves :"
//             << " name " << m_name << " ref_cls " << fClassName << " :"
//             << " type 0 with ID " << fID << "."
//             << std::endl;
//       return true;
//
//     } else if(fID==-1) {
//       // top level branch in non split mode
//       m_out << "tools::rroot::branch_element::read_leaves :"
//             << " name " << m_name << " ref_cls " << fClassName << " :"
//             << " type 0 with ID " << fID
//             << " : fill object."
//             << std::endl;

//       if(!m_obj) {
//         m_out << "tools::rroot::branch_element::read_leaves :"
//               << " name " << m_name << " ref_cls " << fClassName << " :"
//               << " m_obj is null."
//               << std::endl;
//         return false;
//       }
//       if(!m_obj->stream(a_buffer)){
//         m_out << "tools::rroot::branch_element::read_leaves :"
//               << " name " << m_name << " ref_cls " << fClassName << " :"
//               << " obj stream failed."
//               << std::endl;          
//         return false;
//       }
//       return true;

//     } else {
//       m_out << "tools::rroot::branch_element::read_leaves :"
//             << " name " << m_name << " ref_cls " << fClassName << " :"
//             << " type 0 with ID " << fID << " not treated."
//             << std::endl;
//       return false;
//     }

//  //LHCb files :
//  } else if(fType==1) {
//    // parent branch is a base class branch.
//    // Ok, and then ?
//    m_out << "tools::rroot::branch_element::read_leaves :"
//          << " name " << m_name << " ref_cls " << fClassName << " :"
//          << " type " << fType << " with ID " << fID << "."
//          << std::endl;
//    return true;

    } else {
      m_out << "tools::rroot::branch_element::read_leaves :"
            << " name " << m_name << " ref_cls " << fClassName << " :"
            << " type " << fType << " with ID " << fID << "."
            << " unknown case."
            << std::endl;
      return false;
    }
*/
  }

  virtual bool find_entry(ifile& a_file,uint64 a_entry,uint32& a_nbytes){
    //The below line will call the upper read_leaves.
    if(!parent::find_entry(a_file,a_entry,a_nbytes)) return false;

    if(m_branches.size()) {
      //if(!m_obj) {
      //  m_obj = m_fac.create(fClassName);
      //  if(!m_obj) return false;
      //}

      tools_vforcit(branch*,m_branches,it) {
        uint32 n;
        if(!(*it)->find_entry(a_file,a_entry,n)) return false;
        a_nbytes += n;
      } 
    }

    return true;
  }

  virtual bool show(std::ostream& a_out,ifile& a_file,uint64 a_entry){
    uint32 n;
    if(!find_entry(a_file,a_entry,n)) return false;

   {std::string s;
    uint32 len = uint32(name().size())+128;
    sprintf(s,len," %-15s = ",name().c_str());
    a_out << s;}

    a_out << m_obj << std::endl;

    return true;
    //return parent::show(a_out,a_file,a_entry);
  }
public:
  branch_element(std::ostream& a_out,ifac& a_fac)
  :parent(a_out,a_fac)
  ,m_obj(0)
  ,fClassVersion(0)
  ,fID(0)
  ,fType(0)
  ,fStreamerType(-1)
  {}

  virtual ~branch_element(){delete m_obj;}
protected:
  branch_element(const branch_element& a_from)
  :iro(a_from),parent(a_from){}
  branch_element& operator=(const branch_element&){return *this;}
public:
  const std::string& class_name() const {return fClassName;}
  int type() const {return fType;}
  int streamer_type() const {return fStreamerType;}
  int id() const {return fID;}
  iro* object() {return m_obj;}
protected:
  iro* m_obj;
protected:
  std::string fClassName; //Class name of referenced object
  int fClassVersion;  //Version number of class
  int fID;            //element serial number in fInfo
  int fType;          //branch type
  int fStreamerType;  //branch streamer type
};

}}

#endif
