#ifndef RunWriterDataMultiFile_HH
#define RunWriterDataMultiFile_HH

#include <cassert>

#include "DaqRunStart.hh"
#include "IlcRunStart.hh"

#include "RcdUserRO.hh"
#include "RcdWriterDmy.hh"
#include "RcdWriterAsc.hh"
#include "RcdWriterBin.hh"

#include "SubAccessor.hh"


class RunWriterDataMultiFile : public RcdUserRO {

public:
  RunWriterDataMultiFile() : _writer(0) {
  }

  virtual ~RunWriterDataMultiFile() {
  }

  bool record(const RcdRecord &r) {
    if(doPrint(r.recordType())) {
      std::cout << std::endl << "RunWriterDataMultiFile::record()" << std::endl;
      r.RcdHeader::print(std::cout," ") << std::endl;
    }

    if(r.recordType()==RcdHeader::startUp) return true;
    if(r.recordType()==RcdHeader::sequenceStart) return true;
    if(r.recordType()==RcdHeader::sequenceEnd) return true;
    if(r.recordType()==RcdHeader::shutDown) return true;

    if(r.recordType()==RcdHeader::configurationEnd) _nCfg++;

    if(r.recordType()==RcdHeader::runStart) {
      _nCfg=0;
      _nTotal=0;
      _nWrite=0;

      // Access the DaqRunStart
      SubAccessor accessor(r);

#ifndef DAQ_ILC_TIMING
      std::vector<const DaqRunStart*> v(accessor.extract<DaqRunStart>());
#else
      std::vector<const IlcRunStart*> v(accessor.extract<IlcRunStart>());
#endif
      assert(v.size()==1);
      _runType=(v[0]->runType());

      _write=_runType.writeRun();
      _ascii=_runType.ascWriteRun();
      _runNumber=v[0]->runNumber();
      _fileNumber=0;

      assert(open());
    }

    bool doWrite(true);

#ifdef DAQ_ILC_COSMICS_FILTER

    if(_runType.type()==IlcRunType::mpsCosmicsThresholdScan) {
      if(r.recordType()==RcdHeader::bunchTrain) {
	doWrite=false;

	SubAccessor accessor(r);
	std::vector<const MpsLocationData<MpsUsbDaqBunchTrainData>* >
	  v(accessor.access< MpsLocationData<MpsUsbDaqBunchTrainData> >());

	for(unsigned s(0);s<v.size();s++) {
	  //const MpsUsbDaqBunchTrainDatum *p(v[s]->data()->data());
	  if(v[s]->data()->numberOfTags()>0) doWrite=true;
	}

	if(!doWrite) {
	  std::vector<const MpsLocationData<MpsSensor1BunchTrainData>* >
	    w(accessor.access< MpsLocationData<MpsSensor1BunchTrainData> >());
	  
	  unsigned ta[4][8000];
	  memset(&(ta[0][0]),0,4*4*8000);
	  
	  unsigned j(0);
	  for(unsigned s(0);s<w.size() && s<5 && !doWrite;s++) {
	    if(!w[s]->usbDaqMaster()) {
	      assert(j<4);
	      for(unsigned region(0);region<4;region++) {
		const MpsSensor1BunchTrainDatum *p(w[s]->data()->regionData(region));
		for(unsigned i(0);i<w[s]->data()->numberOfRegionHits(region);i++) {
		  if(p[i].timeStamp()<8000) ta[j][p[i].timeStamp()]++;
		}
	      }
	      j++;
	    }
	  }
	  
	  unsigned phase(_nCfg%53);
	  unsigned sensor(4);
	  if(phase>0) sensor=(phase-1)/13;
	  
	  for(unsigned t(0);t<8000 && !doWrite;t++) {
	    unsigned n(0);
	    for(unsigned j(0);j<4;j++) {
	      if(j!=sensor) {
		if(ta[j][t]>0) n++;
	      }
	    }
	    if(phase==0 && n>3) doWrite=true;
	    if(phase!=0 && n>2) doWrite=true;
	  }
	}

	_nTotal++;
	if(doWrite) {
	  _nWrite++;
	  std::cout << "mpsCosmicsThresholdScan written " << _nWrite
		    << " bunch trains out of " << _nTotal;
	  if(_nTotal>0) std::cout << ", fraction = " << (double)_nWrite/(double)_nTotal;
	  std::cout << std::endl;
	}
      }
    }

#endif

    // Write out records
    if(doWrite) assert(_writer->write(r));

    if(r.recordType()==RcdHeader::runEnd) {
      assert(close(true && _write));

    // Check for file size
    } else {

      unsigned limit(2000000000);
      /*
      if(r.recordType()==RcdHeader::configurationEnd) limit=1700000000;
      if(r.recordType()==RcdHeader::acquisitionEnd  ) limit=1800000000;
      if(r.recordType()==RcdHeader::spillEnd        ) limit=1900000000;
      if(r.recordType()==RcdHeader::spill           ) limit=1900000000;
      if(r.recordType()==RcdHeader::transferEnd     ) limit=1900000000;
      if(r.recordType()==RcdHeader::transfer        ) limit=1900000000;
      */
      
      if(_writer->numberOfBytes()>limit) {
	if(doPrint(r.recordType()),1) std::cout
	  << " Number of bytes written = " << _writer->numberOfBytes()
	  << " > " << limit << std::endl;
	
	RcdRecord fileContinuation;
	fileContinuation.initialise(RcdHeader::fileContinuation);
	fileContinuation.recordTime(r.recordTime()+UtlTimeDifference(0,1));
	
	assert(_writer->write(fileContinuation));
	assert(close(false));
	assert(open());
	assert(_writer->write(fileContinuation));
      }
    }
    
    return true;
  }

  bool open() {
    // Check for no writer
    assert(_writer==0);

    if(_write) {
      if(_ascii) _writer=new RcdWriterAsc;
      else       _writer=new RcdWriterBin;
    } else {
      _writer=new RcdWriterDmy;
    }
    
    std::ostringstream dout;
    dout << "data/run/Run";

    if(_runNumber<100000) dout << "0";
    if(_runNumber<10000)  dout << "0";
    if(_runNumber<1000)   dout << "0";
    if(_runNumber<100)    dout << "0";
    if(_runNumber<10)     dout << "0";
    dout << _runNumber << ".";

    if(_fileNumber<100)   dout << "0";
    if(_fileNumber<10)    dout << "0";
    dout << _fileNumber;

    // Open data output file
    assert(_writer->open(dout.str()));

    // Increment file number for next file
    _fileNumber++;

    return true;
  }

  bool close(bool s) {

    // Check for writer
    assert(_writer!=0);
    
    // Close file and delete writer
    assert(_writer->close());
    delete _writer;
    _writer=0;

    // Launch summary job
    if(s) {
      std::ostringstream sout;
      sout << "summary " << _runNumber << " &";
      std::cout << "About to execute: " << sout.str() << std::endl;      
      system(sout.str().c_str());
    }

    return true;
  }


private:
  RcdWriter *_writer;
  bool _write;
  bool _ascii;

#ifndef DAQ_ILC_TIMING
  DaqRunType _runType;
#else
  IlcRunType _runType;
#endif

  unsigned _runNumber;
  unsigned _fileNumber;


  // BIG HACK COUNTERS!!!
  unsigned _nCfg;
  unsigned _nTotal;
  unsigned _nWrite;
};

#endif
