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

#ifndef tools_aida_ntuple
#define tools_aida_ntuple

// An in memory ntuple able to have "sub ntuple" on a column.
// It is used in ioda to read ntuples in XML/AIDA files.

#include "vmanip"
#include "typedefs"
#include "scast"
#include "forit"
#include "ntuple_binding"
#include "mnmx"

#include <string>
#include <vector>
#include <ostream>

namespace tools {
namespace aida {

class base_col {
public:
  static const std::string& s_class() {
    static const std::string s_v("tools::aida::base_col");
    return s_v;
  }
  virtual void* cast(const std::string& a_class) const {
    if(void* p = cmp_cast<base_col>(this,a_class)) {return p;}
    return 0;
  }
public:
  virtual base_col* copy() const = 0;
  virtual uint64 num_elems() const = 0;
  virtual bool add() = 0;
  virtual bool reset() = 0;
  //binded column reading API :
  virtual bool fetch_entry() const = 0;
  virtual void set_user_variable(void*) = 0;
protected:
  base_col(std::ostream& a_out,const std::string& a_name)
  :m_out(a_out)
  ,m_name(a_name),m_index(0){
  }
public:
  virtual ~base_col(){
  }
protected:
  base_col(const base_col& a_from)
  :m_out(a_from.m_out)
  ,m_name(a_from.m_name)
  ,m_index(a_from.m_index){
  }
  base_col& operator=(const base_col& a_from){
    m_name = a_from.m_name;
    m_index = a_from.m_index;
    return *this;
  }
public:
  const std::string& name() const {return m_name;}

  void set_index(uint64 a_index){m_index = a_index;}
protected:
  std::ostream& m_out;
  std::string m_name;
  uint64 m_index;
};

class base_ntu {
public:
  static const std::string& s_class() {
    static const std::string s_v("tools::aida::base_ntu");
    return s_v;
  }
  virtual void* cast(const std::string& a_class) const {
    if(void* p = cmp_cast<base_ntu>(this,a_class)) {return p;}
    return 0;
  }
protected:
  base_ntu(std::ostream& a_out,const std::string& a_title)
  :m_out(a_out),m_title(a_title),m_index(-1){
  }
  virtual ~base_ntu() {
    clear();
  }
protected:
  base_ntu(const base_ntu& a_from)
  :m_out(a_from.m_out)
  ,m_title(a_from.m_title),m_index(a_from.m_index)
  {
    tools_vforcit(base_col*,a_from.m_cols,it) {
      base_col* column = (*it)->copy();
      if(!column) {
        m_out << s_class() << "::cstor :"
              << " can't copy column."
              << std::endl;
        safe_clear<base_col>(m_cols);
        m_index = -1;
        return; //throw
      }
      m_cols.push_back(column);
    }
  }
  base_ntu& operator=(const base_ntu& a_from){
    if(&a_from==this) return *this;

    safe_clear<base_col>(m_cols);
    m_index = a_from.m_index;

    m_title = a_from.m_title;
    tools_vforcit(base_col*,a_from.m_cols,it) {
      base_col* column = (*it)->copy();
      if(!column) {
        m_out << s_class() << "::operator=() :"
              << " can't copy column."
              << std::endl;
        safe_clear<base_col>(m_cols);
        m_index = -1;
        return *this;
      }
      m_cols.push_back(column);
    }

    return *this;
  }
public:
  std::ostream& out() const {return m_out;}
  const std::vector<base_col*>& columns() const {return m_cols;}
  size_t number_of_columns() const {return m_cols.size();}

  void column_names(std::vector<std::string>& a_names) const {
    a_names.clear();
    tools_vforcit(base_col*,m_cols,it) a_names.push_back((*it)->name());
  }

  const std::string& title() const {return m_title;}
  void set_title(const std::string& a_title) {m_title = a_title;}

  uint64 rows() const {
    if(m_cols.empty()) return 0;
    return m_cols.front()->num_elems();
  }
  bool number_of_entries(uint64& a_value) const {
    if(m_cols.empty()) {a_value = 0;return false;}
    a_value = m_cols.front()->num_elems();
    return true;
  }

