#ifndef UtlAverage_HH
#define UtlAverage_HH

#include <cmath>


class UtlAverage {

public:
  
  UtlAverage() {
    reset();
  }

  virtual ~UtlAverage() {
  }

  virtual std::ostream& print(std::ostream &o) const {
    o << "UtlAverage::print()" << std::endl;
    o << " Number " << _number << ", sum " << _sum 
      << ", sum of squares " << _sumOfSquares << std::endl;
    o << " Average = " << average() << " +/- " << errorOnAverage() << std::endl;
    o << " Sigma = " << sigma() << " +/- " << errorOnSigma() << std::endl;
    return o;
  }

  virtual void reset() {
    _number=0;
    _sum=0.0;
    _sumOfSquares=0.0;
  }

  virtual void operator+=(double x) {
    _number++;
    _sum+=x;
    _sumOfSquares+=x*x;
  }

  virtual void operator-=(double x) {
    _number--;
    _sum-=x;
    _sumOfSquares-=x*x;
  }

  virtual void operator+=(const UtlAverage &a) {
    _number+=a._number;
    _sum+=a._sum;
    _sumOfSquares+=a._sumOfSquares;
  }

  virtual void event(double x) {
    operator+=(x);
  }

  virtual unsigned number() const {
    return _number;
  }

  virtual double average() const {
    if(_number==0) return 0.0;
    return _sum/_number;
  }

  virtual double sigma() const {
    if(_number<=1) return -1.0;
    double dNumber(_number); // _number > 65k doesn't work due to being squared
    return sqrt((dNumber*_sumOfSquares-_sum*_sum)/(dNumber*(dNumber-1.0)));
  }

  virtual double errorOnAverage() const {
    if(_number<=1) return 0.0;
    double dNumber(_number);
    return sigma()/sqrt(dNumber);
  }

  virtual double errorOnSigma() const {
    if(_number<=1) return 0.0;
    double dNumber(_number);
    return sigma()/sqrt(2.0*(dNumber-1.0));
  }


private:
  unsigned _number;
  double _sum;
  double _sumOfSquares;
};

#endif
