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

#ifndef tools_rroot_tree_manip
#define tools_rroot_tree_manip

#include "file"
#include "tree"
#include "stl_vector"

namespace tools {
namespace rroot {

inline tree* find_tree(file& a_file,ifac& a_fac,const std::string& a_name,bool a_map_objs = false) {
  std::ostream& out = a_file.out();
  //out << "tools::rroot::find_tree : name : " << file << std::endl;

  key* key = a_file.dir().find_key(a_name);
  if(!key) {
    out << "tools::rroot::find_tree :"
        << " key " << sout(a_name) << " not found."
        << std::endl;
    return 0;     
  }

  unsigned int sz;    
  char* buf = key->get_object_buffer(a_file,sz); //we don't have ownership of buf.
  if(!buf) {
    out << "tools::rroot::find_tree :"
        << " can't get data buffer of "
        << sout(key->object_name()) << "."
        << std::endl;
    return 0;     
  }
  
  //out << "tools::rroot::find_tree :"
  //    << " get data buffer size " << sz << "."
  //    << std::endl;

  if(key->object_class()!=TTree_cls()) {
    out << "tools::rroot::find_tree :"
        << " key object class "
        << sout(key->object_class())
        << " is not a TTree."
        << std::endl;
    return 0;     
  }
     
  buffer b(out,a_file.byte_swap(),sz,buf,key->key_length(),false);
  b.set_map_objs(a_map_objs);
  
  tree* _tree = new tree(a_file,a_fac);
  if(!_tree->stream(b)) {
    out << "tools::rroot::find_tree :"
        << " TTree streaming failed"
        << std::endl;
    delete _tree;
    return 0;     
  }
 
  return _tree; 
}

inline branch_element* find_be(tree& a_tree,const std::string& a_name){
  std::ostream& out = a_tree.file().out();
    
  branch* _branch = a_tree.find_branch(a_name,true);
  if(!_branch) {
    out << "tools::rroot::find_be :"
        << " branch not found."
        << std::endl;
    return 0;     
  }

  branch_element* be = id_cast<branch,branch_element>(*_branch);
  if(!be) {
    out << "tools::rroot::find_be :"
        << " branch not a branch_element."
        << std::endl;
    return 0;     
  }
  
  return be;
}

template <class T>
inline stl_vector<T>* find_vec(ifile& a_file,branch_element& a_be,uint64 a_event){
  std::ostream& out = a_file.out();

  unsigned int n;
  if(!a_be.find_entry(a_file,a_event,n)) {
    out << "tools::rroot::find_vec : branch_element.find_entry() failed." << std::endl;
    return 0;     
  }

  iro* o = a_be.object();
  stl_vector<T>* od = id_cast<iro, stl_vector<T> >(*o);
  if(!od) {
    out << "tools::rroot::find_vec : object not a tools::rroot::stl_vector<T>." << std::endl;
    return 0;     
  }

  return od; //WARNING : we are not owner.
}

}}

#include "leaf"

namespace tools {
namespace rroot {

template <class LEAF>
inline bool find_leaf(tree& a_tree,const std::string& a_name,branch*& a_branch,LEAF*& a_leaf) {
  //used in MEMPHYS sim.
  base_leaf* _base_leaf = a_tree.find_leaf(a_name);
  if(!_base_leaf) {
    a_tree.out() << "tools::rroot::find_leaf : base_leaf " << sout(a_name) << " not found." << std::endl;
    a_branch = 0;
    a_leaf = 0;
    return false;
  }
  a_branch = a_tree.find_leaf_branch(*_base_leaf);
  if(!a_branch) {
    a_tree.out() << "tools::rroot::find_leaf : branch of base_leaf " << sout(a_name) << " not found." << std::endl;
    a_branch = 0;
    a_leaf = 0;
    return false;
  }
  a_leaf = safe_cast<base_leaf,LEAF>(*_base_leaf);
  if(!a_leaf) {
    a_tree.out() << "tools::rroot::find_leaf : base_leaf " << sout(a_name) << " is not a LEAF." << std::endl;
    a_branch = 0;
    a_leaf = 0;
    return false;
  }
  return true;
}

inline branch_element* find_branch_element(tree& a_tree,const std::string& a_name) {
  branch* _branch = a_tree.find_branch(a_name);
  if(!_branch) {
    a_tree.out() << "tools::rroot::find_branch_element : branch " << sout(a_name) << " not found." << std::endl;
    return 0;
  }
  branch_element* be = safe_cast<branch,branch_element>(*_branch);
  if(!be) {
    a_tree.out() << "tools::rroot::find_branch_element : branch " << sout(a_name) << " not a branch_element."
                 << " It is a " << sout(_branch->s_cls()) << "."
                 << std::endl;
    return 0;
  }
  return be;
}

template <class TYPE>
inline bool read_leaf(ifile& a_file,branch& a_branch,leaf<TYPE>& a_leaf,uint64 a_event,TYPE& a_value) {
  unsigned int n;
  if(!a_branch.find_entry(a_file,a_event,n)) {
    a_file.out() << "tools::rroot::read_leaf : a_branch.find_entry() failed." << std::endl;
    a_value = TYPE(0);
    return false;
  }
  return a_leaf.value(0,a_value);
}

inline bool read_leaf_object(ifile& a_file,branch& a_branch,leaf_object& a_leaf,uint64 a_event) {
  unsigned int n;
  if(!a_branch.find_entry(a_file,a_event,n)) {
    a_file.out() << "tools::rroot::read_leaf_object : a_branch.find_entry() failed." << std::endl;
    return false;
  }
  return true;
}

template <class TYPE>
inline stl_vector<TYPE>* read_std_vec(ifile& a_file,branch_element& a_branch,uint64 a_event) {
  unsigned int n;
  if(!a_branch.find_entry(a_file,a_event,n)) {
    a_file.out() << "tools::rroot::read_std_vec : a_branch.find_entry() failed." << std::endl;
    return 0;
  }
  iro* obj = a_branch.object(); //Not owner.
  if(!obj) return 0;
  return id_cast<iro, stl_vector<TYPE> >(*obj);
}

}}

#endif
