/**
* S4 Calibration Quick Look
* Author Marcelli-Malvezzi
* Version 1.00 - 27 February 2006
*
* Description: The aim of S4 Calibration QL software is to keep under control the bahaviour of S4 Calibration.
*              It creates only one output canvas relative to the time behaviour of collected calibration data.
*              See documentation for a more detailed description of the output.
*
* Parameters:
* 	       TSTring base    - the path to the root directory for the specific Pamela unpack session
*                         There is no default value, without this input the program will not run
*              TString outDir  - the path where to save the output image (Default = ./) 
*              TString format  - the format which will be used fo rsave the produced images (Default = "jpg") 
*
*
* Version 1.1 - June 2006
* Fixed bugs: for a large namber of events is not possible to initialize vectors, so all graphs have been converted in histograms
*
* Known bugs: it is no possible to choise the figure format
*
* Version 1.2 - August 2006
* Fixed bugs: is possible to choise figure format; all calibration are drown
**************/

#include <fstream>
#include <iostream>
#include <iostream>
#include <sstream>
#include "TStyle.h"
#include "TFile.h"
#include "TList.h"
#include "TTree.h"
#include "TLatex.h"
#include "TObjString.h"
#include "TCanvas.h"
#include "TGraph.h"
#include "TH1F.h"
#include "TF1.h"
#include "TGaxis.h"
#include "TString.h"
#include "TPaveText.h"
#include "TMultiGraph.h"
#include "TGraphErrors.h"
#include "EventHeader.h"
#include "PscuHeader.h"
#include "physics/S4/S4Event.h"
#include "CalibS4Event.h"
#include "tmtc/TmtcEvent.h"
#include "tmtc/TmtcRecord.h"

using namespace std;

//--------------- root function ----------------------------------

