#ifndef ChkCount_HH
#define ChkCount_HH

#include <iostream>
#include <iomanip>
#include <fstream>

// dual/inc/rcd
#include "RcdHeader.hh"
#include "RcdUserRO.hh"

// dual/inc/sub
#include "SubInserter.hh"


class ChkCount : public RcdUserRO {

public:
  ChkCount() : RcdUserRO() {
    for(unsigned i(0);i<=RcdHeader::endOfRecordTypeEnum;i++) {
      _resetRecord[i]=false;
    }

    reset();
  }

  ChkCount(unsigned p) : RcdUserRO(p) {
    for(unsigned i(0);i<=RcdHeader::endOfRecordTypeEnum;i++) {
      _resetRecord[i]=false;
    }

    reset();
  }

  virtual ~ChkCount() {
    if(_printRecord[RcdHeader::endOfRecordTypeEnum]) print(std::cout);
  }

  void reset() {
    _totalCount=0;
    for(unsigned i(0);i<=RcdHeader::endOfRecordTypeEnum;i++) {
      _count[i]=0;
      _printRecord[i]=false;
    }

    // Default to printing in dtor
    _printRecord[RcdHeader::endOfRecordTypeEnum]=true;
  }

  std::ostream& print(std::ostream& o, std::string s="") const {
    o << s << "ChkCount::print()" << std::endl;
    o << s << "Total number of records = " 
      << std::setw(10) << _totalCount << std::endl;

    for(unsigned i(0);i<RcdHeader::endOfRecordTypeEnum;i++) {
      if(_count[i]>0) {
	o << s << " Number of records of type " << std::setw(2) << i << " = " 
	  << RcdHeader::recordTypeName((RcdHeader::RecordType)i) << " = "
	  << std::setw(10) << _count[i] << std::endl;
      }
    }

    if(_count[RcdHeader::endOfRecordTypeEnum]>0)
      o << s << " Number of records of unknown type                 = " 
	<< std::setw(10) << _count[RcdHeader::endOfRecordTypeEnum]
	<< std::endl;

    return o;
  }

  unsigned count(RcdHeader::RecordType rt) const {
    if(rt<RcdHeader::endOfRecordTypeEnum) {
      return _count[rt];
    } else {
      return 0;
    }
  }

  bool resetRecord(RcdHeader::RecordType rt=RcdHeader::endOfRecordTypeEnum, bool e=true) {
    if(rt<=RcdHeader::endOfRecordTypeEnum) {
      _resetRecord[rt]=e;
      return true;
    }
    return false;
  }

  bool printRecord(RcdHeader::RecordType rt=RcdHeader::endOfRecordTypeEnum, bool e=true) {
    if(rt<=RcdHeader::endOfRecordTypeEnum) {
      _printRecord[rt]=e;
      return true;
    }
    return false;
  }

  bool record(const RcdRecord &r) {
    _totalCount++;
    unsigned rt(r.recordType());
    if(rt<RcdHeader::endOfRecordTypeEnum) {
      _count[rt]++;

      if((_printLevel>0 && r.recordType()==RcdHeader::runStart) ||
	 (_printLevel>0 && r.recordType()==RcdHeader::runStop) ||
	 (_printLevel>0 && r.recordType()==RcdHeader::runEnd) ||
	 (_printLevel>2 && r.recordType()==RcdHeader::configurationStart) ||
	 (_printLevel>2 && r.recordType()==RcdHeader::configurationStop) ||
	 (_printLevel>2 && r.recordType()==RcdHeader::configurationEnd) ||
	 (_printLevel>4 && r.recordType()==RcdHeader::spillStart) ||
	 (_printLevel>4 && r.recordType()==RcdHeader::spillStop) ||
	 (_printLevel>4 && r.recordType()==RcdHeader::spillEnd) ||
	 (_printLevel>6 && r.recordType()==RcdHeader::event)) {
	std::cout << " Record " << std::setw(10) << _count[rt]
		  << " (out of " << std::setw(10) << _totalCount
		  << ") of type " << std::setw(2) << rt << " = " 
		  << RcdHeader::recordTypeName((RcdHeader::RecordType)rt)
		  << std::endl;
      }

      if(_resetRecord[rt]) reset();
      if(_printRecord[rt] || _printLevel>8) print(std::cout);

    } else {
      std::cout << "Unknown record type = " << rt << std::endl;
      r.RcdHeader::print(std::cout);
      _count[RcdHeader::endOfRecordTypeEnum]++;

      if(_printLevel>8) print(std::cout);
    }

    return true;
  }

private:
  unsigned _totalCount;
  unsigned _count[RcdHeader::endOfRecordTypeEnum+1];
  bool _resetRecord[RcdHeader::endOfRecordTypeEnum+1];
  bool _printRecord[RcdHeader::endOfRecordTypeEnum+1];
};

#endif
