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

#ifndef tools_rroot_fac
#define tools_rroot_fac

#include "../sout"
#include "../S_STRING"

#include "branch_element"
#include "branch_object"
#include "leaf"
#include "basket"
#include "tree_index"
#include "stl_vector"
#include "dummy"
#include "obj_list"
#include "vector3"
#include "matrix"

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

namespace tools {
namespace rroot {

class fac : public virtual ifac {
public:
  TOOLS_SCLASS(tools::rroot::fac)
public: //ifac
  virtual std::ostream& out() const {return m_out;}
  virtual iro* create(const std::string& a_class,const args&) {
    //m_out << "tools::rroot::fac::create :"
    //      << " create object of class " << a_class << "..."
    //      << std::endl;
    if(a_class=="TBranch") {
      return new branch(m_out,*this);
    } else if(a_class=="TBranchElement") {
      return new branch_element(m_out,*this);
    } else if(a_class=="TBranchObject") {
      return new branch_object(m_out,*this);

    } else if(a_class=="TLeafB") {
      return new leaf<char>(m_out,*this);

    } else if(a_class=="TLeafS") {
      return new leaf<short>(m_out,*this);

    } else if(a_class=="TLeafI") {
      return new leaf<int>(m_out,*this);

    } else if(a_class=="TLeafF") {
      return new leaf<float>(m_out,*this);

    } else if(a_class=="TLeafD") {
      return new leaf<double>(m_out,*this);

    } else if(a_class=="TLeafO") {
      return new leaf<bool>(m_out,*this);

    } else if(a_class=="TLeafC") {
      return new leaf_string(m_out,*this);

    } else if(a_class=="TLeafElement") {
      return new leaf_element(m_out,*this);

    } else if(a_class=="TLeafObject") {
      return new leaf_object(m_out,*this);

    } else if(a_class=="TBasket") {
      return new basket(m_out);

    // L.Duflot ATLAS file :
    } else if(a_class=="TTreeIndex") {
      return new tree_index();

    } else if(a_class=="TList") {
      return new obj_list(*this);
    } else if(a_class=="TVector3") {
      return new vector3();
    } else if(a_class=="TMatrix") {
      return new matrix();

    } else if(a_class=="TNamed") {
      return new named();

    } else if(a_class=="vector<unsigned short>") {
      return new stl_vector<unsigned short>();
    } else if(a_class=="vector<short>") {
      return new stl_vector<short>();
    } else if(a_class=="vector<unsigned int>") {
      return new stl_vector<unsigned int>();
    } else if(a_class=="vector<int>") {
      return new stl_vector<int>();
    } else if(a_class=="vector<float>") {
      return new stl_vector<float>();
    } else if(a_class=="vector<double>") {
      return new stl_vector<double>();

    } else if(a_class=="vector<unsigned long>") { //beurk
      return new stl_vector<uint64>(); //is it ok to map to an uint64 ?

    } else if(a_class=="vector<string>") {
      return new stl_vector_string();

    } else if(a_class=="vector<vector<unsigned short> >") {
      return new stl_vector_vector<unsigned short>();
    } else if(a_class=="vector<vector<short> >") {
      return new stl_vector_vector<short>();
    } else if(a_class=="vector<vector<unsigned int> >") {
      return new stl_vector_vector<unsigned int>();
    } else if(a_class=="vector<vector<int> >") {
      return new stl_vector_vector<int>();
    } else if(a_class=="vector<vector<float> >") {
      return new stl_vector_vector<float>();
    } else if(a_class=="vector<vector<double> >") {
      return new stl_vector_vector<double>();

    } else if(a_class=="TBranchRef") {
      return new dummy();

    } else {
      m_out << "tools::rroot::fac::create :"
                   << " unknown class " << sout(a_class) << "."
                   << " Create a tools::rroot::dummy object."
                   << std::endl;
      return new dummy();
    }
  }
public:
  fac(std::ostream& a_out):m_out(a_out){
#ifdef TOOLS_MEM
    mem::increment(s_class().c_str());
#endif
  }
  virtual ~fac(){
#ifdef TOOLS_MEM
    mem::decrement(s_class().c_str());
#endif
  }
public:
  fac(const fac& a_from):ifac(a_from),m_out(a_from.m_out){
#ifdef TOOLS_MEM
    mem::increment(s_class().c_str());
#endif
  }
  fac& operator=(const fac&){return *this;}
protected:
/*
  branch* arg_branch(const args& a_args) {
    void* p = ifac::find_args(a_args,ifac::arg_branch());
    if(!p) {
      m_out << "tools::rroot::fac::arg_branch :"
                   << " branch not found in args."
                   << std::endl;
      return 0;
    }
    return (branch*)p;
  }
*/
protected:
  std::ostream& m_out;
};

}}

#endif
