//#include <sys/types.h>
//#include <sys/stat.h>
//#include <signal.h>
//#include <fcntl.h>
//#include <unistd.h>

#include <iostream>
#include <sstream>
#include <vector>
#include <map>
//#include <cstdio>

//#include "UtlTime.hh"
#include "UtlArguments.hh"
#include "RcdArena.hh"
#include "RcdReaderBin.hh"
#include "RunReader.hh"
#include "SubAccessor.hh"

using namespace std;

std::map<unsigned,unsigned short> DAC;
std::map<unsigned,bool> wasSet;

bool newRun;
RcdHeader runHeader;


unsigned makeKey(unsigned slot, unsigned fe, unsigned chip, unsigned chan) {
  return (slot-5)*8*12*18 + fe*12*18 + chip*18 + chan;
}



void doCheck(const RcdRecord &arena, const unsigned printlevel) {
  if(arena.recordType()==RcdHeader::runStart) {
    newRun=true;
    runHeader=arena;
  }

  SubAccessor accessor(arena);

  std::vector<const CrcLocationData<AhcVfeStartUpDataFine>*>
    vF(accessor.access<CrcLocationData<AhcVfeStartUpDataFine> >());

  std::vector<const CrcLocationData<AhcVfeStartUpDataCoarse>*>
    vC(accessor.access<CrcLocationData<AhcVfeStartUpDataCoarse> >());


  if(vF.size()>0 || vC.size()>0) {
    if(newRun) {
      newRun=false;
      if (printlevel > 1) runHeader.print(std::cout) << std::endl;
    }

    if (printlevel > 1) arena.RcdHeader::print(std::cout) << std::endl;
    
    unsigned good=0;
    unsigned bad=0;
    
    for(unsigned i(0);i<vF.size();i++) {
      unsigned slot = vF[i]->slotNumber();
      unsigned fe = vF[i]->crcComponent();
      unsigned label = vF[i]->label();
     
      if (slot <20 && fe <8) {
	if (label == 1 && printlevel > 1) std::cout << "found programmming record of slot " << slot << " fe " << fe << std::endl;
	for (unsigned chip=0;chip<12;chip++) 
	  for (unsigned chan=0;chan<18;chan++) 
	    if (label == 1) {
	      unsigned key = makeKey(slot,fe,chip,chan);
	      DAC[key] = vF[i]->data()->dac(chip,chan);
	      wasSet[key] = true; 
	    
	    }
	    else if (label == 2) {
	      unsigned key = makeKey(slot,fe,chip,chan);
	      if (!wasSet[key]) {
		if (printlevel >0) std::cout << "WARNING: no value set for slot "<< slot << " fe "<< fe << " chip " << chip << " chan " << chan << " but read back " << (short)( vF[i]->data()->dac(chip,chan)) <<std::endl;
	      }
	      else if (DAC[key] != vF[i]->data()->dac(chip,chan)) {
		if (printlevel>0) std::cout << "found not matching DAC value for slot "<< slot << " fe "<< fe << " chip " << chip << " chan " << chan << ": is " << (short)( vF[i]->data()->dac(chip,chan)) << " instead of " << (DAC[key]) << std::endl;
		bad++;
	       
	      }
	      else good++;
	      
	    }
	    else if (printlevel>0) std::cout << "WARNING: found record with wronge type: neither read nor write" << std::endl;
      }
    }

    for(unsigned i(0);i<vC.size();i++) {
      unsigned slot = vC[i]->slotNumber();
      unsigned fe = vC[i]->crcComponent();
      unsigned label = vC[i]->label();
     
      if (slot <20 && fe <8) {
	if (label == 1 && printlevel > 1) std::cout << "found programmming record of slot " << slot << " fe " << fe << std::endl;
	for (unsigned chip=0;chip<12;chip++) 
	  for (unsigned chan=0;chan<18;chan++) 
	    if (label == 1 && (chip <4 || chip >7)) {
	      unsigned key = makeKey(slot,fe,chip,chan);
	      DAC[key] = vC[i]->data()->dac(chip,chan);
	      wasSet[key] = true; 
	    
	    }
	    else if (label == 2 && (chip <4 || chip >7) ) {
	      unsigned key = makeKey(slot,fe,chip,chan);
	      if (!wasSet[key]) {
		if (printlevel > 0) std::cout << "WARNING: no value set for slot "<< slot << " fe "<< fe << " chip " << chip << " chan " << chan << " but read back " << (short)( vC[i]->data()->dac(chip,chan)) <<std::endl;
	      }
	      else if (DAC[key] != vC[i]->data()->dac(chip,chan)) {
		if (printlevel > 0) std::cout << "found not matching DAC value for slot "<< slot << " fe "<< fe << " chip " << chip << " chan " << chan << ": is " << (short)( vC[i]->data()->dac(chip,chan)) << " instead of " << (DAC[key]) << std::endl;
		bad++;
	      }
	      else good++;
	      
	    }
	    else if (chip < 4 || chip > 7 ) if (printlevel >0) std::cout << "WARNING: found record with wronge type: neither read nor write" << std::endl;
      }
      
    }
    
    std::cout << "found " << good << " properly programmed DACs" << std::endl;
    std::cout << "found " << bad << " bad programmed DACs" << std::endl;
    std::cout << good/(float)(good+bad)*100 << "% good out of " << good+bad << " total DACs" << std::endl;
  }
  
  if(arena.recordType()==RcdHeader::runEnd) newRun=false;
}


int main(int argc, const char **argv) {

  UtlArguments argh(argc,argv);
  const unsigned vnum(argh.lastArgument(999999));
  const unsigned printlevel(argh.optionArgument('p',1,"print level"));

  RcdArena arena;
  newRun=false;

  // Is is a run number or Unix epoch time?
  if(vnum>999999) {
    RcdReaderBin reader;

    reader.printLevel(printlevel);

    std::ostringstream sout;
    sout << "data/slw/Slw" << vnum;

    assert(reader.open(sout.str()));
    while(reader.read(arena)) doCheck(arena,printlevel);
    assert(reader.close());

  } else {
    RunReader reader;
    //    reader.printLevel(printlevel);   missing function in RunReader class!!
    assert(reader.open(vnum));
    while(reader.read(arena)) doCheck(arena,printlevel);
    assert(reader.close());
  }

  return 0;
}