void S4_Calibration_QL(TString base, TString outDir, TString format){

  //--------------- Variables initialization -----------------------------------//
  const Int_t channels = 4096;
  Double_t calib_1_MEAN;
  Double_t calib_2_MEAN;
  Double_t calib_4_MEAN;
  Double_t calib_1_RMS;
  Double_t calib_2_RMS;
  Double_t calib_4_RMS;
  Double_t calib_1=0, calib_2=0, calib_4=0;
  Double_t obt;
  TString status;
  Int_t IPM1status, IPM2status;
  ULong_t lastime, firstime, obt1, utile;
  double obmin=0.;
  double obmax=0.;
  double limitdown=0;
  double limitup=0;


  //------------------------- Open data file -------------------------------------//
  TFile  *file  =new TFile(base.Data()) ;
  TString filename = ((TObjString*)base.Tokenize('/')->Last())->GetString();
  filename = ((TObjString*)filename.Tokenize('.')->First())->GetString();

  if (!file){
    printf("No such file in the directory has been found");
    return;
  }
  
  TTree *CalibS4tr = (TTree*)file->Get("CalibS4");
  TBranch *S4Br = CalibS4tr->GetBranch("CalibS4");
  TBranch *headBr = CalibS4tr->GetBranch("Header");
  TTree *tmtcTr = (TTree*)file->Get("Tmtc");
  TBranch *tmtcBr = tmtcTr->GetBranch("Tmtc");
 
  pamela::TmtcEvent *tme = 0;
  pamela::TmtcRecord *tmr = 0; 
  pamela::S4::S4Event  *s4Record;
  pamela::CalibS4Event *s4Event = new  pamela::CalibS4Event();  
  pamela::EventHeader  *eh   = 0;
  pamela::PscuHeader   *ph   = 0;
 
  CalibS4tr->SetBranchAddress("CalibS4", &s4Event);
  CalibS4tr->SetBranchAddress("Header", &eh);
  tmtcTr->SetBranchAddress("Tmtc", &tme);
  Long64_t nevents= CalibS4tr->GetEntries();
  Long64_t neventstmtc = tmtcBr->GetEntries();

  if (neventstmtc<=0) {
    printf("Tmtc packet: nevents =  %i\n", nevents);
    printf("             No info about kind of calibration (hot or cold) \n");
  }
  //----------------- if nevents = 0 ----------------------------------------------//
  if (nevents<=0){
    cout<<"WARNING: No Entries, RETURN"<<"\n";

    TCanvas *canvas4 = new TCanvas("No entries", "No entries ", 400, 200);
    canvas4->SetFillColor(10);
    canvas4->cd();

    TLatex *l = new TLatex();
    l->SetTextAlign(12);
    l->SetTextSize(0.15);
    l->SetTextColor(2);
    stringstream oss, noentries;
    noentries.str("");
    noentries<< "S4_Calibration_QL:";
    l->DrawLatex(0.05, 0.7, noentries.str().c_str()); 
    noentries.str("");
    noentries<< "No entries for this files";
    l->DrawLatex(0.05, 0.5, noentries.str().c_str()); 

    if (outDir== "./") {
      oss.str("");
      oss << filename.Data() << "_S4_Calibration_QL." << format.Data();
    } else {
      oss.str("");
      oss << outDir.Data() << filename.Data() << "_S4_Calibration_QL." << format.Data();
    }
  
    canvas4->Update();
    canvas4->SaveAs(oss.str().c_str()); 
    return;
  }

  //---------------Look for configuration hot or cold -----------------------//
  if(neventstmtc!=0){
    Int_t recordstot=0;
    for (Int_t i = 0; i < neventstmtc; i++){
      tmtcBr->GetEntry(i);  
      Long64_t tmpSizetmtc = tme->Records->GetEntries();  
      recordstot=recordstot+tmpSizetmtc;
    }  
    const Int_t lungmax=16*recordstot;
    Double_t xrecordobtcc[lungmax], yccdiagacq[lungmax], xrecordobtcc_1[lungmax], yccdiagacq_1[lungmax];
    recordstot=0;
    for (Int_t i = 0; i < neventstmtc; i++){
      tmtcBr->GetEntry(i);  
      Long64_t tmpSizetmtc = tme->Records->GetEntries();  
      Int_t size_b = tmpSizetmtc; 
      for (Int_t j = 0; j < size_b; j++){
	tmr = (pamela::TmtcRecord*)tme->Records->At(j);
	for (Int_t k =0; k <16; k++){
	  yccdiagacq[16*recordstot+16*j+k]   = (((tmr->TM_DIAG_AND_BILEVEL_ACQ)>>(15-k))&0x0001); 	
	  xrecordobtcc[16*recordstot+16*j+k] = tmr->TM_RECORD_OBT;
	}
      }
      recordstot=recordstot+tmpSizetmtc;
    }
    Int_t riftime = recordstot/2;
    //CC (0=IPM1=hot; 1=IPM2=cold for S4 calibration)
    for (Int_t k =0; k<16; k++){
      for (Int_t i = 0; i < recordstot; i++){
	yccdiagacq_1[i]= yccdiagacq[16*i+k];
	xrecordobtcc_1[i]= xrecordobtcc[16*i+k];
      }
      if (k==0) IPM1status=(Int_t)yccdiagacq_1[riftime];
      if (k==1) IPM2status=(Int_t)yccdiagacq_1[riftime];
    }
    if (IPM1status==0 && IPM2status==1){
      status="CONFIGURATION: HOT";
    }
    if (IPM1status==1 && IPM2status==0){
      status="CONFIGURATION: COLD";
    }
  }else{
    status=" No info about kind of calibration (hot or cold)";
  }

  //----------- search max and min OBT -----------------------------------------------------//
  headBr->GetEntry(0);
  ph = eh->GetPscuHeader();
  firstime = ph->GetOrbitalTime();
  headBr->GetEntry(nevents-1);
  ph = eh->GetPscuHeader();
  lastime = ph->GetOrbitalTime();
  obmin=firstime;
  obmax=lastime; 
  if(nevents < 2){
    for(Int_t kk = 0; kk<nevents; kk++){
      headBr->GetEntry(kk);
      ph = eh->GetPscuHeader();
      utile=ph->GetOrbitalTime();
      if(obmin >= utile)obmin=utile;
      if(obmax <= utile)obmax=utile;
    }
   limitdown= obmin - 1000000;
   limitup= obmax + 1000000;
  }else{
    for(Int_t kk = 0; kk<nevents; kk++){
      headBr->GetEntry(kk);
      ph = eh->GetPscuHeader();
      utile=ph->GetOrbitalTime();
      //cout<<"OrbitalTime()"<<ph->GetOrbitalTime()<<"\n";
      if(obmin >= utile)obmin=utile;
      if(obmax <= utile)obmax=utile;
    }
    limitdown=obmin;
    limitup=obmax;
  }
  //------------- Create and fill histograms -------------------------------------------//
  stringstream oss1;
  oss1.str("");
  oss1 << "S4 Calibration: "<< filename.Data();
  TH1F *calibS4_1 =new TH1F("S4-1", oss1.str().c_str(), channels, 0, channels);
  TH1F *calibS4_2 =new TH1F("S4-2", oss1.str().c_str(), channels, 0, channels);
  TH1F *calibS4_4 =new TH1F("S4-3", oss1.str().c_str(), channels, 0, channels);  

  stringstream oss;
  oss.str("");
  oss << "S4_Calibration_QL: "<< filename.Data();
  const Int_t size = nevents;
  //cout<<"size "<<size <<"\n";
  TH1F *cal1 =new TH1F("calibS4_1", oss.str().c_str(), size, obmin-1000000, obmax+ 1000000);
  TH1F *cal2 =new TH1F("calibS4_2", oss.str().c_str(), size, obmin-1000000, obmax+ 1000000);
  TH1F *cal4 =new TH1F("calibS4_4", oss.str().c_str(), size, obmin-1000000, obmax+ 1000000);  

  for(Int_t k = 0; k<nevents; k++){ 
    headBr->GetEntry(k);
    S4Br->GetEntry(k);
    ph = eh->GetPscuHeader();
    Int_t tmpSize = s4Event->Records->GetEntries();
    for (Int_t j = 0; j < 4; j++){
      for (Int_t i = 0; i < 128; i++){
	s4Record = (pamela::S4::S4Event*)s4Event->Records->At((j*128 + i));
	switch (j) {
	case 0 :{
	  calibS4_1->Fill(s4Record->S4_DATA);
	  calib_1 = calib_1+s4Record->S4_DATA;
	  break;
	}
	case 1 :{
	  calibS4_2->Fill(s4Record->S4_DATA);
	  calib_2 = calib_2+s4Record->S4_DATA;
	  break;
	}
	case 3 :{
	  calibS4_4->Fill(s4Record->S4_DATA);
	  calib_4 = calib_4+s4Record->S4_DATA;
	  break;
	}
	}
      }
    }
    utile=ph->GetOrbitalTime();
    //obt=ph->GetOrbitalTime(); 
    calib_1_MEAN=calib_1/128;
    //calib_1_RMS=calibS4_1->GetRMS(1);
    calib_2_MEAN=calib_2/128;
    //calib_2_RMS=calibS4_2->GetRMS(1);
    calib_4_MEAN=calib_4/128;
    //calib_4_RMS=calibS4_4->GetRMS(1);
    cal1->Fill(utile,calib_1_MEAN);
    cal2->Fill(utile,calib_2_MEAN);
    cal4->Fill(utile,calib_4_MEAN);
    calib_1=calib_2=calib_4=0;

  }

  //----------------- Create and draw canvas -----------------------------------------//
  TCanvas *finalCanv = new TCanvas("S4Calib","Calibration_QL", 1280, 1024);
  finalCanv->SetFillColor(10);
  finalCanv->Divide(2,2);

  finalCanv->cd(1);
  gPad->SetLogy();
  cal1->SetStats(kFALSE);
  cal1->SetMarkerSize(.5);
  cal1->SetMarkerStyle(21);
  cal1->SetMarkerColor(3);
  cal1->SetMinimum(1);
  cal1->SetMaximum(10000);
  cal1->GetYaxis()->SetTitle("S4 mean value (ADC)");
  cal1->GetYaxis()->SetTitleSize(0.03);
  cal1->GetYaxis()->SetTitleOffset(1);
  cal1->GetYaxis()->CenterTitle(); 
  cal1->GetYaxis()->SetLabelSize(0.02);
  cal1->GetXaxis()->CenterTitle();
  cal1->GetXaxis()->SetTitleSize(0.03);
  cal1->GetXaxis()->SetTitleOffset(1);
  cal1->GetXaxis()->SetLabelSize(0.02);
  cal1->GetXaxis()->SetTitle("OBT (ms)");
  cal1->Draw("9p");

  cal2->SetStats(kFALSE);
  cal2->SetMarkerSize(.5);
  cal2->SetMarkerStyle(21);
  cal2->SetMarkerColor(6);
  cal2->SetMinimum(1);
  cal2->SetMaximum(10000);
  cal2->Draw("9psame");

  cal4->SetStats(kFALSE);
  cal4->SetMarkerSize(.5);
  cal4->SetMarkerStyle(21);
  cal4->SetMarkerColor(4);
  cal4->SetMinimum(1);
  cal4->SetMaximum(10000);
  cal4->Draw("9psame");
 if (IPM1status==0 && IPM2status==1){    ////hot configuration
    TF1 *func1 = new TF1("func1", "1560");   ///valore di riferimento 1300
    //func1->SetRange(obmin, obmax); 
    func1->SetRange(limitdown, limitup);
    func1->SetLineColor(4);
    func1->SetLineStyle(1);
    func1->SetLineWidth(3);
    func1->Draw("same");
    TF1 *func2 = new TF1("func2", "1040");   ///valore di riferimento 1300
    //func2->SetRange(obmin, obmax);
    func2->SetRange(limitdown, limitup);
    func2->SetLineColor(4);
    func2->SetLineStyle(1);
    func2->SetLineWidth(3);
    func2->Draw("same");
    TF1 *func3 = new TF1("func3", "109");    ///valore di riferimento 95
    //func3->SetRange(obmin, obmax);
    func3->SetRange(limitdown, limitup);
    func3->SetLineColor(6);
    func3->SetLineStyle(1);
    func3->SetLineWidth(3);
    func3->Draw("same");
    TF1 *func4 = new TF1("func4", "71");    ///valore di riferimento 95
    //func4->SetRange(obmin, obmax);
    func4->SetRange(limitdown, limitup);
    func4->SetLineColor(6);
    func4->SetLineStyle(1);
    func4->SetLineWidth(3);
    func4->Draw("same");
    TF1 *func5 = new TF1("func5", "38.4");    //valore di riferimento 32
    //func5->SetRange(obmin, obmax);
    func5->SetRange(limitdown, limitup);
    func5->SetLineStyle(1);
    func5->SetLineColor(3);
    func5->SetLineWidth(3);
    func5->Draw("same");
    TF1 *func6 = new TF1("func6", "25.6");    //valore di riferimento 32
    //func6->SetRange(obmin, obmax);
    func6->SetRange(limitdown, limitup);
    func6->SetLineStyle(1);
    func6->SetLineColor(3);
    func6->SetLineWidth(3);
    func6->Draw("same");
   }

  if (IPM1status==1 && IPM2status==0){    ////cold configuration
    TF1 *func1 = new TF1("func1", "2400");
    //func1->SetRange(obmin, obmax);
    func1->SetRange(limitdown, limitup);
    func1->SetLineColor(4);
    func1->SetLineStyle(1);
    func1->SetLineWidth(3);
    func1->Draw("same");
    TF1 *func2 = new TF1("func2", "1600");   ///valore di riferimento 2000
    //func2->SetRange(obmin, obmax);
    func2->SetRange(limitdown, limitup);
    func2->SetLineColor(4);
    func2->SetLineStyle(1);
    func2->SetLineWidth(3);
    func2->Draw("same");
    TF1 *func3 = new TF1("func3", "180");
    //func3->SetRange(obmin, obmax);
    func3->SetRange(limitdown, limitup);
    func3->SetLineColor(6);
    func3->SetLineStyle(1);
    func3->SetLineWidth(3);
    func3->Draw("same");
    TF1 *func4 = new TF1("func4", "120");    ///valore di riferimento 150
    //func4->SetRange(obmin, obmax);
    func4->SetRange(limitdown, limitup);
    func4->SetLineColor(6);
    func4->SetLineStyle(1);
    func4->SetLineWidth(3);
    func4->Draw("same");
    TF1 *func5 = new TF1("func5", "38.4");
    //func5->SetRange(obmin, obmax);
    func5->SetRange(limitdown, limitup);
    func5->SetLineStyle(1);
    func5->SetLineColor(3);
    func5->SetLineWidth(3);
    func5->Draw("same");
    TF1 *func6 = new TF1("func6", "25.6");    //valore di riferimento 32
    //func6->SetRange(obmin, obmax);
    func6->SetRange(limitdown, limitup);
    func6->SetLineStyle(1);
    func6->SetLineColor(3);
    func6->SetLineWidth(3);
    func6->Draw("same");
  }

  //TPad *pad = new TPad("pad","pad", .75, .93, .99, .99);
  TPad *pad = new TPad("pad","pad", .58, .85, .92, .94);
  pad->SetFillColor(10);
  pad->Draw();
  pad->cd();
  TLatex *l = new TLatex();
  l->SetTextAlign(12);
  l->SetTextSize(0.4);
  l->SetTextColor(kRed);
  l->DrawLatex(0.05, 0.65, status.Data()); 


  finalCanv->cd(2);
  gPad->SetLogy();
  gStyle->SetOptStat("nemrou");
  calibS4_1->SetLineColor(kBlack);
  calibS4_1->SetFillColor(kRed);
  calibS4_1->GetYaxis()->SetTitle("Number of events");
  calibS4_1->GetYaxis()->SetTitleSize(0.03);
  calibS4_1->GetYaxis()->SetTitleOffset(1);
  calibS4_1->GetYaxis()->CenterTitle(); 
  calibS4_1->GetYaxis()->SetLabelSize(0.02);
  calibS4_1->GetXaxis()->CenterTitle();
  calibS4_1->GetXaxis()->SetTitleSize(0.03);
  calibS4_1->GetXaxis()->SetTitleOffset(1);
  calibS4_1->GetXaxis()->SetLabelSize(0.02);
  calibS4_1->GetXaxis()->SetTitle("ADC (ch)");
  calibS4_1->SetAxisRange(0,200);
  calibS4_1->Draw();

  finalCanv->cd(3);
  gPad->SetLogy();
  gStyle->SetOptStat("nemrou");
  calibS4_2->SetLineColor(kBlack);
  calibS4_2->SetFillColor(kRed);
  calibS4_2->GetYaxis()->SetTitle("Number of events");
  calibS4_2->GetYaxis()->SetTitleSize(0.03);
  calibS4_2->GetYaxis()->SetTitleOffset(1);
  calibS4_2->GetYaxis()->CenterTitle(); 
  calibS4_2->GetYaxis()->SetLabelSize(0.02);
  calibS4_2->GetXaxis()->CenterTitle();
  calibS4_2->GetXaxis()->SetTitleSize(0.03);
  calibS4_2->GetXaxis()->SetTitleOffset(1);
  calibS4_2->GetXaxis()->SetLabelSize(0.02);
  calibS4_2->GetXaxis()->SetTitle("ADC (ch)");
  calibS4_2->SetAxisRange(50,250);
  calibS4_2->Draw();

  finalCanv->cd(4);
  gPad->SetLogy();
  gStyle->SetOptStat("nemrou");
  calibS4_4->SetLineColor(kBlack);
  calibS4_4->SetFillColor(kRed);
  calibS4_4->GetYaxis()->SetTitle("Number of events");
  calibS4_4->GetYaxis()->SetTitleSize(0.03);
  calibS4_4->GetYaxis()->SetTitleOffset(1);
  calibS4_4->GetYaxis()->CenterTitle(); 
  calibS4_4->GetYaxis()->SetLabelSize(0.02);
  calibS4_4->GetXaxis()->CenterTitle();
  calibS4_4->GetXaxis()->SetTitleSize(0.03);
  calibS4_4->GetXaxis()->SetTitleOffset(1);
  calibS4_4->GetXaxis()->SetLabelSize(0.02);
  calibS4_4->GetXaxis()->SetTitle("ADC (ch)");
  calibS4_4->SetAxisRange(500,2500);
  calibS4_4->Draw();

  oss.str("");
  if (outDir == "./") {
    oss << filename.Data() << "_S4_Calibration_QL." << format.Data();
  } else {
    oss << outDir.Data() << filename.Data() << "_S4_Calibration_QL." << format.Data();
  }
  finalCanv->SaveAs(oss.str().c_str()); 
}

