//
// C3PO.cpp -- standalone program to convert Level2 data. 
//    by David Fedele
//
//   v1r00 
//
// C/C++ headers
//
#include <iostream>
//
// ROOT headers
//
#include <TString.h>
#include <TFile.h>
#include <TTree.h>
#include <TSystem.h>
//
//  header of Level2 classes
//
#include <TrkLevel2.h>
#include <ToFLevel2.h>
#include <AcLevel2.h>
#include <CaloLevel2.h>
#include <NDLevel2.h>
#include <S4Level2.h>
#include <TrigLevel2.h>
#include <OrbitalInfo.h>
#include <GLTables.h>
#include <RunInfo.h>

//
// Detector's package headers
//
//
using namespace std;
//
// Usage subroutine
//
void usage(){ 
  printf("\nUsage:\n");
  printf("\n C3PO filename.root [OPTIONS]\n\n");
  printf("\t -h | --help:      print this help and exit \n");
  printf("\t filename:         file.root to be converted with complete path [give at least this parameter]\n");
  printf("\nOPTIONS:\n");
  printf("\t --version:        print informations about compilation and exit\n");
  printf("\t -v | --verbose:   be verbose [default: print nothing on STDOUT]\n");
  printf("\t -outDir:          path to the output directory [default = ./] \n");
  printf("\t -outFile:         name of the output file with the '.rz' extension [default = filename.rz] \n");
  printf("\t +all:             call all detectors software [default]\n");
  printf("\t -all:             call nothing\n");
  printf("\t +detector:        process detector; detector can be: TOF,TRK,CAL,TRG,ORB,S4,ND,AC,RUN\n");
  printf("\t -detector:        do not process detector (as above)\n");
  printf("\nExamples: \n");
  printf("\tStandard call: C3PO 42.Level2.root \n");
  printf("\tProcess only Calorimeter and Tracker: C3PO 42.Level2.root -all +CAL +TRK -outFile miofile.rz -outDir ~/tmp -v\n");
};

//
// Fortran functions and ntuples
//
extern "C" {

  void openlev2_();
  void closelev2_();

  //
  // Tracker
  extern struct cTrkLevel2 tracker_;
  void booktrackerntupla_();
  void filltrackerntupla_();
  void closetrackerntupla_();

  //
  // Calorimeter
  extern struct cCaloLevel2 calo_;
  void bookcalontupla_();
  void fillcalontupla_();
  void closecalontupla_();

  //
  // ToF
  extern struct cToFLevel2 tof_;
  void booktofntupla_();
  void filltofntupla_();
  void closetofntupla_();

  //
  // Trigger
  extern struct cTrigLevel2 trigger_;
  void booktriggerntupla_();
  void filltriggerntupla_();
  void closetriggerntupla_();
 
  //
  // Anticounter
  extern struct cAcLevel2 antic_;
  void bookanticntupla_();
  void fillanticntupla_();
  void closeanticntupla_();

  //
  // S4
  extern struct cS4Level2 s4_;
  void books4ntupla_();
  void fills4ntupla_();
  void closes4ntupla_();

  //
  // NeutronD
  extern struct cNDLevel2 nd_;
  void bookndntupla_();
  void fillndntupla_();
  void closendntupla_();

  //
  //OrbitalInfo
  extern struct cOrbitalInfo orbinfo_;
  void bookorbitalinfontupla_();
  void fillorbitalinfontupla_();
  void closeorbitalinfontupla_();

  //
  //RunInfo
  extern struct cGLRun glrun_;
  extern struct cSoftInfo softinfo_;
  void bookruninfontupla_();
  void fillruninfontupla_();
  void closeruninfontupla_();

};


