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

#ifndef tools_hbook_base_histo
#define tools_hbook_base_histo

#include "axis"

#include <map> //for annotations

namespace tools {
namespace hbook {

class base_histo {
protected:
  base_histo(int aID):m_path(CHPWD()),m_id(aID){}
  virtual ~base_histo(){}
protected:
  base_histo(const base_histo& a_from)
  :m_path(a_from.m_path)
  ,m_id(a_from.m_id)
  ,m_annotations(a_from.m_annotations)
  {}
  base_histo& operator=(const base_histo& a_from){
    m_path = a_from.m_path;
    m_id = a_from.m_id;
    m_annotations = a_from.m_annotations;
    return *this;
  }
public:
  int hbook_id() const {return m_id;}

  bool scale(rarg aScale) {
    //FIXME : Do we want the E option ?
    cd_beg();
    CHOPERA(m_id,"+E",m_id,m_id,aScale,0);
    cd_end();
    return true;
  }

  bool add(const base_histo& a_histo,rarg a_1 = 1,rarg a_2 = 1){
    // this = a_1*this + a_2*a_histo
    //NOTE : it is assumed that m_id and a_histo.m_id are in the
    //       same HBOOK directory.
    cd_beg();
    CHOPERA(m_id,"+E",a_histo.m_id,m_id,a_1,a_2);
    cd_end();
    return true;
  }
  bool subtract(const base_histo& a_histo,rarg a_1 = 1,rarg a_2 = 1){
    // this = a_1*this - a_2*a_histo
    //NOTE : it is assumed that m_id and a_histo.m_id are in the
    //       same HBOOK directory.
    cd_beg();
    CHOPERA(m_id,"-E",a_histo.m_id,m_id,a_1,a_2);
    cd_end();
    return true;
  }
  bool multiply(const base_histo& a_histo,rarg a_1 = 1,rarg a_2 = 1){
    // this = a_1*this * a_2*a_histo
    //NOTE : it is assumed that m_id and a_histo.m_id are in the
    //       same HBOOK directory.
    cd_beg();
    CHOPERA(m_id,"*E",a_histo.m_id,m_id,a_1,a_2);
    cd_end();
    return true;
  }
  bool divide(const base_histo& a_histo,rarg a_1 = 1,rarg a_2 = 1){
    // this = a_1*this / a_2*a_histo
    //NOTE : it is assumed that m_id and a_histo.m_id are in the
    //       same HBOOK directory.
    cd_beg();
    CHOPERA(m_id,"/E",a_histo.m_id,m_id,a_1,a_2);
    cd_end();
    return true;
  }

  std::string title() const {
    std::string _title;
    int ncx,ncy;
    rarg xmin,xmax,ymin,ymax;
    cd_beg();
    CHGIVE(m_id,_title,ncx,xmin,xmax,ncy,ymin,ymax);
    cd_end();
    return _title;
  }
  bool reset() {
    cd_beg();
    CHRESET(m_id," ");
    cd_end();
    return true;
  }
  int all_entries() const { 
    cd_beg();
    int v = CHNOENT(m_id);
    cd_end();
    return v;
  }

public: //annotations :
  typedef std::map<std::string,std::string> annotations_t;
  const annotations_t& annotations() const {return m_annotations;}
  annotations_t annotations() {return m_annotations;}

  void add_annotation(const std::string& a_key,const std::string& a_value) {
    m_annotations[a_key] = a_value; //override if a_key already exists.
  }
  bool annotation(const std::string& a_key,std::string& a_value) const {
    annotations_t::const_iterator it = m_annotations.find(a_key);
    if(it==m_annotations.end()) {a_value.clear();return false;}
    a_value = (*it).second;
    return true;
  }

protected:
  void cd_beg() const{
    base_histo& self = const_cast<base_histo&>(*this);
    CHPWDF(self.m_tmp);
    CHCDIR(m_path," ");
  }
  void cd_end() const {CHCDIR(m_tmp," ");}
protected:
  static int hindex(int aIndex,const hbook::axis& aAxis){
    if(aIndex==hbook::axis::UNDERFLOW_BIN) 
      return 0;
    else if(aIndex==hbook::axis::OVERFLOW_BIN) 
      return aAxis.bins()+1;
    else 
      return aIndex+1;
  }
protected:
  std::string m_path;
  int m_id;
  char m_tmp[1024];
  // etc :
  annotations_t m_annotations;
};

// predefined annotation keys :
inline const std::string& key_axis_x_title() {
  static const std::string s_v("axis_x.title");
  return s_v;
}
inline const std::string& key_axis_y_title() {
  static const std::string s_v("axis_y.title");
  return s_v;
}
inline const std::string& key_axis_z_title() {
  static const std::string s_v("axis_z.title");
  return s_v;
}

}}

#endif
