#ifndef HstCfgScan_HH
#define HstCfgScan_HH

#include <cassert>

#include "TH1F.h"
#include "TH2F.h"
#include "TProfile.h"

#include "UtlAverage.hh"


class HstCfgScan {

public:
  HstCfgScan(const char *l, const char *t, int nb, double lo, double hi) :
    _label(l), _title(t), _nBins(nb), _lowEdge(lo), _highEdge(hi) {
  }

  virtual ~HstCfgScan() {
    runStart(0);
  }

  void runStart(unsigned r, std::string v="Value") {
    _run=r;
    _variable=v;

    _vLength=0;
    _vAverage.clear();

    for(unsigned i(0);i<_vScatter.size();i++) delete _vScatter[i];
    _vScatter.clear();

    delete _average;
    _average=0;

    delete _scatter;
    _scatter=0;
  }

  void configurationStart() {
    configurationStart(_vLength);
  }

  //void configurationStart(double x) {
  void configurationStart(int x) {
    for(unsigned i(0);i<_vLength;i++) {
      if(x==_vValue[i]) {
	_vFill=i;
	return;
      }
    }

    if(_vLength==0) _first=x;
    else            _last=x;

    std::ostringstream sLabel;
    sLabel << "Cfg" << std::setfill('0') << std::setw(6) << _vLength << _label;
    std::ostringstream sTitle;
    sTitle << "Run " << _run << ", " << _variable << " " << x << ", " << _title;

    _vFill=_vLength;
    _vLength++;
    _vValue.push_back(x);
    _vAverage.push_back(UtlAverage());
    _vScatter.push_back(new TH1F(sLabel.str().c_str(),sTitle.str().c_str(),_nBins,_lowEdge,_highEdge));
  }

  void runEnd() {
    if(_vLength<2) return;
    if(_average!=0 || _scatter!=0) return;

    std::ostringstream sTitle;
    sTitle << "Run " << _run << ", " << _title;

    double lo(_first);
    double hi(_first+_vLength*double(_last-_first)/(_vLength-1.0));

    bool invert(lo>hi);
    if(invert) {
      lo=hi;
      hi=_first;
    }

    _average=new TH1F((_label+"Profile").c_str(),
		      (sTitle.str()+" vs "+_variable+";"+_variable).c_str(),
		      _vLength,lo,hi);
    
    _scatter=new TH2F((_label+"Scatter").c_str(),
		      (sTitle.str()+" vs "+_variable+";"+_variable).c_str(),
		      _vLength,lo,hi,_nBins,_lowEdge,_highEdge);
    
    for(unsigned x(0);x<_vLength;x++) {
      if(invert) {
	_average->SetBinContent(_vLength-x,_vAverage[x].average());
	_average->SetBinError(_vLength-x,_vAverage[x].errorOnAverage());
      } else {
	_average->SetBinContent(       x+1,_vAverage[x].average());
	_average->SetBinError(       x+1,_vAverage[x].errorOnAverage());
      }
      
      for(int y(0);y<_nBins;y++) {
	if(invert) {
	  _scatter->SetBinContent(_vLength-x,y+1,_vScatter[x]->GetBinContent(y+1));
	} else {
	  _scatter->SetBinContent(       x+1,y+1,_vScatter[x]->GetBinContent(y+1));
	}
      }
    }
  }

  void Fill(double x) {
    if(_vLength==0) return;
    _vAverage[_vFill]+=x;
    _vScatter[_vFill]->Fill(x);
  }


private:
  std::string _label;
  std::string _title;
  int _nBins;
  double _lowEdge;
  double _highEdge;

  unsigned _run;
  std::string _variable;
  //double _first;
  //double _last;
  int _first;
  int _last;
  unsigned _vLength;
  unsigned _vFill;
  std::vector<int>        _vValue;
  std::vector<UtlAverage> _vAverage;
  std::vector<TH1F*>      _vScatter;

  TH1F *_average;
  TH2F *_scatter;
};

#endif