  void clear() { //must not be confused with reset().
    safe_clear<base_col>(m_cols);
    m_index = -1;
  }

  bool reset() { //clear data in columns (but not the column set)
    bool status = true;
    tools_vforit(base_col*,m_cols,it) {
      if(!(*it)->reset()) status = false;
    }
    m_index = -1;
    return status;
  }

  // reading :
  void start() {m_index = -1;set_columns_index(0);}
  bool next() {
    // a tuple loop is of the form :
    //  tuple.start();
    //  while(tuple.next()) {
    //    ...
    //    double v;
    //    if(!col->get_entry(v)) {}
    //    ...
    //  }
    if((m_index+1)>=(int64)rows()) return false;
    m_index++;
    set_columns_index(m_index);
    return true;
  }
  int64 row_index() const {return m_index;}

  // filling :
  bool add_row() {
    bool status = true;
    tools_vforit(base_col*,m_cols,it) {
      if(!(*it)->add()) status = false;
    }
    return status;
  }
public:
  base_col* find_column(const std::string& a_name){
    return find_named<base_col>(m_cols,a_name);
  }

  void add_column(base_col* a_col) { //we take ownership.
    m_cols.push_back(a_col);
  }

protected:
  void set_columns_index(uint64 a_index) {
    tools_vforit(base_col*,m_cols,it) {
      (*it)->set_index(a_index);
    }
  }
protected:
  std::ostream& m_out;
  std::string m_title;
  int64 m_index;
  std::vector<base_col*> m_cols;
};

}}

#include "tos"
#include "sto"
#include "columns"
#include "stype"

