#ifndef IlcAnalysis_HH
#define IlcAnalysis_HH

#include <cassert>

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

#include "RcdUserRO.hh"
#include "SubAccessor.hh"


class IlcAnalysis : public RcdUserRO {

public:
  IlcAnalysis() : _lastSize(0), _rootFile(0) {
  }
  
  virtual ~IlcAnalysis() {
    endRoot();
  }
  
  bool record(const RcdRecord &r) {
    if(doPrint(r.recordType())) {
      std::cout << "IlcAnalysis::record()" << std::endl;
      r.RcdHeader::print(std::cout," ") << std::endl;
    }

    SubAccessor accessor(r);
    
    switch (r.recordType()) {
      
    case RcdHeader::runStart: {
      std::vector<const IlcRunStart*>
        vs(accessor.access<IlcRunStart>());
      assert(vs.size()==1);
      if(doPrint(r.recordType(),1)) vs[0]->print(std::cout) << std::endl;

      _runNumber=vs[0]-> runNumber();

      std::ostringstream sFile;
      sFile << "IlcAnalysis" << std::setfill('0') << std::setw(6)
	    << _runNumber << ".root";
      
      if(doPrint(r.recordType())) {
	std::cout << "IlcAnalysis::record()  Creating ROOT file "
		  << sFile.str() << std::endl << std::endl;
      }
      _rootFile = new TFile(sFile.str().c_str(),"RECREATE");
      
      std::ostringstream sTitle;
      sTitle << "Run " << vs[0]->runNumber();

      _rootFile->cd();

      _hRunType=new TH1F("RunType",
			 (sTitle.str()+" Type;Type").c_str(),
			 RcdHeader::endOfRecordTypeEnum,0.0,RcdHeader::endOfRecordTypeEnum);
      for(unsigned i(0);i<RcdHeader::endOfRecordTypeEnum;i++) {
	_hRunType->GetXaxis()->SetBinLabel(i+1,RcdHeader::recordTypeName((RcdHeader::RecordType)i).c_str());
      }

      _hRunSize=new TH1F("RunSize",
			 (sTitle.str()+" Size;kBytes").c_str(),
			 128,0.0,128.0);
      _hRunSizeVsType=new TH2F("RunSizeVsType",
			       (sTitle.str()+" Size vs Type;Type;kBytes").c_str(),
			       RcdHeader::endOfRecordTypeEnum,0.0,RcdHeader::endOfRecordTypeEnum,
			       128,0.0,128.0);
      
      _hRunTime=new TH1F("RunTime",
			 (sTitle.str()+" Time;secs").c_str(),
			 100,0.0,0.1);
      _hRunTimeVsType=new TH2F("RunTimeVsType",
			       (sTitle.str()+" Time vs Type;Type;secs").c_str(),
			       RcdHeader::endOfRecordTypeEnum,0.0,RcdHeader::endOfRecordTypeEnum,
			       100,0.0,0.1);
      
      _hRunSizeVsTime=new TH2F("RunSizeVsTime",
			       (sTitle.str()+" Size vs Time;secs;kBytes").c_str(),
			       100,0.0,0.1,
			       128,0.0,128.0);
      
      _configurationNumber=0xffffffff;

      _vCfgType.clear();

      _vCfgSize.clear();
      _vCfgSizeVsType.clear();
      
      _vCfgTime.clear();
      _vCfgTimeVsType.clear();
      
      _vCfgSizeVsTime.clear();

      break;
    }
      
    case RcdHeader::runEnd: {
      _configurationNumber=0xffffffff;
      break;
    }
      
    case RcdHeader::configurationStart: {
      std::vector<const IlcConfigurationStart*>
	vs(accessor.access<IlcConfigurationStart>());
      assert(vs.size()==1);
      if(doPrint(r.recordType(),1)) vs[0]->print(std::cout) << std::endl;

      _configurationNumber=vs[0]->configurationNumberInRun();
      
      std::ostringstream sLabel;
      sLabel << "Cfg" << std::setfill('0') << std::setw(6)
	     << _configurationNumber;
      
      std::ostringstream sTitle;
      sTitle << "Run " << _runNumber << ", Cfg " << _configurationNumber;

      _rootFile->cd();

      _vCfgType.push_back(new TH1F((sLabel.str()+"Type").c_str(),
				   (sTitle.str()+" Type;Type").c_str(),
				   RcdHeader::endOfRecordTypeEnum,0.0,RcdHeader::endOfRecordTypeEnum));

      _vCfgSize.push_back(new TH1F((sLabel.str()+"Size").c_str(),
				   (sTitle.str()+" Size;kBytes").c_str(),
				   128,0.0,128.0));
      _vCfgSizeVsType.push_back(new TH2F((sLabel.str()+"SizeVsType").c_str(),
					 (sTitle.str()+" Size vs type;Type;kBytes").c_str(),
					 RcdHeader::endOfRecordTypeEnum,0.0,RcdHeader::endOfRecordTypeEnum,
					 128,0.0,128.0));

      _vCfgTime.push_back(new TH1F((sLabel.str()+"Time").c_str(),
				   (sTitle.str()+" Time;secs").c_str(),
				   100,0.0,0.1));
      _vCfgTimeVsType.push_back(new TH2F((sLabel.str()+"TimeVsType").c_str(),
					 (sTitle.str()+" Size vs type;Type;secs").c_str(),
					 RcdHeader::endOfRecordTypeEnum,0.0,RcdHeader::endOfRecordTypeEnum,
					 100,0.0,0.1));

      _vCfgSizeVsTime.push_back(new TH2F((sLabel.str()+"SizeVsTime").c_str(),
					 (sTitle.str()+" Size vs time;secs;kBytes").c_str(),
					 100,0.0,0.1,
					 128,0.0,128.0));
      break;
    }
      
    default: {
      break;
    }
    };

    if(_rootFile!=0) {
      _hRunType->Fill(r.recordType());
      _hRunSize->Fill(r.totalNumberOfBytes()/1024.0);
      _hRunSizeVsType->Fill(r.recordType(),r.totalNumberOfBytes()/1024.0);
      
      if(_configurationNumber!=0xffffffff) {
	_vCfgSize[_configurationNumber]->Fill(r.totalNumberOfBytes()/1024.0);
	_vCfgSizeVsType[_configurationNumber]->Fill(r.recordType(),r.totalNumberOfBytes()/1024.0);
	_vCfgType[_configurationNumber]->Fill(r.recordType());
      }
      
      if(_lastSize>0) {
	const double t((r.recordTime()-_lastHeader.recordTime()).deltaTime());
	
	_hRunTime->Fill(t);
	_hRunTimeVsType->Fill(_lastHeader.recordType(),t);
	_hRunSizeVsTime->Fill(t,_lastSize/1024.0);
	
	if(_configurationNumber!=0xffffffff) {
	  _vCfgTime[_configurationNumber]->Fill(t);
	  _vCfgTimeVsType[_configurationNumber]->Fill(_lastHeader.recordType(),t);
	  _vCfgSizeVsTime[_configurationNumber]->Fill(t,_lastSize/1024.0);
	}
      }
    }
    
    _lastHeader=r;
    _lastSize=r.totalNumberOfBytes();

    if(r.recordType()==RcdHeader::runEnd) endRoot();

    return true;
  }

  virtual void endRoot() {
    if(_rootFile!=0) {
      _rootFile->cd();
      _rootFile->Write();
      _rootFile->Close();
      delete _rootFile;
      _rootFile=0;
    }
  }


private:
  unsigned _runNumber;
  unsigned _configurationNumber;
  
  RcdHeader _lastHeader;
  unsigned _lastSize;
  
  TFile* _rootFile;

  TH1F *_hRunType;
  std::vector<TH1F*> _vCfgType;

  TH1F *_hRunSize;
  TH2F *_hRunSizeVsType;
  std::vector<TH1F*> _vCfgSize;
  std::vector<TH2F*> _vCfgSizeVsType;
  
  TH1F *_hRunTime;
  TH2F *_hRunTimeVsType;
  std::vector<TH1F*> _vCfgTime;
  std::vector<TH2F*> _vCfgTimeVsType;
  
  TH2F *_hRunSizeVsTime;
  std::vector<TH2F*> _vCfgSizeVsTime;
};

#endif
