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

#include "HstCaen767Store.hh"
#include "ShmObject.hh"


void HstCaen767(const unsigned bits=0x7f007f,
		const unsigned granularity=10,
		const unsigned sleepMs=1000) {

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

  // Reset ROOT
  gROOT->Reset();

  UtlPack uBits(bits);

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

  // Canvas and histogram variables
  TCanvas *glbCanvas;
  TCanvas *tdcCanvas[HstCaen767Store::maximumNumberOfTdcs];
  TCanvas *chnCanvas[HstCaen767Store::maximumNumberOfTdcs]
    [HstCaen767Store::maximumNumberOfChannels];

  std::string glbTitle[4];
  std::string tdcTitle[HstCaen767Store::maximumNumberOfTdcs][10];
  std::string chnTitle[HstCaen767Store::maximumNumberOfTdcs]
    [HstCaen767Store::maximumNumberOfChannels][8];

  TH1F *glbHist[4];
  TH1F *tdcHist[HstCaen767Store::maximumNumberOfTdcs][10];
  TH1F *chnHist[HstCaen767Store::maximumNumberOfTdcs]
    [HstCaen767Store::maximumNumberOfChannels][8];
  
  std::string nums[10]={"0","1","2","3","4","5","6","7","8","9"};


  // Make the global canvas
  std::string glbLabel("HstCaen767Global");
  glbCanvas=new TCanvas((glbLabel+"Canvas").c_str(),
			glbLabel.c_str(),
			cx,cy,(cx+=10)+dx,(cy+=10)+dy);
  
  // Set up global histogram titles
  glbTitle[0]="Number of subrecords;Number;Events";
  glbTitle[1]="Number of subrecords (errors);Number;Events";
  glbTitle[2]="Subrecords per TDC;Number;Events";
  glbTitle[3]="Subrecords per TDC (errors);Number;Events";

  for(unsigned i(0);i<4;i++) {
    if(i<2) {
      glbHist[i]=_pShm->_size.makeTH1F(glbLabel+"Hist"+nums[i],"Initialising...");
      //				       _pShm->title()+glbTitle[i]);
    } else {
      glbHist[i]=_pShm->_tdcs.makeTH1F(glbLabel+"Hist"+nums[i],"Initialising...");
      //				       _pShm->title()+glbTitle[i]);
    }
  }
  
  // Layout the canvas
  glbCanvas->Divide(1,2);
  glbCanvas->cd(1);
  glbHist[0]->Draw();
  glbHist[1]->Draw("same");
  glbHist[1]->SetFillColor(kRed);
  glbCanvas->cd(2);
  glbHist[2]->Draw();
  glbHist[3]->Draw("same");
  glbHist[3]->SetFillColor(kRed);


  for(unsigned t(0);t<_pShm->_numberOfTdcs;t++) {
    if(t<2 && uBits.halfWord(t)!=0) {
    
      // Set up global per TDC canvases
      std::ostringstream sout;
      sout << "HstCaen767GlobalTdc" << t;
      std::string tdcLabel(sout.str());
      
      tdcCanvas[t]=new TCanvas((tdcLabel+"HistCanvas").c_str(),
			       tdcLabel.c_str(),
			       cx,cy,(cx+=10)+dx,(cy+=10)+dy);
      
      // Set up global per TDC histograms
      tdcTitle[t][0]="Number of subrecords;Number;Events";
      tdcTitle[t][1]="Number of subrecords (errors);Number;Events";
      tdcTitle[t][2]="Number of headers;Number;Events";
      tdcTitle[t][3]="Number of headers (errors);Number;Events";
      tdcTitle[t][4]="Number of eobs;Number;Events";
      tdcTitle[t][5]="Number of eobs (errors);Number;Events";
      tdcTitle[t][6]="Number of invalids;Number;Events";
      tdcTitle[t][7]="Number of invalids (errors);Number;Events";
      tdcTitle[t][8]="Number of words;Number;Events";
      tdcTitle[t][9]="Number of words (errors);Number;Events";
      
      for(unsigned i(0);i<10;i++) {
	if(i<2) {
	  tdcHist[t][i]=_pShm->_sizePerTdc[t].makeTH1F(tdcLabel+"Hist"+nums[i],"Initialising...");
//						       _pShm->title()+tdcTitle[t][i]);
	} else if(i<8) {
	  tdcHist[t][i]=_pShm->_labels[t][(i-2)/2].makeTH1F(tdcLabel+"Hist"+nums[i],"Initialising...");
//							    _pShm->title()+tdcTitle[t][i]);
	} else {
	  tdcHist[t][i]=_pShm->_numberOfWords[t].makeTH1F(tdcLabel+"Hist"+nums[i],"Initialising...");
//							  _pShm->title()+tdcTitle[t][i]);
	}
      }

      // Layout the canvas
      tdcCanvas[t]->Divide(1,3);
      
      tdcCanvas[t]->cd(1);
      gPad->Divide(2,1);
      
      tdcCanvas[t]->cd(1);
      gPad->cd(1);
      tdcHist[t][0]->Draw();
      tdcHist[t][1]->Draw("same");
      tdcHist[t][1]->SetFillColor(kRed);
      
      tdcCanvas[t]->cd(1);
      gPad->cd(2);
      tdcHist[t][2]->Draw();
      tdcHist[t][3]->Draw("same");
      tdcHist[t][3]->SetFillColor(kRed);
      
      tdcCanvas[t]->cd(2);
      gPad->Divide(2,1);
      
      tdcCanvas[t]->cd(2);
      gPad->cd(1);
      tdcHist[t][4]->Draw();
      tdcHist[t][5]->Draw("same");
      tdcHist[t][5]->SetFillColor(kRed);
      
      tdcCanvas[t]->cd(2);
      gPad->cd(2);
      tdcHist[t][6]->Draw();
      tdcHist[t][7]->Draw("same");
      tdcHist[t][7]->SetFillColor(kRed);
      
      tdcCanvas[t]->cd(3);
      tdcHist[t][8]->Draw();
      tdcHist[t][9]->Draw("same");
      tdcHist[t][9]->SetFillColor(kRed);
      

      // Now do channel stuff
      for(unsigned c(0);c<_pShm->maximumNumberOfChannels;c++) {
	if(t<2 && c<16 && uBits.bit(16*t+c)) {
	  
	  std::ostringstream sout;
	  sout << "HstCaen767Tdc" << t << "Channel" 
	       << std::setfill('0') << c << std::setfill(' ');
	  std::string chnLabel(sout.str());
	  
	  chnCanvas[t][c]=new TCanvas((chnLabel+"HistCanvas").c_str(),
				      chnLabel.c_str(),
				      cx,cy,(cx+=10)+dx,(cy+=10)+dy);
	  
	  // Set up per TDC histograms
	  chnTitle[t][c][0]="Number of leading;Number;Events";
	  chnTitle[t][c][1]="Number of leading (errors);Number;Events";
	  chnTitle[t][c][2]="Number of falling;Number;Events";
	  chnTitle[t][c][3]="Number of falling (errors);Number;Events";
	  chnTitle[t][c][4]="Number of starts;Number;Events";
	  chnTitle[t][c][5]="Number of starts (errors);Number;Events";
	  chnTitle[t][c][6]="Leading edge time;Time (TDC units = 0.78ns);Events";
	  chnTitle[t][c][7]="Falling edge time;Time (TDC units = 0.78ns);Events";
	  
	  for(unsigned i(0);i<8;i++) {
	    if(i<6) {
	      chnHist[t][c][i]=
		_pShm->_numberOfWordsPerChannel[t][c][i/2].makeTH1F(chnLabel+"Hist"+nums[i],"Initialising...");
//								    _pShm->title()+chnTitle[t][c][i]);
	    } else {
	      chnHist[t][c][i]=_pShm->_tdcValues[t][c][i-6].makeTH1F(chnLabel+"Hist"+nums[i],"Initialising...",
//								     _pShm->title()+chnTitle[t][c][i],
								     granularity);
	    }
	  }
	  
	  chnCanvas[t][c]->Divide(1,3);
	  chnCanvas[t][c]->cd(1);
	  gPad->Divide(3,1);
	  
	  chnCanvas[t][c]->cd(1);
	  gPad->cd(1);
	  chnHist[t][c][0]->Draw();
	  chnHist[t][c][1]->Draw("same");
	  chnHist[t][c][1]->SetFillColor(kRed);
	  
	  chnCanvas[t][c]->cd(1);
	  gPad->cd(2);
	  chnHist[t][c][2]->Draw();
	  chnHist[t][c][3]->Draw("same");
	  chnHist[t][c][3]->SetFillColor(kRed);
	  
	  chnCanvas[t][c]->cd(1);
	  gPad->cd(3);
	  chnHist[t][c][4]->Draw();
	  chnHist[t][c][5]->Draw("same");
	  chnHist[t][c][5]->SetFillColor(kRed);
	  
	  chnCanvas[t][c]->cd(2);
	  chnHist[t][c][6]->Draw();
	  
	  chnCanvas[t][c]->cd(3);
	  chnHist[t][c][7]->Draw();
	}
      }
    }
  }
  

  // Loop to fill histograms

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

  //while(!gSystem->ProcessEvents() && _pShm->_inJob) {
  while(!gSystem->ProcessEvents()) { // Don't quit at end!

    //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) {

      // Global plots

      glbHist[0]->SetTitle((_pShm->title()+glbTitle[0]).c_str());
      glbHist[1]->SetTitle((_pShm->title()+glbTitle[1]).c_str());

      _pShm->_size.fillTH1F(glbHist[0]);

      for(unsigned i(0);i<_pShm->_size.numberOfBins();i++) {
	if(i>2) {
	  glbHist[1]->SetBinContent(i+1,_pShm->_size.contents(i));
	} else {
	  glbHist[1]->SetBinContent(i+1,0);
	}
      }


      glbHist[2]->SetTitle((_pShm->title()+glbTitle[2]).c_str());
      glbHist[3]->SetTitle((_pShm->title()+glbTitle[3]).c_str());

      _pShm->_tdcs.fillTH1F(glbHist[2]);

      for(unsigned i(0);i<_pShm->_tdcs.numberOfBins();i++) {
	if(i>=_pShm->maximumNumberOfTdcs) {
	  glbHist[3]->SetBinContent(i+1,_pShm->_tdcs.contents(i));
	} else {
	  glbHist[3]->SetBinContent(i+1,0);
	}
      }

      // Do number of subrecords plot

      for(unsigned t(0);t<_pShm->_numberOfTdcs;t++) {
	if(t<2 && uBits.halfWord(t)!=0) {

	  tdcHist[t][0]->SetTitle((_pShm->title()+tdcTitle[t][0]).c_str());
	  tdcHist[t][1]->SetTitle((_pShm->title()+tdcTitle[t][1]).c_str());
	  
	  _pShm->_sizePerTdc[t].fillTH1F(tdcHist[t][0]);

	  for(unsigned i(0);i<_pShm->_sizePerTdc[t].numberOfBins();i++) {
	    if(i>1) {
	      tdcHist[t][1]->SetBinContent(i+1,_pShm->_sizePerTdc[t].contents(i));
	    } else {
	      tdcHist[t][1]->SetBinContent(i+1,0);
	    }
	  }
	  
	  // Do labels plots

	  for(unsigned l(0);l<3;l++) {	
	    tdcHist[t][2+2*l]->SetTitle((_pShm->title()+tdcTitle[t][2+2*l]).c_str());
	    tdcHist[t][3+2*l]->SetTitle((_pShm->title()+tdcTitle[t][3+2*l]).c_str());
	    
	    _pShm->_labels[t][l].fillTH1F(tdcHist[t][2+2*l]);

	    for(unsigned i(0);i<_pShm->_labels[t][l].numberOfBins();i++) {
	      if((l<2 && i>1) || (l==2 && i>0)) {
		tdcHist[t][3+2*l]->SetBinContent(i+1,_pShm->_labels[t][l].contents(i));
	      } else {
		tdcHist[t][3+2*l]->SetBinContent(i+1,0);
	      }
	    }
	  }
	  
	  
	  tdcHist[t][8]->SetTitle((_pShm->title()+tdcTitle[t][8]).c_str());
	  tdcHist[t][9]->SetTitle((_pShm->title()+tdcTitle[t][9]).c_str());
	  
	  _pShm->_numberOfWords[t].fillTH1F(tdcHist[t][8]);
	    
	  for(unsigned i(0);i<_pShm->_numberOfWords[t].numberOfBins();i++) {
	    if(i>=100) {
	      tdcHist[t][9]->SetBinContent(i+1,_pShm->_numberOfWords[t].contents(i));
	    } else {
	      tdcHist[t][9]->SetBinContent(i+1,0);
	    }
	  }


	  for(unsigned c(0);c<_pShm->maximumNumberOfChannels;c++) {
	    if(t<2 && c<16 && uBits.bit(16*t+c)) {

	      for(unsigned l(0);l<3;l++) {
		chnHist[t][c][2*l  ]->SetTitle((_pShm->title()+chnTitle[t][c][2*l  ]).c_str());
		chnHist[t][c][2*l+1]->SetTitle((_pShm->title()+chnTitle[t][c][2*l+1]).c_str());
	      
		_pShm->_numberOfWordsPerChannel[t][c][l].fillTH1F(chnHist[t][c][2*l]);

		for(unsigned i(0);i<_pShm->_numberOfWordsPerChannel[t][c][l].numberOfBins();i++) {
		  if(l==2 && i>0) {
		    chnHist[t][c][2*l+1]->SetBinContent(i+1,_pShm->_numberOfWordsPerChannel[t][c][l].contents(i));
		  } else {
		    chnHist[t][c][2*l+1]->SetBinContent(i+1,0);
		  }
		}
	      }


	      chnHist[t][c][6]->SetTitle((_pShm->title()+chnTitle[t][c][6]).c_str());
	      _pShm->_tdcValues[t][c][0].fillTH1F(chnHist[t][c][6]);
	      
	      chnHist[t][c][7]->SetTitle((_pShm->title()+chnTitle[t][c][7]).c_str());
	      _pShm->_tdcValues[t][c][1].fillTH1F(chnHist[t][c][7]);
	    }
	  }
	}
      }
    
      
      glbCanvas->cd(1);
      gPad->Modified();
      glbCanvas->cd(2);
      gPad->Modified();

      for(unsigned t(0);t<_pShm->_numberOfTdcs;t++) {
	if(t<2 && uBits.halfWord(t)!=0) {
	  tdcCanvas[t]->cd(1);
	  gPad->cd(1);
	  gPad->Modified();
	  tdcCanvas[t]->cd(1);
	  gPad->cd(2);
	  gPad->Modified();
	  tdcCanvas[t]->cd(2);
	  gPad->cd(1);
	  gPad->Modified();
	  tdcCanvas[t]->cd(2);
	  gPad->cd(2);
	  gPad->Modified();
	  tdcCanvas[t]->cd(3);
	  gPad->Modified();
	
	  for(unsigned c(0);c<_pShm->maximumNumberOfChannels;c++) {
	    if(t<2 && c<16 && uBits.bit(16*t+c)) {
	      chnCanvas[t][c]->cd(1);
	      gPad->cd(1);
	      gPad->Modified();
	      chnCanvas[t][c]->cd(1);
	      gPad->cd(2);
	      gPad->Modified();
	      chnCanvas[t][c]->cd(1);
	      gPad->cd(3);
	      gPad->Modified();
	      chnCanvas[t][c]->cd(2);
	      gPad->Modified();
	      chnCanvas[t][c]->cd(3);
	      gPad->Modified();
	    }
	  }
	}
      }

      // Finally do all the updates
      glbCanvas->Update();

      for(unsigned t(0);t<_pShm->_numberOfTdcs;t++) {
	if(t<2 && uBits.halfWord(t)!=0) {
	  tdcCanvas[t]->Update();

	  for(unsigned c(0);c<_pShm->maximumNumberOfChannels;c++) {
	    if(t<2 && c<16 && uBits.bit(16*t+c)) {
	      chnCanvas[t][c]->Update();
	    } 
	  } 
	}
      }
    }

    gSystem->Sleep(sleepMs);
  }
}
