/**
 *  FTrkScanQlook_EXPERT.cxx
 *
 * autor: D.Fedele
 * version v1r15
 * Parameters:
 * 	file - the path to the root file to analyze
 *      outdir - total path of output file 
 *      event - the number of the single event to analyze
 *      DSPprint - the number of a particular DSP to draw (0 don't draw)
 * 	outfile - extension of output file (pdf,ps,gif,jpg)
 *               
 */
//
#include <iostream>
#include <sstream>
//
#include <TPaveText.h>
#include <TLatex.h>
#include <TCanvas.h>
#include <TGraph.h>
#include <TFile.h>
#include <TTree.h>
#include <TStyle.h>
#include <TString.h>
//
#include <physics/tracker/TrackerEvent.h>
#include <PscuHeader.h>
#include <EventHeader.h>
#include <RunHeaderEvent.h>
//

using namespace std;

typedef struct trkword{
  int type;
  int decode;
};

/*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*
 *
 |   The function "datadecode" decodes the tracker words.
 *   
 |   Tracker words are of three types:
 *   - ADC data 
 |   - strip address
 *   - end of ladder
 |   
 *   The function returns a struct variable (trkword) 
 |   that contains two quantities, type and decode, which are assigned 
 *   the following values:
 |   
 *   type                     decode              
 |   ----------------------------------------------------
 *   -1     error             0          
 |    0     data              0-4095   ADC values
 *    1     address           0-1023   strip address (relative to ladder)
 |    2     end-of-ladder     1,2,3    ladder number     (compressed acq mode)      
 *                            4,5,6    ladder number + 3 (full acq mode)
 |       
 *-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/
trkword datadecode(int word){
  int type =0;
  int data =0;
  int nodata = word&0xf000;
  int zero = 0;

  trkword thisword;
    
  switch (nodata>>12){

  case 0:      
	
    thisword.decode = word;
    thisword.type = 0;
    //	cout << thisword.decode << "\n";
    return (thisword);              //>>>>> ADC data (0)

  case 1:       

    type = word&0xC00;
    data = word&0x3ff;

    switch(type>>10){

    case 0:   
      thisword.decode = data;
      thisword.type = 1; //>>> address (1)
      return (thisword);          

    case 2:  
      //	    if(data>=4)data = data-3;
      if(data>6){
	printf("Error on data \n");
	thisword.decode = zero;
	thisword.type = -1;
	return (thisword);     //>>>>> error (-1)
      }
      thisword.decode = data;	    
      thisword.type = 2;
      return (thisword);       //>>> end-of-ladder 

    default:
      printf("Error on data \n");
      thisword.decode = zero;
      thisword.type = -1;
      return (thisword);              //>>>>> error (-1)
	    
    }

  default:

    printf("Error on data \n");
    thisword.decode = zero;
    thisword.type = -1;
    return (thisword);              //>>>>> error (-1)
  }
}


void FTrkScanQLook_EXPERT(TString file, TString outdir,Int_t event, Int_t DSPprint, TString outfile)
{

  // 
  //   obtain information about the data file and select the output file
  Int_t dwpos = file.Last('/');
  Int_t dwpos1 = file.Last('.');
  TString base,ffile ;
  ffile=file(dwpos+1,dwpos1-(dwpos+1));
  if(dwpos>0) base=file(0,dwpos);

  TString out;
  if(outdir.Length()==0){
    out = base;
  }else{
    out = outdir;
  }
  if(out.Last('/')+1<out.Length()) out+="/";
    
  pamela::tracker::TrackerEvent *trk=0;
  pamela::EventHeader *eh=0,*eH=0;
  pamela::PscuHeader *ph=0,*pH=0;
  pamela::RunHeaderEvent *reh=0;

  // open files
  TFile *trackerFile = new TFile(file);
  if ( !trackerFile ){
    trackerFile->Close();
    printf("No tracker file! \n");
    return;
  }

  //Takes the tree and branches
  TTree *tr = (TTree*)trackerFile->Get("Physics");
  tr->SetBranchAddress("Tracker",&trk);
  tr->SetBranchAddress("Header",&eh);

  TTree *otr  = (TTree*)trackerFile->Get("RunHeader");
  otr->SetBranchAddress("Header",&eH);
  otr->SetBranchAddress("RunHeader",&reh);

  // Define variables 
  Int_t nevents = tr->GetEntries();
  Int_t neventH = otr->GetEntries();
  if ( nevents <= 0 ) {
    trackerFile->Close();
    printf("The file is empty, exiting...\n");
    return;
  }

 
  printf("\n Number of Entries: %d\n",nevents);
  printf(" Number of Header Entries: %d\n",neventH);
   
  Long64_t obt=0;  
  Int_t ev[2];
  TString cal="";

  ev[0]=0;
  ev[1]=0;
  for(Int_t i=0;i<neventH;i++){
    otr->GetEntry(i);
    pH = eH->GetPscuHeader();
    if(reh->TRK_CALIB_USED!=104){
      obt = pH->GetOrbitalTime();
      cal="Event with online calibration";
      break;
    }
    if(i==neventH-1){
      cal="*****  ONLINE CALIBRATION NOT FOUND IN THIS FILE  *****";
      ev[0]=2;
      ev[1]=3;
    }
  }
  if(ev[0]==0){
    for(Int_t i=0;i<nevents;i++){
      tr->GetEntry(i); 
      ph = eh->GetPscuHeader();
      if(ph->GetOrbitalTime()>obt){
	ev[0]=i+3;
	ev[1]=i+4;
	break;
      }
    }
  }


  TH1F *histomax[12][2];           //histos of max signals
  TH1F *histocomp[12][2];          //histos of compressed data
  TH1F *histofull[12][2];          //histos of full data
  TCanvas *c1[2];

  for(Int_t e=0;e<2;e++){
    if(event==0)
      event=ev[e];
    else {
      event=event+e;
      if(event>ev[e] && ev[0]!=2)
	cal="Event with online calibration";
      else 
	cal="*****  ONLINE CALIBRATION NOT FOUND IN THIS FILE  *****";
    }
    printf("Scan of Entry %d\n",event); 
	    
    tr->GetEntry(event);    
    //============================================================================  

    gStyle->SetLabelSize(0.06,"x");
    gStyle->SetLabelSize(0.06,"y");
    gStyle->SetTitleFontSize(0.1);
    gStyle->SetFillColor(10);  
    gStyle->SetTitleFillColor(10);
    gStyle->SetTitleOffset(-1,"Y");
    gStyle->SetOptStat(0);
    
    //  draw display area	

    Int_t canvasx=1200;
    Int_t canvasy=900;
    stringstream figsav;
    figsav.str("");
    figsav<<out<<ffile<<"_FTrkScanQLook_EXPERT_ev"<<event+1<<"."<<outfile.Data();
    c1[e] = new TCanvas(figsav.str().c_str(),"FTrkQLookSCAN",canvasx,canvasy);
    c1[e]->SetFillColor(10);
    c1[e]->Range(0,0,1,1);
    stringstream fromfile;
    fromfile<<"FTrkScanQLook_EXPERT      File: "<<ffile<<"            ---->  Entry  "<<event;
    TLatex *t=new TLatex();
    t->SetTextFont(32);
    t->SetTextColor(1);
    t->SetTextAlign(12);
    t->SetTextSize(0.02);
    t->DrawLatex(0.02,0.98,fromfile.str().c_str());
    t->DrawLatex(0.60,0.98,cal.Data());

    //  draw pads
    TPad *trkpad[12];          //pad for histos
    TPaveText *trkpadtext[12]; //pad for header
    Double_t posy = 0.95;    // up y-coord - top pads
    Double_t hpad = 0.15;   // pad height
    Double_t posx1=0;          // left  x-coord - pad column 
    Double_t posx2=0;          // right x-coord - pad olumn
    Double_t posx0=0;          //       x-coord - column division
    Double_t wrel = 0.6;     // relative x size of first sub-column
    Double_t marg = 0.004;   // margin among pads


    stringstream title;
    stringstream hid;
    for(Int_t n = 0; n<12; n++){
      if ( (n+1)%2 ) {
	if(n>1)posy = posy-(marg*2+hpad);
	posx1 = marg;
	posx2 = 0.5 - marg;
	posx0 = 0.5*wrel;
      } else {
	posx1 = posx1 + 0.5;
	posx2 = posx2 + 0.5;
	posx0 = posx0 + 0.5;
      };
    
      /* -----------> pad for histograms  */
      trkpad[n] = new TPad("pad"," ",posx1,posy-hpad,posx0-marg,posy,18,0,0);
      trkpad[n]->SetFillColor(19);
      trkpad[n]->SetFrameFillColor(10);
      /* -----------> pad for header dump */
      trkpadtext[n] = new TPaveText((posx0+marg),(posy-hpad),posx2,posy);
      /* -----------> HISTOGRAMS          */

      title<<"DSP "<<n+1;
      hid<<"h"<<n+e*100;
      histomax[n][e] = new TH1F(hid.str().c_str(),title.str().c_str(),3073,-0.5,3072.5);
      hid<<"hh"<<n+e*100;
      histocomp[n][e] = new TH1F(hid.str().c_str(),title.str().c_str(),3073,-0.5,3072.5);
      hid<<"hhh"<<n+e*100;
      histofull[n][e] = new TH1F(hid.str().c_str(),title.str().c_str(),3073,-0.5,3072.5);
      title.str("");
      hid.str("");
    }                     //end loop on views

    // = = = = = = = = = = = = = = = = = = = = = = = = =
    //  create header dump retrieving event info
    // = = = = = = = = = = = = = = = = = = = = = = = = =
    Int_t ndsp=0;
    stringstream message;

    Double_t whistomax[3072];
    Double_t whisto[3072];
    Double_t whistocomp[3072];
    Double_t whistofull[3072];

    //=============================================
    //      transmitted words
    Int_t word = 0;
    Int_t iword = 0;
    Int_t TOTDATAlength_check = 0;    
    Int_t ii=0,ifull[12],icomp[12],imax[12],nn=0;    
    trkword thisword;

    Int_t address,ladder;

    for(Int_t n = 0; n<12; n++){
    
      ndsp = trk->DSPnumber[n];
      nn = ndsp-1;
      ifull[nn]=0;
      icomp[nn]=0;
      imax[nn]=0;
      if(ndsp>0){
	if(ndsp<13){
	
	  /*.*.*.*.*.*.*.*.*.*.*.*.*.*.*.*.*.*.*.*.*.*.*.*.*.*.*.*.*
	   *
	   * Write event LEVEL0 report
	   *
	   *.*.*.*.*.*.*.*.*.*.*.*.*.*.*.*.*.*.*.*.*.*.*.*.*.*.*.*.*/

	  trkpadtext[nn]->SetTextFont(40);
	  trkpadtext[nn]->SetFillColor(33);
	  trkpadtext[nn]->SetTextSize(0.012);
	  trkpadtext[nn]->SetTextAlign(13);

	  trkpadtext[nn]->AddText(" ");
	  message<<"DAQ mode  --------> "<<trk->DAQmode[n];
	  trkpadtext[nn]->AddText(message.str().c_str());
	  message.str("");
	  message<<"Event number  --------> "<<trk->eventn[n];
	  trkpadtext[nn]->AddText(message.str().c_str());
	  message.str("");
	  message<<"13-bit words --------> "<<trk->DATAlength[n];
	  trkpadtext[nn]->AddText(message.str().c_str());
	  message.str("");
	  if (!(nn%2)&&trk->signcluster[n][0]!=0) message<<"L1  add:  "<<trk->addrcluster[n][0]<<" - sign: "<<1024-(trk->signcluster[n][0]);
	  else message<<"L1  add:  "<<trk->addrcluster[n][0]<<" - sign: "<<(trk->signcluster[n][0]);
	  trkpadtext[nn]->AddText(message.str().c_str());
	  message.str("");
	  if (!(nn%2)&&trk->signcluster[n][1]!=0) message<<"L2  add:  "<<trk->addrcluster[n][1]<<" - sign: "<<1024-(trk->signcluster[n][1]);
	  else message<<"L2  add:  "<<trk->addrcluster[n][1]<<" - sign: "<<trk->signcluster[n][1];
	  trkpadtext[nn]->AddText(message.str().c_str());
	  message.str("");
	  if (!(nn%2)&&trk->signcluster[n][2]!=0) message<<"L3  add:  "<<trk->addrcluster[n][2]<<" - sign: "<<1024-(trk->signcluster[n][2]);
	  else message<<"L3  add:  "<<trk->addrcluster[n][2]<<" - sign: "<<trk->signcluster[n][2];
	  trkpadtext[nn]->AddText(message.str().c_str());
	  message.str("");
	  message<<"NCLUST "<<trk->nclust[n]<<"    CUTC "<<trk->cutc[n]<<"   CUTCL "<<trk->cutcl[n];
	  trkpadtext[nn]->AddText(message.str().c_str());
	  message.str("");
	  message<<"Comp. time "<<trk->compressiontime[n]<<" x 0.051ms = "<<0.051*trk->compressiontime[n]<<" ms";
	  trkpadtext[nn]->AddText(message.str().c_str());
	  message.str("");
	  trkpadtext[nn]->AddText(" ");
	  message<<"CRC -->  "<<trk->crc[n];
	  trkpadtext[nn]->AddText(message.str().c_str());
	  message.str("");
	  message<<"FL1-6 -->  "<<trk->fl1[n]<<" "<<trk->fl2[n]<<" "<<trk->fl3[n]<<" "<<trk->fl4[n]<<" "<<trk->fl5[n]<<" "<<trk->fl6[n]<<" FC "<<trk->fc[n];
	  trkpadtext[nn]->AddText(message.str().c_str());
	  message.str(""); 
	  trkpadtext[nn]->AddText(" ");
	  trkpadtext[nn]->AddLine(0,0,0,0);
	  message<<"PNum "<<trk->pnum[n]<<" - BId "<<trk->bid[n]<<"       ALARM  "<<trk->alarm[n];
	  trkpadtext[nn]->AddText(message.str().c_str());
	  message.str("");
	  message<<"Cmd "<<trk->cmdnum[n]<<" --- Answer length "<<trk->aswr[n]<<" byte";
	  trkpadtext[nn]->AddText(message.str().c_str());
	  message.str("");
	  trkpadtext[nn]->AddText(" ");
	
	  TOTDATAlength_check = TOTDATAlength_check + trk->DATAlength[n];

	  /*.*.*.*.*.*.*.*.*.*.*.*.*.*.*.*.*.*.*.*.*.*.*.*.*.*.*.*.*
	   *
	   * Plot event LEVEL0 histo
	   *
	   *.*.*.*.*.*.*.*.*.*.*.*.*.*.*.*.*.*.*.*.*.*.*.*.*.*.*.*.*/

	  //=============================================

	  for(Int_t i = 0; i< 3072; i++){
	    whistomax[i] = -200;
	    whistocomp[i] = -200;
	    whistofull[i] = -200;
	    whisto[i] = -200;
	  }

	  //      ===============
	  //      trasmitted data
	  //      ===============

	  address = 0;
	  ladder = 1;
	  for(Int_t i = 0; i < trk->DATAlength[n] ; i++){
	    word = trk->TrackerData.At(iword);	    
	    thisword = datadecode(word);
	    iword++;
	    switch (thisword.type){
	    
	    case 0:  //ADC value
	      whisto[address] = thisword.decode;
	      address++;    
	      //	cout << "    adr " << address << "\n"; 
	      break;

	    case 1:  //address
	      address = 1024*(ladder-1) + thisword.decode;
	      //	cout << "    adr " << address << "\n";
	      break;

	    case 2:  //end-of-ladder
	      ladder = thisword.decode;
	      //		cout << "Ladder " << ladder << "\n"; 
	      if(ladder==3){
		//                  end of compressed data - FILL HISTO
		//cout << ">>> COMPRESSED data" << "\n";
		for(ii = 0; ii < 3072; ii++){
		  whistocomp[ii]=whisto[ii];
		  whisto[ii] = -200;
		}
		address = 0;
		ladder = 1;		    
	      }else if(ladder==6){
		//                  end of full data - FILL HISTO
		//cout << ">>> FULL data" << "\n";
		for(ii = 0; ii < 3072; ii++){
		  whistofull[ii]=whisto[ii];
		  whisto[ii] = -200;
		}
		address = 0;
		ladder = 1;
	      }else{		
		if(ladder>3)	ladder=ladder-3;
		address= ladder*1024;		
		ladder = ladder + 1;	
	      }
	    }    
	  }    
	

	  //      ===============
	  //      maximum signals
	  //      ===============
	  if(trk->signcluster[nn][0]!=0) whistomax[   0+(int)trk->addrcluster[nn][0]] = whistocomp[   0+(int)trk->addrcluster[nn][0]];
	  if(trk->signcluster[nn][1]!=0) whistomax[1024+(int)trk->addrcluster[nn][1]] = whistocomp[1024+(int)trk->addrcluster[nn][1]];
	  if(trk->signcluster[nn][2]!=0) whistomax[2048+(int)trk->addrcluster[nn][2]] = whistocomp[2048+(int)trk->addrcluster[nn][2]];

	  for(Int_t i = 0; i < 3072; i++){
	    if(whistomax[i]>-200) imax[nn]=1;
	    if(whistocomp[i]>-200) icomp[nn]=1;
	    if(whistofull[i]>-200) ifull[nn]=1;
	    histomax[nn][e]->Fill((Float_t)i,whistomax[i]);
	    histocomp[nn][e]->Fill((Float_t)i,whistocomp[i]);
	    histofull[nn][e]->Fill((Float_t)i,whistofull[i]);
	  }
    
	  TBox b;

	  c1[e]->cd();           
	  trkpadtext[nn]->Draw();
	  trkpad[nn]->Draw();
	  trkpad[nn]->cd();
	  trkpad[nn]->SetFillColor(10);

	  histocomp[nn][e]->GetYaxis()->SetRangeUser(-500,4500);
	  histocomp[nn][e]->SetLineStyle(1);
	  histocomp[nn][e]->SetLineColor(38);
	  histocomp[nn][e]->SetFillColor(38);
	  histocomp[nn][e]->SetLineWidth(1);
	  histocomp[nn][e]->Draw("");

	  histofull[nn][e]->SetLineColor(40);
	  histofull[nn][e]->SetFillColor(40);
	  histofull[nn][e]->SetLineWidth(1);
	  histofull[nn][e]->SetLineStyle(2);

	  histomax[nn][e]->SetLineColor(2);
	  histomax[nn][e]->SetLineWidth(1);
	  histomax[nn][e]->SetLineStyle(3);

	  if(ifull[nn]==1) histofull[nn][e]->Draw("9bsame][");
	  if(icomp[nn]==1) histocomp[nn][e]->Draw("9bsame][");
	  if(imax[nn]==1) histomax[nn][e]->Draw("same][");
	  histocomp[nn][e]->Draw("axis same");
	  if(nn==0){
	    b.SetFillColor(107);
	    b.SetFillStyle(3945);
	    b.DrawBox(768.,-500.,2047.,4500.);
	  }
	  else if(nn==1){
	    b.SetFillColor(6);
	    b.SetFillStyle(3945);
	    b.DrawBox(2944.,-500.,3060.,4500.);
	
	    b.SetFillColor(107);
	    b.SetFillStyle(3954);
	    b.DrawBox(2816.,-500.,2944.,4500.);
	    b.DrawBox(2048.,-500.,2176.,4500.);
	  }
	  else if(nn==4){
	    b.SetFillColor(107);
	    b.SetFillStyle(3954);
	    b.DrawBox(384.,-500.,512.,4500.);
	  }
	  else if(nn==6){
	    b.SetFillColor(6);
	    b.SetFillStyle(3945);
	    b.DrawBox(2560.,-500.,2816.,4500.);
	    b.DrawBox(1024.,-500.,1535.,4500.);
	
	    b.SetFillColor(107);
	    b.SetFillStyle(3954);
	    b.DrawBox(512.,-500.,768.,4500.);
	    b.DrawBox(1536.,-500.,1792.,4500.);
	  }
	  else if(nn==7){
	    b.SetFillColor(107);
	    b.SetFillStyle(3954);
	    b.DrawBox(512.,-500.,768.,4500.);
	  }
	  else if(nn==8){
	    b.SetFillColor(107);
	    b.SetFillStyle(3954);
	    b.DrawBox(512.,-500.,768.,4500);
	  }
	  else if(nn==9){
	    b.SetFillColor(107);
	    b.SetFillStyle(3954);
	    b.DrawBox(256.,-500.,384.,4500);
	  }
	  else if(nn==11){
	    b.SetFillColor(6);
	    b.SetFillStyle(3945);
	    b.DrawBox(768.,-500.,1024.,4500.);
	
	    b.SetFillColor(107);
	    b.SetFillStyle(3954);
	    b.DrawBox(0.,-500.,512.,4500);
	    b.DrawBox(1920.,-500.,2560.,4500);
	  }
	  c1[e]->Update();
	}
      }
  
    }//end loop on views
  
    c1[e]->Print(figsav.str().c_str());
  }
  return;
}
