#ifndef HstArray_HH
#define HstArray_HH

#include <cstring>

#include "TH1F.h"


template <unsigned NumberOfBins> class HstArray {

public:
  HstArray() {
    reset();
  }

  void reset() {
    memset(_array,0,(NumberOfBins+2)*sizeof(int));
  }

  unsigned numberOfBins() const {
    return NumberOfBins;
  }

  int binToArray(int bin) const {
    if(bin<0) return 0;
    else if(bin>=(int)NumberOfBins) return NumberOfBins+1;
    else return bin+1;
  }

  int underflow() const {
    return _array[0];
  }

  int contents(int bin) const {
    return _array[binToArray(bin)];
  }

  int overflow() const {
    return _array[NumberOfBins+1];
  }

  int entries() const {
    int sum(0);
    for(unsigned i(0);i<NumberOfBins+2;i++) sum+=_array[i];
    return sum;
  }

  void fill(int bin, int weight=1) {
    _array[binToArray(bin)]+=weight;
    return;
  }

  void fillUnderflow(int weight=1) {
    _array[0]+=weight;
  }

  void fillOverflow(int weight=1) {
    _array[NumberOfBins+1]+=weight;
  }

  // ROOT interface
  TH1F* makeTH1F(const std::string &label, const std::string &title,
		 unsigned granularity=1,
		 double lo=0.0, double hi=NumberOfBins) {
    assert(granularity>0);
    unsigned bins((NumberOfBins+granularity-1)/granularity);
    return new TH1F(label.c_str(),title.c_str(),bins,lo,hi);
  }

  void fillTH1F(TH1F *hst) {
    unsigned granularity((NumberOfBins+hst->GetNbinsX()-1)/hst->GetNbinsX());
 
    for(unsigned i(0);i<(unsigned)hst->GetNbinsX();i++) {
      int sum(0);
      for(unsigned j(granularity*i);j<granularity*(i+1) && j<NumberOfBins;j++) {
	sum+=contents(j);
      }
      hst->SetBinContent(i+1,sum);
    }
 
    hst->SetBinContent(0,underflow());
    hst->SetBinContent(hst->GetNbinsX()+1,overflow());
    hst->SetEntries(entries());
  }


  std::ostream& print(std::ostream &o, std::string s="") const {
    o << s << "HstArray<" << NumberOfBins << ">::print()" << std::endl;

    o << s << " Entries   = " << std::setw(6) << entries() << std::endl;
    o << s << " Underflow = " << std::setw(6) << underflow() << std::endl;
    for(int i(0);i<(int)NumberOfBins;i++) {
      o << s << " Bin " << std::setw(5) << i << " = " 
	<< std::setw(6) << contents(i) << std::endl;
    }
    o << s << " Overflow  = " << std::setw(6) << overflow() << std::endl;

    return o;
  }


private:
  int _array[NumberOfBins+2];
};

#endif