//
// Here the main
//
int main(int argc, char *argv[]){
  //
  // Variables booking
  //
  TString FILE,OUTDIR="./",OUTFILE="default";
  TString message;
  int nul = 0;
  //  Int_t error = 0;
  //  Bool_t debug = false;
  Bool_t beverbose = false;
  Bool_t CAL = true;
  Bool_t TRK = true;
  Bool_t TRG = true;
  Bool_t TOF = true;
  Bool_t S4 = true;
  Bool_t ND = true;
  Bool_t AC = true;
  Bool_t ORB = true;
  Bool_t RUN = true;
  //
  // Checking input parameters
  //

  if(argc>1){
    if ( !strcmp(argv[1],"--version") ){
      printf("Sorry, at the moment no infos available!");
      //      info();
      exit(0);
    };
    if(!strcmp(argv[1], "-h") || !strcmp(argv[1], "--help") || argc>11){
      usage();
      exit(0);
    }
    if ( (!strcmp(argv[1],"-v") || !strcmp(argv[1],"--verbose"))&& argc == 2 ){
      printf("Sorry, at the moment no infos available!");
      //      info();
      exit(0);    
    }
    else {
      
      FILE = argv[1];
      for(int i=2; i<argc;i++){

      	if ( !strcmp(argv[i],"-v") || !strcmp(argv[i],"--verbose") )
	  beverbose = true;

	if (!strcmp(argv[i], "-outDir")){
	  if (++i >= argc || !strncmp(argv[i],"-",1) || !strncmp(argv[i],"+",1)){
	    printf( "\n-outDir needs arguments. \n");
	    usage();
	    exit(0);
	  } 
	  else{
	    OUTDIR = argv[i];
	    continue;
	  }
	}

	if (!strcmp(argv[i], "-outFile")){
	  if (++i >= argc || !strncmp(argv[i],"-",1) || !strncmp(argv[i],"+",1)){
	    printf( "\n-outFile needs arguments. \n");
	    usage();
	    exit(0);
	  } 
	  else{
	    OUTFILE = argv[i];
	    continue;
	  }
	}

	//
	if ( !strcmp(argv[i],"+all") ) {
	  CAL = true;
	  ORB = true;
	  TRK = true;
	  TRG = true;
	  TOF = true;
	  S4 = true;
	  ND = true;
	  AC = true;
	  RUN = true;
	};  
	if ( !strcmp(argv[i],"+CAL") ) {
	  CAL = true;
	};
	if ( !strcmp(argv[i],"+TRK") ) {
	  TRK = true;
	};
	if ( !strcmp(argv[i],"+TOF") ) {
	  TOF = true;
	};
	if ( !strcmp(argv[i],"+TRG") ) {
	  TRG = true;
	};
	if ( !strcmp(argv[i],"+S4") ) {
	  S4 = true;
	};
	if ( !strcmp(argv[i],"+ND") ) {
	  ND = true;
	};
	if ( !strcmp(argv[i],"+AC") ) {
	  AC = true;
	};
	if ( !strcmp(argv[i],"+RUN") ) {
	  RUN = true;
	};
	if ( !strcmp(argv[i],"+ORB") ) {
	  ORB = true;
	};
	//
	//
	if ( !strcmp(argv[i],"-all") ) {
	  CAL = false;
	  ORB = false;
	  TRK = false;
	  TRG = false;
	  TOF = false;
	  S4 = false;
	  ND = false;
	  AC = false;
	  RUN = false;
	}; 
	if ( !strcmp(argv[i],"-CAL") ) {
	  CAL = false;
	};
	if ( !strcmp(argv[i],"-TRK") ) {
	  TRK = false;
	};
	if ( !strcmp(argv[i],"-TOF") ) {
	  TOF = false;
	};
	if ( !strcmp(argv[i],"-TRG") ) {
	  TRG = false;
	};
	if ( !strcmp(argv[i],"-S4") ) {
	  S4 = false;
	};
	if ( !strcmp(argv[i],"-ND") ) {
	  ND = false;
	};
	if ( !strcmp(argv[i],"-AC") ) {
	  AC = false;
	};
	if ( !strcmp(argv[i],"-RUN") ) {
	  RUN = false;
	};
	if ( !strcmp(argv[i],"-ORB") ) {
	  ORB = false;
	};
	//

	if (strcmp(argv[i],"-v") && strcmp(argv[i],"--verbose") && strcmp(argv[i],"-outDir")  && strcmp(argv[i],"-outFile") && strcmp(argv[i], "-all") && strcmp(argv[i], "+all") && strcmp(argv[i], "-TOF") && strcmp(argv[i], "-TRK") && strcmp(argv[i], "-CAL") && strcmp(argv[i], "-TRG") && strcmp(argv[i], "-ORB") && strcmp(argv[i], "-S4") && strcmp(argv[i], "-ND") && strcmp(argv[i], "-AC") && strcmp(argv[i], "-RUN") && strcmp(argv[i], "+TOF") && strcmp(argv[i], "+TRK") && strcmp(argv[i], "+CAL") && strcmp(argv[i], "+TRG") && strcmp(argv[i], "+ORB") && strcmp(argv[i], "+S4") && strcmp(argv[i], "+ND") && strcmp(argv[i], "+AC") && strcmp(argv[i], "+RUN")){
	  printf( "\n------>Warning: WRONG OPTIONS!\n");
	  usage();
	  exit(0);
	} 
      }
    }
  }

  else if(argc==1){
    printf("\n\tYou have to insert at least the file to analyze \n");
    usage();
    exit(0);
  }	
  //
  
  //
  // If not in verbose mode redirect to /dev/null the stdout and stderr
  //
  if ( !beverbose ){
    nul = open("/dev/null", O_CREAT | O_RDWR,S_IREAD | S_IWRITE);
    dup2(nul,1);
    dup2(nul,2);
  };
  
  printf("\n Welcome to C3PO! \n\n");

  //
  // Open root File
  //  
  TFile *Lev2file = new TFile(FILE);
  if ( !Lev2file ){
    printf("No Level2 data file, exiting...\n");
    exit(0);
  }

  //
  // Open rz File
  //
  TString rzfile;
  if(OUTFILE=="default"){
    Int_t posi=FILE.Last('/');
    Int_t posf=FILE.Last('.');
    rzfile=FILE(posi+1,posf-(posi+1));
    rzfile+=".rz";
  }
  else rzfile=OUTFILE;
  if(OUTDIR.Last('/')+1<OUTDIR.Length()) OUTDIR+="/";
  if(OUTDIR.Length()+rzfile.Length()>=80) {
    printf("%s%s\n\t\t   ERROR: The name of the rz file is bigger then 80 characters ^\n\n",OUTDIR.Data(),rzfile.Data());
    exit(0);
  }
  else {
    path_.FillWith(OUTDIR+rzfile);
    openlev2_();
  }
  
  //
  // Run the Converter program for the detectors
  //
  if ( RUN ) {
    printf(" Calling RunInfoConverter... ");
    GL_RUN *glr=0;
    SoftInfo *si=0;
    TTree *runtree = (TTree*)Lev2file->Get("Run");
    if(!runtree)    printf("No Run Tree, exiting...\n");
    else{
      runtree->SetBranchAddress("RunInfo",&glr);
      runtree->SetBranchAddress("SoftInfo",&si);
      Int_t runevent=runtree->GetEntries();
      if(runevent!=0){
	glrun_.InitcGLRun();
	bookruninfontupla_();
	
	for(Int_t ev=0;ev<runevent;ev++){
	  runtree->GetEntry(ev);
	  glr->GetLevel2Struct(&glrun_);
	  si->GetLevel2Struct(&softinfo_);
 	  fillruninfontupla_();
	}

	closeruninfontupla_();	
	printf("done\n");
      }
      else  printf("The RunInfo Tree is empty, exiting...\n");
    }
  };


  if ( TRK ) {
    printf(" Calling TrackerLevel2Converter... ");
    TrkLevel2 *trk=0;
    TTree *trktree = (TTree*)Lev2file->Get("Tracker");
    if(!trktree)    printf("No Tracker Tree, exiting...\n");
    else{
      trktree->SetBranchAddress("TrkLevel2",&trk);
      Int_t trkevent=trktree->GetEntries();
      if(trkevent!=0){
	tracker_.InitcTrkLevel2();
	booktrackerntupla_();
	
	for(Int_t ev=0;ev<trkevent;ev++){
	  trktree->GetEntry(ev);
	  trk->GetLevel2Struct(&tracker_);
 	  filltrackerntupla_();
	}

	closetrackerntupla_();
	printf("done\n");
      }
      else  printf("The Tracker Tree is empty, exiting...\n");
    }
  };


  if ( TOF ) {
    printf(" Calling ToFLevel2Converter... ");
    ToFLevel2 *tof=0;
    TTree *toftree = (TTree*)Lev2file->Get("ToF");
    if(!toftree)    printf("No ToF Tree, exiting...\n");
    else{
      toftree->SetBranchAddress("ToFLevel2",&tof);
      Int_t tofevent=toftree->GetEntries();
      if(tofevent!=0){
	tof_.InitcToFLevel2();
	booktofntupla_();
	
	for(Int_t ev=0;ev<tofevent;ev++){
	  toftree->GetEntry(ev);
	  tof->GetLevel2Struct(&tof_);
 	  filltofntupla_();
	}

	closetofntupla_();
	printf("done\n");
      }
      else  printf("The ToF Tree is empty, exiting...\n");
    }
  };


  if ( CAL ) {
    printf(" Calling CalorimeterLevel2Converter... ");
    CaloLevel2 *calo=0;
    TTree *calotree = (TTree*)Lev2file->Get("Calorimeter");
    if(!calotree)    printf("No Calorimeter Tree, exiting...\n");
    else{
      calotree->SetBranchAddress("CaloLevel2",&calo);
      Int_t caloevent=calotree->GetEntries();
      if(caloevent!=0){
	calo_.InitcCaloLevel2();
	bookcalontupla_();
	
	for(Int_t ev=0;ev<caloevent;ev++){
	  calotree->GetEntry(ev);
	  calo->GetLevel2Struct(&calo_);
 	  fillcalontupla_();
	}

	closecalontupla_();
	printf("done\n");
      }
      else  printf("The Calorimeter Tree is empty, exiting...\n");
    }
  };
  

  if ( TRG ) {
    printf(" Calling TriggerLevel2Converter... ");
    TrigLevel2 *trig=0;
    TTree *trigtree = (TTree*)Lev2file->Get("Trigger");
    if(!trigtree)    printf("No Trigger Tree, exiting...\n");
    else{
      trigtree->SetBranchAddress("TrigLevel2",&trig);
      Int_t trigevent=trigtree->GetEntries();
      if(trigevent!=0){
	trigger_.InitcTrigLevel2();
	booktriggerntupla_();
	
	for(Int_t ev=0;ev<trigevent;ev++){
	  trigtree->GetEntry(ev);
	  trig->GetLevel2Struct(&trigger_);
 	  filltriggerntupla_();
	}

	closetriggerntupla_();
	printf("done\n");
      }
      else  printf("The Trigger Tree is empty, exiting...\n");
    }
  };
  
  
  if ( AC ) {
    printf(" Calling AnticounterLevel2Converter... ");
    AcLevel2 *ac=0;
    TTree *actree = (TTree*)Lev2file->Get("Anticounter");
    if(!actree)    printf("No Anticounter Tree, exiting...\n");
    else{
      actree->SetBranchAddress("AcLevel2",&ac);
      Int_t acevent=actree->GetEntries();
      if(acevent!=0){
	antic_.InitcAcLevel2();
	bookanticntupla_();
	
	for(Int_t ev=0;ev<acevent;ev++){
	  actree->GetEntry(ev);
	  ac->GetLevel2Struct(&antic_);
 	  fillanticntupla_();
	}

	closeanticntupla_();
	printf("done\n");
      }
      else  printf("The Anticounter Tree is empty, exiting...\n");
    }
  };
  

  if ( S4 ) {
    printf(" Calling S4Level2Converter... ");
    S4Level2 *s4=0;
    TTree *s4tree = (TTree*)Lev2file->Get("S4");
    if(!s4tree)    printf("No S4 Tree, exiting...\n");
    else{
      s4tree->SetBranchAddress("S4Level2",&s4);
      Int_t s4event=s4tree->GetEntries();
      if(s4event!=0){
	s4_.InitcS4Level2();
	books4ntupla_();
	
	for(Int_t ev=0;ev<s4event;ev++){
	  s4tree->GetEntry(ev);
	  s4->GetLevel2Struct(&s4_);
 	  fills4ntupla_();
	}

	closes4ntupla_();
	printf("done\n");
      }
      else  printf("The S4 Tree is empty, exiting...\n");
    }
  };
  

  if ( ND ) {
    printf(" Calling NDLevel2Converter... ");
    NDLevel2 *nd=0;
    TTree *ndtree = (TTree*)Lev2file->Get("NeutronD");
    if(!ndtree)    printf("No NeutronD Tree, exiting...\n");
    else{
      ndtree->SetBranchAddress("NDLevel2",&nd);
      Int_t ndevent=ndtree->GetEntries();
      if(ndevent!=0){
	nd_.InitcNDLevel2();
	bookndntupla_();
	
	for(Int_t ev=0;ev<ndevent;ev++){
	  ndtree->GetEntry(ev);
	  nd->GetLevel2Struct(&nd_);
 	  fillndntupla_();
	}

	closendntupla_();
	printf("done\n");
      }
      else  printf("The NeutronD Tree is empty, exiting...\n");
    }
  };
  

  if ( ORB ) {
    printf(" Calling OrbitalInfoConverter... ");
    OrbitalInfo *oi=0;
    TTree *oitree = (TTree*)Lev2file->Get("OrbitalInfo");
    if(!oitree)    printf("No OrbitalInfo Tree, exiting...\n");
    else{
      oitree->SetBranchAddress("OrbitalInfo",&oi);
      Int_t oievent=oitree->GetEntries();
      if(oievent!=0){
	orbinfo_.InitcOrbitalInfo();
	bookorbitalinfontupla_();
	
	for(Int_t ev=0;ev<oievent;ev++){
	  oitree->GetEntry(ev);
	  oi->GetLevel2Struct(&orbinfo_);
 	  fillorbitalinfontupla_();
	}
	
	closeorbitalinfontupla_();
       	printf("done\n\n");
      }
      else  printf("The OrbitalInfo Tree is empty, exiting...\n");
    }
  };
  
  //
  // Close root file
  //
  Lev2file->Close();

  //
  // Close rz file
  //
  
  closelev2_();

  //
  // Close redirection if the case.
  //
  if ( !beverbose ) close(nul);
  //
  //
  exit(0);
}