namespace tools {
namespace aida {

inline const std::string& s_aida_type(short) {
  static const std::string s_v("short");
  return s_v;
}
inline const std::string& s_aida_type(int) {
  static const std::string s_v("int");
  return s_v;
}
inline const std::string& s_aida_type(float) {
  static const std::string s_v("float");
  return s_v;
}
inline const std::string& s_aida_type(double) {
  static const std::string s_v("double");
  return s_v;
}

inline const std::string& s_aida_type(bool) {
  static const std::string s_v("boolean");
  return s_v;
}
inline const std::string& s_aida_type(const std::string&) {
  static const std::string s_v("string");
  return s_v;
}
inline const std::string& s_aida_type(int64) {
  static const std::string s_v("long");
  return s_v;
}

inline const std::string& s_aida_type_ituple() {
  static const std::string s_v("ITuple");
  return s_v;
}

/////////////////////////////////////////
/// not AIDA ! //////////////////////////
/////////////////////////////////////////
inline const std::string& s_aida_type(unsigned short) {
  static const std::string s_v("ushort");
  return s_v;
}
inline const std::string& s_aida_type(unsigned int) {
  static const std::string s_v("uint");
  return s_v;
}
inline const std::string& s_aida_type(uint64) {
  static const std::string s_v("ulong");
  return s_v;
}

class aida_base_col : public base_col {
public:
  static const std::string& s_class() {
    static const std::string s_v("tools::aida::aida_base_col");
    return s_v;
  }
  virtual void* cast(const std::string& a_class) const {
    if(void* p = cmp_cast<aida_base_col>(this,a_class)) {return p;}
    return base_col::cast(a_class);
  }
public:
  virtual const std::string& aida_type() const = 0;
  virtual bool s_default_value(std::string&) const = 0;
  virtual bool s_value(std::string&) const = 0;
  virtual bool s_fill(const std::string&) = 0;
public:
  aida_base_col(std::ostream& a_out,const std::string& a_name)
  :base_col(a_out,a_name){}
public:
  virtual ~aida_base_col(){}
public:
  aida_base_col(const aida_base_col& a_from)
  :base_col(a_from)
  {}
  aida_base_col& operator=(const aida_base_col& a_from){
    base_col::operator=(a_from);
    return *this;
  }
};

inline bool s__fill(const std::string& a_s,std::string& a_v) {
  a_v = a_s;
  return true;
}
inline bool s__fill(const std::string& a_s,char& a_v) {
  //for exlib/cbk/aida_ntu
  if(a_s.empty()) return false;
  a_v = a_s[0];
  return true;
}
inline bool s__fill(const std::string& a_s,unsigned char& a_v) {
  //for exlib/cbk/aida_ntu
  if(a_s.empty()) return false;
  a_v = a_s[0];
  return true;
}
inline bool s__fill(const std::string& a_s,bool& a_v) {
  return to(a_s,a_v);
}
inline bool s__fill(const std::string& a_s,short& a_v) {
  return to<short>(a_s,a_v);
}
inline bool s__fill(const std::string& a_s,unsigned short& a_v) {
  return to<unsigned short>(a_s,a_v);
}
inline bool s__fill(const std::string& a_s,int& a_v) {
  return to<int>(a_s,a_v);
}
inline bool s__fill(const std::string& a_s,unsigned int& a_v) {
  return to<unsigned int>(a_s,a_v);
}
inline bool s__fill(const std::string& a_s,int64& a_v) {
  return to<int64>(a_s,a_v);
}
inline bool s__fill(const std::string& a_s,uint64& a_v) {
  return to<uint64>(a_s,a_v);
}
inline bool s__fill(const std::string& a_s,float& a_v) {
  return to<float>(a_s,a_v);
}
inline bool s__fill(const std::string& a_s,double& a_v) {
  return to<double>(a_s,a_v);
}

template <class T>
class aida_col : public aida_base_col {
public:
  typedef T entry_t;
public:
  static const std::string& s_class() {
    static const std::string s_v("tools::aida::aida_col<"+stype(T())+">");
    return s_v;
  }
  virtual void* cast(const std::string& a_class) const {
    if(void* p = cmp_cast< aida_col<T> >(this,a_class)) {return p;}
    return aida_base_col::cast(a_class);
  }
public:
  virtual base_col* copy() const {return new aida_col(*this);}
  virtual bool add() {m_data.push_back(m_tmp);m_tmp = m_default;return true;}
  virtual bool reset() {
    m_data.clear();
    m_index = 0;
    m_tmp = m_default;
    return true;
  }
  virtual uint64 num_elems() const {return m_data.size();}
public:
  virtual const std::string& aida_type() const {return s_aida_type(T());}
  virtual bool s_default_value(std::string& a_s) const {
    a_s = tos(m_default);
    return true;
  }
  virtual bool s_value(std::string& a_s) const {
    typedef typename std::vector<T>::size_type sz_t;
    a_s = tos(m_data[sz_t(m_index)]);
    return true;
  }

  // for exlib/raxml/tuple :
  virtual bool s_fill(const std::string& a_s) {
    //if(!to<T>(a_s,m_tmp)) {
    if(!s__fill(a_s,m_tmp)) {
      m_out << s_class() << "::fill :"
            << " can't convert " << sout(a_s) << "."
            << std::endl;
      return false;
    }
    return true;
  }

