/**
* 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
**************/

#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;
  Double_t calib_2;
  Double_t calib_4;
  Double_t calib_1_RMS;
  Double_t calib_2_RMS;
  Double_t calib_4_RMS;
  Double_t obt;
  TString status;
  Int_t IPM1status, IPM2status;
  //------------------------- 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 -----------------------//
  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";
  }

  //------------- Create and fill histograms -------------------------------------------//
 
  TH1F *calibS4_1 =new TH1F("calibS4_1", "calibS4_1", channels, 0, channels);
  TH1F *calibS4_2 =new TH1F("calibS4_2", "calibS4_2", channels, 0, channels);
  TH1F *calibS4_4 =new TH1F("calibS4_4", "calibS4_4", channels, 0, channels);  
  ULong_t lastime, firstime;
  double obmin=0.;
  double obmax=0.; 
  const Int_t size = nevents;
  headBr->GetEntry(0);
  ph = eh->GetPscuHeader();
  firstime = ph->GetOrbitalTime();
  headBr->GetEntry(nevents-1);
  ph = eh->GetPscuHeader();
  lastime = ph->GetOrbitalTime();
  obmin=firstime;
  obmax=lastime; 
  stringstream oss;
  oss.str("");
  oss << "S4_Calibration_QL: "<< filename.Data();
  TH1F *cal1 =new TH1F("calibS4_1", oss.str().c_str(), size, obmin, obmax);
  TH1F *cal2 =new TH1F("calibS4_2", oss.str().c_str(), size, obmin, obmax);
  TH1F *cal4 =new TH1F("calibS4_4", oss.str().c_str(), size, obmin, obmax);  

  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);
	  break;
	}
	case 1 :{
	  calibS4_2->Fill(s4Record->S4_DATA);
	  break;
	}
	case 3 :{
	  calibS4_4->Fill(s4Record->S4_DATA);
	  break;
	}
	}
      }
    }

    obt=ph->GetOrbitalTime(); 
    calib_1=calibS4_1->GetMean(1);
    //calib_1_RMS=calibS4_1->GetRMS(1);
    calib_2=calibS4_2->GetMean(1);
    //calib_2_RMS=calibS4_2->GetRMS(1);
    calib_4=calibS4_4->GetMean(1);
    //calib_4_RMS=calibS4_4->GetRMS(1);
    cal1->Fill(obt,calib_1);
    cal2->Fill(obt,calib_2);
    cal4->Fill(obt,calib_4);

    //cout<<calib_1_RMS<<"\n";
    //cout<<calib_2_RMS<<"\n";
    //cout<<calib_4_RMS<<"\n";
    //cout<<k<<"     "<<obt<<"  \n  "<<calib_1<<"    "<<calib_2<<"     "<<calib_4<<"\n";

  }

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

  finalCanv->cd();
  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->SetLineColor(4);
    func1->SetLineStyle(4);
    func1->SetLineWidth(4);
    func1->Draw("same");
    TF1 *func2 = new TF1("func2", "1040");   ///valore di riferimento 1300
    func2->SetRange(obmin, obmax);
    func2->SetLineColor(4);
    func2->SetLineStyle(4);
    func2->SetLineWidth(4);
    func2->Draw("same");
    TF1 *func3 = new TF1("func3", "109");    ///valore di riferimento 95
    func3->SetRange(obmin, obmax);
    func3->SetLineColor(6);
    func3->SetLineStyle(4);
    func3->SetLineWidth(4);
    func3->Draw("same");
    TF1 *func4 = new TF1("func4", "71");    ///valore di riferimento 95
    func4->SetRange(obmin, obmax);
    func4->SetLineColor(6);
    func4->SetLineStyle(4);
    func4->SetLineWidth(4);
    func4->Draw("same");
    TF1 *func5 = new TF1("func5", "38.4");    //valore di riferimento 32
    func5->SetRange(obmin, obmax);
    func5->SetLineStyle(4);
    func5->SetLineColor(3);
    func5->SetLineWidth(4);
    func5->Draw("same");
    TF1 *func6 = new TF1("func6", "25.6");    //valore di riferimento 32
    func6->SetRange(obmin, obmax);
    func6->SetLineStyle(4);
    func6->SetLineColor(3);
    func6->SetLineWidth(4);
    func6->Draw("same");
   }

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

  TPad *pad = new TPad("pad","pad", .75, .93, .99, .99);
  pad->SetFillColor(10);
  pad->Draw();
  pad->cd();
  TLatex *l = new TLatex();
  l->SetTextAlign(12);
  l->SetTextSize(0.35);
  l->SetTextColor(8);
  l->DrawLatex(0.05, 0.65, status.Data()); 

  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);

}