int main(int argc, char* argv[]){
  TString path;
  TString outDir  ="./";
  TString format  ="jpg";
   
 if (argc < 2){
    printf("You have to insert at least the file to analyze \n");
    printf("Try '--help' for more information. \n");
    exit(1);
  }  

  if (!strcmp(argv[1], "--help")){
        printf( "Usage: S4_Calibration_QL FILE [OPTION] \n");
        printf( "\t --help                 Print this help and exit \n");
        printf( "\t -outDir[path]          Path where to put the output [default ./] \n");
	// printf( "\t -format[]              Format for output files [default 'jpg'] \n");
        exit(1);
  }

  path=argv[1];

  for (int i = 2; i < argc; i++){
   
    if (!strcmp(argv[i], "-outDir")){
      if (++i >= argc){
	printf( "-outDir needs arguments. \n");
	printf( "Try '--help' for more information. \n");
	  exit(1);
      } 
      else{
	outDir = argv[i];
	continue;
      }
    }
 
    if (!strcmp(argv[i], "-format")){
      if (++i >= argc){
	printf( "-format needs arguments. \n");
	printf( "Try '--help' for more information. \n");
	exit(1);
      }
      else{
	format = argv[i];
	continue;
      }
    }
    
    
  }


  S4_Calibration_QL(argv[1], outDir, format);

}


