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

#include "HstCrcNoiseStore.hh"
#include "ShmObject.hh"


void HstCrcNoise(const unsigned swi=0, 
		 const unsigned bits=0x1ffffff, 
		 const bool acqRefresh=true,
		 const unsigned sleepMs=1000) {

  gROOT->Reset();
  
  ShmObject<HstCrcNoiseStore> _shmHstCrcNoiseStore(HstCrcNoiseStore::shmKey);
  HstCrcNoiseStore *_pShm(_shmHstCrcNoiseStore.payload());
  assert(_pShm!=0);



  bool big(swi!=0);

  //std::cout << "SHM ECAL   bits set to " << printHex(_pShm->_crcs[0]) << std::endl;
  //std::cout << "SHM HCAL   bits set to " << printHex(_pShm->_crcs[1]) << std::endl;
  //std::cout << "SHM DHECAL bits set to " << printHex(_pShm->_crcs[2]) << std::endl;


  // Create a new canvas and 3 pads
  TCanvas *hstCrcNoiseCanvas[3][22];
  
  // Create pointers to the objects in shared memory.
  //TH1F *hstCrcNoise[3][22][4];
  std::string hTitle[3][22][4];
  unsigned nCanvas(0);
  
  // Loop over crates
  for(unsigned c(0);c<3;c++) {
    for(unsigned i(0);i<22;i++) hstCrcNoiseCanvas[c][i]=0;
    if((bits&(1<<(22+c)))!=0) {
      
      // Loop over slots
      for(unsigned i(0);i<=21;i++) {
	if((bits&(1<<i))!=0 && _pShm->_crcs[c].bit(i)) {
	  
	  // Make title strings
	  std::ostringstream title;
	  title << "HstCrcNoiseCrate" << c << "Slot";
	  if(i<10) title << "0";
	  title << i;
	  if (swi != 0) title << "Tot";
	  
	  //std::cout << title.str() << std::endl;
	  
	  hTitle[c][i][0]=title.str()+std::string("Number");
	  hTitle[c][i][1]=title.str()+std::string("Average");
	  hTitle[c][i][2]=title.str()+std::string("Rms");
	  hTitle[c][i][3]=title.str()+std::string("Unverified");
	  
	  std::string cTitle(title.str());
	  hstCrcNoiseCanvas[c][i]=new TCanvas((cTitle+"Canvas").c_str(),
					      cTitle.c_str(),
					      10+20*nCanvas,10+20*nCanvas,
					      610+20*nCanvas,760+20*nCanvas);
	  hstCrcNoiseCanvas[c][i]->Divide(1,3);
	  nCanvas++;
	}
      }
    }
  }

  if(nCanvas==0) {
    std::cout << "No canvases made" << std::endl;
    return;
  }
  
  // Create pointers to the objects in shared memory
  TH1F *localHstCrcNoise[3][22][4];
  for(unsigned c(0);c<3;c++) {
    unsigned bins(96);
    if(big) {
      if(c<2) bins=96*18;
      else    bins=96*64;
    }

    for(unsigned i(0);i<22;i++) {
      if(hstCrcNoiseCanvas[c][i]!=0) {
	
	for(unsigned j(0);j<4;j++) {
	  if(j==0) localHstCrcNoise[c][i][j]=new 
	    TH1F(hTitle[c][i][j].c_str(),"Initialising...",bins,0,bins);
	  if(j==1) localHstCrcNoise[c][i][j]=new 
	    TH1F(hTitle[c][i][j].c_str(),"Initialising...",bins,0,bins);
	  if(j==2) localHstCrcNoise[c][i][j]=new 
	    TH1F(hTitle[c][i][j].c_str(),"Initialising...",bins,0,bins);
	  if(j==3) localHstCrcNoise[c][i][j]=new 
	    TH1F(hTitle[c][i][j].c_str(),"Initialising...",bins,0,bins);
	  
	  if(j<3) {
	    hstCrcNoiseCanvas[c][i]->cd(j+1);
	    localHstCrcNoise[c][i][j]->Draw();
	  } else {
	    hstCrcNoiseCanvas[c][i]->cd(1);
	    localHstCrcNoise[c][i][j]->SetFillColor(kRed);
	    localHstCrcNoise[c][i][j]->Draw("same");
	  }
	}
      }
    }
  }

  //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) {
      for(unsigned c(0);c<3;c++) {
	unsigned bins(96);
	if(big) {
	  if(c<2) bins=96*18;
	  else    bins=96*64;
	}

	for(unsigned s(0);s<22;s++) {
	  if(hstCrcNoiseCanvas[c][s]!=0) {
	    
	    if(!big) {
	      localHstCrcNoise[c][s][0]->SetTitle((_pShm->title()+"Number;12*FE+ADC;Events").c_str());
	      localHstCrcNoise[c][s][1]->SetTitle((_pShm->title()+"Mean;12*FE+ADC;ADC counts").c_str());
	      localHstCrcNoise[c][s][2]->SetTitle((_pShm->title()+"Rms;12*FE+ADC;ADC counts").c_str());
	      localHstCrcNoise[c][s][3]->SetTitle((_pShm->title()+"Unverified;12*FE+ADC;Events").c_str());
	      
	      for(int f(0);f<8;f++) {
		for(int a(0);a<12;a++) {
		  if(c<2) {
		    localHstCrcNoise[c][s][0]->SetBinContent(12*f+a+1,_pShm->_average[c][s][f][a][18].number());
		    localHstCrcNoise[c][s][1]->SetBinContent(12*f+a+1,_pShm->_average[c][s][f][a][18].average());
		    localHstCrcNoise[c][s][1]->SetBinError  (12*f+a+1,_pShm->_average[c][s][f][a][18].errorOnAverage()+0.001); // Error exactly zero suppresses display!!!
		    localHstCrcNoise[c][s][2]->SetBinContent(12*f+a+1,_pShm->_average[c][s][f][a][18].sigma());
		    localHstCrcNoise[c][s][2]->SetBinError  (12*f+a+1,_pShm->_average[c][s][f][a][18].errorOnSigma()+0.001);
		    localHstCrcNoise[c][s][3]->SetBinContent(12*f+a+1,_pShm->_unverified[c][s]);
		  } else {
		    localHstCrcNoise[c][s][0]->SetBinContent(12*f+a+1,_pShm->_average64[s][f][a][64].number());
		    localHstCrcNoise[c][s][1]->SetBinContent(12*f+a+1,_pShm->_average64[s][f][a][64].average());
		    localHstCrcNoise[c][s][1]->SetBinError  (12*f+a+1,_pShm->_average64[s][f][a][64].errorOnAverage()+0.001);
		    localHstCrcNoise[c][s][2]->SetBinContent(12*f+a+1,_pShm->_average64[s][f][a][64].sigma());
		    localHstCrcNoise[c][s][2]->SetBinError  (12*f+a+1,_pShm->_average64[s][f][a][64].errorOnSigma()+0.001);
		    localHstCrcNoise[c][s][3]->SetBinContent(12*f+a+1,_pShm->_unverified[c][s]);
		  }
		}
	      }

	      localHstCrcNoise[c][s][0]->SetEntries(bins);
	      localHstCrcNoise[c][s][1]->SetEntries(bins);
	      localHstCrcNoise[c][s][2]->SetEntries(bins);
	      
	    } else {
	      if(c<2) {
		localHstCrcNoise[c][s][0]->SetTitle((_pShm->title()+"Number;216*FE+18*Chip+Chan;Events").c_str());
		localHstCrcNoise[c][s][1]->SetTitle((_pShm->title()+"Mean;216*FE+18*Chip+Chan;ADC counts").c_str());
		localHstCrcNoise[c][s][2]->SetTitle((_pShm->title()+"Rms;216*FE+18*Chip+Chan;ADC counts").c_str());
		localHstCrcNoise[c][s][3]->SetTitle((_pShm->title()+"Unverified;216*FE+18*Chip+Chan;Events").c_str());
	      } else {
		localHstCrcNoise[c][s][0]->SetTitle((_pShm->title()+"Number;768*FE+64*Chip+Chan;Events").c_str());
		localHstCrcNoise[c][s][1]->SetTitle((_pShm->title()+"Mean;768*FE+64*Chip+Chan;ADC counts").c_str());
		localHstCrcNoise[c][s][2]->SetTitle((_pShm->title()+"Rms;768*FE+64*Chip+Chan;ADC counts").c_str());
		localHstCrcNoise[c][s][3]->SetTitle((_pShm->title()+"Unverified;768*FE+64*Chip+Chan;Events").c_str());
	      }

	      for(int f(0);f<8;f++) {
		for(int a(0);a<12;a++) {
		  if(c<2) {
		    for(int chan(0);chan<18;chan++) {
		      localHstCrcNoise[c][s][0]->SetBinContent(18*12*f+18*a+chan+1,_pShm->_average[c][s][f][a][chan].number());
		      localHstCrcNoise[c][s][1]->SetBinContent(18*12*f+18*a+chan+1,_pShm->_average[c][s][f][a][chan].average());
		      localHstCrcNoise[c][s][1]->SetBinError  (18*12*f+18*a+chan+1,_pShm->_average[c][s][f][a][chan].errorOnAverage()+0.001);
		      localHstCrcNoise[c][s][2]->SetBinContent(18*12*f+18*a+chan+1,_pShm->_average[c][s][f][a][chan].sigma());
		      localHstCrcNoise[c][s][2]->SetBinError  (18*12*f+18*a+chan+1,_pShm->_average[c][s][f][a][chan].errorOnSigma()+0.001);
		      localHstCrcNoise[c][s][3]->SetBinContent(18*12*f+18*a+chan+1,_pShm->_unverified[c][s]);
		    }
		  } else {
		    for(int chan(0);chan<64;chan++) {
		      localHstCrcNoise[c][s][0]->SetBinContent(64*12*f+64*a+chan+1,_pShm->_average64[s][f][a][chan].number());
		      localHstCrcNoise[c][s][1]->SetBinContent(64*12*f+64*a+chan+1,_pShm->_average64[s][f][a][chan].average());
		      localHstCrcNoise[c][s][1]->SetBinError  (64*12*f+64*a+chan+1,_pShm->_average64[s][f][a][chan].errorOnAverage()+0.001);
		      localHstCrcNoise[c][s][2]->SetBinContent(64*12*f+64*a+chan+1,_pShm->_average64[s][f][a][chan].sigma());
		      localHstCrcNoise[c][s][2]->SetBinError  (64*12*f+64*a+chan+1,_pShm->_average64[s][f][a][chan].errorOnSigma()+0.001);
		      localHstCrcNoise[c][s][3]->SetBinContent(64*12*f+64*a+chan+1,_pShm->_unverified[c][s]);
		    }
		  }
		}
	      }
	      localHstCrcNoise[c][s][0]->SetEntries(bins);
	      localHstCrcNoise[c][s][1]->SetEntries(bins);
	      localHstCrcNoise[c][s][2]->SetEntries(bins);
	    }
	  }
	}
      }
    }

    for(unsigned c(0);c<3;c++) {
      for(unsigned s(0);s<22;s++) {
	if(hstCrcNoiseCanvas[c][s]!=0) {	  
	  
	  hstCrcNoiseCanvas[c][s]->cd(1);
	  gPad->Modified();
	  hstCrcNoiseCanvas[c][s]->cd(2);
	  gPad->Modified();
	  hstCrcNoiseCanvas[c][s]->cd(3);
	  gPad->Modified();
	  
	  //hstCrcNoiseCanvas[c][s]->Modified();
	  hstCrcNoiseCanvas[c][s]->Update();
	}
      }
    }    

    gSystem->Sleep(sleepMs);
  }
}

void HstCrcNoise(unsigned swi, unsigned crate, const unsigned slot, const unsigned sleepMs) {
  if(crate==0xec) crate=0;
  if(crate==0xce) crate=0;
  if(crate==0xac) crate=1;
  if(crate==0xde) crate=2;

  if(crate>2) return;
  if(slot>21) return;

  HstCrcNoise(swi,(1<<(crate+22))+(1<<slot),sleepMs);
}