  virtual void set_user_variable(void* a_user_var) {m_user_var = (T*)a_user_var;} //not owner.
public:
  aida_col(std::ostream& a_out,const std::string& a_name,const T& a_def)
  :aida_base_col(a_out,a_name)
  ,m_default(a_def)
  ,m_tmp(a_def)
  ,m_user_var(0) //not owner
  {}
public:
  virtual ~aida_col(){}
public:
  aida_col(const aida_col& a_from)
  :aida_base_col(a_from)
  ,m_data(a_from.m_data)
  ,m_default(a_from.m_default)
  ,m_tmp(a_from.m_tmp)
  ,m_user_var(a_from.m_user_var)
  {}
  aida_col& operator=(const aida_col& a_from){
    aida_base_col::operator=(a_from);
    if(&a_from==this) return *this;
    m_data = a_from.m_data;
    m_default = a_from.m_default;
    m_tmp = a_from.m_tmp;
    m_user_var = a_from.m_user_var;
    return *this;
  }
public:
  bool fill(const T& a_value) {m_tmp = a_value;return true;}
  bool get_entry(T& a_v) const {
    if(m_index>=m_data.size()) {
      m_out << s_class() << "::get_entry :"
            << " bad index " << m_index
            << ". Vec size is " << m_data.size() << "."
            << "."
            << std::endl;
      a_v = T();
      return false;
    }
    typedef typename std::vector<T>::size_type sz_t;
    a_v = m_data[sz_t(m_index)];
    return true;
  }
  virtual bool fetch_entry() const {
    //NOTE : it is ok to have a NULL m_user_var.
    if(m_index>=m_data.size()) {
      m_out << s_class() << "::get_entry :"
            << " bad index " << m_index
            << ". Vec size is " << m_data.size() << "."
            << "."
            << std::endl;
      if(m_user_var) *m_user_var = T();
      return false;
    }
    typedef typename std::vector<T>::size_type sz_t;
    if(m_user_var) *m_user_var = m_data[sz_t(m_index)];
    return true;
  }
protected:
  std::vector<T> m_data;
  T m_default;
  T m_tmp;
  T* m_user_var;
};

class ntuple : public base_ntu {
public:
  static cid id_class() {return 2000;} //for ntuple_binding.
public:
  static const std::string& s_class() {
    static const std::string s_v("tools::aida::ntuple");
    return s_v;
  }
  virtual void* cast(const std::string& a_class) const {
    if(void* p = cmp_cast<ntuple>(this,a_class)) {return p;}
    return base_ntu::cast(a_class);
  }
  virtual const std::string& s_cls() const {return s_class();}
public:
  ntuple(std::ostream& a_out,const std::string& a_title)
  :base_ntu(a_out,a_title)
  {}
  virtual ~ntuple() {}
public:
  ntuple(const ntuple& a_from): base_ntu(a_from){}
  ntuple& operator=(const ntuple& a_from){
    base_ntu::operator=(a_from);
    return *this;
  }
public:
  template <class T>
  aida_col<T>* create_col(const std::string& a_name,const T& a_def = T()) {
    if(find_named<base_col>(m_cols,a_name)) {
      m_out << s_class() << "::create_col :"
            << " a column with name " << sout(a_name) << " already exists."
            << std::endl;
      return 0;
    }
    aida_col<T>* col = new aida_col<T>(m_out,a_name,a_def);
    if(!col) {
      m_out << s_class() << "::create_col :"
            << " can't create aida_col<T> " << sout(a_name) << "."
            << std::endl;
      return 0;
    }
    m_cols.push_back(col);
    return col;
  }

  template <class T>
  aida_col<T>* find_column(const std::string& a_name){
    base_col* col = find_named<base_col>(m_cols,a_name);
    if(!col) return 0;
    return safe_cast<base_col, aida_col<T> >(*col);
  }

  template <class T>
  bool find_column(const std::string& a_name,aida_col<T>*& a_col,bool a_case_sensitive = true) { //for exlib::evaluator.
    base_col* col = a_case_sensitive ? find_named<base_col>(m_cols,a_name) : find_named_case_insensitive<base_col>(m_cols,a_name);
    if(!col) {a_col = 0;return false;}
    a_col = safe_cast<base_col, aida_col<T> >(*col);
    return a_col?true:false;
  }

  aida_base_col* find_aida_base_column(const std::string& a_name,bool a_case_sensitive = true){ //for opaw/panntu.
    base_col* col = a_case_sensitive ? find_named<base_col>(m_cols,a_name) : find_named_case_insensitive<base_col>(m_cols,a_name);
    if(!col) return 0;
    return safe_cast<base_col,aida_base_col>(*col);
  }

  bool get_row() const {
    bool status = true;
    tools_vforcit(base_col*,m_cols,it) {
      if(!(*it)->fetch_entry()) status = false;
    }
    return status;
  }

