//#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"


//ROOT includes
#include "TROOT.h"
#include "TH1I.h"
#include "TFile.h"


using namespace std;


bool newRun, mapped, _newVcalib;
unsigned _runNumber;

RcdHeader runHeader;
AhcMapping mapping;

struct  moduleHists {
  TH1S* hist[12][18];
};

typedef std::map<unsigned,unsigned> vcalib_t;

vcalib_t _vcalib;

std::map<unsigned,moduleHists> _hists;



void fillHists(unsigned module, unsigned chip, unsigned chan, short value) {
  if (_hists[module].hist[0][0] == 0) // if not existing initialize
    for (unsigned chi=0;chi<12;chi++) 
      for (unsigned cha=0;cha<18;cha++) {
	if (chi==0&&cha==0) std::cout << "initializing module " << module << std::endl;
	std::stringstream histName;
	histName << "hist_" << module << "_" << chi << "_" << cha; 
	_hists[module].hist[chi][cha] = new TH1S(histName.str().c_str(),histName.str().c_str(),11000,-999,10000);
      }
  _hists[module].hist[chip][chan]->Fill(value);
}

void writeToFile(vcalib_t vcalib) {
  for (std::map<unsigned,moduleHists>::iterator iter= _hists.begin();iter != _hists.end();iter++) {
    unsigned module = (*iter).first;
    std::cout << "writing module " << module << " at vcalib: " << vcalib[module] << std::endl;
    std::stringstream fileName;
    fileName << "Run" << _runNumber << "." << module << "." << vcalib[module] << ".root";
    TFile *f = new TFile(fileName.str().c_str(),"RECREATE");
    for (unsigned chip=0;chip<12;chip++)
      for(unsigned chan=0;chan<18;chan++)
	(*iter).second.hist[chip][chan]->Write();
    f->Write();
    f->Close();
    delete f;
    
    //closing the file should already delete all histogram objects, but with root you can never be sure
    for (unsigned chip=0;chip<12;chip++)
      for(unsigned chan=0;chan<18;chan++) {
	if ((*iter).second.hist[chip][chan]!=0) 
	  delete (*iter).second.hist[chip][chan];
	(*iter).second.hist[chip][chan]=0;
	}
  }
}

void processData(const RcdRecord &arena) {

  if(arena.recordType()==RcdHeader::runStart) {
    newRun=true;
    mapped=false;
    runHeader=arena;
    runHeader.print(std::cout) << std::endl;
  }

  SubAccessor accessor(arena);

  if (newRun) {
    std::vector<const AhcMapping*>
      v(accessor.access<AhcMapping >());
    
    if(v.size()>0) {
      newRun=false;
      mapped=true;
      _newVcalib=true;
      std::cout << "found "<< v.size() <<" mappings, using last: " << std::endl;
      arena.RcdHeader::print(std::cout) << std::endl;
      for(unsigned i(0);i<v.size();i++) 
	v[i]->print(std::cout," ") << std::endl;
      mapping = *(v[v.size()-1]);
    }
  }

  /*
  if (arena.recordType()==RcdHeader::configurationStart) {
    configCounter++;
  }
  */

  if (mapped) {

    if (arena.recordType()==RcdHeader::configurationStart ){

      std::vector<const CrcLocationData<CrcFeConfigurationData>*>
	vc(accessor.access< CrcLocationData<CrcFeConfigurationData> >());      
      
      for(unsigned i(0);i<vc.size();i++) {
	unsigned slot = vc[i]->slotNumber();
	unsigned fe = vc[i]->crcComponent();

	if (vc[i]->label()!=0) {
	  std::cout << "skipped write Fe configuration record, accept only read records" << std::endl;
	  continue;
	}


	unsigned module = mapping.module(slot,fe);

	if (module!=999) {
	  if (_vcalib[module]!= vc[i]->data()->dacData(CrcFeConfigurationData::boardB) && !_newVcalib) {
	    _newVcalib = true;
	    writeToFile(_vcalib);
	  }
	  _vcalib[module] = vc[i]->data()->dacData(CrcFeConfigurationData::boardB);
	}
      }
    }


    if (arena.recordType()==RcdHeader::event){
      _newVcalib = false;
      std::vector<const CrcLocationData<CrcVlinkEventData>* > v(accessor.extract< CrcLocationData<CrcVlinkEventData> >());


      for(unsigned i(0);i<v.size();i++) {
	//	v[i]->print(std::cout," ") << std::endl;

	unsigned slot = v[i]->slotNumber();
	if (v[i]->crateNumber()!=0xac) continue;
	for(unsigned fe(0);fe<8;fe++) {
	  unsigned module = mapping.module(slot,fe);
	  if (module!=999) {
	    const CrcVlinkFeData *fd(v[i]->data()->feData(fe));
	    if(fd!=0) {
	      for(unsigned chan(0);chan<v[i]->data()->feNumberOfAdcSamples(fe) && chan<18;chan++) {
		const CrcVlinkAdcSample *as(fd->adcSample(chan));
		if(as!=0) {
		  for(unsigned chip(0);chip<12;chip++) {
		    fillHists(module,chip,chan,as->adc(chip));
		  }
		}
	      }
	    }
	  }
	  
	}
      }
     }

  }

  if(arena.recordType()==RcdHeader::runEnd) {
    newRun=false;
    writeToFile(_vcalib);
  }    
}

int main(int argc, const char **argv) {
  UtlArguments argh(argc,argv);
  const unsigned vnum(argh.lastArgument(999999));

  RcdArena arena;
  newRun=false;
  mapped=false;

  _runNumber = vnum;

  RunReader reader;
  assert(reader.open(vnum));
  while(reader.read(arena)) processData(arena);
  assert(reader.close());


  return 0;
}
