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

#include <iostream>
#include <sstream>
#include <vector>
#include <cstdio>
#include <cstdlib>
#include <cmath>

#include "UtlTime.hh"
#include "UtlArguments.hh"
#include "RcdArena.hh"
#include "RcdWriterAsc.hh"
#include "RcdWriterBin.hh"
#include "RcdWriterDmy.hh"

#include "DaqRunStart.hh"
#include "DaqEvent.hh"
#include "RcdReaderAsc.hh"

#include "SubAccessor.hh"

#include "ChkCount.hh"
#include "ChkPrint.hh"
#include "EmcMap.hh"
#include "EmcCalibration.hh"

using namespace std;

const double rand_norm(1.0/RAND_MAX);

double randFlat() {
  return rand_norm*rand();
}

double randGaussian() {
  double x,y;

  do {
    x=10.0*(randFlat()-0.5);
    y=exp(-0.5*x*x);
  } while(randFlat()>y);
  
  return x;
}



bool continueJob=true;

void signalHandler(int signal) {
  std::cout << "Process " << getpid() << " received signal "
	    << signal << std::endl;
  continueJob=false;
}

int main(int argc, const char **argv) {
  UtlArguments argh(argc,argv);
  //argh.print(cout);

  const unsigned vnum(argh.lastArgument(999999));
  ostringstream sout;
  sout << vnum;

  RcdArena arena;
  SubInserter inserter(arena);
  RcdWriterAsc writer;
  //RcdWriterBin writer;
  ChkCount hn;
  ChkPrint pn;
  pn.enable(subRecordType< CrcLocationData<CrcVlinkEventData> >(),true);

  const unsigned rn(1234567891);
  unsigned ms(4);
  if(rn==1234567891) ms=20;
  const unsigned me(250);

  arena.deleteData();
  arena.updateRecordTime();
  arena.recordType(RcdHeader::runStart);

  DaqRunStart *drs(inserter.insert<DaqRunStart>());
  drs->runNumber(rn);
  drs->runType(0);
  drs->maximumNumberOfConfigurationsInRun(1);
  drs->maximumNumberOfSpillsInRun(ms);
  drs->maximumNumberOfEventsInRun(ms*me);
  drs->numberOfWords(0);

  hn.record(arena);
  pn.record(arena);

  ostringstream sout3;
  sout3 << "dat/Run" << rn;
  writer.open(sout3.str());
  writer.write(arena);

  arena.deleteData();
  arena.updateRecordTime();
  arena.recordType(RcdHeader::configurationStart);
  hn.record(arena);
  pn.record(arena);
  writer.write(arena);


  bool noiseOnly(rn==1234567890);

  unsigned d,wx,wy,px,py,l;
  double x,y,z,e;
  int a,b;
  double en[18][18][30];
  short int adc[22][8][12][18];

  EmcMap mp;
  EmcCalibration cl;

  /*
  for(unsigned j(0);j<18;j++) {
    for(unsigned k(0);k<18;k++) {
      for(unsigned l(0);l<30;l++) {
	EmcPhysicalPad pp(j,k,l);
	cl.pedestal(pp,50.0*randGaussian());
	cl.linear(pp,0.004*(1+0.01*randGaussian()));
	cl.threshold(pp,cl.pedestal(pp)+15.0);
      }
    }
  }

  ostringstream sout4;
  sout4 << "cal/Cal" << rn << ".txt";
  assert(cl.write(sout4.str()));
  */

  ostringstream sout4;
  sout4 << "cal/Cal" << rn << ".txt";
  assert(cl.read(sout4.str()));
  cl.print(cout);


  unsigned event(0);

  for(unsigned s(0);s<ms;s++) {
    arena.deleteData();
    arena.updateRecordTime();
    arena.recordType(RcdHeader::spillStart);
    hn.record(arena);
    pn.record(arena);
    writer.write(arena);
    
    for(unsigned i(0);i<me;i++) {
      arena.deleteData();
      arena.updateRecordTime();
      arena.recordType(RcdHeader::event);
      
      DaqEvent *de(inserter.insert<DaqEvent>());
      de->eventNumberInRun(me*s+i);
      de->eventNumberInConfiguration(me*s+i);
      de->eventNumberInSpill(i);

      for(unsigned j(0);j<18;j++) {
	for(unsigned k(0);k<18;k++) {
	  for(unsigned l(0);l<30;l++) {
	    en[j][k][l]=randGaussian()*0.2/6.0; // Signal = 0.2MeV, S/N=6.0
	  }
	}
      }
      
      if(!noiseOnly) {
	ostringstream sout2;
	if(                event<10   ) sout2 << "/vols/calice/calice/simData/10000_TestBeam_30_0_30_20GeV_electrons/proto00000" << event << ".hits";
	if(event>=   10 && event<100  ) sout2 << "/vols/calice/calice/simData/10000_TestBeam_30_0_30_20GeV_electrons/proto0000"  << event << ".hits";
	if(event>=  100 && event<1000 ) sout2 << "/vols/calice/calice/simData/10000_TestBeam_30_0_30_20GeV_electrons/proto000"   << event << ".hits";
	if(event>= 1000 && event<10000) sout2 << "/vols/calice/calice/simData/10000_TestBeam_30_0_30_20GeV_electrons/proto00"    << event << ".hits";
	
	cout << "File = " << sout2.str() << endl;
	
	ifstream fin(sout2.str().c_str());
	
	while(fin >> d) {
	  fin >> wx >> wy >> px >> py >> l >> x >> y >> z >> e >> a >> b;
	  //cout << d << " " << wx << " " << wy << " " << px << " " << py << " " << l << " " << x << " " << y << " " << z << " " << e << " "  << a << " " << b;
	  
	  if(wx>=2 && wx<=4 && wy>=1 && wy<=3) {
	    unsigned rx(6*(wx-2)+px);
	    unsigned ry(6*(wy-1)+py);
	    en[rx][ry][l]+=e;

	    if(s==0 && i==0) cout << rx << " " << ry << " " << l << " " << x << " " << y << " " << z << " " << e << endl;
	  } else {
	    //cout << " <<< OUTSIDE RANGE";
	  }
	  //cout << endl;
	}
      }

      event++;

      for(unsigned j(0);j<18;j++) {
	for(unsigned k(0);k<18;k++) {
	  for(unsigned l(0);l<30;l++) {
	    EmcPhysicalPad pp(j,k,l);
	    EmcReadoutPad rp(mp.map(pp));
	    adc[rp.slot()][rp.frontend()][rp.chip()][rp.channel()]=cl.adc(pp,en[j][k][l]);
	  }
	}
      }
      
      for(unsigned j(5);j<20;j+=2) {
	if(j!=11 && j!=13) {
	  CrcLocationData<CrcVlinkEventData> *l(inserter.insert< CrcLocationData<CrcVlinkEventData> >());
	  l->crateNumber(0xec);
	  l->slotNumber(j);
	  l->crcComponent(CrcLocation::be);
	  l->label(0);
	  
	  l->data()->numberOfWords(1062);
	  l->data()->bufferNumber(i+1);
	  
	  l->data()->header()->data(0x52000000+i,0x000cec10+((rand()%4096)<<20));
	  
	  for(unsigned k(0);k<8;k++) {
	    if(k==0) l->data()->feHeader(k)->data(0x03040506,0x0708090a,0x02002f00,0x0102);
	    else     l->data()->feHeader(k)->data(0x03040506,0x0708090a,0x02000000,0x0102);
	  }

	  for(unsigned k(0);k<8;k++) {
	    CrcVlinkFeData *d(l->data()->feData(k));
	    d->fe(k);
	    d->fifoStatus(0x00010000);
	    d->triggerCounter(i);

	    for(unsigned m(0);m<l->data()->feNumberOfAdcSamples(k) && m<18;m++) {
	      CrcVlinkAdcSample *s(d->adcSample(m));
	      for(unsigned chip(0);chip<12;chip++) {
		s->adc(chip,adc[j][k][chip][m]);
	      }
	      if(m<17) s->flags(0);
	      else     s->flags(3);
	    }

	    /*
	    unsigned *u((unsigned*)l->data()->feData(k));
	    u[0]=0x01000000+k;
	    u[1]=i;
	    short int *p((short int*)l->data()->feData(k));
	    p+=4;
	    for(unsigned chip(0);chip<12;chip++) {
	      for(unsigned channel(0);channel<18;channel++) {
		p[18*chip+channel]=adc[j][k][chip][channel];///!!!
	      }
	    }
	    */


	  }
	  
	  l->data()->trailer()->data(0xa0000000+530,0x00000500+((rand()%65536)<<16));
	  l->data()->totalLength(1060*i);
	  
	  inserter.extend(l->data()->numberOfWords()*4);
      }
    }
    
    hn.record(arena);
    pn.record(arena);
    pn.enable(subRecordType< CrcLocationData<CrcVlinkEventData> >(),false);
    writer.write(arena);
  }
  
  arena.deleteData();
  arena.updateRecordTime();
  arena.recordType(RcdHeader::spillEnd);
  hn.record(arena);
  pn.record(arena);
  writer.write(arena);
}

  arena.deleteData();
  arena.updateRecordTime();
  arena.recordType(RcdHeader::configurationEnd);
  hn.record(arena);
  pn.record(arena);
  writer.write(arena);

  arena.deleteData();
  arena.updateRecordTime();
  arena.recordType(RcdHeader::runEnd);
  hn.record(arena);
  pn.record(arena);
  writer.write(arena);

  hn.print(cout);
  writer.close();
}