  bool set_binding(std::ostream& a_out,const ntuple_binding& a_bd = ntuple_binding()) {
    tools_vforcit(column_binding,a_bd.columns(),itb) {
      bool found = false;
      tools_vforcit(base_col*,m_cols,itc) {
        if((*itc)->name()==(*itb).name()) {
          (*itc)->set_user_variable((*itb).user_obj());
          found = true;
        }
      }
      if(!found) {
        a_out << "tools::aida::ntuple :"
              << " binding name " << sout((*itb).name()) << " does not match any ntuple column."
              << std::endl;
        return false;
      }
    }
    return true;
  }

  template <class T>
  bool column_min(unsigned int a_col,T& a_value) {
    a_value = T();
    if(m_cols.empty()) return false;
    if(a_col>=m_cols.size()) return false;
    base_col* _base_col = m_cols[a_col];
    aida_col<T>* _col = safe_cast<base_col, aida_col<T> >(*_base_col);
    if(!_col) return false;
    start();
    uint64 _rows = rows();
    T v;
   {for(uint64 row=0;row<_rows;row++) {
      if(!next()) {a_value = T();return false;}
      if(!_col->get_entry(v)) {}
      if(!row) {
        a_value = v;
      } else {
        a_value = min_of<T>(a_value,v);
      }
    }}
    return true;
  }

  template <class T>
  bool column_max(unsigned int a_col,T& a_value) {
    a_value = T();
    if(m_cols.empty()) return false;
    if(a_col>=m_cols.size()) return false;
    base_col* _base_col = m_cols[a_col];
    aida_col<T>* _col = safe_cast<base_col, aida_col<T> >(*_base_col);
    if(!_col) return false;
    start();
    uint64 _rows = rows();
    T v;
   {for(uint64 row=0;row<_rows;row++) {
      if(!next()) {a_value = T();return false;}
      if(!_col->get_entry(v)) {}
      if(!row) {
        a_value = v;
      } else {
        a_value = max_of<T>(a_value,v);
      }
    }}
    return true;
  }

};

////////////////////////////////////////////////////////////
/// some special column that can't be done with aida_col<T> ////
////////////////////////////////////////////////////////////

class aida_col_ntu : public base_col {
public:
  static const std::string& s_class() {
    static const std::string s_v("tools::aida::aida_col_ntu");
    return s_v;
  }
  virtual void* cast(const std::string& a_class) const {
    if(void* p = cmp_cast<aida_col_ntu>(this,a_class)) {return p;}
    return base_col::cast(a_class);
  }
public:
  virtual base_col* copy() const {return new aida_col_ntu(*this);}
  virtual bool add() {m_data.push_back(m_tmp);m_tmp.reset();return true;}
  virtual bool reset() {m_data.clear();m_index = 0;return true;}
  virtual uint64 num_elems() const {return m_data.size();}
public:
  base_ntu* get_entry() {
    if(m_index>=m_data.size()) {
      m_out << s_class() << "::get_entry :"
            << " bad index " << m_index
            << ". Vec size is " << m_data.size() << "."
            << "."
            << std::endl;
      return 0;
    }
    typedef std::vector<ntuple>::size_type sz_t;
    return &(m_data[sz_t(m_index)]);
  }

  virtual void set_user_variable(void* a_user_var) {m_user_var = (ntuple*)a_user_var;} //not owner.
  virtual bool fetch_entry() const {
    if(m_index>=m_data.size()) {
      m_out << s_class() << "::fetch_entry :"
            << " bad index " << m_index
            << ". Vec size is " << m_data.size() << "."
            << "."
            << std::endl;
      if(m_user_var) *m_user_var = ntuple(m_out,"");
      return false;
    }
    typedef std::vector<ntuple>::size_type sz_t;
    if(m_user_var) *m_user_var = m_data[sz_t(m_index)];
    return true;
  }

  virtual base_ntu* get_to_fill() {return &m_tmp;}
public:
  aida_col_ntu(std::ostream& a_out,const std::string& a_name)
  :base_col(a_out,a_name)
  ,m_tmp(a_out,"tmp")
  ,m_user_var(0) //not owner
  {}
public:
  virtual ~aida_col_ntu(){}
public:
  aida_col_ntu(const aida_col_ntu& a_from)
  :base_col(a_from)
  ,m_data(a_from.m_data)

