#include "TSystem.h"
#include "TCanvas.h"
#include "TH1F.h"

#include "HstRecordStore.hh"
#include "ShmObject.hh"


void HstRecord(const unsigned bits=0x1f, const unsigned sleepMs=1000) {

  // Check for something requested
  const UtlPack uBits(bits);
  if(uBits.bits(0,4)==0) {
    std::cerr << "HstRecord  ERROR  No histograms selected" << std::endl;
    return;
  }

  /////////////////////////////////
  const unsigned granularity(5);
  /////////////////////////////////

  // Connect to shared memory  
  ShmObject<HstRecordStore> _shmHstRecordStore(HstRecordStore::shmKey);
  HstRecordStore *_pShm(_shmHstRecordStore.payload());
  assert(_pShm!=0);

  // Set up ROOT
  gROOT->Reset();

  // Canvas locations, sizes and labels
  const unsigned dx(600),dy(750);
  unsigned cx(10),cy(10);

  std::string tags[4];
  tags[0]="Job";
  tags[1]="Run";
  tags[2]="Cfg";
  tags[3]="Acq";
  
  // Set up the canvasses
  TCanvas *hstCanvas[5];
  std::string strCanvas[5];

  for(unsigned i(0);i<4;i++) {
    if(uBits.bit(i)) {
      strCanvas[i]=std::string("HstRecord")+tags[i];
      hstCanvas[i]=new TCanvas((strCanvas[i]+"Canvas").c_str(),
			       strCanvas[i].c_str(),
			       cx,cy,(cx+=10)+dx,(cy+=10)+dy);
   } else {
      hstCanvas[i]=0;
    }
  }

  if(uBits.bit(4)) {
    strCanvas[4]=std::string("HstRecordSizeTime");
    hstCanvas[4]=new TCanvas((strCanvas[4]+"Canvas").c_str(),
			     strCanvas[4].c_str(),
			     cx,cy,(cx+=10)+dx,(cy+=10)+dy);
  } else {
    hstCanvas[4]=0;
  }

  // Define the histograms
  TH1F *hstRecord[5][6];
  std::string hstTitle[5][6];
  std::string hLabel[5][6];

  for(unsigned i(0);i<4;i++) {
    if(uBits.bit(i)) {
      hstTitle[i][0]=tags[i]+" record rate;Time (sec);Rate (Hz)";
      hstTitle[i][1]=tags[i]+" event rate;Time (sec);Rate (Hz)";
      hstTitle[i][2]=tags[i]+" trigger rate;Time (sec);Rate (Hz)";
      hstTitle[i][3]=tags[i]+" record data rate;Time (sec);Data rate (MBytes/s)";
      hstTitle[i][4]=tags[i]+" event data rate;Time (sec);Data rate (MBytes/s)";
      hstTitle[i][5]=tags[i]+" trigger data rate;Time (sec);Data rate (MBytes/s)";
      hLabel[i][0]=tags[i]+"RecordRate";
      hLabel[i][1]=tags[i]+"EventRate";
      hLabel[i][2]=tags[i]+"TriggerRate";
      hLabel[i][3]=tags[i]+"RecordDataRate";
      hLabel[i][4]=tags[i]+"EventDataRate";
      hLabel[i][5]=tags[i]+"TriggerDataRate";


      for(unsigned j(0);j<6;j++) {
	hstRecord[i][j]=new TH1F(hLabel[i][j].c_str(),
				 "Initialising...",
				 (1000+granularity-1)/granularity,
				 0.0,_pShm->_rateRange[i]);
      }
    }
  }

  if(uBits.bit(4)) {
    hstTitle[4][0]="Record size;Size (kBytes);Events";
    hstTitle[4][1]="Trigger size;Size (kBytes);Events";
    hstTitle[4][2]="Event size;Size (kBytes);Events";
    hstTitle[4][3]="Record process time;Time (sec);Events";
    hstTitle[4][4]="Trigger process time;Time (sec);Events";
    hstTitle[4][5]="Event process time;Time (sec);Events";

    hLabel[4][0]="SizeRecord";
    hLabel[4][1]="SizeTrigger";
    hLabel[4][2]="SizeEvent";
    hLabel[4][3]="TimeRecord";
    hLabel[4][4]="TimeTrigger";
    hLabel[4][5]="TimeEvent";

    for(unsigned j(0);j<3;j++) {
      hstRecord[4][j]=_pShm->_size.xMakeTH1F(hLabel[4][j],
					     "Initialising...",
					     1,0.0,100.0);
    }
    for(unsigned j(3);j<6;j++) {
      hstRecord[4][j]=_pShm->_time.xMakeTH1F(hLabel[4][j],
					     "Initialising...",
					     1,0.0,0.02);
    }
  }

  
  // Lay out the canvasses
  for(unsigned i(0);i<5;i++) {
    if(uBits.bit(i)) {
      hstCanvas[i]->Divide(1,2);
      
      hstCanvas[i]->cd(1);
      hstRecord[i][0]->Draw();
      hstRecord[i][1]->Draw("same");
      hstRecord[i][1]->SetFillColor(kGreen);
      hstRecord[i][2]->Draw("same");
      hstRecord[i][2]->SetFillColor(kBlue);
      
      hstCanvas[i]->cd(2);
      hstRecord[i][3]->Draw();
      hstRecord[i][4]->Draw("same");
      hstRecord[i][4]->SetFillColor(kGreen);
      hstRecord[i][5]->Draw("same");
      hstRecord[i][5]->SetFillColor(kBlue);

      /*
      hstCanvas[i]->Divide(2,3);
      
      for(unsigned j(0);j<6;j++) {
	hstCanvas[i]->cd(j+1);
	hstRecord[i][j]->Draw();
      }
      */
    }
  }

  // Now loop over refresh cycles

  //const unsigned sMs(5);
  //HstFlags::Level refresh(HstFlags::event);
  //if(acqRefresh) refresh=HstFlags::acquisition;

  //while(!gSystem->ProcessEvents() && _pShm->_inJob) {
  while(!gSystem->ProcessEvents()) {

    //for(unsigned i(0);i<sleepMs && (_pShm->_inAcquisition || !_pShm->_validEvent);i+=sMs) {
    /*
    for(unsigned i(0);i<sleepMs && !_pShm->ready(refresh);i+=sMs) {
      std::cout << "NOT FINISHED" << std::endl;
      gSystem->Sleep(sMs);
    }

    if(_pShm->ready(refresh)) {
    */
    if(true) {

      // Do number of words plot
      for(unsigned i(0);i<4;i++) {
	if(uBits.bit(i)) {
	  for(unsigned m(0);m<6;m++) {
	    hstRecord[i][m]->SetTitle((_pShm->title()+hstTitle[i][m]).c_str());
	    hstRecord[i][m]->SetBins((1000+granularity-1)/granularity,
				     0,_pShm->_rateRange[i]);
	  }
	  
	  for(unsigned j(0);j<(1000+granularity-1)/granularity;j++) {
	    unsigned sum[6];
	    for(unsigned m(0);m<6;m++) sum[m]=0;

	    for(unsigned k(granularity*j);k<granularity*(j+1);k++) {
	      for(unsigned r(0);r<RcdHeader::endOfRecordTypeEnum;r++) {
		sum[0]+=_pShm->_rate[i][r][k];
		if(r==RcdHeader::event || r==RcdHeader::trigger || r==RcdHeader::triggerBurst)
		  sum[1]+=_pShm->_rate[i][r][k];
		if(r==RcdHeader::event || r==RcdHeader::bunchTrain)
		  sum[2]+=_pShm->_rate[i][r][k];

		sum[3]+=_pShm->_data[i][r][k];
		if(r==RcdHeader::event || r==RcdHeader::trigger || r==RcdHeader::triggerBurst)
		  sum[4]+=_pShm->_data[i][r][k];
		if(r==RcdHeader::event || r==RcdHeader::bunchTrain)
		  sum[5]+=_pShm->_data[i][r][k];
	      }
	    }
	    
	    for(unsigned m(0);m<3;m++) {
	      hstRecord[i][m]->SetBinContent(j+1,1000.0*sum[m]/(granularity*_pShm->_rateRange[i]));
	    }
	    for(unsigned m(3);m<6;m++) {
	      hstRecord[i][m]->SetBinContent(j+1,1000.0*sum[m]/(1024.0*1024.0*granularity*_pShm->_rateRange[i]));
	    }
	  }
	}
      }

      // Do size and time plots
      if(uBits.bit(4)) {
	for(unsigned m(0);m<3;m++) {
	  hstRecord[4][m]->SetTitle((_pShm->title()+hstTitle[4][m]).c_str());
	  if(m==0) _pShm->_size.xFillTH1F(hstRecord[4][m]);
	  if(m==1) _pShm->_size.xFillTH1F(hstRecord[4][m],RcdHeader::trigger,RcdHeader::event);
	  if(m==2) _pShm->_size.xFillTH1F(hstRecord[4][m],RcdHeader::event);
	}
	for(unsigned m(3);m<6;m++) {
	  hstRecord[4][m]->SetTitle((_pShm->title()+hstTitle[4][m]).c_str());
	  if(m==3) _pShm->_time.xFillTH1F(hstRecord[4][m]);
	  if(m==4) _pShm->_time.xFillTH1F(hstRecord[4][m],RcdHeader::trigger,RcdHeader::event);
	  if(m==5) _pShm->_time.xFillTH1F(hstRecord[4][m],RcdHeader::event);
	}
      }

      // Label pads as modified
      for(unsigned i(0);i<5;i++) {
	if(uBits.bit(i)) {
	  hstCanvas[i]->cd(1);
	  gPad->Modified();
	  hstCanvas[i]->cd(2);
	  gPad->Modified();
	}    
      }

      // Finally update all the canvasses
      for(unsigned i(0);i<5;i++) {
	if(uBits.bit(i)) {
	  hstCanvas[i]->Update();
	}    
      }    
    }

    // Sleep until next update
    gSystem->Sleep(sleepMs);
  }
}