  ,m_tmp(a_from.m_tmp)
  ,m_user_var(a_from.m_user_var)
  {}
  aida_col_ntu& operator=(const aida_col_ntu& a_from){
    base_col::operator=(a_from);
    if(&a_from==this) return *this;
    m_data = a_from.m_data;

    m_tmp = a_from.m_tmp;
    m_user_var = a_from.m_user_var;
    return *this;
  }
protected:
  std::vector<ntuple> m_data;
  ntuple m_tmp;
  ntuple* m_user_var;
};

inline bool create_cols_from_vals(ntuple& a_ntu,
                                  const std::vector<value>& a_vars,
                                  bool a_verbose = false){
  tools_vforcit(value,a_vars,it) {
      if((*it).type()==value::VOID_STAR) {
        if(a_verbose){
          a_ntu.out() << "tools::aida::create_cols_from_vals :"
                      << " ITuple : " << (*it).label() << " : begin "
                      << std::endl;
        }
        std::vector<value>* vars = (std::vector<value>*)(*it).get_void_star();

        aida_col_ntu* col_ntu = new aida_col_ntu(a_ntu.out(),(*it).label());
        // create sub columns on the "fillable" of col_ntu :
        base_ntu* sub_base_ntu = col_ntu->get_to_fill();
        if(!sub_base_ntu) {
          delete col_ntu;
          return false;
        }
        ntuple* sub_aida = safe_cast<base_ntu,ntuple>(*sub_base_ntu);
        if(!sub_aida) {
          delete col_ntu;
          return false;
        }

        if(!create_cols_from_vals(*sub_aida,*vars,a_verbose)) {
          delete col_ntu;
          return false;
        }

        a_ntu.add_column(col_ntu);

    } else {
        if(a_verbose){
          std::string stype;
          (*it).s_type(stype);
          std::string sval;
          (*it).tos(sval);
          a_ntu.out() << "tools::aida::create_cols_from_vals :"
                      << " " << stype << " : "
                      << (*it).label() << " : "
                      << sval
                      << std::endl;
        }

        //   char,short,int,float,double
        //   byte,boolean,string,long(for int64)
        //   double[]

        base_col* col = 0;
        if((*it).type()==value::SHORT) {
          col = a_ntu.create_col<short>((*it).label(),(*it).get_short());
        } else if((*it).type()==value::INT) {
          col = a_ntu.create_col<int>((*it).label(),(*it).get_int());
        } else if((*it).type()==value::INT64) {
          col = a_ntu.create_col<int64>((*it).label(),(*it).get_int64());
        } else if((*it).type()==value::FLOAT) {
          col = a_ntu.create_col<float>((*it).label(),(*it).get_float());
        } else if((*it).type()==value::DOUBLE) {
          col = a_ntu.create_col<double>((*it).label(),(*it).get_double());
        } else if((*it).type()==value::UNSIGNED_SHORT) {
          col = a_ntu.create_col<unsigned short>((*it).label(),(*it).get_unsigned_short());
        } else if((*it).type()==value::UNSIGNED_INT) {
          col = a_ntu.create_col<unsigned int>((*it).label(),(*it).get_unsigned_int());
        } else if((*it).type()==value::UNSIGNED_INT64) {
          col = a_ntu.create_col<uint64>((*it).label(),(*it).get_unsigned_int64());

        } else if((*it).type()==value::BOOL) {
          col = a_ntu.create_col<bool>((*it).label(),(*it).get_bool());
        } else if((*it).type()==value::STRING) {
          col = a_ntu.create_col<std::string>((*it).label(),(*it).get_string());
        } else if((*it).type()==value::INT64) {
          col = a_ntu.create_col<int64>((*it).label(),(*it).get_int64());
        }

        if(!col) {
          std::string stype;
          (*it).s_type(stype);
          std::string sval;
          (*it).tos(sval);
          a_ntu.out() << "tools::aida::create_cols_from_vals :"
                      << " failed for " << stype << " : "
                      << (*it).label() << " : "
                      << sval
                      << std::endl;
          return false;
        }
      }
  }
  return true;
}

// for raxml :
inline bool create_col(ntuple& a_ntu,
                       const std::string& a_type,
                       const std::string& a_name,
                       const std::string& a_s, //def or booking.
                       bool a_is_ntu){
  if(a_type==s_aida_type((short)0)) {
    short v = 0;
    if(a_s.size()&&!to<short>(a_s,v)) {
      a_ntu.out() << "tools::aida::create_col :"
                  << " can't convert def " << sout(a_s)
                  << " to a " << a_type
                  << std::endl;
      return false;
    }
    if(!a_ntu.create_col<short>(a_name,v)) {
      a_ntu.out() << "tools::aida::create_col :"
                  << " can't create column of type " << sout(a_type)
                  << std::endl;
      return false;
    }

  } else if(a_type==s_aida_type((int)0)) {
    int v = 0;
    if(a_s.size()&&!to<int>(a_s,v)) {
      a_ntu.out() << "tools::aida::create_col :"
                  << " can't convert def " << sout(a_s)
                  << " to a " << a_type
                  << std::endl;
      return false;
    }
    if(!a_ntu.create_col<int>(a_name,v)) {
      a_ntu.out() << "tools::aida::create_col :"
                  << " can't create column of type " << sout(a_type)
                  << std::endl;
      return false;
    }

  } else if(a_type==s_aida_type((int64)0)) {
    int64 v = 0;
    if(a_s.size()&&!to<int64>(a_s,v)) {
      a_ntu.out() << "tools::aida::create_col :"
                  << " can't convert def " << sout(a_s)
                  << " to a " << a_type
                  << std::endl;
      return false;
    }
    if(!a_ntu.create_col<int64>(a_name,v)) {
      a_ntu.out() << "tools::aida::create_col :"
                  << " can't create column of type " << sout(a_type)
                  << std::endl;
      return false;
    }

  } else if(a_type==s_aida_type((float)0)) {
    float v = 0;
    if(a_s.size()&&!to<float>(a_s,v)) {
      a_ntu.out() << "tools::aida::create_col :"
                  << " can't convert def " << sout(a_s)
                  << " to a " << a_type
                  << std::endl;
      return false;
    }
    if(!a_ntu.create_col<float>(a_name,v)) {
      a_ntu.out() << "tools::aida::create_col :"
                  << " can't create column of type " << sout(a_type)
                  << std::endl;
      return false;
    }


  } else if(a_type==s_aida_type((double)0)) {
    double v = 0;
    if(a_s.size()&&!to<double>(a_s,v)) {
      a_ntu.out() << "tools::aida::create_col :"
                  << " can't convert def " << sout(a_s)
                  << " to a " << a_type
                  << std::endl;
      return false;
    }
    if(!a_ntu.create_col<double>(a_name,v)) {
      a_ntu.out() << "tools::aida::create_col :"
                  << " can't create column of type " << sout(a_type)
                  << std::endl;
      return false;
    }
  } else if(a_type==s_aida_type((unsigned short)0)) {
    unsigned short v = 0;
    if(a_s.size()&&!to<unsigned short>(a_s,v)) {
      a_ntu.out() << "tools::aida::create_col :"
                  << " can't convert def " << sout(a_s)
                  << " to a " << a_type
                  << std::endl;
      return false;
    }
    if(!a_ntu.create_col<unsigned short>(a_name,v)) {
      a_ntu.out() << "tools::aida::create_col :"
                  << " can't create column of type " << sout(a_type)
                  << std::endl;
      return false;
    }

  } else if(a_type==s_aida_type((unsigned int)0)) {
    unsigned int v = 0;
    if(a_s.size()&&!to<unsigned int>(a_s,v)) {
      a_ntu.out() << "tools::aida::create_col :"
                  << " can't convert def " << sout(a_s)
                  << " to a " << a_type
                  << std::endl;
      return false;
    }
    if(!a_ntu.create_col<unsigned int>(a_name,v)) {
      a_ntu.out() << "tools::aida::create_col :"
                  << " can't create column of type " << sout(a_type)
                  << std::endl;
      return false;
    }

  } else if(a_type==s_aida_type((uint64)0)) {
    uint64 v = 0;
    if(a_s.size()&&!to<uint64>(a_s,v)) {
      a_ntu.out() << "tools::aida::create_col :"
                  << " can't convert def " << sout(a_s)
                  << " to a " << a_type
                  << std::endl;
      return false;
    }
    if(!a_ntu.create_col<uint64>(a_name,v)) {
      a_ntu.out() << "tools::aida::create_col :"
                  << " can't create column of type " << sout(a_type)
                  << std::endl;
      return false;
    }

  /////////////////////////////////////////
  /////////////////////////////////////////
  } else if(a_type==s_aida_type((bool)true)) {
    bool v = false;
    if(a_s.size()&&!to(a_s,v)) {
      a_ntu.out() << "tools::aida::create_col :"
                  << " can't convert def " << sout(a_s)
                  << " to a " << a_type
                  << std::endl;
      return false;
    }
    if(!a_ntu.create_col<bool>(a_name,v)) {
      a_ntu.out() << "tools::aida::create_col :"
                  << " can't create column of type " << sout(a_type)
                  << std::endl;
      return false;
    }

  } else if(a_type==s_aida_type(std::string())) {
    if(!a_ntu.create_col<std::string>(a_name,a_s)) {
      a_ntu.out() << "tools::aida::create_col :"
                  << " can't create column of type " << sout(a_type)
                  << std::endl;
      return false;
    }

  } else if(a_type==s_aida_type((int64)0)) {
    int64 v = 0;
    if(a_s.size()&&!to<int64>(a_s,v)) {
      a_ntu.out() << "tools::aida::create_col :"
                  << " can't convert def " << sout(a_s)
                  << " to a " << a_type
                  << std::endl;
      return false;
    }
    if(!a_ntu.create_col<int64>(a_name,v)) {
      a_ntu.out() << "tools::aida::create_col :"
                  << " can't create column of type " << sout(a_type)
                  << std::endl;
      return false;
    }

  } else if(a_type==s_aida_type_ituple()) {
    // we expect a booking string on a_s.

    if(!a_is_ntu) {
      a_ntu.out() << "tools::aida::create_col :"
                  << " mismatch a_is_ntu/a_type."
                  << std::endl;
      return false;
    }
    if(a_s.empty()) {
      a_ntu.out() << "tools::aida::create_col :"
                  << " empty booking string."
                  << std::endl;
      return false;
    }

    columns::finder f(a_ntu.out(),a_s);
    if(!f.find_variables()) {
      a_ntu.out() << "tools::aida::create_col :"
            << " find_variables() failed for " << sout(a_s) << "."
            << std::endl;
      return false;
    }

    aida_col_ntu* col_ntu = new aida_col_ntu(a_ntu.out(),a_name);
    //create columns on the fillable.
    base_ntu* sub_base_ntu = col_ntu->get_to_fill();
    if(!sub_base_ntu) {delete col_ntu;return false;}
    ntuple* sub_aida = safe_cast<base_ntu,ntuple>(*sub_base_ntu);
    if(!sub_aida) {delete col_ntu;return false;}

    std::vector<value> vars;f.result(vars);
    if(!create_cols_from_vals(*sub_aida,vars)) {
      columns::delete_columns(vars);
      delete col_ntu;
      return false;
    }
    columns::delete_columns(vars);
    a_ntu.add_column(col_ntu);

    //FIXME : double[]

  } else {
    a_ntu.out() << "tools::aida::create_col :"
                << " col type " << sout(a_type)
                << " not yet handled."
                << std::endl;
    return false;
  }

  return true;
}


}}

#endif
