#include <PamLevel2.h>

/////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////

void GPamela::Clear() {
  Irun = 0;
  Ievnt = 0;
  Ipa = 0;
  X0 = 0.;
  Y0 = 0.;
  Z0 = 0.;
  Theta = 0.;
  Phi = 0.;
  P0 = 0.;
  Nthtof = 0;
  Nthcat = 0;
  Nthcas = 0;
  Nthspe = 0;
  Nstrpx = 0;
  Nstrpy = 0;
  Nthcali = 0;
  Nthcal = 0;
  Nthnd = 0;
  Nthcard = 0;
}

void GPamela::Delete() {

  Clear();
  /* EM all these are in the stack not in the heap, so no need to delete by hand...
  delete[] Ipltof;
  delete[] Ipaddle;
  delete[] Ipartof;
  delete[] Xintof;
  delete[] Yintof;
  delete[] Zintof;
  delete[] Xouttof;
  delete[] Youttof;
  delete[] Zouttof;
  delete[] Ereltof;
  delete[] Timetof;
  delete[] Pathtof;
  delete[] P0tof;
  delete[] Iparcat;
  delete[] Icat;
  delete[] Xincat;
  delete[] Yincat;
  delete[] Zincat;
  delete[] Xoutcat;
  delete[] Youtcat;
  delete[] Zoutcat;
  delete[] Erelcat;
  delete[] Timecat;
  delete[] Pathcat;
  delete[] P0cat;
  delete[] Iparcas;
  delete[] Icas;
  delete[] Xincas;
  delete[] Yincas;
  delete[] Zincas;
  delete[] Xoutcas;
  delete[] Youtcas;
  delete[] Zoutcas;
  delete[] Erelcas;
  delete[] Timecas;
  delete[] Pathcas;
  delete[] P0cas;
  delete[] Iparspe;
  delete[] Itrpb;
  delete[] Itrsl;
  delete[] Itspa;
  delete[] Xinspe;
  delete[] Yinspe;
  delete[] Zinspe;
  delete[] Xoutspe;
  delete[] Youtspe;
  delete[] Zoutspe;
  delete[] Xavspe;
  delete[] Yavspe;
  delete[] Zavspe;
  delete[] Erelspe;
  delete[] Pathspe;
  delete[] P0spe;
  delete[] Nxmult;
  delete[] Nymult;
  delete[] Npstripx;
  delete[] Ntstripx;
  delete[] Istripx;
  delete[] Qstripx;
  delete[] Xstripx;
  delete[] Npstripy;
  delete[] Ntstripy;
  delete[] Istripy;
  delete[] Qstripy;
  delete[] Ystripy;
  delete[] Icaplane;
  delete[] Icastrip;
  delete[] Icamod;
  delete[] Enestrip;
  delete[] Icapl;
  delete[] Icasi;
  delete[] Icast;
  delete[] Xincal;
  delete[] Yincal;
  delete[] Zincal;
  delete[] Erelcal;
  delete[] Itubend;
  delete[] Iparnd;
  delete[] Xinnd;
  delete[] Yinnd;
  delete[] Zinnd;
  delete[] Xoutnd;
  delete[] Youtnd;
  delete[] Zoutnd;
  delete[] Erelnd;
  delete[] Timend;
  delete[] Pathnd;
  delete[] P0nd;
  delete[] Iparcard;
  delete[] Icard;
  delete[] Xincard;
  delete[] Yincard;
  delete[] Zincard;
  delete[] Xoutcard;
  delete[] Youtcard;
  delete[] Zoutcard;
  delete[] Erelcard;
  delete[] Timecard;
  delete[] Pathcard;
  delete[] P0card;
  */
}


void GPamela::SetBranchAddress(TChain* fhBookTree) {

  //    cout << "fhBookTree "<<fhBookTree << endl;
  // prepare tree
  fhBookTree->SetBranchAddress("Irun", &Irun);
  fhBookTree->SetBranchAddress("Ievnt", &Ievnt);
  fhBookTree->SetBranchAddress("Ipa", &Ipa);
  fhBookTree->SetBranchAddress("X0", &X0);
  fhBookTree->SetBranchAddress("Y0", &Y0);
  fhBookTree->SetBranchAddress("Z0", &Z0);
  fhBookTree->SetBranchAddress("Theta", &Theta);
  fhBookTree->SetBranchAddress("Phi", &Phi);
  fhBookTree->SetBranchAddress("P0", &P0);
  fhBookTree->SetBranchAddress("Nthtof", &Nthtof);
  fhBookTree->SetBranchAddress("Ipltof", Ipltof);
  fhBookTree->SetBranchAddress("Ipaddle", Ipaddle);
  fhBookTree->SetBranchAddress("Ipartof", Ipartof);
  fhBookTree->SetBranchAddress("Xintof", Xintof);
  fhBookTree->SetBranchAddress("Yintof", Yintof);
  fhBookTree->SetBranchAddress("Zintof", Zintof);
  fhBookTree->SetBranchAddress("Xouttof", Xouttof);
  fhBookTree->SetBranchAddress("Youttof", Youttof);
  fhBookTree->SetBranchAddress("Zouttof", Zouttof);
  fhBookTree->SetBranchAddress("Ereltof", Ereltof);
  fhBookTree->SetBranchAddress("Timetof", Timetof);
  fhBookTree->SetBranchAddress("Pathtof", Pathtof);
  fhBookTree->SetBranchAddress("P0tof", P0tof);
  fhBookTree->SetBranchAddress("Nthcat", &Nthcat);
  fhBookTree->SetBranchAddress("Iparcat", Iparcat);
  fhBookTree->SetBranchAddress("Icat", Icat);
  fhBookTree->SetBranchAddress("Xincat", Xincat);
  fhBookTree->SetBranchAddress("Yincat", Yincat);
  fhBookTree->SetBranchAddress("Zincat", Zincat);
  fhBookTree->SetBranchAddress("Xoutcat", Xoutcat);
  fhBookTree->SetBranchAddress("Youtcat", Youtcat);
  fhBookTree->SetBranchAddress("Zoutcat", Zoutcat);
  fhBookTree->SetBranchAddress("Erelcat", Erelcat);
  fhBookTree->SetBranchAddress("Timecat", Timecat);
  fhBookTree->SetBranchAddress("Pathcat", Pathcat);
  fhBookTree->SetBranchAddress("P0cat", P0cat);
  fhBookTree->SetBranchAddress("Nthcas", &Nthcas);
  fhBookTree->SetBranchAddress("Iparcas", Iparcas);
  fhBookTree->SetBranchAddress("Icas", Icas);
  fhBookTree->SetBranchAddress("Xincas", Xincas);
  fhBookTree->SetBranchAddress("Yincas", Yincas);
  fhBookTree->SetBranchAddress("Zincas", Zincas);
  fhBookTree->SetBranchAddress("Xoutcas", Xoutcas);
  fhBookTree->SetBranchAddress("Youtcas", Youtcas);
  fhBookTree->SetBranchAddress("Zoutcas", Zoutcas);
  fhBookTree->SetBranchAddress("Erelcas", Erelcas);
  fhBookTree->SetBranchAddress("Timecas", Timecas);
  fhBookTree->SetBranchAddress("Pathcas", Pathcas);
  fhBookTree->SetBranchAddress("P0cas", P0cas);
  fhBookTree->SetBranchAddress("Nthspe", &Nthspe);
  fhBookTree->SetBranchAddress("Iparspe", Iparspe);
  fhBookTree->SetBranchAddress("Itrpb", Itrpb);
  fhBookTree->SetBranchAddress("Itrsl", Itrsl);
  fhBookTree->SetBranchAddress("Itspa", Itspa);
  fhBookTree->SetBranchAddress("Xinspe", Xinspe);
  fhBookTree->SetBranchAddress("Yinspe", Yinspe);
  fhBookTree->SetBranchAddress("Zinspe", Zinspe);
  fhBookTree->SetBranchAddress("Xoutspe", Xoutspe);
  fhBookTree->SetBranchAddress("Youtspe", Youtspe);
  fhBookTree->SetBranchAddress("Zoutspe", Zoutspe);
  fhBookTree->SetBranchAddress("Xavspe", Xavspe);
  fhBookTree->SetBranchAddress("Yavspe", Yavspe);
  fhBookTree->SetBranchAddress("Zavspe", Zavspe);
  fhBookTree->SetBranchAddress("Erelspe", Erelspe);
  fhBookTree->SetBranchAddress("Pathspe", Pathspe);
  fhBookTree->SetBranchAddress("P0spe", P0spe);
  fhBookTree->SetBranchAddress("Nxmult", Nxmult);
  fhBookTree->SetBranchAddress("Nymult", Nymult);
  fhBookTree->SetBranchAddress("Nstrpx", &Nstrpx);
  fhBookTree->SetBranchAddress("Npstripx", Npstripx);
  fhBookTree->SetBranchAddress("Ntstripx", Ntstripx);
  fhBookTree->SetBranchAddress("Istripx", Istripx);
  fhBookTree->SetBranchAddress("Qstripx", Qstripx);
  fhBookTree->SetBranchAddress("Xstripx", Xstripx);
  fhBookTree->SetBranchAddress("Nstrpy", &Nstrpy);
  fhBookTree->SetBranchAddress("Npstripy", Npstripy);
  fhBookTree->SetBranchAddress("Ntstripy", Ntstripy);
  fhBookTree->SetBranchAddress("Istripy", Istripy);
  fhBookTree->SetBranchAddress("Qstripy", Qstripy);
  fhBookTree->SetBranchAddress("Ystripy", Ystripy);
  fhBookTree->SetBranchAddress("Nthcali", &Nthcali);
  fhBookTree->SetBranchAddress("Icaplane", Icaplane);
  fhBookTree->SetBranchAddress("Icastrip", Icastrip);
  fhBookTree->SetBranchAddress("Icamod", Icamod);
  fhBookTree->SetBranchAddress("Enestrip", Enestrip);
  fhBookTree->SetBranchAddress("Nthcal", &Nthcal);
  fhBookTree->SetBranchAddress("Icapl", Icapl);
  fhBookTree->SetBranchAddress("Icasi", Icasi);
  fhBookTree->SetBranchAddress("Icast", Icast);
  fhBookTree->SetBranchAddress("Xincal", Xincal);
  fhBookTree->SetBranchAddress("Yincal", Yincal);
  fhBookTree->SetBranchAddress("Zincal", Zincal);
  fhBookTree->SetBranchAddress("Erelcal", Erelcal);
  fhBookTree->SetBranchAddress("Nthnd", &Nthnd);
  fhBookTree->SetBranchAddress("Itubend", Itubend);
  fhBookTree->SetBranchAddress("Iparnd", Iparnd);
  fhBookTree->SetBranchAddress("Xinnd", Xinnd);
  fhBookTree->SetBranchAddress("Yinnd", Yinnd);
  fhBookTree->SetBranchAddress("Zinnd", Zinnd);
  fhBookTree->SetBranchAddress("Xoutnd", Xoutnd);
  fhBookTree->SetBranchAddress("Youtnd", Youtnd);
  fhBookTree->SetBranchAddress("Zoutnd", Zoutnd);
  fhBookTree->SetBranchAddress("Erelnd", Erelnd);
  fhBookTree->SetBranchAddress("Timend", Timend);
  fhBookTree->SetBranchAddress("Pathnd", Pathnd);
  fhBookTree->SetBranchAddress("P0nd", P0nd);
  fhBookTree->SetBranchAddress("Nthcard", &Nthcard);
  fhBookTree->SetBranchAddress("Iparcard", Iparcard);
  fhBookTree->SetBranchAddress("Icard", Icard);
  fhBookTree->SetBranchAddress("Xincard", Xincard);
  fhBookTree->SetBranchAddress("Yincard", Yincard);
  fhBookTree->SetBranchAddress("Zincard", Zincard);
  fhBookTree->SetBranchAddress("Xoutcard", Xoutcard);
  fhBookTree->SetBranchAddress("Youtcard", Youtcard);
  fhBookTree->SetBranchAddress("Zoutcard", Zoutcard);
  fhBookTree->SetBranchAddress("Erelcard", Erelcard);
  fhBookTree->SetBranchAddress("Timecard", Timecard);
  fhBookTree->SetBranchAddress("Pathcard", Pathcard);
  fhBookTree->SetBranchAddress("P0card", P0card);

  //    fhBookTree->SetBranchStatus("*",0);

}

ClassImp( GPamela);

/////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
//--------------------------------------
//
//
//--------------------------------------
/**
 * Default constructor
 */
PamTrack::PamTrack() {
  trk_track = 0;
  trk_ext_track = 0;
  calo_track = 0;
  tof_track = 0;
  orb_track = 0;
  candeleteobj = 0;
  pscore = 0;
  iscore = 0;
}
;
//--------------------------------------
//
//
//--------------------------------------
/**
 * Constructor
 */
PamTrack::PamTrack(TrkTrack* t, CaloTrkVar* c, ToFTrkVar* o, OrbitalInfoTrkVar *r) {

  trk_ext_track = 0;
  trk_track = 0;
  calo_track = 0;
  tof_track = 0;
  orb_track = 0;
  //     if(t)trk_track  = new TrkTrack(*t);
  //     if(c)calo_track = new CaloTrkVar(*c);
  //     if(o)tof_track  = new ToFTrkVar(*o);
//   if (t)
//     trk_track = t;
//   if (c)
//     calo_track = c;
//   if (o)
//     tof_track = o;
//   if (r)
//     orb_track = r;

//   candeleteobj = 0;

//  cout << t<<"--"<<c<<"--"<<o<<"--"<<r<<"--"<< endl;

  if (t){
      trk_track = new TrkTrack(*t);
      trk_ext_track = new ExtTrack(*t);//NB!! ha dimensione 6 invece che 8
  }else{
      trk_track = new TrkTrack();
      trk_ext_track = new ExtTrack();
      
  }

  if (c)
    calo_track = new CaloTrkVar(*c);
  else
    calo_track = new CaloTrkVar();
  
  if (o)
    tof_track = new ToFTrkVar(*o);
  else
    tof_track = new ToFTrkVar();

  if (r)
    orb_track = new OrbitalInfoTrkVar(*r);
  else
    orb_track = new OrbitalInfoTrkVar();

//  cout << trk_track<<"--"<< calo_track <<"--"<<tof_track<<"--"<<orb_track<<"--"<< endl;

  candeleteobj = 1;

}
;
/**
 * Constructor
 */
PamTrack::PamTrack(ExtTrack* t, CaloTrkVar* c, ToFTrkVar* o, OrbitalInfoTrkVar *r) {

    

  trk_ext_track = 0;
  trk_track = 0;
  calo_track = 0;
  tof_track = 0;
  orb_track = 0;
  //     if(t)trk_track  = new TrkTrack(*t);
  //     if(c)calo_track = new CaloTrkVar(*c);
  //     if(o)tof_track  = new ToFTrkVar(*o);
//   if (t)
//     trk_track = t;
//   if (c)
//     calo_track = c;
//   if (o)
//     tof_track = o;
//   if (r)
//     orb_track = r;

//   candeleteobj = 0;

//  cout << t<<"--"<<c<<"--"<<o<<"--"<<r<<"--"<< endl;


  if (t){
////      trk_track = new TrkTrack(*t);//in this case TrkTrack object remains null
      trk_ext_track = new ExtTrack(*t);
  }else{
      trk_ext_track = new ExtTrack();
  }
  if (c)
    calo_track = new CaloTrkVar(*c);
  else
      calo_track = new CaloTrkVar();

  if (o)
    tof_track = new ToFTrkVar(*o);
  else
    tof_track = new ToFTrkVar();

  if (r)
    orb_track = new OrbitalInfoTrkVar(*r);
  else
    orb_track = new OrbitalInfoTrkVar();

//  cout << trk_track<<"--"<< calo_track <<"--"<<tof_track<<"--"<<orb_track<<"--"<< endl;

  candeleteobj = 1;
  pscore = 0;
  iscore = 0;

}
;

PamTrack::PamTrack(const PamTrack& track) {

  TrkTrack *t = track.trk_track;
  ExtTrack *e = track.trk_ext_track;
  CaloTrkVar *c = track.calo_track;
  ToFTrkVar *o = track.tof_track;
  OrbitalInfoTrkVar *r = track.orb_track;

  trk_ext_track = 0;
  trk_track     = 0;
  calo_track    = 0;
  tof_track     = 0;
  orb_track     = 0;
  if(e)
      trk_ext_track = new ExtTrack(*e);
  if (t)
    trk_track = new TrkTrack(*t);
  if (c)
    calo_track = new CaloTrkVar(*c);
  if (o)
    tof_track = new ToFTrkVar(*o);
  if (r)
    orb_track = new OrbitalInfoTrkVar(*r);

  candeleteobj = 1;
  pscore = 0;
  iscore = 0;

}

void PamTrack::Copy( PamTrack& track) const {

    track.trk_track = trk_track;
    track.trk_ext_track = trk_ext_track;
    track.calo_track = calo_track;
    track.tof_track = tof_track;
    track.orb_track = orb_track;
    
    track.candeleteobj = candeleteobj;
    track.pscore = pscore;
    track.iscore = iscore;
    
}



void PamTrack::Clear(Option_t *option) {

//    cout << "PamTrack::Clear( "<<option<<" ) "<<candeleteobj<<endl;
  if (candeleteobj) {
      
    if (trk_ext_track)
      trk_ext_track->ExtTrack::Clear(option);
    if (trk_track)
      trk_track->TrkTrack::Clear();
    if (calo_track)
      calo_track->CaloTrkVar::Clear();//???
    if (tof_track)
      tof_track->ToFTrkVar::Clear();//???
    if (orb_track)
      orb_track->OrbitalInfoTrkVar::Clear();//???
  }
  else {
    trk_ext_track = 0;
    trk_track = 0;
    calo_track = 0;
    tof_track = 0;
    orb_track = 0;
  }
  pscore = 0;
  iscore = 0;

}
void PamTrack::Delete() {
  //    cout << "PamTrack::Delete() "<<candeleteobj<<endl;
  if (candeleteobj) {
    if (trk_ext_track) {
//	trk_ext_track->ExtTrack::Clear("C");//Clear is called for all the array elements 
	trk_ext_track->ExtTrack::Clear("C+C");//Clear is called for all the array elements passing option 'C'
      delete trk_ext_track;
    }
    if (trk_track) {
      trk_track->TrkTrack::Clear();
      delete trk_track;
    }
    if (calo_track) {
      calo_track->CaloTrkVar::Clear();//???
      delete calo_track;
    }
    if (tof_track) {
      tof_track->ToFTrkVar::Clear();//???
      delete tof_track;
    }
    if (orb_track) {
      orb_track->OrbitalInfoTrkVar::Clear();//???
      delete orb_track;
    }
  }
  else {
    Clear();
  }
}




//--------------------------------------
//
//
//--------------------------------------
/**
 * Default Constructor
 */
PamLevel2::PamLevel2() {
  Initialize();
}


/**
 * Constructor
 * @param ddir Name of directory where level2 files are stored.
 * @param list Name of an ascii file containing the list of file names
 * @param detlist Options to chose what to load.
 * Possible options are:
 *       +AUTO --> load all trees/branches in the input files
 *       +(-)ALL --> inlcude(exclude) all trees/branches
 *       +(-)TRK1+(-)TRK2+(-)CAL1+(-)CAL2+(-)TOF+(-)TRG+(-)ND+(-)S4+(-)ORB+(-)AC --> inlcude(exclude) trees and branches
 *       +(-)TRK0 --> include(exclude) tracker level0 tree
 *       +(-)GP --> include exclude GPAMELA output tree
 * If no options are specified, the default is assumed. Default is:
 * +TRK2+CAL2+CAL1+TOF+TRG+ND+AC+S4+ORB
 */
PamLevel2::PamLevel2(TString ddir, TString llist, TString detlist) {
  Initialize();
  TList* listf = GetListOfLevel2Files(ddir, llist);
  if (listf)
    GetPamTree(listf, detlist);
  if (listf)
    GetRunTree(listf);
  SetMaxShift(-1);
}


PamLevel2::PamLevel2(TString ddir, TList *llist, TString detlist) {
  Initialize();
  GetPamTree(llist, detlist);
  GetRunTree(llist);
  SetMaxShift(-1);
}

/**
 * Constructor
 * @param ddir Name of directory where level2 files are stored.
 * @param list Name of an ascii file containing the list of file names
 * Default trees/branches are loaded. Default is:
 * +TRK2+CAL2+CAL1+TOF+TRG+ND+AC+S4+ORB
 */
PamLevel2::PamLevel2(TString ddir, TString llist) {
  Initialize();
  TList* listf = GetListOfLevel2Files(ddir, llist); 
  cout << "GetPamTree: "<<endl;
  GetPamTree(listf, "");
  cout << "GetRunTree: "<<endl;
  GetRunTree(listf);
  SetMaxShift(-1);
}


void PamLevel2::Initialize() {

  h0_obj = 0;
  trk0_obj = 0;
  calo0_obj = 0;

  trk2_obj = 0;
  trk1_obj = 0;
  trkh_obj = 0;
  calo1_obj = 0;
  calo2_obj = 0;
  tof2_obj = 0;
  trig_obj = 0;
  s4_obj = 0;
  nd_obj = 0;
  ac_obj = 0;
  orb2_obj = 0;
  gp_obj = 0;

  extAlgFlag=0;

  trk_ext_obj     = 0;
  trk_ext_nuc_obj = 0;
  trk_nuc_obj     = 0;
  
  calo_ext_obj     = 0;
  calo_ext_nuc_obj = 0;
  calo_nuc_obj     = 0;
  
  tof_ext_obj     = 0;
  tof_ext_nuc_obj = 0;
  tof_nuc_obj     = 0;
  
  orb_ext_obj     = 0;
  orb_ext_nuc_obj = 0;
  orb_nuc_obj     = 0;

  trk2_nuc_obj  = 0;
  calo2_nuc_obj = 0;
  tof2_nuc_obj  = 0;
  orb2_nuc_obj  = 0;


  run_obj = 0;//new GL_RUN();
  soft_obj = 0;// Emiliano
  proc_obj = 0;// Emiliano
  irun = -1LL;
  irunt = -1LL;
  totrunentry = 0LL;
  totrunentrymax = 0LL;
  totrunentrymin = 0LL;
  runfirstentry = 0LL;
  runlastentry = 0LL;
  gltsync = 0; // Emiliano
  fUpdateRunInfo = true; // Emiliano
  fUseDBinRunInfo = true; // Emiliano
  fDiscarded = false; //EM
  isSync = false; // by default assume that the level2 file(s) is(are) not sinchronized between L0/DB and L2, that is we miss some packets in L2 due to nested/DV-skipped events
  il0entry = 0LL;
  //  hasL0EE = true;

  l0_file = NULL;
  l0_tree = NULL;
  iroot = -1;
  dbc = 0;

  prevshift = 0;
  yprevshift = 0;
  maxshift = 10; //EMILIANO now overridden by SetMaxShift(-1) called by constructors

  run_tree = NULL;
  run_tree_clone = NULL;

  proc_tree = NULL;
  proc_tree_clone = NULL;

  sel_tree = NULL;
  sel_tree_clone = NULL;

  irunentry = -1LL;
  pam_tree = NULL;
  for (Int_t i = 0; i < NCLONES; i++)
    pam_tree_clone[i] = NULL;

  totdltime[0] = 0LL;
  totdltime[1] = 0LL;
  totdltime[2] = 0LL;

  host = "mysql://localhost/pamelaprod";
  user = "anonymous";
  psw = "";
  const char *pamdbhost = gSystem->Getenv("PAM_DBHOST");
  const char *pamdbuser = gSystem->Getenv("PAM_DBUSER");
  const char *pamdbpsw = gSystem->Getenv("PAM_DBPSW");
  if (!pamdbhost)
    pamdbhost = "";
  if (!pamdbuser)
    pamdbuser = "";
  if (!pamdbpsw)
    pamdbpsw = "";
  if (strcmp(pamdbhost, ""))
    host = pamdbhost;
  if (strcmp(pamdbuser, ""))
    user = pamdbuser;
  if (strcmp(pamdbpsw, ""))
    psw = pamdbpsw;

  customString = "";

  //    sorted_tracks = 0;//new TRefArray();

  CAL0 = false;
  CAL1 = true;
  CAL2 = true;
  TRK2 = true;
  TRK1 = false;
  TRK0 = false;
  TRKh = false;
  TRG = true;
  TOF = true;
  TOF0 = false;
  S4 = true;
  ND = true;
  AC = true;
  ORB = true;
  PROC = true;
  GP = false;

  EXT = false;
  NUC = false;
  trkAlg = "STD";//default tracking algorythm

  RUN = true;

  SELLI = -1;

  ISGP = false;

  DBG = false;

  tsorted = 0;
  timage = 0;
  text = 0 ;

  tsorted_nuc = 0;
  timage_nuc = 0;
  text_nuc = 0 ;

  howtosort = "+CAL+TOF";
  //howtosort = "+TOF";
  sortthr = 100.;

  issorted = false;
  lastsorted = -1;
  issorted_new = false;
  lastsorted_new = -1;

}
;
/**
 * Delete the event (act as Dtor)
 */
void PamLevel2::Delete() {

  if (run_obj)
    delete run_obj;
  if (soft_obj)
    delete soft_obj; //Emiliano
  if (proc_obj)
    delete proc_obj; //Emiliano

  //    cout << "void PamLevel2::Clear()"<<endl;
  if (h0_obj)
    delete h0_obj;
  if (trk0_obj)
    delete trk0_obj;
  if (calo0_obj)
    delete calo0_obj;
  if (trk1_obj)
    delete trk1_obj;
  if (trk2_obj)
    delete trk2_obj;
  if (trkh_obj)
    delete trkh_obj;
  if (calo1_obj)
    delete calo1_obj;
  if (calo2_obj)
    delete calo2_obj;
  if (tof2_obj)
    delete tof2_obj;
  if (trig_obj)
    delete trig_obj;
  if (s4_obj)
    delete s4_obj;
  if (nd_obj)
    delete nd_obj;
  if (ac_obj)
    delete ac_obj;
  if (orb2_obj)
    delete orb2_obj;
  if (gp_obj)
    delete gp_obj;

  if(trk_nuc_obj)trk_nuc_obj->Delete();
  if(trk_ext_obj)trk_ext_obj->Delete();
  if(trk_ext_nuc_obj)trk_ext_nuc_obj->Delete();

  if(calo_nuc_obj)calo_nuc_obj->Delete();
  if(calo_ext_obj)calo_ext_obj->Delete();
  if(calo_ext_nuc_obj)calo_ext_nuc_obj->Delete();

  if(tof_nuc_obj)tof_nuc_obj->Delete();
  if(tof_ext_obj)tof_ext_obj->Delete();
  if(tof_ext_nuc_obj)tof_ext_nuc_obj->Delete();

  if(orb_nuc_obj)orb_nuc_obj->Delete();
  if(orb_ext_obj)orb_ext_obj->Delete();
  if(orb_ext_nuc_obj)orb_ext_nuc_obj->Delete();


  if(trk2_nuc_obj)trk2_nuc_obj->Delete();;
  if( calo2_nuc_obj)calo2_nuc_obj->Delete();;
  if(tof2_nuc_obj)tof2_nuc_obj->Delete();;
  if(orb2_nuc_obj)orb2_nuc_obj->Delete();;
  


  if (tsorted) {
    tsorted->Delete();
    delete tsorted;
  }
  if (timage) {
    timage->Delete();
    delete timage;
  }
  if (text) {
    text->Delete();
    delete text;
  }
  if (tsorted_nuc) {
    tsorted_nuc->Delete();
    delete tsorted_nuc;
  }
  if (timage_nuc) {
    timage_nuc->Delete();
    delete timage_nuc;
  }
  if (text_nuc) {
    text_nuc->Delete();
    delete text_nuc;
  }



  if (dbc) {
    dbc->Close();
    delete dbc;
    dbc=0;
  }

  if (gltsync)
    delete gltsync;

  if (l0_file)
    l0_file->Close();
  //    if(pam_tree)pam_tree->Delete();;

  if (pam_tree) {
    //
    // we have first to find which chains we have to delete, then delete the main chain and only after delete the friend chains. Any other order causes a segfault...
    //
    TList *temp = pam_tree->GetListOfFriends();
    TList *contents = new TList; // create chain friend list
    contents->SetOwner();
    TIter next(temp);
    TChain *questo = 0;
    while ((questo = (TChain*) next())) {
      TString name = questo->GetName();
      contents->Add((TChain*) gROOT->FindObject(name.Data()));// add object to the list
    };
    //
    // deleting the main chain
    //
    pam_tree->Delete();
    //
    // deleting the friends...
    //
    TIter next2(contents);
    TChain *questa = 0;
    while ( (questa = (TChain*)next2()) ) {
      TString name = questa->GetName();
      questa->Delete();
      questa = NULL;
    };
    //
  };
  pam_tree = NULL;

  if (run_tree)
    run_tree->Delete();;
  if (sel_tree)
    sel_tree->Delete();;

  // The following lines are commented out since they may generate a double delete error
  // if the file containing the clone trees is closed. This is because the file owns the
  // clone trees which are written into it, so it will delete them when it is closed; if
  // also PamLevel2 will try to delete these trees, a double delete error will be generated
  // when exiting from analysis program. (Nicola 28/11/2011)

  /*for (Int_t i = 0; i < NCLONES; i++)
    if (pam_tree_clone[i])
      pam_tree_clone[i]->Delete();;
  if (run_tree_clone)
    run_tree_clone->Delete();;
  if (sel_tree_clone)
    sel_tree_clone->Delete();;*/

  if (irunoffset)
    delete[] irunoffset;


  Initialize();

}
;

/**
 * Clear the event (NB! does not deallocate objects)
 */
void PamLevel2::Clear() {

  //    cout << "void PamLevel2::Clear()"<<endl;

  //
  // This method is called once for every entry but RunInfo and SoftInfo do not change until the next run so we cannot clear them here unless we don't
  // want to load them for each event even if they are the same...
  //
  //    if(run_obj)delete run_obj;
  //    if(run_obj) run_obj->Clear();  // Emiliano: Do not deallocate run_obj here, it will give segmentation fault! call clear instead
  //    if(soft_obj) soft_obj->Clear();

  if (h0_obj)
    h0_obj->Clear();
  //    if(trk0_obj) trk0_obj->Clear();
  if (trk1_obj)
    trk1_obj->Clear();
  if (trk2_obj)
    trk2_obj->Clear();
  if (trkh_obj)
    trkh_obj->Clear();
  if (calo0_obj)
    calo0_obj->Clear();
  if (calo1_obj)
    calo1_obj->Clear();
  if (calo2_obj)
    calo2_obj->Clear();
  if (tof2_obj)
    tof2_obj->Clear();
  if (trig_obj)
    trig_obj->Clear();
  if (s4_obj)
    s4_obj->Clear();
  if (nd_obj)
    nd_obj->Clear();
  if (ac_obj)
    ac_obj->Clear();
  if (orb2_obj)
    orb2_obj->Clear();
  if (gp_obj)
    gp_obj->Clear();
  if (proc_obj)
    proc_obj->Clear();

  //    if(sorted_tracks)sorted_tracks->Clear();
  //    sorted_tracks.Clear();

  if(trk_nuc_obj)trk_nuc_obj->Clear();
  if(trk_ext_obj)trk_ext_obj->Clear();
  if(trk_ext_nuc_obj)trk_ext_nuc_obj->Clear();

  if(calo_nuc_obj)calo_nuc_obj->Clear();
  if(calo_ext_obj)calo_ext_obj->Clear();
  if(calo_ext_nuc_obj)calo_ext_nuc_obj->Clear();

  if(tof_nuc_obj)tof_nuc_obj->Clear();
  if(tof_ext_obj)tof_ext_obj->Clear();
  if(tof_ext_nuc_obj)tof_ext_nuc_obj->Clear();

  if(orb_nuc_obj)orb_nuc_obj->Clear();
  if(orb_ext_obj)orb_ext_obj->Clear();
  if(orb_ext_nuc_obj)orb_ext_nuc_obj->Clear();

  if(trk2_nuc_obj)trk2_nuc_obj->Clear();;
  if( calo2_nuc_obj)calo2_nuc_obj->Clear();;
  if(tof2_nuc_obj)tof2_nuc_obj->Clear();;
  if(orb2_nuc_obj)orb2_nuc_obj->Clear();;

  if (tsorted)tsorted->Delete();
  if (timage)timage->Delete(); 
  if (text) text->Delete();
 
  if (tsorted_nuc)tsorted_nuc->Delete();
  if (timage_nuc)timage_nuc->Delete(); 
  if (text_nuc) text_nuc->Delete();
}
;

void PamLevel2::Reset() {
  //
  // First of all clear everything
  //
  Clear();
  //
  // close and reset chains and pointers
  //
  if (pam_tree) {
    //
    // we have first to find which chains we have to delete, then delete the main chain and only after delete the friend chains. Any other order causes a segfault...
    //
    TList *temp = pam_tree->GetListOfFriends();
    TList *contents = new TList; // create chain friend list
    contents->SetOwner();
    TIter next(temp);
    TChain *questo = 0;
    while ((questo = (TChain*) next())) {
      TString name = questo->GetName();
      contents->Add((TChain*) gROOT->FindObject(name.Data()));// add object to the list
    };
    //
    // deleting the main chain
    //
    pam_tree->Delete();
    //
    // deleting the friends...
    //
    TIter next2(contents);
    TChain *questa = 0;
    while ( (questa = (TChain*) next2()) ) {
      TString name = questa->GetName();
      questa->Delete();
      questa = NULL;
    };
    //
  };
  pam_tree = NULL;
  //
  if (run_tree)
    run_tree->Delete();;
  run_tree = NULL;
  if (sel_tree)
    sel_tree->Delete();;
  sel_tree = NULL;

  if (proc_tree)
    proc_tree->Delete();
  proc_tree = NULL;
  //
  // Close file
  //
  if (l0_file)
    l0_file->Close("R");
  l0_file = NULL;
  //
  h0_obj = 0;
  trk0_obj = 0;
  calo0_obj = 0;
  //
  trk2_obj = 0;
  trk1_obj = 0;
  trkh_obj = 0;
  calo1_obj = 0;
  calo2_obj = 0;
  tof2_obj = 0;
  trig_obj = 0;
  s4_obj = 0;
  nd_obj = 0;
  ac_obj = 0;
  orb2_obj = 0;
  gp_obj = 0;
  proc_obj = 0;

  trk_ext_obj     = 0;
  trk_ext_nuc_obj = 0;
  trk_nuc_obj     = 0;
  
  calo_ext_obj     = 0;
  calo_ext_nuc_obj = 0;
  calo_nuc_obj     = 0;
  
  tof_ext_obj     = 0;
  tof_ext_nuc_obj = 0;
  tof_nuc_obj     = 0;
  
  orb_ext_obj     = 0;
  orb_ext_nuc_obj = 0;
  orb_nuc_obj     = 0;

  trk2_nuc_obj  = 0;
  calo2_nuc_obj = 0;
  tof2_nuc_obj  = 0;
  orb2_nuc_obj  = 0;

  trk2_nuc_obj  = 0;
  calo2_nuc_obj = 0;
  tof2_nuc_obj  = 0;
  orb2_nuc_obj  = 0;
  //
  // Reset run pointers
  //
  run_obj = 0;//new GL_RUN();
  soft_obj = 0;// Emiliano
  proc_obj = 0;// Emiliano
  irun = -1;
  irunt = -1;
  totrunentry = 0LL;
  totrunentrymax = 0LL;
  totrunentrymin = 0LL;
  runfirstentry = 0ULL;
  runlastentry = 0ULL;
  prevabstime = 0ULL;
  prevpktnum = 0;
  abstime = 0ULL;
  pktnum = 0;
  isFragment = false;
  //
  totdltime[0] = 0LL;
  totdltime[1] = 0LL;
  totdltime[2] = 0LL;
  //
}
;

Bool_t PamLevel2::IsGood(Bool_t strict) {
  Bool_t goodev = true;
  //
  if (calo2_obj && !calo2_obj->IsGood(strict))
    goodev = false;
  //
  if (strict) {
    if (trk2_obj && trk2_obj->UnpackError() != 0)
      goodev = false;
    if (tof2_obj && tof2_obj->unpackError != 0)
      goodev = false;
    if (trig_obj && trig_obj->unpackError != 0)
      goodev = false;
    if (s4_obj && s4_obj->unpackError != 0)
      goodev = false;
    if (nd_obj && nd_obj->unpackError != 0)
      goodev = false;
    if (ac_obj && (ac_obj->unpackError != 0 || ((ac_obj->status[0] >> 2) & 1) || ((ac_obj->status[1] >> 2) & 1)))
      goodev = false;
    //  if(orb2_obj)
  }
  else {
    if (nd_obj && nd_obj->unpackError != 0)
      goodev = false;
    if (ac_obj && (ac_obj->unpackError != 0 || ((ac_obj->status[0] >> 2) & 1) || ((ac_obj->status[1] >> 2) & 1)))
      goodev = false;
  };
  return (goodev);
}
;

void PamLevel2::SkipRunInfoUpdate(){
  printf("\n\n ******** WARNING ******** \n Skip DB connections, DO NOT USE PamLevel2::GetRunInfo() method! \n\n");
  fUpdateRunInfo = false;
  this->SetSELLI(2);
  printf(" ===============> W A R N I N G <================ \n");
  printf(" in case PamLevel2::CreateCloneTrees() will be called \n");
  printf(" it will be reverted to PadmeAmidala level2 structure , i.e. NO SELECTIONLIST WILL BE CREATED IN THE NEW LEVEL2 FILE! \n\n");
  if ( run_tree_clone ){
    printf(" ===============> W A R N I N G <================ \n");
    printf(" PamLevel2::SkipRunIndoUpdate or PamLevel2::NoDBconnections() has been called together with PamLevel2::CreateCloneTrees() \n");
    printf(" TO AVOID CRASHES call PamLevel2::CreateCloneTrees() after PamLevel2::SkipRunIndoUpdate or PamLevel2::NoDBconnections() \n");    
  };
}

void PamLevel2::SetMaxShift(Int_t sh){
  if ( sh >=  0 ){
    printf("PamLevel2::SetMaxShift(Int_t) --WARNING-- the default is optimized by checking the level2 file\n it is strongly suggested to let PamLevel2 choose the max shift!\n");
    maxshift = sh; 
  } else {
    ULong64_t nev = GetEntries();
    ULong64_t runnev = 0ULL;
    for (Int_t r=0; r< run_tree->GetEntries();r++){
      run_tree->GetEntry(r);//update runinfo
      runnev += GetRunInfo()->NEVENTS;
    }
    maxshift = (Int_t)(runnev-nev) + 10; // +10 just to be conservative
    if ( (runnev-nev) == 0 ) isSync = true;
    if (DBG) printf("PamLevel2::SetMaxShift(Int_t_) - sh negative %i - nev is %lld runnnev is %lld so maxshift set to %i \n",sh,nev,runnev,maxshift);
    //    printf("PamLevel2::SetMaxShift(Int_t_) - sh negative %i - nev is %lld runnnev is %lld so maxshift set to %i \n",sh,nev,runnev,maxshift); // TOGLITOGLI
  }
}

//--------------------------------------
//
//
//--------------------------------------
void *PamLevel2::GetPointerTo(const char* c) {

  TString objname = c;

  if (!objname.CompareTo("TrkLevel1")) {
    if (!trk1_obj) {
      trk1_obj = new TrkLevel1();
      trk1_obj->Set();
    }
    return &trk1_obj;
  };
  if (!objname.CompareTo("TrkLevel2")) {
    if (!trk2_obj) {
      trk2_obj = new TrkLevel2();
      trk2_obj->Set();
    }
    return &trk2_obj;
  };
  if (!objname.CompareTo("TrkHough")) {
    if (!trkh_obj) {
      trkh_obj = new TrkHough();
      trkh_obj->Set();
    }
    return &trkh_obj;
  };
  if (!objname.CompareTo("CaloLevel1")) {
    if (!calo1_obj)
      calo1_obj = new CaloLevel1();
    return &calo1_obj;
  };
  if (!objname.CompareTo("CaloLevel2")) {
    if (!calo2_obj) {
      calo2_obj = new CaloLevel2();
      calo2_obj->Set();
    };
    return &calo2_obj;
  };
  if (!objname.CompareTo("ToFLevel2")) {
    if (!tof2_obj) {
      tof2_obj = new ToFLevel2();
      tof2_obj->Set();
    }
    return &tof2_obj;
  };
  if (!objname.CompareTo("TrigLevel2")) {
    if (!trig_obj)
      trig_obj = new TrigLevel2();
    return &trig_obj;
  };
  if (!objname.CompareTo("S4Level2")) {
    if (!s4_obj)
      s4_obj = new S4Level2();
    return &s4_obj;
  };
  if (!objname.CompareTo("NDLevel2")) {
    if (!nd_obj)
      nd_obj = new NDLevel2();
    return &nd_obj;
  };
  if (!objname.CompareTo("AcLevel2")) {
    if (!ac_obj)
      ac_obj = new AcLevel2();
    return &ac_obj;
  };
  if (!objname.CompareTo("OrbitalInfo")) {
    if (!orb2_obj) {
      orb2_obj = new OrbitalInfo();
      orb2_obj->Set();
    }
    return &orb2_obj;
  };
  //     if(!objname.CompareTo("OrbitalInfo")){
  // 	if(!orb2_obj)   orb2_obj   = new OrbitalInfo();
  // 	return &orb2_obj;
  //     };
  if (!objname.CompareTo("GPamela")) {
    if (!gp_obj)
      gp_obj = new GPamela();
    return &gp_obj;
  };

  if (!objname.CompareTo("RunInfo"))
    return &run_obj;

  if (!objname.CompareTo("SoftInfo"))
    return &soft_obj; // Emiliano

  if (!objname.CompareTo("ProcInfo")){
    if (!proc_obj) 
      proc_obj = new ProcInfo();    
    return &proc_obj; // Emiliano
  }

  return NULL;
}
;
//--------------------------------------
//
//
//--------------------------------------
/**
 * Retrieves the calorimeter track matching the seqno-th tracker stored track.
 * (If seqno = -1 retrieves the self-trigger calorimeter track)
 */
CaloTrkVar *PamLevel2::GetCaloStoredTrack(int seqno) {

  if (!calo2_obj)
    return 0;

  if (calo2_obj->CaloLevel2::ntrk() == 0) {
      if( seqno >=0 ){
	  cout << "PamLevel2::GetCaloStoredTrack(int) : requested tracker SeqNo " << seqno;
	  cout << " but no Calorimeter tracks are stored" << endl;
      }
      return NULL;
  };

  CaloTrkVar *c = 0;
  Int_t it_calo = 0;

  do {
    c = calo2_obj->CaloLevel2::GetCaloTrkVar(it_calo);
    it_calo++;
  } while (c && seqno != c->trkseqno && it_calo < calo2_obj->CaloLevel2::ntrk());

  if (!c || seqno != c->trkseqno) {
    c = 0;
    if (seqno != -1 && seqno>=0) 
      cout << "PamLevel2::GetCaloStoredTrack(int) : requested tracker SeqNo " << seqno
          << " does not match Calorimeter stored tracks" << endl;
  };
  return c;

}
;
//--------------------------------------
//
//
//--------------------------------------
/**
 * Retrieves the ToF track matching the seqno-th tracker stored track.
 * (If seqno = -1 retrieves the tracker-independent tof track)
 */
ToFTrkVar *PamLevel2::GetToFStoredTrack(int seqno) {

  if (!tof2_obj)
    return 0;

  if (tof2_obj->ToFLevel2::ntrk() == 0) {
    cout << "PamLevel2::GetToFStoredTrack(int) : requested tracker SeqNo " << seqno << " but no ToF tracks are stored"
        << endl;
    return NULL;
  };

  ToFTrkVar *c = 0;
  Int_t it_tof = 0;

  do {
    c = tof2_obj->ToFLevel2::GetToFTrkVar(it_tof);
    it_tof++;
  } while (c && seqno != c->trkseqno && it_tof < tof2_obj->ToFLevel2::ntrk());

  if (!c || seqno != c->trkseqno) {
    c = 0;
    if (seqno != -1)
      cout << "PamLevel2::GetToFStoredTrack(int) : requested tracker SeqNo " << seqno
          << " does not match ToF stored tracks" << endl;
  };
  return c;

}
;

//--------------------------------------
//
//
//--------------------------------------
/**
 * Retrieves the OrbitalInfo track matching the seqno-th tracker stored track.
 * (If seqno = -1 retrieves the tracker-independent tof related track)
 */
OrbitalInfoTrkVar *PamLevel2::GetOrbitalInfoStoredTrack(int seqno) {

  if (!orb2_obj)
    return 0;

  if (orb2_obj->OrbitalInfo::ntrk() == 0) {
    //       // TRICK BEGIN
    //       OrbitalInfoTrkVar  *r = new OrbitalInfoTrkVar(); // TEMPORARY TRICK
    //       Int_t nn = 0;
    //       TClonesArray &tor = *orb2_obj->OrbitalInfoTrk;
    //       for(Int_t nt=0; nt < tof2_obj->ToFLevel2::ntrk(); nt++){
    // 	//
    // 	ToFTrkVar *ptt = tof2_obj->ToFLevel2::GetToFTrkVar(nt);
    // 	if ( ptt->trkseqno != -1  ){
    // 	  //
    // 	  r->trkseqno = ptt->trkseqno;
    // 	  //
    // 	  r->Eij = 0;
    // 	  //
    // 	  r->Sij = 0;
    // 	  //
    // 	  r->pitch = -1000.;
    // 	  //
    // 	  r->cutoff = -1000.;
    // 	  //
    // 	  new(tor[nn]) OrbitalInfoTrkVar(*r);
    // 	  nn++;
    // 	  //
    // 	  r->Clear();
    // 	  //
    // 	};
    //       };
    //       delete r;
    //       OrbitalInfoTrkVar *c = 0;
    //       c = orb2_obj->OrbitalInfo::GetOrbitalInfoTrkVar(0);
    //       return c;
    //       //TRICK END
    cout << "PamLevel2::GetOrbitalInfoStoredTrack(int) : requested tracker SeqNo " << seqno
        << " but no OrbitalInfo tracks are stored" << endl;
    return NULL;
  };

  OrbitalInfoTrkVar *c = 0;
  Int_t it_tof = 0;

  do {
    c = orb2_obj->OrbitalInfo::GetOrbitalInfoTrkVar(it_tof);
    it_tof++;
  } while (c && seqno != c->trkseqno && it_tof < orb2_obj->OrbitalInfo::ntrk());

  if (!c || seqno != c->trkseqno) {
    c = 0;
    if (seqno != -1)
      cout << "PamLevel2::GetOrbitalInfoStoredTrack(int) : requested tracker SeqNo " << seqno
          << " does not match OrbitalInfo stored tracks" << endl;
  };
  return c;

}
;

//--------------------------------------
//
//
//--------------------------------------
// /**
//  * Give the pamela track associated to a tracker track, retrieving related calorimeter, orbitalinfo and tof track information.
//  */
// PamTrack* PamLevel2::GetPamTrackAlong(TrkTrack* t) {

//   cout << "PamLevel2::GetPamTrackAlong(TrkTrack* t) **obsolete** " << endl;
//   cout << "(if you use it, remember to delete the PamTrack object)" << endl;

//   CaloTrkVar *c = 0;
//   ToFTrkVar *o = 0;
//   OrbitalInfoTrkVar *r = 0;

//   if (CAL2)
//     c = GetCaloStoredTrack(t->GetSeqNo());
//   if (TOF)
//     o = GetToFStoredTrack(t->GetSeqNo());
//   if (ORB)
//     r = GetOrbitalInfoStoredTrack(t->GetSeqNo());

//   //    if(t && c && o)track = new PamTrack(t,c,o);
//   PamTrack *track = new PamTrack(t, c, o, r);

//   return track;

// }
// ;
//--------------------------------------
//
//
//--------------------------------------
// /**
//  * Retrieves the it-th stored track.
//  * It override TrkLevel2::GetTrack(int it).
//  * @param itrk Track number, ranging from 0 to GetNTracks().
//  */

// PamTrack* PamLevel2::GetStoredTrack(Int_t itrk) {

//   cout << "PamLevel2::GetStoredTrack(Int_t itrk) **to-be-updated** " << endl;
//   cout
//       << "for the moment, better use separately the methods: TrkLevel2::GetStoredTrack(seqno) CaloLevel2::GetCaloTrkVar(Int_t notrack) ToFLevel2::GetToFTrkVar(Int_t notrack) OrbitalInfo::GetOrbitalInfoTrkVar(Int_t notrack)"
//       << endl;
//   cout << "(if you use it, remember to delete the PamTrack object)" << endl;
//   PamTrack *track = 0;

//   if (itrk >= 0 && itrk < trk2_obj->TrkLevel2::ntrk()) {

//     TrkTrack *t = trk2_obj->TrkLevel2::GetStoredTrack(itrk);
//     track = GetPamTrackAlong(t);

//   }
//   else {
//     cout << "PamLevel2::GetStoredTrack(int) : tracker track SeqNo " << itrk << " does not exist (GetNTracks() = "
//         << trk2_obj->TrkLevel2::GetNTracks() << ")" << endl;
//   };

//   return track;

// }
//--------------------------------------
//

/**
 * Sort physical (tracker) tracks. Left here as backward compatibility method.
 **/
void PamLevel2::SortTracks(TString how) {
  printf(
      " WARNING! obsolete, use SortTracks() and SetSortingMethod(TString) instead! \n Setting sorting method to %s \n",
      how.Data());
  howtosort = how;
  SortTracks();
}
;

//
//--------------------------------------
/**
 * Sort physical (tracker) tracks.
 * @param how String to set the sorting cryterium (es: "CAL" or "TRK+CAL+TOF" ecc...).
 * Sorting cryteria:
 * TRK: lower chi**2
 * CAL: lower Y spatial residual on the first calorimeter plane
 * TOF: bigger numebr of hit PMTs along the track, on S12 S21 S32 (where paddles are along the Y axis).
 * S1: (ask Emiliano)
 * S2: (ask Emiliano)
 * S3: (ask Emiliano)
 * GP: more GP hits
 * The default sorting cryterium is "TOF+CAL".
 *
 * The total number of physical tracks is always given by GetNTracks() and the it-th physical track can be retrieved by means of the methods GetTrack(int it) and GetTrack(int it, TString how).
 */
void PamLevel2::SortTracks() {

  //Check if the current event has already been sorted
  if (issorted && lastsorted == GetReadEntry()) {
    return;
  }
  //Reset the sort flags, just in case something will go wrong...
  issorted = false;
  lastsorted = -1;

  TString how = howtosort;

  //  cout <<" PamLevel2::SortTracks(TString how) "<<endl;
  if (!trk2_obj) {
    cout << "void PamLevel2::SortTracks():  TrkLevel2 not loaded !!!";
    return;
  };
  //Save current Object count
  Int_t ObjectNumber = TProcessID::GetObjectCount();

  // create TCloneArrays to store tracks and its images
//   if (!tsorted)
//     tsorted = new TClonesArray("PamTrack", trk2_obj->GetNTracks());
//   tsorted->Clear("C+C");//Delete();
//   if (!timage)
//     timage = new TClonesArray("PamTrack", trk2_obj->GetNTracks());
//   timage->Clear("C+C");//Delete();

  if(tsorted)delete tsorted;
  if(timage) delete timage;
  tsorted = new TClonesArray("PamTrack", trk2_obj->GetNTracks());
  timage = new TClonesArray("PamTrack", trk2_obj->GetNTracks());


  TClonesArray &ttsorted = *tsorted;
  TClonesArray &ttimage = *timage;



  //--------------------------------------------------
  // retrieve sorting method
  //--------------------------------------------------
  Bool_t use_TRK = how.Contains("TRK", TString::kIgnoreCase);
  Bool_t use_CAL = how.Contains("CAL", TString::kIgnoreCase);
  Bool_t use_TOF = how.Contains("TOF", TString::kIgnoreCase);
  Bool_t use_S1 = how.Contains("S1", TString::kIgnoreCase);
  Bool_t use_S2 = how.Contains("S2", TString::kIgnoreCase);
  Bool_t use_S3 = how.Contains("S3", TString::kIgnoreCase);
  Bool_t use_GP = how.Contains("GP", TString::kIgnoreCase);

  if (use_TOF) {
    use_S1 = true;
    use_S2 = true;
    use_S3 = true;
  };
  if (!CAL2 && use_CAL)
    use_CAL = false;
  if (!TOF) {
    use_TOF = false;
    use_S1 = false;
    use_S2 = false;
    use_S3 = false;
  }
  if (!GP) {
    use_GP = false;
  }

  if (!TRK2) {
    cout << "SortTracks() : without tracker does not work!!! (not yet)" << endl;
    return;
  };

  //   cout << "use_CAL "<<use_CAL<<" use_TOF "<<use_TOF<<" use_TRK "<<use_TRK <<endl;


  //--------------------------------------------------
  // loop over "physical" tracks sorted by the tracker
  //--------------------------------------------------
  for (Int_t i = 0; i < trk2_obj->TrkLevel2::GetNTracks(); i++) {

    TrkTrack *ts = 0;
    CaloTrkVar *cs = 0;
    ToFTrkVar *os = 0;
    OrbitalInfoTrkVar *rs = 0;

    // get tracker tracks
    TrkTrack *tp = trk2_obj->TrkLevel2::GetTrack(i); //tracker
    CaloTrkVar *cp = GetCaloStoredTrack(tp->GetSeqNo());
    ToFTrkVar *op = GetToFStoredTrack(tp->GetSeqNo());
    OrbitalInfoTrkVar *rp = GetOrbitalInfoStoredTrack(tp->GetSeqNo());

    TrkTrack *ti = 0; //tracker (image)
    CaloTrkVar *ci = 0;
    ToFTrkVar *oi = 0;
    OrbitalInfoTrkVar *ri = 0;
    //	cout << "trk track n. "<<i << " "<<hex<< tp <<dec<< endl;
    // if track has an image, check image selection

    Int_t tp_score = 0; //main track sorted by the tracker
    Int_t ti_score = 0; //image track
    Int_t totp_score = 0; //main track sorted by the tracker
    Int_t toti_score = 0; //image track

    if (tp->HasImage()) {

      ti = trk2_obj->TrkLevel2::GetTrackImage(i); //tracker (image)
      ci = GetCaloStoredTrack(ti->GetSeqNo());
      oi = GetToFStoredTrack(ti->GetSeqNo());
      ri = GetOrbitalInfoStoredTrack(ti->GetSeqNo());

      //	    cout << "its image "<<i << " "<<hex<< ti <<dec<< endl;

      //assign starting scores
      tp_score = 0; //main track sorted by the tracker
      ti_score = 0; //image track

      // -----------------------------------------------------------------------------------------
      // *****************************************************************************************
      // -----------------------------------------------------------------------------------------
      // calorimeter check
      // -----------------------------------------------------------------------------------------
      if (use_CAL && !calo2_obj) {
        cout << "void PamLevel2::SortTracks(): howtosort= " << how << " but CaloLevel2 not loaded !!!";
        return;
      };
      if (use_CAL && !cp && ci) {
        ti_score++;
        toti_score++;
      };
      if (use_CAL && cp && !ci) {
        tp_score++;
        totp_score++;
      };
      if (use_CAL && cp && ci && true) {

        if (cp->npresh > ci->npresh && true) {
          tp_score++;
          totp_score++;
        };
        if (cp->npresh < ci->npresh && true) {
          ti_score++;
          toti_score++;
        };

        //	cout << "CALO "<<tp_score<<ti_score<<endl;

      };
      // -----------------------------------------------------------------------------------------
      // *****************************************************************************************
      // -----------------------------------------------------------------------------------------
      // TOF check
      // -----------------------------------------------------------------------------------------
      // check the number of hit pmts along the track
      // on S12 S21 and S32, where paddles are parallel to Y axis
      if ((use_TOF || use_S1 || use_S2 || use_S3) && !tof2_obj) {
        cout << "void PamLevel2::SortTracks(): howtosort= " << how << " but ToFLevel2 not loaded !!!";
        return;
      };
      //
      if ((use_TOF || use_S1 || use_S2 || use_S3) && !op && oi) {
        ti_score++;
        toti_score++;
      };
      if ((use_TOF || use_S1 || use_S2 || use_S3) && op && !oi) {
        tp_score++;
        totp_score++;
      };
      if ((use_TOF || use_S1 || use_S2 || use_S3) && op && oi) {
        //
        Float_t sen = 0.;
        for (Int_t ih = 0; ih < op->npmtadc; ih++) {
          Int_t pl = tof2_obj->GetPlaneIndex((op->pmtadc).At(ih));
          if (pl == 2 || pl == 3 || pl == 4 || pl == 5)
            sen += (op->dedx).At(ih);
        };
        for (Int_t ih = 0; ih < oi->npmtadc; ih++) {
          Int_t pl = tof2_obj->GetPlaneIndex((oi->pmtadc).At(ih));
          if (pl == 2 || pl == 3 || pl == 4 || pl == 5)
            sen += (oi->dedx).At(ih);
        };
        //
        if (sen >= sortthr && false) { // temporary disabled NUCLEI special algorithm since the new one should work for every particle (to be checked!)
          //printf(" IS A NUCLEUS! en = %f \n",sen);
          //
          // is a nucleus use a different algorithm
          //
          Int_t nz = 6;
          Float_t zin[6]; // << define TOF z-coordinates
          for (Int_t ip = 0; ip < nz; ip++)
            zin[ip] = tof2_obj->ToFLevel2::GetZTOF(tof2_obj->ToFLevel2::GetToFPlaneID(ip)); // << read ToF plane z-coordinates
          Trajectory *tr = new Trajectory(nz, zin);
          //
          Int_t nphit_p = 0;
          Int_t nphit_i = 0;
          Float_t enhit_p = 0.;
          Float_t enhit_i = 0.;
          //
          for (Int_t ih = 0; ih < op->npmtadc; ih++) {
            Int_t pl = tof2_obj->GetPlaneIndex((op->pmtadc).At(ih));
            if (pl == 1 || pl == 2 || pl == 5) {
              nphit_p++;
              enhit_p += (op->dedx).At(ih);
            };
          };
          //
          tp->DoTrack2(tr);
          //
          if (fabs(tr->y[0] - oi->ytofpos[0]) < 2.) {
            for (Int_t ih = 0; ih < op->npmtadc; ih++) {
              Int_t pl = tof2_obj->GetPlaneIndex((op->pmtadc).At(ih));
              if (pl == 0) {
                nphit_p++;
                enhit_p += (op->dedx).At(ih);
              };
            };
          };
          if (fabs(tr->y[3] - oi->ytofpos[1]) < 2.) {
            for (Int_t ih = 0; ih < op->npmtadc; ih++) {
              Int_t pl = tof2_obj->GetPlaneIndex((op->pmtadc).At(ih));
              if (pl == 3) {
                nphit_p++;
                enhit_p += (op->dedx).At(ih);
              };
            };
          };
          if (fabs(tr->y[4] - oi->ytofpos[2]) < 2.) {
            for (Int_t ih = 0; ih < op->npmtadc; ih++) {
              Int_t pl = tof2_obj->GetPlaneIndex((op->pmtadc).At(ih));
              if (pl == 4) {
                nphit_p++;
                enhit_p += (op->dedx).At(ih);
              };
            };
          };

          for (Int_t ih = 0; ih < oi->npmtadc; ih++) {
            Int_t pl = tof2_obj->GetPlaneIndex((oi->pmtadc).At(ih));
            if (pl == 1 || pl == 2 || pl == 5) {
              nphit_i++;
              enhit_i += (op->dedx).At(ih);
            };
          };
          //
          ti->DoTrack2(tr);
          //
          if (fabs(tr->y[0] - oi->ytofpos[0]) < 2.) {
            for (Int_t ih = 0; ih < oi->npmtadc; ih++) {
              Int_t pl = tof2_obj->GetPlaneIndex((oi->pmtadc).At(ih));
              if (pl == 0) {
                nphit_i++;
                enhit_i += (op->dedx).At(ih);
              };
            };
          };
          if (fabs(tr->y[3] - oi->ytofpos[1]) < 2.) {
            for (Int_t ih = 0; ih < oi->npmtadc; ih++) {
              Int_t pl = tof2_obj->GetPlaneIndex((oi->pmtadc).At(ih));
              if (pl == 3) {
                nphit_i++;
                enhit_i += (op->dedx).At(ih);
              };
            };
          };
          if (fabs(tr->y[4] - oi->ytofpos[2]) < 2.) {
            for (Int_t ih = 0; ih < oi->npmtadc; ih++) {
              Int_t pl = tof2_obj->GetPlaneIndex((oi->pmtadc).At(ih));
              if (pl == 4) {
                nphit_i++;
                enhit_i += (op->dedx).At(ih);
              };
            };
          };

          if ((use_TOF || use_S1 || use_S2 || use_S3) && (nphit_p + nphit_i) != 0 && true) {

            //	    printf(" seqno %i nphit_p %i nphit_i %i enhit_p %f enhit_i %f \n",trk2_obj->TrkLevel2::GetSeqNo(i),nphit_p,nphit_i,enhit_p,enhit_i);
            //	    printf(" score p %i score i %i \n",tp_score,ti_score);
            //		  if( enhit_p > enhit_i ) tp_score++;
            //		  if( nphit_p >= nphit_i && enhit_p > enhit_i ) tp_score++;
            if (nphit_p > nphit_i)
              tp_score++;
            if (nphit_p < nphit_i)
              ti_score++;
            if (nphit_p == nphit_i) {
              if (enhit_p > enhit_i)
                tp_score++;
              else
                ti_score++;
            };
            //	    printf(" dopo score p %i score i %i \n",tp_score,ti_score);
          };
          delete tr;
          //
        }
        else {
          // -------------
          // NOT a NUCLEUS
          // -------------
          //printf(" NOT a NUCLEUS! en = %f \n",sen);

          Int_t nphit_p = 0;
          Int_t nphit_i = 0;

          /*				cout << "track: npmtadc "<< op->npmtadc << endl;
           cout << "track: npmttdc "<< op->npmttdc << endl;
           cout << "image: npmtadc "<< oi->npmtadc << endl;
           cout << "image: npmttdc "<< oi->npmttdc << endl;*/

          // 	  for (Int_t ih=0; ih < op->npmtadc; ih++){
          // 	    Int_t pl = tof2_obj->GetPlaneIndex( (op->pmtadc).At(ih) );
          // 	    if(pl == 1 || pl == 2 || pl == 5)nphit_p++;
          // 	  };

          // 	  for (Int_t ih=0; ih < oi->npmtadc; ih++){
          // 	    Int_t pl = tof2_obj->GetPlaneIndex( (oi->pmtadc).At(ih) );
          // 	    if(pl == 1 || pl == 2 || pl == 5)nphit_i++;
          // 	  };
          // --- modified to count tdc signals (more efficient?)
          // --- and to implement check on tdcflag
          for (Int_t ih = 0; ih < op->npmttdc; ih++) {
            Int_t pl = tof2_obj->GetPlaneIndex((op->pmttdc).At(ih));
            //	    if( (op->tdcflag).At(ih)==0 && (pl == 1 || pl == 2 || pl == 5) )nphit_p++;
            if ((use_S1 && (pl == 0 || pl == 1)) || (use_S2 && (pl == 2 || pl == 3))
                || (use_S3 && (pl == 4 || pl == 5))) {
              if ((op->tdcflag).At(ih) == 0)
                nphit_p++;
            };
          };

          for (Int_t ih = 0; ih < oi->npmttdc; ih++) {
            Int_t pl = tof2_obj->GetPlaneIndex((oi->pmttdc).At(ih));
            //	    if( (oi->tdcflag).At(ih)==0 && (pl == 1 || pl == 2 || pl == 5) )nphit_i++;
            if ((use_S1 && (pl == 0 || pl == 1)) || (use_S2 && (pl == 2 || pl == 3))
                || (use_S3 && (pl == 4 || pl == 5))) {
              if ((oi->tdcflag).At(ih) == 0)
                nphit_i++;
            };
          };

          if ((nphit_p + nphit_i) != 0 && true) {

            if (nphit_p != nphit_i) {
              totp_score += nphit_p;
              toti_score += nphit_i;
              tp_score += nphit_p;
              ti_score += nphit_i;
            };
            //	    if     ( nphit_p > nphit_i) tp_score+=nphit_p;
            //	    else if( nphit_p < nphit_i) ti_score+=nphit_i;
            //	    else ;//niente
          };
        };
        //	cout << "TOF "<<tp_score<<ti_score<<endl;
      };

      //      if(tp_score == ti_score) use_TRK = true;


      // -----------------------------------------------------------------------------------------
      // *****************************************************************************************
      // -----------------------------------------------------------------------------------------
      // tracker check
      // -----------------------------------------------------------------------------------------
      // chi**2 difference is not always large enough to distinguish among
      // the real track and its image.
      // Tracker check will be applied always when calorimeter and tof information is ambiguous.
      // *** MODIFIED ON AUGUST 2007 ***
      if (use_TRK) {
        // 	if(      tp->chi2 > 0 && tp->chi2 < ti->chi2 ) tp_score++ ;
        // 	else if( ti->chi2 > 0 && ti->chi2 < tp->chi2 ) ti_score++ ;

        // CHECK 1 : number of points along X
        if (tp->GetNX() >= ti->GetNX()) {
          tp_score++;
          totp_score++;
        };
        if (tp->GetNX() <= ti->GetNX()) {
          ti_score++;
          toti_score++;
        };
        // CHECK 2 : number of points along Y
        if (tp->GetNY() >= ti->GetNY()) {
          tp_score++;
          totp_score++;
        };
        if (tp->GetNY() <= ti->GetNY()) {
          ti_score++;
          toti_score++;
        };

        //	cout << "TRK "<<tp_score<<ti_score<<endl;
      };

      // -----------------------------------------------------------------------------------------
      // *****************************************************************************************
      // -----------------------------------------------------------------------------------------
      // GPamela check
      // -----------------------------------------------------------------------------------------

      //---------------------------------------------------
      // count the number of GP hits
      //---------------------------------------------------
      if (use_GP) {
        int ngphits_p = 0;
        int ngphits_i = 0;
        float toll = 0.02; //200 micron
        for (int ih = 0; ih < GetGPamela()->Nthspe; ih++) {
          int ip = (Int_t) GetGPamela()->Itrpb[ih] - 1;
          if (tp && tp->YGood(ip) && fabs(tp->ym[ip] - GetGPamela()->Yavspe[ih]) < toll && true)
            ngphits_p++;
          if (ti && ti->YGood(ip) && fabs(ti->ym[ip] - GetGPamela()->Yavspe[ih]) < toll && true)
            ngphits_i++;
        }
        if (ngphits_p > ngphits_i && true) {
          tp_score++;
          totp_score++;
        }
        if (ngphits_p < ngphits_i && true) {
          ti_score++;
          toti_score++;
        }
      }

      // *-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*
      // the winner is....
      // *-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*
      if (tp_score > ti_score) {

      }
      else if (tp_score < ti_score) {

        ts = ti;//its image!!
        cs = ci;
        os = oi;
        rs = ri;
        Int_t totis = toti_score;

        ti = tp;//its image!!
        ci = cp;
        oi = op;
        ri = rp;

        tp = ts;//its image!!
        cp = cs;
        op = os;
        rp = rs;

        toti_score = totp_score;
        totp_score = totis;

      }
      else {

        //	cout << "Warning - track image ambiguity not solved" << endl;

      };

    }
    else {
      totp_score = 1;
      toti_score = 0;

      // 	    ts = tp;
      // 	    cs = cp;
      // 	    os = op;
    };

    //	cout <<" SortTracks() "<<i<<" -- "<<ts<<endl;
    //	sorted_tracks->Add(ts);//save the track in the sorted array
    //	sorted_tracks.Add(ts);//save the track in the sorted array
    //	sorted_tracks.Add(tp);//save the track in the sorted array
    //	cout << "SortTracks:: sorted_tracks->Add(it) "<<i<<" "<<ts<<endl;
    //	cout<<"o "<<tp<<endl;
    //	cout<<"o "<<cp<<endl;
    //	cout<<"o "<<op<<endl;

//     cout <<"old p:"<< tp<<"--"<<cp<<"--"<<op<<"--"<<rp<<"--"<< endl;
//     cout <<"old i:"<< ti<<"--"<<ci<<"--"<<oi<<"--"<<ri<<"--"<< endl;

    new (ttsorted[i]) PamTrack(tp, cp, op, rp);
    new (ttimage[i]) PamTrack(ti, ci, oi, ri);

    ((PamTrack*) (ttsorted[i]))->SetPScore(totp_score);
    ((PamTrack*) (ttsorted[i]))->SetIScore(toti_score);
    ((PamTrack*) (ttimage[i]))->SetPScore(totp_score);
    ((PamTrack*) (ttimage[i]))->SetIScore(toti_score);
  };

  if (tsorted->GetEntries() != trk2_obj->GetNTracks()) {
    cout << "void PamLevel2::SortTracks(): tsorted->GetEntries() " << tsorted->GetEntries()
        << " != trk2_obj->GetNTracks() = " << trk2_obj->GetNTracks() << endl;
    tsorted->Delete();
    tsorted = 0;
    timage->Delete();
    timage = 0;
  }

  //Restore Object count
  //To save space in the table keeping track of all referenced objects
  //We reset the object count to what it was at the beginning of the event.
  TProcessID::SetObjectCount(ObjectNumber);

  //Everything went fine so the current event can be tagged as sorted
  issorted = true;
  lastsorted = GetReadEntry();

//  cout <<" SortTracks() -- end"<<endl;

}
;
//
//--------------------------------------
/**
 * Sort physical (tracker) tracks.
 * @param how String to set the sorting cryterium (es: "CAL" or "TRK+CAL+TOF" ecc...).
 * Sorting cryteria:
 * TRK: lower chi**2
 * CAL: lower Y spatial residual on the first calorimeter plane
 * TOF: bigger numebr of hit PMTs along the track, on S12 S21 S32 (where paddles are along the Y axis).
 * S1: (ask Emiliano)
 * S2: (ask Emiliano)
 * S3: (ask Emiliano)
 * GP: more GP hits
 * The default sorting cryterium is "TOF+CAL".
 *
 * The total number of physical tracks is always given by GetNTracks() and the it-th physical track can be retrieved by means of the methods GetTrack(int it) and GetTrack(int it, TString how).
 * 
 * New version, with handling of extended tracks and nuclei tracks. 
 */
void PamLevel2::SortTracksNew() {

  //--------------------------------------------------
  //Check if the current event has already been sorted
  //--------------------------------------------------
  if (issorted_new && lastsorted_new == GetReadEntry()) {
      return; //already done for this event
  }


//  cout << "SORT" << endl;

  //Reset the sort flags, just in case something will go wrong...
  issorted_new = false;
  lastsorted_new = -1;

  //--------------------------------------------------
  // set input variables
  //--------------------------------------------------

  TString how = howtosort;
  //Save current Object count
  Int_t ObjectNumber = TProcessID::GetObjectCount();




  TrkLevel2  * trk2 ;
  CaloLevel2 * calo2;
  ToFLevel2  * tof2  ;
  OrbitalInfo  * orb2 ;
  
  TClonesArray * trkext ;
  TClonesArray * caloext;
  TClonesArray * tofext ;
  TClonesArray * orbext ;


//   cout << "trk2_obj" << trk2_obj<< endl;
//   cout << "trk2_nuc_obj" << trk2_nuc_obj<< endl;
//   cout << " trk_ext_obj "<<trk_ext_obj<< endl;
//   cout << " trk_ext_nuc_obj "<<trk_ext_nuc_obj<< endl;

  //-----------------------------------------------------------
  // create/reset TCloneArrays to store tracks and their images
  //-----------------------------------------------------------

//  cout << " PamLevel2::SortTracksNew() --- Clear TClonesArray objects"<<endl;
  
  // main tracks from standard alg
//   if (!tsorted)
//       tsorted = new TClonesArray("PamTrack", trk2_obj->GetNTracks());
//   tsorted->Clear("C+C");//Delete();
//   // track images from standard alg
//   if (!timage)
//       timage = new TClonesArray("PamTrack", trk2_obj->GetNTracks());
//   timage->Clear("C+C");//Delete();
//   // tracks from extended algorythm
//   if(EXT && !text)
//       text = new TClonesArray("PamTrack",trk_ext_obj->GetEntries()); 
//   if(text)text->Clear("C+C");//Delete();

  if(tsorted)delete tsorted;
  if(timage) delete timage;
  if(text)   delete text;
  tsorted = new TClonesArray("PamTrack", trk2_obj->GetNTracks());
  timage = new TClonesArray("PamTrack", trk2_obj->GetNTracks());
  text = new TClonesArray("PamTrack",trk_ext_obj->GetEntries()); 

  //-----------------------------------------------------------
  // create/reset TCloneArrays to store tracks and their images
  //-----------------------------------------------------------
  if(NUC){

      
      if(tsorted_nuc)delete tsorted_nuc;
      if(timage_nuc) delete timage_nuc;
      if(text_nuc)   delete text_nuc;
      tsorted_nuc = new TClonesArray("PamTrack", trk2_nuc_obj->GetNTracks());
      timage_nuc = new TClonesArray("PamTrack", trk2_nuc_obj->GetNTracks());
      text_nuc = new TClonesArray("PamTrack",trk_ext_nuc_obj->GetEntries()); 

  // main tracks from standard alg
//       if (!tsorted_nuc)
// 	  tsorted_nuc = new TClonesArray("PamTrack", trk2_nuc_obj->GetNTracks());
//       tsorted_nuc->Clear("C+C");//Delete();
//       // track images from standard alg
//       if (!timage_nuc)
// 	  timage_nuc = new TClonesArray("PamTrack", trk2_nuc_obj->GetNTracks());
//       timage_nuc->Clear("C+C");//Delete();
//       // tracks from extended algorythm
//       if(EXT && !text_nuc)
// 	  text_nuc = new TClonesArray("PamTrack",trk_ext_nuc_obj->GetEntries()); 
//       if(text_nuc)text_nuc->Clear("C+C");//Delete();

  }
  //--------------------------------------------------
  // retrieve sorting method
  //--------------------------------------------------
  Bool_t use_TRK = how.Contains("TRK", TString::kIgnoreCase);
  Bool_t use_CAL = how.Contains("CAL", TString::kIgnoreCase);
  Bool_t use_TOF = how.Contains("TOF", TString::kIgnoreCase);
  Bool_t use_S1 = how.Contains("S1", TString::kIgnoreCase);
  Bool_t use_S2 = how.Contains("S2", TString::kIgnoreCase);
  Bool_t use_S3 = how.Contains("S3", TString::kIgnoreCase);
  Bool_t use_GP = how.Contains("GP", TString::kIgnoreCase);

  if (use_TOF) {
    use_S1 = true;
    use_S2 = true;
    use_S3 = true;
  };
  if (!CAL2 && use_CAL)
    use_CAL = false;
  if (!TOF) {
    use_TOF = false;
    use_S1 = false;
    use_S2 = false;
    use_S3 = false;
  }
  if (!GP) {
    use_GP = false;
  }

  if (!TRK2) {
    cout << "SortTracks() : without tracker does not work!!! (not yet)" << endl;
    return;
  };


  ///////////////////////////////////////////////////////////////////////////////////
  //
  //   sort tracks and fill PamTrack arrays 
  //
  ///////////////////////////////////////////////////////////////////////////////////
  for(int doit=0; doit<2; doit++){

//       cout << "doit "<<doit<<endl;


      if(doit == 0){

  	  trk2  = (TRK2 ? trk2_obj: NULL);;
	  calo2 = (CAL2 ? calo2_obj: NULL);;
	  tof2  = (TOF  ?tof2_obj: NULL);;
	  orb2  = (ORB ? orb2_obj: NULL);;
      
	  trkext = (TRK2 ? trk_ext_obj: NULL);;
	  caloext = (CAL2 ? calo_ext_obj: NULL);;
	  tofext = (TOF  ?tof_ext_obj: NULL);;
	  orbext = (ORB ? orb_ext_obj: NULL);;

      }else if (doit == 1){

	  if(!NUC)break;

      
	  trk2  = (TRK2 ?trk2_nuc_obj: NULL);;
	  calo2 = (CAL2 ? calo2_nuc_obj: NULL);;
	  tof2  = (TOF  ?tof2_nuc_obj: NULL);;
	  orb2  = (ORB ? orb2_nuc_obj: NULL);;
      
	  trkext = (TRK2 ?trk_ext_nuc_obj: NULL);;
	  caloext = (CAL2 ? calo_ext_nuc_obj: NULL);;
	  tofext = (TOF  ?tof_ext_nuc_obj: NULL);;
	  orbext = (ORB ? orb_ext_nuc_obj: NULL);;
      
      
      

      }

//       cout << "trk2" << trk2<<endl;
//       cout << "calo2" << calo2<<endl;
//       cout << "tof2" << tof2<<endl;
//       cout << "orb2" << orb2<<endl;
//       cout << "trkext" <<trkext <<endl;
//       cout << "tofext" << tofext<<endl;
//       cout << "caloext" << caloext<<endl;
//       cout << "orbext" << orbext<<endl;

      TClonesArray &ttext    = (doit==0 ? *text : *text_nuc);
      TClonesArray &ttimage  = (doit==0 ? *timage : *timage_nuc);
      TClonesArray &ttsorted = (doit==0 ? *tsorted : *tsorted_nuc);
  
//       cout << "tsorted + timage "<<doit<<endl;

      //--------------------------------------------------
      // loop over "physical" tracks sorted by the tracker
      //--------------------------------------------------
      for (Int_t i = 0; i < trk2->TrkLevel2::GetNTracks(); i++) {

	  TrkTrack *ts = 0;
	  CaloTrkVar *cs = 0;
	  ToFTrkVar *os = 0;
	  OrbitalInfoTrkVar *rs = 0;

	  // get tracker tracks
	  TrkTrack *tp          = (TRK2 ? trk2->GetTrack(i): NULL); //tracker
	  CaloTrkVar *cp        = (CAL2 ? calo2->GetCaloStoredTrack(tp->GetSeqNo()) : NULL);
	  ToFTrkVar *op         = (TOF  ? tof2->GetToFStoredTrack(tp->GetSeqNo())   : NULL);
	  OrbitalInfoTrkVar *rp = (ORB ? orb2->GetOrbitalInfoStoredTrack(tp->GetSeqNo()) : NULL);

//	  cout << "ORB="<<ORB<<" rp="<<rp<<endl;

	  TrkTrack *ti = 0; //tracker (image)
	  CaloTrkVar *ci = 0;
	  ToFTrkVar *oi = 0;
	  OrbitalInfoTrkVar *ri = 0;
	  //	cout << "trk track n. "<<i << " "<<hex<< tp <<dec<< endl;
	  // if track has an image, check image selection

	  Int_t tp_score = 0; //main track sorted by the tracker
	  Int_t ti_score = 0; //image track
	  Int_t totp_score = 0; //main track sorted by the tracker
	  Int_t toti_score = 0; //image track

	  if (tp->HasImage()) {

	      ti = (TRK2 ? trk2->GetTrackImage(i) : NULL); //tracker (image)
	      ci = (CAL2 ? calo2->GetCaloStoredTrack(ti->GetSeqNo()): NULL);
	      oi = (TOF  ? tof2->GetToFStoredTrack(ti->GetSeqNo()): NULL);
	      ri = (ORB ? orb2->GetOrbitalInfoStoredTrack(ti->GetSeqNo()): NULL);

	      //	    cout << "its image "<<i << " "<<hex<< ti <<dec<< endl;

	      //assign starting scores
	      tp_score = 0; //main track sorted by the tracker
	      ti_score = 0; //image track

	      // -----------------------------------------------------------------------------------------
	      // *****************************************************************************************
	      // -----------------------------------------------------------------------------------------
	      // calorimeter check
	      // -----------------------------------------------------------------------------------------
	      if (use_CAL && !calo2) {
		  cout << "void PamLevel2::SortTracks(): howtosort= " << how << " but CaloLevel2 not loaded !!!";
		  return;
	      };
	      if (use_CAL && !cp && ci) {
		  ti_score++;
		  toti_score++;
	      };
	      if (use_CAL && cp && !ci) {
		  tp_score++;
		  totp_score++;
	      };
	      if (use_CAL && cp && ci && true) {

		  if (cp->npresh > ci->npresh && true) {
		      tp_score++;
		      totp_score++;
		  };
		  if (cp->npresh < ci->npresh && true) {
		      ti_score++;
		      toti_score++;
		  };

		  //	cout << "CALO "<<tp_score<<ti_score<<endl;

	      };
	      // -----------------------------------------------------------------------------------------
	      // *****************************************************************************************
	      // -----------------------------------------------------------------------------------------
	      // TOF check
	      // -----------------------------------------------------------------------------------------
	      // check the number of hit pmts along the track
	      // on S12 S21 and S32, where paddles are parallel to Y axis
	      if ((use_TOF || use_S1 || use_S2 || use_S3) && !tof2) {
		  cout << "void PamLevel2::SortTracks(): howtosort= " << how << " but ToFLevel2 not loaded !!!";
		  return;
	      };
	      //
	      if ((use_TOF || use_S1 || use_S2 || use_S3) && !op && oi) {
		  ti_score++;
		  toti_score++;
	      };
	      if ((use_TOF || use_S1 || use_S2 || use_S3) && op && !oi) {
		  tp_score++;
		  totp_score++;
	      };
	      if ((use_TOF || use_S1 || use_S2 || use_S3) && op && oi) {
		  //
		  Float_t sen = 0.;
		  for (Int_t ih = 0; ih < op->npmtadc; ih++) {
		      Int_t pl = tof2->GetPlaneIndex((op->pmtadc).At(ih));
		      if (pl == 2 || pl == 3 || pl == 4 || pl == 5)
			  sen += (op->dedx).At(ih);
		  };
		  for (Int_t ih = 0; ih < oi->npmtadc; ih++) {
		      Int_t pl = tof2->GetPlaneIndex((oi->pmtadc).At(ih));
		      if (pl == 2 || pl == 3 || pl == 4 || pl == 5)
			  sen += (oi->dedx).At(ih);
		  };
		  //
		  if (sen >= sortthr && false) { // temporary disabled NUCLEI special algorithm since the new one should work for every particle (to be checked!)
		      //printf(" IS A NUCLEUS! en = %f \n",sen);
		      //
		      // is a nucleus use a different algorithm
		      //
		      Int_t nz = 6;
		      Float_t zin[6]; // << define TOF z-coordinates
		      for (Int_t ip = 0; ip < nz; ip++)
			  zin[ip] = tof2->GetZTOF(tof2->GetToFPlaneID(ip)); // << read ToF plane z-coordinates
		      Trajectory *tr = new Trajectory(nz, zin);
		      //
		      Int_t nphit_p = 0;
		      Int_t nphit_i = 0;
		      Float_t enhit_p = 0.;
		      Float_t enhit_i = 0.;
		      //
		      for (Int_t ih = 0; ih < op->npmtadc; ih++) {
			  Int_t pl = tof2->GetPlaneIndex((op->pmtadc).At(ih));
			  if (pl == 1 || pl == 2 || pl == 5) {
			      nphit_p++;
			      enhit_p += (op->dedx).At(ih);
			  };
		      };
		      //
		      tp->DoTrack2(tr);
		      //
		      if (fabs(tr->y[0] - oi->ytofpos[0]) < 2.) {
			  for (Int_t ih = 0; ih < op->npmtadc; ih++) {
			      Int_t pl = tof2->GetPlaneIndex((op->pmtadc).At(ih));
			      if (pl == 0) {
				  nphit_p++;
				  enhit_p += (op->dedx).At(ih);
			      };
			  };
		      };
		      if (fabs(tr->y[3] - oi->ytofpos[1]) < 2.) {
			  for (Int_t ih = 0; ih < op->npmtadc; ih++) {
			      Int_t pl = tof2->GetPlaneIndex((op->pmtadc).At(ih));
			      if (pl == 3) {
				  nphit_p++;
				  enhit_p += (op->dedx).At(ih);
			      };
			  };
		      };
		      if (fabs(tr->y[4] - oi->ytofpos[2]) < 2.) {
			  for (Int_t ih = 0; ih < op->npmtadc; ih++) {
			      Int_t pl = tof2->GetPlaneIndex((op->pmtadc).At(ih));
			      if (pl == 4) {
				  nphit_p++;
				  enhit_p += (op->dedx).At(ih);
			      };
			  };
		      };

		      for (Int_t ih = 0; ih < oi->npmtadc; ih++) {
			  Int_t pl = tof2->GetPlaneIndex((oi->pmtadc).At(ih));
			  if (pl == 1 || pl == 2 || pl == 5) {
			      nphit_i++;
			      enhit_i += (op->dedx).At(ih);
			  };
		      };
		      //
		      ti->DoTrack2(tr);
		      //
		      if (fabs(tr->y[0] - oi->ytofpos[0]) < 2.) {
			  for (Int_t ih = 0; ih < oi->npmtadc; ih++) {
			      Int_t pl = tof2->GetPlaneIndex((oi->pmtadc).At(ih));
			      if (pl == 0) {
				  nphit_i++;
				  enhit_i += (op->dedx).At(ih);
			      };
			  };
		      };
		      if (fabs(tr->y[3] - oi->ytofpos[1]) < 2.) {
			  for (Int_t ih = 0; ih < oi->npmtadc; ih++) {
			      Int_t pl = tof2->GetPlaneIndex((oi->pmtadc).At(ih));
			      if (pl == 3) {
				  nphit_i++;
				  enhit_i += (op->dedx).At(ih);
			      };
			  };
		      };
		      if (fabs(tr->y[4] - oi->ytofpos[2]) < 2.) {
			  for (Int_t ih = 0; ih < oi->npmtadc; ih++) {
			      Int_t pl = tof2->GetPlaneIndex((oi->pmtadc).At(ih));
			      if (pl == 4) {
				  nphit_i++;
				  enhit_i += (op->dedx).At(ih);
			      };
			  };
		      };

		      if ((use_TOF || use_S1 || use_S2 || use_S3) && (nphit_p + nphit_i) != 0 && true) {

			  //	    printf(" seqno %i nphit_p %i nphit_i %i enhit_p %f enhit_i %f \n",trk2_obj->TrkLevel2::GetSeqNo(i),nphit_p,nphit_i,enhit_p,enhit_i);
			  //	    printf(" score p %i score i %i \n",tp_score,ti_score);
			  //		  if( enhit_p > enhit_i ) tp_score++;
			  //		  if( nphit_p >= nphit_i && enhit_p > enhit_i ) tp_score++;
			  if (nphit_p > nphit_i)
			      tp_score++;
			  if (nphit_p < nphit_i)
			      ti_score++;
			  if (nphit_p == nphit_i) {
			      if (enhit_p > enhit_i)
				  tp_score++;
			      else
				  ti_score++;
			  };
			  //	    printf(" dopo score p %i score i %i \n",tp_score,ti_score);
		      };
		      delete tr;
		      //
		  }
		  else {
		      // -------------
		      // NOT a NUCLEUS
		      // -------------
		      //printf(" NOT a NUCLEUS! en = %f \n",sen);

		      Int_t nphit_p = 0;
		      Int_t nphit_i = 0;

		      /*				cout << "track: npmtadc "<< op->npmtadc << endl;
			cout << "track: npmttdc "<< op->npmttdc << endl;
			cout << "image: npmtadc "<< oi->npmtadc << endl;
			cout << "image: npmttdc "<< oi->npmttdc << endl;*/

		      // 	  for (Int_t ih=0; ih < op->npmtadc; ih++){
		      // 	    Int_t pl = tof2_obj->GetPlaneIndex( (op->pmtadc).At(ih) );
		      // 	    if(pl == 1 || pl == 2 || pl == 5)nphit_p++;
		      // 	  };

		      // 	  for (Int_t ih=0; ih < oi->npmtadc; ih++){
		      // 	    Int_t pl = tof2_obj->GetPlaneIndex( (oi->pmtadc).At(ih) );
		      // 	    if(pl == 1 || pl == 2 || pl == 5)nphit_i++;
		      // 	  };
		      // --- modified to count tdc signals (more efficient?)
		      // --- and to implement check on tdcflag
		      for (Int_t ih = 0; ih < op->npmttdc; ih++) {
			  Int_t pl = tof2->GetPlaneIndex((op->pmttdc).At(ih));
			  //	    if( (op->tdcflag).At(ih)==0 && (pl == 1 || pl == 2 || pl == 5) )nphit_p++;
			  if ((use_S1 && (pl == 0 || pl == 1)) || (use_S2 && (pl == 2 || pl == 3))
			      || (use_S3 && (pl == 4 || pl == 5))) {
			      if ((op->tdcflag).At(ih) == 0)
				  nphit_p++;
			  };
		      };

		      for (Int_t ih = 0; ih < oi->npmttdc; ih++) {
			  Int_t pl = tof2->GetPlaneIndex((oi->pmttdc).At(ih));
			  //	    if( (oi->tdcflag).At(ih)==0 && (pl == 1 || pl == 2 || pl == 5) )nphit_i++;
			  if ((use_S1 && (pl == 0 || pl == 1)) || (use_S2 && (pl == 2 || pl == 3))
			      || (use_S3 && (pl == 4 || pl == 5))) {
			      if ((oi->tdcflag).At(ih) == 0)
				  nphit_i++;
			  };
		      };

		      if ((nphit_p + nphit_i) != 0 && true) {

			  if (nphit_p != nphit_i) {
			      totp_score += nphit_p;
			      toti_score += nphit_i;
			      tp_score += nphit_p;
			      ti_score += nphit_i;
			  };
			  //	    if     ( nphit_p > nphit_i) tp_score+=nphit_p;
			  //	    else if( nphit_p < nphit_i) ti_score+=nphit_i;
			  //	    else ;//niente
		      };
		  };
		  //	cout << "TOF "<<tp_score<<ti_score<<endl;
	      };

	      //      if(tp_score == ti_score) use_TRK = true;


	      // -----------------------------------------------------------------------------------------
	      // *****************************************************************************************
	      // -----------------------------------------------------------------------------------------
	      // tracker check
	      // -----------------------------------------------------------------------------------------
	      // chi**2 difference is not always large enough to distinguish among
	      // the real track and its image.
	      // Tracker check will be applied always when calorimeter and tof information is ambiguous.
	      // *** MODIFIED ON AUGUST 2007 ***
	      if (use_TRK) {
		  // 	if(      tp->chi2 > 0 && tp->chi2 < ti->chi2 ) tp_score++ ;
		  // 	else if( ti->chi2 > 0 && ti->chi2 < tp->chi2 ) ti_score++ ;

		  // CHECK 1 : number of points along X
		  if (tp->GetNX() >= ti->GetNX()) {
		      tp_score++;
		      totp_score++;
		  };
		  if (tp->GetNX() <= ti->GetNX()) {
		      ti_score++;
		      toti_score++;
		  };
		  // CHECK 2 : number of points along Y
		  if (tp->GetNY() >= ti->GetNY()) {
		      tp_score++;
		      totp_score++;
		  };
		  if (tp->GetNY() <= ti->GetNY()) {
		      ti_score++;
		      toti_score++;
		  };

		  //	cout << "TRK "<<tp_score<<ti_score<<endl;
	      };

	      // -----------------------------------------------------------------------------------------
	      // *****************************************************************************************
	      // -----------------------------------------------------------------------------------------
	      // GPamela check
	      // -----------------------------------------------------------------------------------------

	      //---------------------------------------------------
	      // count the number of GP hits
	      //---------------------------------------------------
	      if (use_GP) {
		  int ngphits_p = 0;
		  int ngphits_i = 0;
		  float toll = 0.02; //200 micron
		  for (int ih = 0; ih < GetGPamela()->Nthspe; ih++) {
		      int ip = (Int_t) GetGPamela()->Itrpb[ih] - 1;
		      if (tp && tp->YGood(ip) && fabs(tp->ym[ip] - GetGPamela()->Yavspe[ih]) < toll && true)
			  ngphits_p++;
		      if (ti && ti->YGood(ip) && fabs(ti->ym[ip] - GetGPamela()->Yavspe[ih]) < toll && true)
			  ngphits_i++;
		  }
		  if (ngphits_p > ngphits_i && true) {
		      tp_score++;
		      totp_score++;
		  }
		  if (ngphits_p < ngphits_i && true) {
		      ti_score++;
		      toti_score++;
		  }
	      }

	      // *-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*
	      // the winner is....
	      // *-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*
	      if (tp_score > ti_score) {

	      }
	      else if (tp_score < ti_score) {

		  ts = ti;//its image!!
		  cs = ci;
		  os = oi;
		  rs = ri;
		  Int_t totis = toti_score;

		  ti = tp;//its image!!
		  ci = cp;
		  oi = op;
		  ri = rp;

		  tp = ts;//its image!!
		  cp = cs;
		  op = os;
		  rp = rs;

		  toti_score = totp_score;
		  totp_score = totis;

	      }
	      else {

		  //	cout << "Warning - track image ambiguity not solved" << endl;

	      };

	  }
	  else {
	      totp_score = 1;
	      toti_score = 0;

	      // 	    ts = tp;
	      // 	    cs = cp;
	      // 	    os = op;
	  };

	  //	cout <<" SortTracks() "<<i<<" -- "<<ts<<endl;
	  //	sorted_tracks->Add(ts);//save the track in the sorted array
	  //	sorted_tracks.Add(ts);//save the track in the sorted array
	  //	sorted_tracks.Add(tp);//save the track in the sorted array
	  //	cout << "SortTracks:: sorted_tracks->Add(it) "<<i<<" "<<ts<<endl;
	  //	cout<<"o "<<tp<<endl;
	  //	cout<<"o "<<cp<<endl;
	  //	cout<<"o "<<op<<endl;

// 	  cout <<"p:"<< tp<<"--"<<cp<<"--"<<op<<"--"<<rp<<"--"<< endl;
// 	  cout <<"i:"<< ti<<"--"<<ci<<"--"<<oi<<"--"<<ri<<"--"<< endl;



	  new (ttsorted[i]) PamTrack(tp, cp, op, rp);
	  new (ttimage[i]) PamTrack(ti, ci, oi, ri);

	  ((PamTrack*) (ttsorted[i]))->SetPScore(totp_score);
	  ((PamTrack*) (ttsorted[i]))->SetIScore(toti_score);
	  ((PamTrack*) (ttimage[i]))->SetPScore(totp_score);
	  ((PamTrack*) (ttimage[i]))->SetIScore(toti_score);
      };





//   if (tsorted->GetEntries() != trk2->GetNTracks()) {
//     cout << "void PamLevel2::SortTracks(): tsorted->GetEntries() " << tsorted->GetEntries()
//         << " != trk2->GetNTracks() = " << trk2->GetNTracks() << endl;
//     tsorted->Delete();
//     tsorted = 0;
//     timage->Delete();
//     timage = 0;
//   }


      //      cout << "text "<<orbext<<endl;


      //--------------------------------------------------
      // fill array with extended tracks (this is easy...)
      //--------------------------------------------------
      if(EXT){
	  for(int it=0; it<trkext->GetEntries(); it++){
	      
//	      if( 
// 		  it < caloext->GetEntries() &&
// 		  it < tofext->GetEntries() &&
// 		  it < orbext->GetEntries() &&
//		  true){
	      
	      ExtTrack *t = (trkext ?(ExtTrack*)(*trkext)[it]:NULL ); 
	      CaloTrkVar *c =(caloext ?(CaloTrkVar*)(*caloext)[it]:NULL ); 
	      ToFTrkVar *o = (tofext ?(ToFTrkVar*)(*tofext)[it]:NULL ); 
	      OrbitalInfoTrkVar *r =(orbext ?(OrbitalInfoTrkVar*)(*orbext)[it]:NULL ); 
//	      cout <<"ext:"<< t<<"--"<<c<<"--"<<o<<"--"<<r<<"--"<< endl;
	      
	      new (ttext[it]) PamTrack(t, c, o, r);
// 	      }else{
// 		  cout << " PamLevel2::SortTracksNew() --> ORRORE E RACCAPRICCIO!!!"<<endl;
// 		  cout << " trk  ext-tracks = "<<trkext->GetEntries()<<endl;
// 		  cout << " calo ext-tracks = "<<caloext->GetEntries()<<endl;
// 		  cout << " tof  ext-tracks = "<<tofext->GetEntries()<<endl;
// 		  cout << " orb  ext-tracks = "<<orbext->GetEntries()<<endl;
// 	      }
	  }
      }
      
//  cout <<" SortTracksNew() -- end"<<endl;


  };


  //Restore Object count
  //To save space in the table keeping track of all referenced objects
  //We reset the object count to what it was at the beginning of the event.
  TProcessID::SetObjectCount(ObjectNumber);

  //Everything went fine so the current event can be tagged as sorted
  issorted_new = true;
  lastsorted_new = GetReadEntry();

//   cout << " tsorted "<< tsorted << " "<<(tsorted ? tsorted->GetEntries() : 0)<<endl;
//   cout << " timage  "<< timage  << " "<<(timage  ? timage->GetEntries() : 0)<<endl;
//   cout << " text    "<< text    << " "<<(text    ? text->GetEntries() : 0)<<endl;


};
//--------------------------------------
//
//
//--------------------------------------
/**
 * This method overrides TrkLevel2::GetTracks(), where sorting is done by decreasing number of fit points and increasing chi^2.
 * PamLevel2::GetTracks() keeps the same track order given by TrkLevel2::GetTracks(), but checks image selection by using calorimeter and ToF tracking information.
 */

// TRefArray *PamLevel2::GetTracks(){

// //  *-*-*-*-*-*-*-*-*-*-*-*-*
//     SortTracks("+CAL+TOF");
// //  *-*-*-*-*-*-*-*-*-*-*-*-*

// //   return  sorted_tracks;
//     return &sorted_tracks;

//  };


//--------------------------------------
//
//
//--------------------------------------

/**
 * Retrieves the it-th Pamela "physical" track.
 * It override TrkLevel2::GetTrack(int it).
 * @param it Track number, ranging from 0 to GetNTracks().
 */
PamTrack *PamLevel2::GetTrackOld(int it) {

  PamTrack *track = NULL;

  //  *-*-*-*-*-*-*-*-*-*-*-*-*
  SortTracks();
  //  *-*-*-*-*-*-*-*-*-*-*-*-*
  if (!tsorted)
    return track;
//   if (!tsorted->GetEntries())
//     return track;
  if (tsorted->GetEntries()==0)
    return track;


  if (
      tsorted && 
      it >= 0 && 
      it < trk2_obj->TrkLevel2::GetNTracks() && 
      it < tsorted->GetEntries() && 
      true) {
      track = (PamTrack*)((*tsorted)[it]);
  }
  else {
    cout << "PamLevel2::GetTrackOld(int) : tracker track SeqNo " << it << " does not exist (GetNTracks() = "
        << trk2_obj->TrkLevel2::GetNTracks() << ")" << endl;
  };

  return track;

};

//PamTrack *PamLevel2::GetTrack(int it) { return GetTrack(it,trkAlg); }; 

/**
 * Retrieves the it-th Pamela "physical" track.
 * It override TrkLevel2::GetTrack(int it).
 * @param it Track number, ranging from 0 to GetNTracks().
 * @param alg Algorythm, see SetTrakingAlgorythm(char *alg) for explanation.
 */
PamTrack *PamLevel2::GetTrack(int it, const char* alg) {

    TString s(alg);
    if(!s.CompareTo("") ||!s.CompareTo("STD") )return GetTrackOld(it); //old algorythm

    

    SortTracksNew();
    // >> fill tsorted, timage and text

    if ( ( !s.Contains("EXTF", TString::kIgnoreCase) || !EXT )){ //not forced exteded-alg requested (or exteded-data missing)

	if( s.Contains("NUC")){
	    if(
		tsorted_nuc &&
		it < tsorted_nuc->GetEntries() &&                             //enough tracks found
		it >= 0 &&                                                //valid index 
		true) return (PamTrack*)((*tsorted_nuc)[it]);                 //ok return the track
	}else if( s.Contains("HE" ) ){

	    //-------------------------------- mixed NUC+STD algorythm
	    PamTrack* trnuc = NULL;
	    PamTrack* trstd = NULL;
	    if( tsorted_nuc &&
		it < tsorted_nuc->GetEntries() &&                             //enough NUC tracks found
		it >= 0 &&  		
		true)trnuc = (PamTrack*)((*tsorted_nuc)[it]);
	    if( tsorted &&
		it < tsorted->GetEntries() &&                             //enough NUC tracks found
		it >= 0 &&  		
		true)trstd = (PamTrack*)((*tsorted)[it]);

	    if(!trnuc &&  trstd)return trstd;
	    if( trnuc && !trstd)return trnuc;
	    if( trnuc && trnuc->GetExtTrack()->chi2 < trstd->GetExtTrack()->chi2 )return trnuc;
	    return trstd;

	}else{
	    if(
		tsorted &&
		it < tsorted->GetEntries() &&                             //enough tracks found
		it >= 0 &&                                                //valid index 
		true )return (PamTrack*)((*tsorted)[it]);                 //ok return the track
	}

    }
    

    /////////////////////////////////////////////////////////////////////////
    /// if requested get track from extended algorythm output
    /////////////////////////////////////////////////////////////////////////
    
    if(s.Contains("EXT", TString::kIgnoreCase) && EXT){//if exteded-alg requested
	
	if(s.Contains("NUC")){
	    if(
		text_nuc && 
		it < text_nuc->GetEntries() &&                             //enough tracks found
		it >= 0 &&                                                //valid index 
		true) return (PamTrack*)((*text_nuc)[it]);

	}else if( s.Contains("HE" ) ){

	    //-------------------------------- mixed NUC+STD algorythm
	    PamTrack* trnuc = NULL;
	    PamTrack* trstd = NULL;
	    if( text_nuc &&
		it < text_nuc->GetEntries() &&                             //enough NUC tracks found
		it >= 0 &&  		
		true)trnuc = (PamTrack*)((*text_nuc)[it]);
	    if( text &&
		it < text->GetEntries() &&                                //enough NUC tracks found
		it >= 0 &&  		
		true)trstd = (PamTrack*)((*text)[it]);

	    if(!trnuc &&  trstd)return trstd;
	    if( trnuc && !trstd)return trnuc;
	    if( trnuc && trnuc->GetExtTrack()->chi2 < trstd->GetExtTrack()->chi2 )return trnuc;
	    return trstd;

	}else{
	    if(
		text && 
		it < text->GetEntries() &&                             //enough tracks found
		it >= 0 &&                                                //valid index 
		true) return (PamTrack*)((*text)[it]);
	}

    };
    
    
    cout << "PamTrack *PamLevel2::GetTrack("<<it<<","<<alg<<") -- wrong track number or unrecognised algorithm"<<endl;
    
    return NULL;

}
;
TClonesArray *PamLevel2::GetTracks() {

  //  *-*-*-*-*-*-*-*-*-*-*-*-*
  SortTracks();
  //  *-*-*-*-*-*-*-*-*-*-*-*-*

  return tsorted;

}
;
Int_t  PamLevel2::GetNTracks(const char* alg) {


//    cout << " trk_nuc_obj->GetEntries() "<<trk_nuc_obj->GetEntries()<<" trk2_nuc_obj->GetNTracks() "<<trk2_nuc_obj->GetNTracks()<<endl;

    TString s(alg);

    if(!s.CompareTo("") || !s.CompareTo("STD"))return trk2_obj->TrkLevel2::GetNTracks(); //standard algorythm
        
    if(s.Contains("EXTF", TString::kIgnoreCase) && EXT){
	if(s.Contains("NUC", TString::kIgnoreCase) && NUC)return trk_ext_nuc_obj->GetEntries();//ok
	return trk_ext_obj->GetEntries();//ok
    }
    if( s.Contains("EXT", TString::kIgnoreCase) && EXT) {

	if(s.Contains("HE", TString::kIgnoreCase) && NUC){
	    int nnuc = (trk2_nuc_obj->TrkLevel2::GetNTracks() ?  trk2_nuc_obj->TrkLevel2::GetNTracks() :  trk_ext_nuc_obj->GetEntries() );	
	    int next = (trk2_obj->TrkLevel2::GetNTracks() ?  trk2_obj->TrkLevel2::GetNTracks() :  trk_ext_obj->GetEntries() );
 	    return max(nnuc,next);
	}
	if(s.Contains("NUC", TString::kIgnoreCase) && NUC) 
 	    return (trk2_nuc_obj->TrkLevel2::GetNTracks() ?  trk2_nuc_obj->TrkLevel2::GetNTracks() :  trk_ext_nuc_obj->GetEntries() );	

	
 	return (trk2_obj->TrkLevel2::GetNTracks() ?  trk2_obj->TrkLevel2::GetNTracks() :  trk_ext_obj->GetEntries() );
    }

    if(s.Contains("HE", TString::kIgnoreCase) && NUC )
	return max(trk2_obj->TrkLevel2::GetNTracks(), trk2_nuc_obj->TrkLevel2::GetNTracks()); 

    if(s.Contains("NUC", TString::kIgnoreCase) && NUC )
	return trk2_nuc_obj->TrkLevel2::GetNTracks(); 

    
    cout << "Int_t  PamLevel2::GetNTracks("<<alg<<") -- unrecognised algorithm"<<endl;

    return 0;

}


//--------------------------------------
//
//
//--------------------------------------
/**
 * Retrieves (if present) the image of the it-th Pamela "physical" track, sorted by the method PamLevel2::SortTracks().
 * @param it Track number, ranging from 0 to GetNTracks().
 */
PamTrack *PamLevel2::GetTrackImageOld(int it) {

  //  *-*-*-*-*-*-*-*-*-*-*-*-*
  SortTracks();
  //  *-*-*-*-*-*-*-*-*-*-*-*-*
  if (!timage)
    return 0;
  if (!timage->GetEntries())
    return 0;

  PamTrack *image = 0;

  if (it >= 0 && it < trk2_obj->TrkLevel2::GetNTracks()) {
    TClonesArray &t = *(tsorted);
    PamTrack *temp = (PamTrack*) t[it];
    if (temp->GetTrkTrack()->HasImage()) {
      TClonesArray & t = *(timage);
      image = (PamTrack*) t[it];
    }
    else {
      //	    cout <<"PamLevel2::GetTrackImage(int) : Track SeqNo "<<it<<" does not have image"<<endl;
    };
  }
  else {
    cout << "PamLevel2::GetTrackImageOld(int) : Tracker track SeqNo " << it << " does not exist (GetNTracks() = "
        << trk2_obj->TrkLevel2::GetNTracks() << ")" << endl;
  };

  return image;
}
/**
 * Retrieves (if present) the image of the it-th Pamela "physical" track, sorted by the method PamLevel2::SortTracks().
 * @param it Track number, ranging from 0 to GetNTracks().
 * @param alg Algorythm, see SetTrakingAlgorythm(char *alg) for explanation.
 */
PamTrack *PamLevel2::GetTrackImage(int it, const char* alg) {

    TString s(alg);
    if(!s.CompareTo("") || !s.CompareTo("STD"))return GetTrackImageOld(it); //old algorythm


    SortTracksNew();
    // >> fill tsorted, timage and text

    if ( ( !s.Contains("EXTF", TString::kIgnoreCase) || !EXT )){ //not forced exteded-alg requested (or exteded-data missing)

	if( s.Contains("NUC")){
	    if(
		tsorted_nuc &&
		it < tsorted_nuc->GetEntries() &&                             //enough tracks found
		it >= 0 &&                                                //valid index 
		true){
		TClonesArray &t = *(tsorted_nuc);
		PamTrack *temp = (PamTrack*) t[it];
		if (temp->GetTrkTrack()->HasImage()) {
		    return (PamTrack*)((*timage_nuc)[it]);                 //ok return the track
		}else{
		    return NULL;
		}
		
	    }
	}else{
	    if(
		tsorted &&
		it < tsorted->GetEntries() &&                             //enough tracks found
		it >= 0 &&                                                //valid index 
		true ){
		TClonesArray &t = *(tsorted);
		PamTrack *temp = (PamTrack*) t[it];
		if (temp->GetTrkTrack()->HasImage()) {		    
		    return (PamTrack*)((*timage)[it]);                 //ok return the track
		}else{
		    return NULL;
		}
	    }
	}

    } 

//    cout << "PamTrack *PamLevel2::GetTrackImage("<<it<<","<<alg<<") -- wrong track number or unrecognised algorithm"<<endl;
      
    return NULL;

}
;

//--------------------------------------
//
//
//--------------------------------------
/**
 * Get the Pamela detector trees in a single file and make them friends.
 * @param f TFile pointer
 * @param detlist String to select trees to be included
 * @return Pointer to a TTree
 */
TTree *PamLevel2::GetPamTree(TFile *f, TString detlist) {

  if (detlist.Contains("+AUTO", TString::kIgnoreCase)) {
    cout << "+AUTO" << endl;
    GetWhichTrees(f);
  };
  SetWhichTrees(detlist);

  if (pam_tree) {
    printf("WARNING: TTree *PamLevel2::GetPamTree(TFile *fl, TString detlist) -- pam_tree already exists!\n ");
    return pam_tree;
  };
  //

  cout << "TTree *PamLevel2::GetPamTree(TFile *f, TString detlist ) -- obsolte " << endl;

  //    SetWhichTrees(detlist);

  TTree *Trout = 0;

  TString fname = f->GetName();
  if (!CheckLevel2File(fname))
    return NULL;

  //    UInt_t *found=0;

  cout << "GetPamTree(TFile*,TString): detector list --> ";
  if (TRK1)
    cout << "TRK1 ";
  if (TRK2)
    cout << "TRK2 ";
  if (TRKh)
    cout << "TRKH ";
  if (CAL1)
    cout << "CAL1 ";
  if (CAL2)
    cout << "CAL2 ";
  if (TOF)
    cout << "TOF ";
  if (TRG)
    cout << "TRG ";
  if (AC)
    cout << "AC ";
  if (ND)
    cout << "ND ";
  if (S4)
    cout << "S4 ";
  if (ORB)
    cout << "ORB ";
  if (GP)
    cout << "GP ";
  cout << endl;
  if (SELLI && SELLI != 2)
    cout << ">>> Found selection-list <<<" << endl; //EMILIANO

  f->cd();

  // Tracker
  TTree *T = (TTree*) f->Get("Tracker");
  if (T && (TRK2 || TRK1 || TRKh)) {
    if (TRK2)
      T->SetBranchAddress("TrkLevel2", GetPointerTo("TrkLevel2"));
    //	else    T->SetBranchStatus("TrkLevel2",0,found);
    if (TRK2)
      cout << "Tracker      : set branch address TrkLevel2" << endl;
    if (TRK1)
      T->SetBranchAddress("TrkLevel1", GetPointerTo("TrkLevel1"));
    //	else    T->SetBranchStatus("TrkLevel1",0,found);
    if (TRK1)
      cout << "Tracker      : set branch address TrkLevel1" << endl;
    if (TRKh)
      T->SetBranchAddress("TrkHough", GetPointerTo("TrkHough"));
    //	else    T->SetBranchStatus("TrkHough",0,found);
    if (TRKh)
      cout << "Tracker      : set branch address TrkHough" << endl;
    if (!Trout)
      Trout = T;
    else
	Trout->AddFriend(T);
  }
  else {
    cout << "Tracker      : missing tree" << endl;
  };
  // Calorimeter
  TTree *C = (TTree*) f->Get("Calorimeter");
  if (C && (CAL2 || CAL1)) {
    if (CAL2)
      C->SetBranchAddress("CaloLevel2", GetPointerTo("CaloLevel2"));
    //	else    C->SetBranchStatus("CaloLevel2",0,found);
    if (CAL2)
      cout << "Calorimeter  : set branch address CaloLevel2" << endl;
    if (CAL1)
      C->SetBranchAddress("CaloLevel1", GetPointerTo("CaloLevel1"));
    //	else    C->SetBranchStatus("CaloLevel1",0,found);
    if (CAL1)
      cout << "Calorimeter  : set branch address CaloLevel1" << endl;
    if (!Trout)
      Trout = C;
    else
      Trout->AddFriend(C);
  }
  else {
    cout << "Calorimeter  : missing tree" << endl;
  };

  // ToF
  TTree *O = (TTree*) f->Get("ToF");
  if (O && TOF) {
    O->SetBranchAddress("ToFLevel2", GetPointerTo("ToFLevel2"));
    cout << "ToF          : set branch address ToFLevel2" << endl;
    if (!Trout)
      Trout = O;
    else
      Trout->AddFriend(O);
  }
  else {
    cout << "ToF         : missing tree" << endl;
  };
  // Trigger
  TTree *R = (TTree*) f->Get("Trigger");
  if (R && TRG) {
    R->SetBranchAddress("TrigLevel2", GetPointerTo("TrigLevel2"));
    cout << "Trigger      : set branch address TrigLevel2" << endl;
    if (!Trout)
      Trout = R;
    else
      Trout->AddFriend(R);
  }
  else {
    cout << "Trigger      : missing tree" << endl;
  };
  // S4
  TTree *S = (TTree*) f->Get("S4");
  if (S && S4) {
    S->SetBranchAddress("S4Level2", GetPointerTo("S4Level2"));
    cout << "S4           : set branch address S4Level2" << endl;
    if (!Trout)
      Trout = S;
    else
      Trout->AddFriend(S);
  }
  else {
    cout << "S4           : missing tree" << endl;
  };
  // Neutron Detector
  TTree *N = (TTree*) f->Get("NeutronD");
  if (N && ND) {
    N->SetBranchAddress("NDLevel2", GetPointerTo("NDLevel2"));
    cout << "NeutronD     : set branch address NDLevel2" << endl;
    if (!Trout)
      Trout = N;
    else
      Trout->AddFriend(N);
  }
  else {
    cout << "NeutronD     : missing tree" << endl;
  };
  // Anticounters
  TTree *A = (TTree*) f->Get("Anticounter");
  if (A && AC) {
    A->SetBranchAddress("AcLevel2", GetPointerTo("AcLevel2"));
    cout << "Anticounter  : set branch address AcLevel2" << endl;
    if (!Trout)
      Trout = A;
    else
      Trout->AddFriend(A);
  }
  else {
    cout << "Anticounter  : missing tree" << endl;
  };
  // Orbital Info
  TTree *B = (TTree*) f->Get("OrbitalInfo");
  if (B && ORB) {
    B->SetBranchAddress("OrbitalInfo", GetPointerTo("OrbitalInfo"));
    cout << "OrbitalInfo  : set branch address OrbitalInfo" << endl;
    if (!Trout)
      Trout = B;
    else
      Trout->AddFriend(B);
  }
  else {
    cout << "OrbitalInfo  : missing tree" << endl;
  };

  // GPamela
  TTree *G = (TTree*) f->Get("h20");
  if (G && GP) {
    if (!gp_obj)
      gp_obj = new GPamela();
    //      ------------------------------------
    //      ATTENZIONE!!!
    //      non so per quale arcano motivo,
    //      per l'albero di gpamela il branch address lo devo settare
    //      DOPO aver fatto friend
    //      FGRRRVZZZZUTSALKJMSLKJ!!!
    //      ------------------------------------
    //	gp_obj->SetBranchAddress(G); //ho dovuto fare in maniera diversa dagli altri
    //	cout << "h20          : set branch address GPamela "<<endl;
    if (!Trout)
      Trout = G;
    else
      Trout->AddFriend(G);
  }
  else {
    //	cout << "h20          : missing tree"<<endl;
  };

  TTree *L = (TTree*) f->Get("SelectionList");
  if (L && SELLI == 1) {
    cout << " TTree *PamLevel2::GetPamTree(TFile, TString) >>> SelectionList not implemented!!!!" << endl;
    sel_tree = 0;
  }
  else {
    cout << "SelectionList  : missing tree" << endl;
  };

  cout << endl << " Number of entries: " << Trout->GetEntries() << endl << endl;

  //      ------------------------------------
  //      ATTENZIONE!!!
  //      non so per quale arcano motivo,
  //      per l'albero di gpamela il branch address lo devo settare
  //      DOPO aver fatto friend
  //      FGRRRVZZZZUTSALKJMSLKJ!!!
  //      ------------------------------------
  if (G && GP) {
    gp_obj->SetBranchAddress(Trout); //ho dovuto fare in maniera diversa dagli altri
    cout << "h20          : set branch address GPamela " << endl;
  }
  else {
    cout << "h20          : missing tree" << endl;
  };

  pam_tree = (TChain*) Trout;

  return Trout;

}
//--------------------------------------
//
//
//--------------------------------------
/**
 * Get list of Level2 files.
 * @param ddir Level2 data directory.
 * @param flisttxt Name of txt file containing file list.
 * @return Pointer to a TList of TSystemFiles
 * If no input file list is given , all the Level2 files inside the directory are processed.
 */
TList* PamLevel2::GetListOfLevel2Files(TString ddir, TString flisttxt = "") {

  TString wdir = gSystem->WorkingDirectory();

  if (ddir != "") {
    cout << "Level2 data directory : " << ddir << endl;
  }
  else {
    cout << "Level2 data directory not given as input: trying to evaluate from list or taking working directory "
        << endl;
  };
  TList *contents = new TList; // create output list
  contents->SetOwner();

  // --------------------------------------
  // case 1 : input file/file-list provided
  // --------------------------------------
  if (flisttxt != "") {

    // --------------------------------------
    // a list of files given as input
    // --------------------------------------
    if (!flisttxt.EndsWith(".root")) {

      TString dir = gSystem->DirName(flisttxt);
      //	    cout << " List directory "<<dir<<endl;
      if (dir == "." || dir == "")
        flisttxt = gSystem->ConcatFileName(wdir.Data(), gSystem->BaseName(flisttxt));
      //		flisttxt = gSystem->ConcatFileName(gSystem->DirName(flisttxt),gSystem->BaseName(flisttxt));

      if (!gSystem->ChangeDirectory(ddir)) {
        cout << "Cannot change directory : " << ddir << endl;
        return 0;
      }

      cout << "Input file list : " << flisttxt << endl;
      ifstream in;
      in.open(flisttxt, ios::in); //open input file list
      if (!in.good()) {
        cout << " TList*  PamLevel2::GetListOfLevel2Files(TString, TString) --> ERROR opening the file " << endl;
        gSystem->ChangeDirectory(wdir); // back to the working directory
        return 0;
      }
      int line = 0;
      // ...........................
      // loop over file-list records
      // ...........................
      while (1) {
        TString file;
        in >> file;
        if (!in.good())
          break;
        line++;
        cout << "(*) " << file << endl;
        if (file.IsNull()) {
          cout << "-- list interrupted at line " << line << endl;
          break;
        }
        if (file.Contains("#"))
          file = file(0, file.First("#"));
        //
        // take only root files
        //
        if (file.EndsWith(".root")) {
          TString filedir;
          cout << ddir << endl;
          if ( ddir != "" ) {
            filedir = ddir; // take the input dir
          }
          else {
            gSystem->ChangeDirectory(wdir); // back to the working directory
            filedir = gSystem->DirName(file); // this will take the path if exist in the list otherwise it will return automatically the working dir
          };
          filedir.Append("/");
	  //          char *fullpath = gSystem->ConcatFileName(gSystem->DirName(filedir), gSystem->BaseName(file));
          char *fullpath = gSystem->ConcatFileName(filedir.Data(), gSystem->BaseName(file));
          contents->Add(new TSystemFile(fullpath, gSystem->DirName(fullpath)));// add file to the list
          cout << fullpath << endl;
          delete fullpath;
        }
        //	    }else{
        //		if(file.Data()!="")cout << "File: "<<file<<" ---> missing "<< endl;
        //	    };
      };
      in.close();
      // --------------------------------------
      // a single root file given as input
      // --------------------------------------
    }
    else {
      if (flisttxt.Contains("#"))
        flisttxt = flisttxt(0, flisttxt.First("#"));
      char *fullpath = gSystem->ConcatFileName(gSystem->DirName(flisttxt), gSystem->BaseName(flisttxt));
      contents->Add(new TSystemFile(fullpath, gSystem->DirName(fullpath)));// add file to the list
      delete fullpath;
    };
    // ---------------------------------------------------------------------------------
    // case 2 : no input file/file-list provided --> read all files insede the directory
    // ---------------------------------------------------------------------------------
  }
  else {

    cout << "No input file list given." << endl;
    cout << "Check for existing root files." << endl;
    //		cout << "Warking directory: "<< gSystem->WorkingDirectory()<< endl;
    if (ddir == "") {
      ddir = wdir;
      cout << "Level2 data directory : " << ddir << endl;
    };

    TSystemDirectory *datadir = new TSystemDirectory(gSystem->BaseName(ddir), ddir);
    TList *temp = datadir->GetListOfFiles();
    if (!temp)
      return 0;
    //		temp->Print();
    //		cout << "*************************************" << endl;

    TIter next(temp);
    TSystemFile *questo = 0;

    while ((questo = (TSystemFile*) next())) {
      TString name = questo-> GetName();
      if (name.EndsWith(".root")) {
        //		const char *fullpath = gSystem->FindFile(ddir,name);
        //		char *fullpath;
        //		gSystem->IsFileInIncludePath(name,&fullpath);
        char *fullpath = gSystem->ConcatFileName(gSystem->DirName(ddir), gSystem->BaseName(name));
        contents->Add(new TSystemFile(fullpath, gSystem->DirName(fullpath)));
        delete fullpath;
      };
    }
    delete temp;
    delete datadir;

  };
  gSystem->ChangeDirectory(wdir); // back to the working directory
  //	cout << endl << "Selected files:" << endl;
  //	contents->Print();
  cout << contents->GetEntries() << " files \n";
  //	cout << endl;
  //	cout << "Working directory: "<< gSystem->WorkingDirectory()<< endl;
  return contents;
}
;
//--------------------------------------
//
//
//--------------------------------------
/**
 * Get the Pamela detector chains from a list of files and make them friends.
 * @param fl Pointer to a TList of TSystemFiles
 * @param detlist String to select trees to be included
 * @return Pointer to a TChain
 */
TChain *PamLevel2::GetPamTree(TList *fl, TString detlist) {
  //
  //
  //
  if (pam_tree) {
    printf("WARNING: TChain *PamLevel2::GetPamTree(TList *fl, TString detlist) -- pam_tree already exists!\n ");
    return pam_tree;
  };
  //

  TChain *Trout = 0;

  // -------------------------------------------
  // set flags to include/exclude trees/branches
  // -------------------------------------------
  if (detlist.Contains("+AUTO", TString::kIgnoreCase)) {
    if (fl->GetEntries() > 0) {
      cout << "+AUTO" << endl;
      TFile *fprimo = new TFile(fl->At(0)->GetName());
      GetWhichTrees(fprimo);
      fprimo->Close();// AAAAARGGGGGHHHHH!!!!!!! non commentare questa riga, altrimenti si incasina il TChain
      fprimo->Delete();
    }
  };
  SetWhichTrees(detlist);

  // -------------------------------------------
  // build chains
  // -------------------------------------------
  TChain *T = 0;
  TChain *C = 0;
  TChain *O = 0;
  TChain *R = 0;
  TChain *S = 0;
  TChain *N = 0;
  TChain *A = 0;
  TChain *B = 0;
  TChain *G = 0;

  TChain *L = 0;
  TChain *P = 0;

  if (TRK2 || TRK1 || TRKh)
    T = new TChain("Tracker");
  if (CAL2 || CAL1)
    C = new TChain("Calorimeter");
  if (TOF)
    O = new TChain("ToF");
  if (TRG)
    R = new TChain("Trigger");
  if (S4)
    S = new TChain("S4");
  if (ND)
    N = new TChain("NeutronD");
  if (AC)
    A = new TChain("Anticounter");
  if (ORB)
    B = new TChain("OrbitalInfo");
  if (GP)
    G = new TChain("h20");
  if (PROC)
    P = new TChain("ProcessingInfo");
  L = new TChain("SelectionList");

  // loop over files and create chains
  TIter next(fl);
  TSystemFile *questo = 0;
  while ((questo = (TSystemFile*) next())) {
    TString name = questo->GetName();
    cout << "File: " << name << endl;
    if (CheckLevel2File(name)) {
      if (TRK2 || TRK1 || TRKh)
        T->Add(name);
      if (CAL1 || CAL2)
        C->Add(name);
      if (TOF)
        O->Add(name);
      if (TRG)
        R->Add(name);
      if (S4)
        S->Add(name);
      if (ND)
        N->Add(name);
      if (AC)
        A->Add(name);
      if (ORB)
        B->Add(name);
      if (GP)
        G->Add(name);
      if (P)
        P->Add(name);
      if (SELLI == 1)
        L->Add(name);
     };
  };

  cout << "done data-tree chains  "<<  T->GetNtrees() <<" \n";
  cout << "----------------------------------------------------" << endl;

  // -------------------------------------------
  // make friends
  // -------------------------------------------

  // Tracker
  cout << "Friends: " << endl;
  if (T && (TRK2 || TRK1 || TRKh)) {
    if (!Trout)
      Trout = T;
    else
      Trout->AddFriend("Tracker");
    //	cout << "+Tacker"<<endl;
  };
  // Calorimeter
  if (C && (CAL2 || CAL1)) {
    if (!Trout)
      Trout = C;
    else
      Trout->AddFriend("Calorimeter");
    //	cout << "+Calorimeter"<<endl;
  };
  // ToF
  if (O && TOF) {
    if (!Trout)
      Trout = O;
    else
      Trout->AddFriend("ToF");
    //	cout << "+ToF"<<endl;
  };
  // Trigger
  if (R && TRG) {
    if (!Trout)
      Trout = O;
    else
      Trout->AddFriend("Trigger");
    //	cout << "+Trigger"<<endl;
  };
  // S4
  if (S && S4) {
    if (!Trout)
      Trout = O;
    else
      Trout->AddFriend("S4");
    //	cout << "+S4"<<endl;
  };
  // Neutron Detector
  if (N && ND) {
    if (!Trout)
      Trout = O;
    else
      Trout->AddFriend("NeutronD");
    //	cout << "+NeutronD"<<endl;
  };
  // Anticounters
  if (A && AC) {
    if (!Trout)
      Trout = O;
    else
      Trout->AddFriend("Anticounter");
    //	cout << "+Anticounter"<<endl;
  };
  // Orbital Info
  if (B && ORB) {
    if (!Trout)
      Trout = O;
    else
      Trout->AddFriend("OrbitalInfo");
    //	cout << "+OrbitalInfo"<<endl;
  };
  // GPamela
  if (G && GP) {
    if (!Trout)
      Trout = G;
    else
      Trout->AddFriend("h20");
    //	cout << "+h20"<<endl;
  };

  //  =====================================
  //  SET BRANCH-ADDRESS AFTER CHAIN+FRIEND
  //  =====================================
  if( Trout->GetNtrees() )SetBranchAddress(Trout);

  //  ------------------------------------
  //  finally handle selection trees...
  //  (it is not friend of pamela tree)
  //  ------------------------------------

  cout << "----------------------------------------------------" << endl;

  // Selection List
  if (L && SELLI == 1) {
    cout << ">>> Found selection-list <<<" << endl;
    //	L->SetBranchAddress("RunEntry",&irun);
    L->SetBranchAddress("RunEntry", &irunt);//NEWNEW
    cout << "SelectionList: set branch address RunEntry" << endl;
    L->SetBranchAddress("EventEntry", &irunentry);
    cout << "SelectionList: set branch address EventEntry" << endl;
    /*    if ( L->GetBranch("L0EventEntry") ){
      hasL0EE = true;
      L->SetBranchAddress("L0EventEntry", &il0entry);
      cout << "SelectionList: set branch address L0EventEntry" << endl;
    } else {
      hasL0EE = false; // backward compatibility with old preselected files...
      }*/
    sel_tree = L;
    //   	if(!Trout)Trout=O;
    //   	else Trout->AddFriend("SelectionList");
    cout << "+SelectionList" << endl;
    cout << "----------------------------------------------------" << endl;
  }
  else {
    //	cout << "SelectionList  : missing tree"<<endl;
    if (L)
      L->Delete();
  };

  //ProcessingInfo EM
  if ( P && P->GetEntries() ){
    cout << "----------------------------------------------------" << endl;
    cout << ">>> Found ProcessingInfo <<<" << endl;
    //	L->SetBranchAddress("RunEntry",&irun);
    P->SetBranchAddress("ProcInfo", &proc_obj);//NEWNEW
    proc_tree = P;
  } else {
    //    proc_tree = new TChain("ProcessingInfo","Log of data processing");
    //    proc_tree->Branch("ProcInfo", "ProcInfo", &proc_obj);
    cout << "----------------------------------------------------" << endl;
    cout << ">>> ProcessingInfo not found, PROC set to false and continue (not 10RED files?)<<<" << endl;
    PROC = false;
  }
  //  --------------------------------------------
  //  return the pamela chain with all the friends
  //  --------------------------------------------

  pam_tree = Trout;
  return Trout;
}

//--------------------------------------
//
//
//--------------------------------------
/**
 * Set branch addresses for Pamela friend trees
 */
void PamLevel2::SetBranchAddress(TTree *t) {

//   TRK2 = TRK2 & t->GetBranchStatus("TrkLevel2");
//   TRK1 = TRK1 & t->GetBranchStatus("TrkLevel1");
//   TRKh = TRKh & t->GetBranchStatus("TrkHough");
//   CAL2 = CAL2 & t->GetBranchStatus("CaloLevel2");
//   CAL1 = CAL1 & t->GetBranchStatus("CaloLevel1");
//   TOF = TOF & t->GetBranchStatus("ToFLevel2");
//   TRG = TRG & t->GetBranchStatus("TrigLevel2");
//   S4 = S4 & t->GetBranchStatus("S4Level2");
//   ND = ND & t->GetBranchStatus("NDLevel2");
//   AC = AC & t->GetBranchStatus("AcLevel2");
//   ORB = ORB & t->GetBranchStatus("OrbitalInfo");
//   GP = GP & t->GetBranchStatus("h20");


  // Tracker
  if (TRK1) {
    t->SetBranchAddress("TrkLevel1", GetPointerTo("TrkLevel2"));
    cout << "Tracker      : set branch address TrkLevel1" << endl;
  };
  if (TRK2) {
    t->SetBranchAddress("TrkLevel2", GetPointerTo("TrkLevel1"));
    cout << "Tracker      : set branch address TrkLevel2" << endl;
    NUC = t->GetBranchStatus("TrackNuclei");
    EXT = t->GetBranchStatus("RecoveredTrack") && (NUC ? t->GetBranchStatus("RecoveredTrackNuclei"): true );	
  };
  if (TRKh) {
    t->SetBranchAddress("TrkHough", GetPointerTo("TrkHough"));
    cout << "Tracker      : set branch address TrkHough" << endl;
  };

  // Calorimeter
  if (CAL1) {
    t->SetBranchAddress("CaloLevel1", GetPointerTo("CaloLevel1"));
    cout << "Calorimeter  : set branch address CaloLevel1" << endl;
  };
  if (CAL2) {
    t->SetBranchAddress("CaloLevel2", GetPointerTo("CaloLevel2"));
    cout << "Calorimeter  : set branch address CaloLevel2" << endl;
  };

  // ToF
  if (TOF) {
    t->SetBranchAddress("ToFLevel2", GetPointerTo("ToFLevel2"));
    cout << "ToF          : set branch address ToFLevel2" << endl;
  };
  // Trigger
  if (TRG) {
    t->SetBranchAddress("TrigLevel2", GetPointerTo("TrigLevel2"));
    cout << "Trigger      : set branch address TrigLevel2" << endl;
  };
  // S4
  if (S4) {
    t->SetBranchAddress("S4Level2", GetPointerTo("S4Level2"));
    cout << "S4           : set branch address S4Level2" << endl;
  };
  // Neutron Detector
  if (ND) {
    t->SetBranchAddress("NDLevel2", GetPointerTo("NDLevel2"));
    cout << "NeutronD     : set branch address NDLevel2" << endl;
  };
  // Anticounters
  if (AC) {
    t->SetBranchAddress("AcLevel2", GetPointerTo("AcLevel2"));
    cout << "Anticounter  : set branch address AcLevel2" << endl;
  };
  // OrbitalInfo
  if (ORB) {
    t->SetBranchAddress("OrbitalInfo", GetPointerTo("OrbitalInfo"));
    cout << "OrbitalInfo  : set branch address OrbitalInfo" << endl;
  };
  // GPamela
  if (GP) {
    //	GetPointerTo("GPamela");
    if (!gp_obj)
      gp_obj = new GPamela();
    // 	gp_obj->SetBranchAddress(t); //ho dovuto fare in maniera diversa dagli altri
    // //	t->SetBranchAddress("GPamela", GetPointerTo("GPamela"));
    if (SELLI)
      t->SetBranchAddress("GPamela", GetPointerTo("GPamela"));
    else
      gp_obj->SetBranchAddress(t); //ho dovuto fare in maniera diversa dagli altri

    cout << "h20          : set branch address GPamela " << endl;
  };
  if(NUC){
      
      cout << "Found nuclei-track branches" << endl;

      if( !trk_nuc_obj )trk_nuc_obj = new TClonesArray("TrkTrack");
      if( !calo_nuc_obj)calo_nuc_obj= new TClonesArray("CaloTrkVar");
      if( !tof_nuc_obj)tof_nuc_obj= new TClonesArray("ToFTrkVar");
      if( !orb_nuc_obj)orb_nuc_obj= new TClonesArray("OrbitalInfoTrkVar");
      if (TRK2)t->                          SetBranchAddress("TrackNuclei",&trk_nuc_obj);
      if (CAL2)t->GetFriend("Calorimeter")->SetBranchAddress("TrackNuclei",&calo_nuc_obj);
      if (TOF )t->GetFriend("ToF")->        SetBranchAddress("TrackNuclei",&tof_nuc_obj);
      if (ORB )t->GetFriend("OrbitalInfo")->SetBranchAddress("TrackNuclei",&orb_nuc_obj);

      ///copy the vector content inside a "fake" object (all aother info are missing)    

      if( !trk2_nuc_obj )trk2_nuc_obj =  new TrkLevel2();
      if( !calo2_nuc_obj )calo2_nuc_obj =  new CaloLevel2();
      if( !tof2_nuc_obj )tof2_nuc_obj =  new ToFLevel2();
      if( !orb2_nuc_obj )orb2_nuc_obj =  new OrbitalInfo();
//       *(trk2_nuc_obj->GetPointerToTrackArray()) = new TClonesArray(*trk_nuc_obj);
//       *(calo2_nuc_obj->GetPointerToTrackArray()) = new TClonesArray(*calo_nuc_obj);
//       *(tof2_nuc_obj->GetPointerToTrackArray()) = new TClonesArray(*tof_nuc_obj);
//       *(orb2_nuc_obj->GetPointerToTrackArray()) = new TClonesArray(*orb_nuc_obj);

      trk2_nuc_obj->SetTrackArray(  trk_nuc_obj  );
      calo2_nuc_obj->SetTrackArray( calo_nuc_obj );
      tof2_nuc_obj->SetTrackArray(  tof_nuc_obj  );
      orb2_nuc_obj->SetTrackArray(  orb_nuc_obj  );

      
  }    

  if(EXT){
      
      cout << "Found extended tracking algorythm branches" << endl;

      if( !trk_ext_obj )trk_ext_obj = new TClonesArray("ExtTrack");
      if( !calo_ext_obj)calo_ext_obj= new TClonesArray("CaloTrkVar");
      if( !tof_ext_obj)tof_ext_obj= new TClonesArray("ToFTrkVar");
      if( !orb_ext_obj)orb_ext_obj= new TClonesArray("OrbitalInfoTrkVar");
      
      if (TRK2)t->                          SetBranchAddress("RecoveredTrack",&trk_ext_obj);
      if (CAL2)t->GetFriend("Calorimeter")->SetBranchAddress("RecoveredTrack",&calo_ext_obj);
      if (TOF )t->GetFriend("ToF")->        SetBranchAddress("RecoveredTrack",&tof_ext_obj);
      if (ORB )t->GetFriend("OrbitalInfo")->SetBranchAddress("RecoveredTrack",&orb_ext_obj);

     
      if(NUC){
	  if( !trk_ext_nuc_obj )trk_ext_nuc_obj = new TClonesArray("ExtTrack");
	  if( !calo_ext_nuc_obj)calo_ext_nuc_obj= new TClonesArray("CaloTrkVar");
	  if( !tof_ext_nuc_obj)tof_ext_nuc_obj= new TClonesArray("ToFTrkVar");
	  if( !orb_ext_nuc_obj)orb_ext_nuc_obj= new TClonesArray("OrbitalInfoTrkVar");
	  if (TRK2)t->                          SetBranchAddress("RecoveredTrackNuclei",&trk_ext_nuc_obj);
	  if (CAL2)t->GetFriend("Calorimeter")->SetBranchAddress("RecoveredTrackNuclei",&calo_ext_nuc_obj);
	  if (TOF )t->GetFriend("ToF")->        SetBranchAddress("RecoveredTrackNuclei",&tof_ext_nuc_obj);
	  if (ORB )t->GetFriend("OrbitalInfo")->SetBranchAddress("RecoveredTrackNuclei",&orb_ext_nuc_obj);
      }
  }    
}
/**
 * Set branch addresses for Pamela friend trees
 */
void PamLevel2::SetBranchAddress(TChain *t) {

  //     TRK2    = TRK2 & t->GetBranchStatus("TrkLevel2");
  //     TRK1    = TRK1 & t->GetBranchStatus("TrkLevel1");
  //     TRKh    = TRKh & t->GetBranchStatus("TrkHough");
  //     CAL1    = CAL1 & t->GetBranchStatus("CaloLevel1");
  //     CAL2    = CAL2 & t->GetBranchStatus("CaloLevel2");
  //     TOF    = TOF & t->GetBranchStatus("ToFLevel2");
  //     TRG    = TRG & t->GetBranchStatus("TrigLevel2");
  //     S4     = S4  & t->GetBranchStatus("S4Level2");
  //     ND     = ND  & t->GetBranchStatus("NDLevel2");
  //     AC     = AC  & t->GetBranchStatus("AcLevel2");
  //     ORB    = ORB & t->GetBranchStatus("OrbitalInfo");
  //    GP     = GP & t->GetBranchStatus("h20");

  // Tracker
  if (TRK2) {
    t->SetBranchAddress("TrkLevel2", GetPointerTo("TrkLevel2"));
    cout << "Tracker      : set branch address TrkLevel2" << endl;
    NUC = t->GetBranchStatus("TrackNuclei");
    EXT = t->GetBranchStatus("RecoveredTrack") && (NUC ? t->GetBranchStatus("RecoveredTrackNuclei"): true );
  };
  if (TRK1) {
    t->SetBranchAddress("TrkLevel1", GetPointerTo("TrkLevel1"));
    cout << "Tracker      : set branch address TrkLevel1" << endl;
  };
  if (TRKh) {
    t->SetBranchAddress("TrkHough", GetPointerTo("TrkHough"));
    cout << "Tracker      : set branch address TrkHough" << endl;
  };

  // Calorimeter
  if (CAL2) {
    t->SetBranchAddress("CaloLevel2", GetPointerTo("CaloLevel2"));
    cout << "Calorimeter  : set branch address CaloLevel2" << endl;    
  };
  if (CAL1) {
    t->SetBranchAddress("CaloLevel1", GetPointerTo("CaloLevel1"));
    cout << "Calorimeter  : set branch address CaloLevel1" << endl;
  };

  // ToF
  if (TOF) {
    t->SetBranchAddress("ToFLevel2", GetPointerTo("ToFLevel2"));
    cout << "ToF          : set branch address ToFLevel2" << endl;
  };
  // Trigger
  if (TRG) {
    t->SetBranchAddress("TrigLevel2", GetPointerTo("TrigLevel2"));
    cout << "Trigger      : set branch address TrigLevel2" << endl;
  };
  // S4
  if (S4) {
    t->SetBranchAddress("S4Level2", GetPointerTo("S4Level2"));
    cout << "S4           : set branch address S4Level2" << endl;
  };
  // Neutron Detector
  if (ND) {
    t->SetBranchAddress("NDLevel2", GetPointerTo("NDLevel2"));
    cout << "NeutronD     : set branch address NDLevel2" << endl;
  };
  // Anticounters
  if (AC) {
    t->SetBranchAddress("AcLevel2", GetPointerTo("AcLevel2"));
    cout << "Anticounter  : set branch address AcLevel2" << endl;
  };
  // OrbitalInfo
  if (ORB) {
    t->SetBranchAddress("OrbitalInfo", GetPointerTo("OrbitalInfo"));
    cout << "OrbitalInfo  : set branch address OrbitalInfo" << endl;
  };
  // GPamela
  //    cout <<"GP "<<GP<<endl;
  if (GP) {
    //	GetPointerTo("GPamela");
    if (!gp_obj)
      gp_obj = new GPamela();
    if (SELLI)
      t->SetBranchAddress("GPamela", GetPointerTo("GPamela"));
    else
      gp_obj->SetBranchAddress(t); //ho dovuto fare in maniera diversa dagli altri
    //	gp_obj->SetBranchAddress(t); //ho dovuto fare in maniera diversa dagli altri
    cout << "h20          : set branch address GPamela " << endl;
  };
  // SelectionList
  //     if(SELLI==1){
  // 	t->SetBranchAddress("RunEntry",&irunt);//NEWNEW
  // 	cout << "SelectionList: set branch address RunEntry"<<endl;
  // 	t->SetBranchAddress("EventEntry",&irunentry);
  // 	cout << "SelectionList: set branch address EventEntry"<<endl;

  //     }
  if(NUC){
      
      cout << "Found nuclei-track branches" << endl;

      if( !trk_nuc_obj )trk_nuc_obj = new TClonesArray("TrkTrack");
      if( !calo_nuc_obj)calo_nuc_obj= new TClonesArray("CaloTrkVar");
      if( !tof_nuc_obj)tof_nuc_obj= new TClonesArray("ToFTrkVar");
      if( !orb_nuc_obj)orb_nuc_obj= new TClonesArray("OrbitalInfoTrkVar");
      if (TRK2)t->                          SetBranchAddress("TrackNuclei",&trk_nuc_obj);
      if (CAL2)t->GetFriend("Calorimeter")->SetBranchAddress("TrackNuclei",&calo_nuc_obj);
      if (TOF )t->GetFriend("ToF")->        SetBranchAddress("TrackNuclei",&tof_nuc_obj);
      if (ORB )t->GetFriend("OrbitalInfo")->SetBranchAddress("TrackNuclei",&orb_nuc_obj);
      
      ///copy the vector content inside a "fake" object (all aother info are missing)    

      if( !trk2_nuc_obj )trk2_nuc_obj =  new TrkLevel2();
      if( !calo2_nuc_obj )calo2_nuc_obj =  new CaloLevel2();
      if( !tof2_nuc_obj )tof2_nuc_obj =  new ToFLevel2();
      if( !orb2_nuc_obj )orb2_nuc_obj =  new OrbitalInfo();

//       *(trk2_nuc_obj->GetPointerToTrackArray()) = new TClonesArray(*trk_nuc_obj);
//       *(calo2_nuc_obj->GetPointerToTrackArray()) = new TClonesArray(*calo_nuc_obj);
//       *(tof2_nuc_obj->GetPointerToTrackArray()) = new TClonesArray(*tof_nuc_obj);
//       *(orb2_nuc_obj->GetPointerToTrackArray()) = new TClonesArray(*orb_nuc_obj);
      trk2_nuc_obj->SetTrackArray(  trk_nuc_obj  );
      calo2_nuc_obj->SetTrackArray( calo_nuc_obj );
      tof2_nuc_obj->SetTrackArray(  tof_nuc_obj  );
      orb2_nuc_obj->SetTrackArray(  orb_nuc_obj  );

  }    
  if(EXT){
      
      cout << "Found extended tracking algorythm branches" << endl;

      t->SetBranchAddress("extAlgFlag",&extAlgFlag);

      if( !trk_ext_obj )trk_ext_obj = new TClonesArray("ExtTrack");
      if( !calo_ext_obj)calo_ext_obj= new TClonesArray("CaloTrkVar");
      if( !tof_ext_obj)tof_ext_obj= new TClonesArray("ToFTrkVar");
      if( !orb_ext_obj)orb_ext_obj= new TClonesArray("OrbitalInfoTrkVar");
      
      if (TRK2)t->                          SetBranchAddress("RecoveredTrack",&trk_ext_obj);
      if (CAL2)t->GetFriend("Calorimeter")->SetBranchAddress("RecoveredTrack",&calo_ext_obj);
      if (TOF )t->GetFriend("ToF")->        SetBranchAddress("RecoveredTrack",&tof_ext_obj);
      if (ORB )t->GetFriend("OrbitalInfo")->SetBranchAddress("RecoveredTrack",&orb_ext_obj);
      
      if(NUC){
	  if( !trk_ext_nuc_obj )trk_ext_nuc_obj = new TClonesArray("ExtTrack");
	  if( !calo_ext_nuc_obj)calo_ext_nuc_obj= new TClonesArray("CaloTrkVar");
	  if( !tof_ext_nuc_obj)tof_ext_nuc_obj= new TClonesArray("ToFTrkVar");
	  if( !orb_ext_nuc_obj)orb_ext_nuc_obj= new TClonesArray("OrbitalInfoTrkVar");
	  if (TRK2)t->                          SetBranchAddress("RecoveredTrackNuclei",&trk_ext_nuc_obj);
	  if (CAL2)t->GetFriend("Calorimeter")->SetBranchAddress("RecoveredTrackNuclei",&calo_ext_nuc_obj);
	  if (TOF )t->GetFriend("ToF")->        SetBranchAddress("RecoveredTrackNuclei",&tof_ext_nuc_obj);
	  if (ORB )t->GetFriend("OrbitalInfo")->SetBranchAddress("RecoveredTrackNuclei",&orb_ext_nuc_obj);
      }
  }    
  
}

/**
 * Set the tracking algorythm
 * @param alg String to choose the track. 
 * "" --> take the output of the standard tracking algorythm
 * "STD" --> take the output of the standard tracking algorythm
 * "NUC" --> take the output of the standard tracking algorythm for nuclei cluster selection
 * "EXT" --> in case the standard tracking algorythm has not found any track, take the output of the extended one
 * "EXTF" --> force the extended tracking algorythm
 * "NUCEXT" --> as "EXT", but for nuclei 
 * "NUCEXTF" --> as "EXTF", but for nuclei
 */
// void PamLevel2::SetTrackingAlgorythm(const char *alg){
 

//     TString s(alg);
//     if(s.Contains("NUC", TString::kIgnoreCase) && !NUC)
// 	cout << "Warning! NUC algorythm requested, but branches are missing"<<endl;
//     if(s.Contains("EXT", TString::kIgnoreCase) && !EXT)
// 	cout << "Warning! EXT algorythm requested, but branches are missing"<<endl;;
	    
//     trkAlg = alg;

// };
// const char* PamLevel2::GetTrackingAlgorythm(){


//     cout<<endl<<" Implemented tracking algorythm: ";
//     cout<<endl<<"  \"\" or \"STD\"  --> take the output of the standard tracking algorythm";
//     cout<<endl<<"  \"NUC\"      --> take the output of the standard tracking algorythm for nuclei cluster selection";
//     cout<<endl<<"  \"EXT\"      --> in case the standard tracking algorythm has not found any track,";
//     cout<<endl<<"                 take the output of the extended one";
//     cout<<endl<<"  \"EXTF\"     --> force the extended tracking algorythm";
//     cout<<endl<<"  \"NUCEXT\"   --> as \"EXT\", but for nuclei ";
//     cout<<endl<<"  \"NUCEXTF\"  --> as \"EXTF\", but for nuclei";

//     cout<<endl;
//     cout<<" <<Currently set algorythm>> "<<trkAlg<<endl;
//     cout<<endl;

//     return trkAlg;
// };



//--------------------------------------
//
//
//--------------------------------------
/**
 * Get the Run tree chain from a list of files.
 * @param fl Pointer to a TList of TSystemFiles
 * @return Pointer to a TChain
 */
TChain *PamLevel2::GetRunTree(TList *fl) {
  //
  //
  //
  if (run_tree) {
    printf("WARNING: TChain *PamLevel2::GetRunTree(TList *fl) -- run_tree already exists!\n ");
    return run_tree;
  };
  //


  TChain *R = new TChain("Run");

  // loop over files and create chains
  TIter next(fl);
  TSystemFile *questo = 0;
  while ((questo = (TSystemFile*) next())) {
    TString name = questo->GetName();
    //		cout << "File: "<< name << endl;
    if (CheckLevel2File(name)) {
      R->Add(name);
    };
  }

  cout << "done run chain  "<<  R->GetNtrees() <<" \n";


  if (RUN && R->GetNtrees()) {

    R->SetBranchAddress("RunInfo", GetPointerTo("RunInfo"));
    cout << "Run         : set branch address RunInfo" << endl;
    R->SetBranchAddress("SoftInfo", GetPointerTo("SoftInfo")); // Emiliano
    cout << "Software    : set branch address SoftInfo" << endl; // Emiliano

    irunoffset = new int[R->GetNtrees()];
    if (DBG) {
      cout << "----------------------------------------------------" << endl;
      cout << "irun\t | ";
      cout << "tree\t |";
      //	cout << "offset\t |";
      cout << "RUN\t";
      cout << "FRAG\t";
      cout << "NEVENTS\t";
      cout << "absolute time\t\t\t";
      cout << "on-board time";
      cout << endl;
    }
    for (Int_t ii = 0; ii < R->GetEntries(); ii++) {
      R->GetEntry(ii);
      if (DBG) {
        cout << ii << "\t | ";
        cout << R->GetTreeNumber() << "\t |";
        //	    cout << R->GetChainOffset()<< "\t |";
        cout << GetRunInfo()->ID << "\t";
        cout << GetRunInfo()->ID_RUN_FRAG << "\t";
        cout << GetRunInfo()->NEVENTS << "\t";
        cout << GetRunInfo()->RUNHEADER_TIME << " <---> " << GetRunInfo()->RUNTRAILER_TIME << "\t";
        cout << GetRunInfo()->RUNHEADER_OBT << " <---> " << GetRunInfo()->RUNTRAILER_OBT << "\t";
        cout << endl;
      }
      irunoffset[R->GetTreeNumber()] = R->GetChainOffset();
    }
    cout << "N.run = " << R->GetEntries() << endl;
    cout << "----------------------------------------------------" << endl;

  }
//   else {
//     delete R;
//     R = 0;
//   }

  run_tree = R;

  return R;

}
//--------------------------------------
//
//
//--------------------------------------
/**
 * Get the Run tree  from a file.
 * @param f Pointer to a TFile
 * @return Pointer to a TTree
 */
TTree *PamLevel2::GetRunTree(TFile *f) {
  if (run_tree) {
    printf("WARNING: TTree *PamLevel2::GetRunTree(TFile *f) -- run_tree already exists!\n ");
    return run_tree;
  };

  cout << "TTree *PamLevel2::GetRunTree(TFile *f) -- obsolte " << endl;

  TTree *T = (TTree*) f->Get("Run");

  if (T) {
    T->SetBranchAddress("RunInfo", GetPointerTo("RunInfo"));
    cout << "Run         : set branch address RunInfo" << endl;
    T->SetBranchAddress("SoftInfo", GetPointerTo("SoftInfo")); // Emiliano
    cout << "Software    : set branch address SoftInfo" << endl; // Emiliano

  }

  run_tree = (TChain*) T;

  return T;

}

Bool_t PamLevel2::UpdateRunInfo(Long64_t iev) {

  if (DBG) printf("PamLevel2::UpdateRunInfo(Long64_t) - inside\n");

  if (!run_tree) {
    cout << " Bool_t PamLevel2::UpdateRunInfo(ULong64_t iev) -- ERROR -- run tree not loaded" << endl;
    return false;
  }
  if (run_tree->GetEntries() <= 0) {
    cout << " Bool_t PamLevel2::UpdateRunInfo(ULong64_t iev) -- ERROR -- run tree is empty" << endl;
    return (false);
  }


  Int_t oldrun = irun; // store current run index

  // -----------------------------------------------------------------------
  // the first time the routine is called, set run search from the beginning
  // -----------------------------------------------------------------------

  if (irun < 0) {
    irun = 0LL;
    irunt = 0LL;
    totrunentry = 0LL;
    totrunentrymin = 0LL;
    totrunentrymax = 0LL;
    irunentry = 0LL;
    il0entry = 0LL;
    prevshift = 0;
    yprevshift = 0;
    prevabstime = 0;
    prevpktnum = 0;
    abstime = 0ULL;
    pktnum = 0;
    isFragment = false;
    run_tree->GetEntry(irun);
    if (!GetOrbitalInfo())
	cout << "PamLevel2::UpdateRunInfo(Long64_t "<<iev<<") ** WARNING ** missing OrbitalInfo    ORB="<<ORB << endl;
    if ( fUseDBinRunInfo ){
      if (gltsync)
        delete gltsync; //Emiliano
      if (!dbc || (dbc && !dbc->IsConnected()))
        SetDBConnection(); //Emiliano
      gltsync = new GL_TIMESYNC(GetRunInfo()->ID_ROOT_L0, "ID", dbc, false); //Emiliano // the "false" means not to use level0 file (not necessary here)
      if (dbc){
        dbc->Close();// Emiliano
        delete dbc;
        dbc=0;
      }
    }
  }
  // ---------------------------------------------------------------
  // retrieve OBT and absolute time of the event
  // ---------------------------------------------------------------
  Long64_t obt = 0LL; // Emiliano, Long64_t GL_TIMESYNC::DBobt(UInt_t obt) since depending on the situation OBT is lowered or boosted
  prevabstime = abstime;
  prevpktnum = pktnum;
  if (GetOrbitalInfo()) {
    abstime = GetOrbitalInfo()->absTime;
    if ( fUseDBinRunInfo ) obt = gltsync->DBobt(GetOrbitalInfo()->OBT); // Emiliano
    pktnum = GetOrbitalInfo()->pkt_num; // Emiliano
  }
  else {
    abstime = GetRunInfo()->RUNHEADER_TIME;
    if ( fUseDBinRunInfo ) obt = gltsync->DBobt(GetRunInfo()->RUNHEADER_OBT); // Emiliano
    pktnum = GetRunInfo()->RUNHEADER_PKT; // Emiliano
  }

  if (DBG){
    printf("0abstime %lld %lld pktnum %d %d obt %lld \n",abstime,prevabstime,pktnum,prevpktnum,obt);
    printf("0        rth %d %d nevents %d  \n",GetRunInfo()->RUNHEADER_TIME,GetRunInfo()->RUNTRAILER_TIME,GetRunInfo()->NEVENTS);
    printf("0        rto %d %d \n",GetRunInfo()->RUNHEADER_OBT,GetRunInfo()->RUNTRAILER_OBT);
    if ( fUseDBinRunInfo ) printf("0        rto2 %lld %lld \n",gltsync->DBobt(GetRunInfo()->RUNHEADER_OBT),gltsync->DBobt(GetRunInfo()->RUNTRAILER_OBT));
    printf("0        bo irunentry %lld prevshift %lld irun %lld  \n",irunentry,prevshift,irun);
    printf("0        min %lld iev %lld max %lld tot %lld \n",totrunentrymin,iev,totrunentrymax,totrunentry);
  }

  // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-
  // if it is a full file (not preselected)
  // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-
  if (SELLI == 0 || SELLI == 2) { // Emiliano

    // ---------------------------------------------------------------
    // increment dead and live-time counters
    // (only when reading a file not preselected)
    // ---------------------------------------------------------------
    if (SELLI == 0) {
      if (GetTrigLevel2()) {
        totdltime[0] += GetTrigLevel2()->dltime[0];
        totdltime[1] += GetTrigLevel2()->dltime[1];
      }
      totdltime[2]++;
    }

    //
    bool a = true;
    bool b = true;
    if ( fUseDBinRunInfo ){
      a = false;     
      b = false;
      if ( obt < gltsync->DBobt(GetRunInfo()->RUNHEADER_OBT) ) a = true;
      if ( obt > gltsync->DBobt(GetRunInfo()->RUNTRAILER_OBT) ) b = true;
    }
    if ( iev < totrunentrymin || iev > totrunentrymax // entry is outside run limits
         || iev == 0 // or it is the first entry
         || (!isSync && (
                         (abstime <= GetRunInfo()->RUNHEADER_TIME && a ) // or it is outside obt limits (and abstime limits for security reasons)
                         || (abstime >= GetRunInfo()->RUNTRAILER_TIME && b ) ))// or it is outside obt limits (and abstime limits for security reasons)
         ){ // check on abstime and obt needed to handle nested+DV_skipped packets
      
      // check for a new run (ma prima il primo!)
      if (DBG){
        printf("1abstime %lld %lld pktnum %d %d obt %lld \n",abstime,prevabstime,pktnum,prevpktnum,obt);
        printf("1        rth %d %d nevents %d  \n",GetRunInfo()->RUNHEADER_TIME,GetRunInfo()->RUNTRAILER_TIME,GetRunInfo()->NEVENTS);
        printf("1        rto %d %d \n",GetRunInfo()->RUNHEADER_OBT,GetRunInfo()->RUNTRAILER_OBT);
        if ( fUseDBinRunInfo ) printf("1        rto2 %lld %lld \n",gltsync->DBobt(GetRunInfo()->RUNHEADER_OBT),gltsync->DBobt(GetRunInfo()->RUNTRAILER_OBT));
        printf("1        bo irunentry %lld prevshift %lld irun %lld  \n",irunentry,prevshift,irun);
        printf("1        min %lld iev %lld max %lld tot %lld \n",totrunentrymin,iev,totrunentrymax,totrunentry);
      }
      //        printf("1abstime %lld %lld pktnum %d %d obt %lld \n",abstime,prevabstime,pktnum,prevpktnum,obt);
      //        printf("1        rth %d %d nevents %d  \n",GetRunInfo()->RUNHEADER_TIME,GetRunInfo()->RUNTRAILER_TIME,GetRunInfo()->NEVENTS);
      //        printf("1        rto %d %d \n",GetRunInfo()->RUNHEADER_OBT,GetRunInfo()->RUNTRAILER_OBT);
      //        printf("1        rto2 %lld %lld \n",gltsync->DBobt(GetRunInfo()->RUNHEADER_OBT),gltsync->DBobt(GetRunInfo()->RUNTRAILER_OBT));
      //        printf("1        bo irunentry %lld prevshift %lld irun %lld  \n",irunentry,prevshift,irun);
      //        printf("1        min %lld iev %lld max %lld tot %lld \n",totrunentrymin,iev,totrunentrymax,totrunentry);//TOGLITOGLI

      totrunentry = 0LL;
      runfirstentry = 0LL;
      for (Int_t r=0; r< run_tree->GetEntries();r++){
        // -------------------------------------------------------------------
        // save the index of the first entry of the run, relative to pam_tree,
        // and read a new run
        // -------------------------------------------------------------------
        run_tree->GetEntry(r);//update runinfo
        if ( r > 0 ){
          totrunentrymin = totrunentrymax+1;
        } else {
          totrunentrymin = 0LL;
        }
        totrunentry += GetRunInfo()->NEVENTS;
        totrunentrymax = totrunentry - 1 - prevshift; // prevshift is needed to handle nested+DV_skipped packets
        irun = r;        
        if ( fUseDBinRunInfo ){
          a = false;     
          b = false;
          if ( obt < gltsync->DBobt(GetRunInfo()->RUNHEADER_OBT) ) a = true;
          if ( obt > gltsync->DBobt(GetRunInfo()->RUNTRAILER_OBT) ) b = true;
        }
        if ( (iev >= totrunentrymin && iev <= totrunentrymax) || // entry is inside run limits
             ( !isSync && 
               ( abstime >= GetRunInfo()->RUNHEADER_TIME  && a // or it is inside obt limits (and abstime limits for security reasons)
                 && abstime <= GetRunInfo()->RUNTRAILER_TIME && b))  // or it is inside obt limits (and abstime limits for security reasons)
             ){ // check on abstime and obt needed to handle nested+DV_skipped packets
          if ( totrunentrymin > iev ){ // there is a shift (nested+DV_skipped packets)
            if ( !isSync ){
              if (DBG) printf("PamLevel2::UpdateRunInfo(Long64_t) - unconsistent iev - nevents, probable DBL0-L2 async\n");
              if (DBG) printf("PamLevel2::UpdateRunInfo(Long64_t) - totrunentrymin %lld iev %lld prevshift %lld totrunentrymax %lld \n",totrunentrymin,iev,prevshift,totrunentrymax);
              //              printf("PamLevel2::UpdateRunInfo(Long64_t) - unconsistent iev - nevents, probable DBL0-L2 async\n");
              //              printf("PamLevel2::UpdateRunInfo(Long64_t) - totrunentrymin %lld iev %lld prevshift %lld totrunentrymax %lld \n",totrunentrymin,iev,prevshift,totrunentrymax);//TOGLITOGLI
              prevshift += (totrunentrymin-iev); // add the new shift to total shift
              totrunentrymin -= (totrunentrymin-iev); // shift run position min
              totrunentrymax -= (totrunentrymin-iev); // shift run position max
              if (DBG) printf("PamLevel2::UpdateRunInfo(Long64_t) - totrunentrymin %lld iev %lld prevshift %lld totrunentrymax %lld \n",totrunentrymin,iev,prevshift,totrunentrymax);
              //              printf("PamLevel2::UpdateRunInfo(Long64_t) - totrunentrymin %lld iev %lld prevshift %lld totrunentrymax %lld \n",totrunentrymin,iev,prevshift,totrunentrymax);//TOGLITOGLI
            } else {
              printf(" PamLevel2::UpdateRunInfo(Long64_t) ERROR! sync file but unconsistent totrunetrymin %lld and iev %lld!!! \n",totrunentrymin,iev);
              cout << " OK this is a bug, write to Emiliano, Emiliano.Mocchiutti@ts.infn.it " << endl;
              cout << "\nFor bug reporting instructions, please see for example:\n";
              cout << "     <http://www.ts.infn.it/~mocchiut/bugs/bugs.html>.\n";
              cout << "  " << endl;
            }
          }
          runfirstentry = totrunentrymin; // first entry of the run in the level2
          

          //
          if ( fUseDBinRunInfo ){
            if (gltsync)
              delete gltsync; // Emiliano
            if (!dbc || (dbc && !dbc->IsConnected()))
              SetDBConnection(); //Emiliano
            gltsync = new GL_TIMESYNC(GetRunInfo()->ID_ROOT_L0, "ID", dbc, false); // Emiliano
            TrkParams::Set(GetRunInfo(), dbc);
            if (dbc){
              dbc->Close(); // Emiliano
              delete dbc;
              dbc=0;
            }          
            if (gltsync->DBobt(GetRunInfo()->RUNHEADER_OBT) > gltsync->DBobt(GetRunInfo()->RUNTRAILER_OBT)) { // Emiliano
              cout << "Bool_t PamLevel2::UpdateRunInfo(Long64_t iev) -- WARNING -- irun " << irun
                   << "  has RUNHEADER_OBT>=RUNTRAILER_OBT " << endl;
              cout
                << "                                                            (NB!! in this case some events could be assigned to a wrong run)"
                << endl;
            }
          }
          //
          if (DBG) printf(" found \n");
          //          printf(" found \n");//TOGLITOGLI
          //
          break;
        }
      } // loop over run
      
      // --------------------------------------
      // if there was no need to update the run
      // ---> exit with FALSE
      // --------------------------------------
      if (irun == oldrun){
        if (DBG) printf(" no new run \n");
        //        printf(" no new run \n");//TOGLITOGLI
        return (false);
      }      
      // --------------------------------------
      // ... otherwise
      // ---> exit with TRUE
      // --------------------------------------

      if (SELLI != 2) {
        /// decrement counters since this event belongs to a new run
        if (GetTrigLevel2()) {
          totdltime[0] -= GetTrigLevel2()->dltime[0];//live-time
          totdltime[1] -= GetTrigLevel2()->dltime[1];//dead-time
        }
        totdltime[2]--; //event counter
        if (DBG) {
          cout << endl;
          cout << "n.events     : " << totdltime[2] << endl;
          cout << "RUN LIVE-TIME: " << totdltime[0] * 0.16 << " ms" << endl;
          cout << "RUN DEAD-TIME: " << totdltime[1] * 0.01 << " ms" << endl;
        }
        // add an entry
        if (run_tree_clone && totdltime[2] > 0)
          if (run_tree_clone->GetBranch("DeadLiveTime")->GetEntries() < run_tree->GetEntries())
            run_tree_clone->GetBranch("DeadLiveTime")->Fill();
        // reset counters
        if ( totdltime[2] > 0 ){
          if (GetTrigLevel2()) {
            totdltime[0] = GetTrigLevel2()->dltime[0];//live-time
            totdltime[1] = 0; //dead-time
          }
          totdltime[2] = 1; //event counter
        }
      }

      if (DBG){
        cout << endl << " ))))) UPDATE RUN INFO (((((  @iev " << iev << " run " << GetRunInfo()->ID << " irun " << irun
             << endl;        
        printf("2abstime %lld %lld pktnum %d %d obt %lld \n",abstime,prevabstime,pktnum,prevpktnum,obt);
        printf("2        rth %d %d nevents %d  \n",GetRunInfo()->RUNHEADER_TIME,GetRunInfo()->RUNTRAILER_TIME,GetRunInfo()->NEVENTS);
        printf("2        rto %d %d \n",GetRunInfo()->RUNHEADER_OBT,GetRunInfo()->RUNTRAILER_OBT);
        if ( fUseDBinRunInfo ) printf("2        rto2 %lld %lld \n",gltsync->DBobt(GetRunInfo()->RUNHEADER_OBT),gltsync->DBobt(GetRunInfo()->RUNTRAILER_OBT));
        printf("2        bo irunentry %lld prevshift %lld irun %lld  \n",irunentry,prevshift,irun);
        printf("2        min %lld iev %lld max %lld tot %lld \n",totrunentrymin,iev,totrunentrymax,totrunentry);
      }
      //        printf("2abstime %lld %lld pktnum %d %d obt %lld \n",abstime,prevabstime,pktnum,prevpktnum,obt);
      //        printf("2        rth %d %d nevents %d  \n",GetRunInfo()->RUNHEADER_TIME,GetRunInfo()->RUNTRAILER_TIME,GetRunInfo()->NEVENTS);
      //        printf("2        rto %d %d \n",GetRunInfo()->RUNHEADER_OBT,GetRunInfo()->RUNTRAILER_OBT);
      //        printf("2        rto2 %lld %lld \n",gltsync->DBobt(GetRunInfo()->RUNHEADER_OBT),gltsync->DBobt(GetRunInfo()->RUNTRAILER_OBT));
      //        printf("2        bo irunentry %lld prevshift %lld irun %lld  \n",irunentry,prevshift,irun);
      //        printf("2        min %lld iev %lld max %lld tot %lld \n",totrunentrymin,iev,totrunentrymax,totrunentry);//TOGLITOGLI

      return (true);
    } // need for run upgrade
    if (DBG) printf("return false\n");
    return (false);
  }// SELLI = 0 SELLI = 2 
  
  // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-
  // if it is a preselected file (there is SelectionList)
  // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-
  // irun  = run entry relative to the chain
  // irunt = run entry relative to the tree
  if (SELLI == 1) {
    sel_tree->GetEntry(iev);// read irunt from SelectionList
    irun = irunt + irunoffset[sel_tree->GetTreeNumber()];//NEWNEW
    if (irun != oldrun) {
      if (irun < run_tree->GetEntries())
        run_tree->GetEntry(irun);
      // check if the time is ok (with merged files it is not...)
      // if not loop over run and look for the proper entry
      bool SECONDO_GIRO = false;
      //	    Long64_t irun_start   = irun;
      int offset_start = irunoffset[sel_tree->GetTreeNumber()];
      while (((!(abstime >= GetRunInfo()->RUNHEADER_TIME && // check on absolute time (s)
          abstime <= GetRunInfo()->RUNTRAILER_TIME)
      // 			||
      // 			!(obt >= GetRunInfo()->RUNHEADER_OBT &&         // additional check on OBT (ms)
      // 			  obt <= GetRunInfo()->RUNTRAILER_OBT)
      ) || GetRunInfo()->NEVENTS == 0)
      //		&& irun < run_tree->GetEntries()
      ) {

        if (DBG) {
          cout << " (test) ";
          cout << " tree " << sel_tree->GetTreeNumber();
          cout << " irunt " << irunt;
          cout << " offset " << irunoffset[sel_tree->GetTreeNumber()];
          cout << " abs " << abstime;
          cout << " >> " << GetRunInfo()->RUNHEADER_TIME << " " << GetRunInfo()->RUNTRAILER_TIME;
          cout << " obt " << obt;
          cout << " >> " << GetRunInfo()->RUNHEADER_OBT << " " << GetRunInfo()->RUNTRAILER_OBT;
          cout << " *** JUMP RUN *** irun " << irun;
          cout << endl;
        }
        //		irun++;
        irunoffset[sel_tree->GetTreeNumber()]++;
        irun = irunt + irunoffset[sel_tree->GetTreeNumber()];//NEWNEW
        if (irun == run_tree->GetEntries() && SECONDO_GIRO) {
          //		if(irun == irun_start ){
          cout << " ...grrrvzzkhhhajsdkj!!!! " << endl;
          irunoffset[sel_tree->GetTreeNumber()] = offset_start;
          return false;
        }
        if (irun >= run_tree->GetEntries() || irun < 0) {
          cout << "irun = " << irun << " >>  search from the beginning... <<" << endl;
          SECONDO_GIRO = true;
          irun = 0;
          irunoffset[sel_tree->GetTreeNumber()] = -irunt;
        }
        run_tree->GetEntry(irun);
      }

      if (DBG) {
        cout << " (test) ";
        cout << " tree " << sel_tree->GetTreeNumber();
        cout << " irunt " << irunt;
        cout << " offset " << irunoffset[sel_tree->GetTreeNumber()];
        cout << " abs " << abstime;
        cout << " >> " << GetRunInfo()->RUNHEADER_TIME << " " << GetRunInfo()->RUNTRAILER_TIME;
        cout << " obt " << obt;
        cout << " >> " << GetRunInfo()->RUNHEADER_OBT << " " << GetRunInfo()->RUNTRAILER_OBT;
      }
      if (DBG)
        cout << endl;
      if (DBG)
        cout << endl << " ))))) UPDATE RUN INFO (((((  @iev " << iev << " run " << GetRunInfo()->ID << " (run-entry "
            << irun << ")" << endl;
      // ----------------------------------------------------
      // update the tracker parameters
      // (non ho trovato nessun altro modo sicuro di farlo...)
      // ----------------------------------------------------
      if ( fUseDBinRunInfo ){
        if (!dbc || (dbc && !dbc->IsConnected()))
          SetDBConnection();
        TrkParams::Set(GetRunInfo(), dbc);
        if (dbc){
          dbc->Close();
          delete dbc;
          dbc=0;
        }
      }
      //	    cout << endl;
      prevshift = 0;
      yprevshift = 0;
      return true;
    }
    return false;
  }

  return false;
  //
}

/**
 * Update the runinfo informations (to be used to have Run infos event by event basis)
 * @param run Pointer to the chain/tree which contains run infos
 * @return true if a new run has been read, false if it is still the same run
 */
Bool_t PamLevel2::UpdateRunInfo(TChain *run, Long64_t iev) {
  return (UpdateRunInfo(iev));
}

/**
 * Update the runinfo informations (to be used to have Run infos event by event basis)
 * @param run Pointer to the chain/tree which contains run infos
 * @return true if a new run has been read, false if it is still the same run
 */
Bool_t PamLevel2::UpdateRunInfo(TTree *run, Long64_t iev) {
  return (UpdateRunInfo((TChain*) run, iev));
}


//--------------------------------------
//
//
//--------------------------------------
/**
 * Set which trees shoul be analysed
 * @param detlist TString containing the sequence of trees required
 */
void PamLevel2::SetWhichTrees(TString detlist) {

  //    if(detlist.IsNull() || detlist.Contains("+ALL", TString::kIgnoreCase)){
  if (detlist.Contains("+ALL", TString::kIgnoreCase)) {

    cout << " ======================================================== " << endl;
    cout << "                       (( WARNING ))                      " << endl;
    cout << " The meaning of the option +ALL has changed!!             " << endl;
    cout << " Now it includes really all (level0+level1+level2+gpamela)" << endl;
    cout << " and the file is discarded if it does not contain         " << endl;
    cout << " all trees or  if level0 files are not available!!        " << endl;
    cout << " ======================================================== " << endl;

    CAL0 = true;
    CAL1 = true;
    CAL2 = true;
    TRK2 = true;
    TRK1 = true;
    TRKh = true;
    TRK0 = true;
    TRG = true;
    TOF = true;
    TOF0 = true;
    S4 = true;
    ND = true;
    AC = true;
    ORB = true;
    GP = true;
  }
  else if (detlist.Contains("-ALL", TString::kIgnoreCase)) {
    CAL0 = false;
    CAL1 = false;
    CAL2 = false;
    TRK2 = false;
    TRK1 = false;
    TRKh = false;
    TRK0 = false;
    TRG = false;
    TOF = false;
    TOF0 = false;
    S4 = false;
    ND = false;
    AC = false;
    ORB = false;
    GP = false;
  };

  //  -------------------------------------------------------------------------
  if (detlist.Contains("CAL1", TString::kIgnoreCase)) {
    if (detlist.Contains("-CAL1", TString::kIgnoreCase))
      CAL1 = false;
    if (detlist.Contains("+CAL1", TString::kIgnoreCase))
      CAL1 = true;
  };

  if (detlist.Contains("CAL0", TString::kIgnoreCase)) {
    if (detlist.Contains("-CAL0", TString::kIgnoreCase))
      CAL0 = false;
    if (detlist.Contains("+CAL0", TString::kIgnoreCase))
      CAL0 = true;
  };

  if (detlist.Contains("CAL2", TString::kIgnoreCase)) {
    if (detlist.Contains("-CAL2", TString::kIgnoreCase))
      CAL2 = false;
    if (detlist.Contains("+CAL2", TString::kIgnoreCase))
      CAL2 = true;
  };

  if (detlist.Contains("+CAL", TString::kIgnoreCase) && !CAL1 && !CAL2)
    CAL2 = true;
  if (detlist.Contains("-CAL", TString::kIgnoreCase) && CAL1 && CAL2) {
    CAL2 = false;
    CAL1 = false;
  }
  //  -------------------------------------------------------------------------
  if (detlist.Contains("TRK0", TString::kIgnoreCase)) {
    if (detlist.Contains("-TRK0", TString::kIgnoreCase))
      TRK0 = false;
    if (detlist.Contains("+TRK0", TString::kIgnoreCase))
      TRK0 = true;
  };

  if (detlist.Contains("TRK1", TString::kIgnoreCase)) {
    if (detlist.Contains("-TRK1", TString::kIgnoreCase))
      TRK1 = false;
    if (detlist.Contains("+TRK1", TString::kIgnoreCase))
      TRK1 = true;
  };

  if (detlist.Contains("TRK2", TString::kIgnoreCase)) {
    if (detlist.Contains("-TRK2", TString::kIgnoreCase))
      TRK2 = false;
    if (detlist.Contains("+TRK2", TString::kIgnoreCase))
      TRK2 = true;
  };

  if (detlist.Contains("TRKh", TString::kIgnoreCase)) {
    if (detlist.Contains("-TRKh", TString::kIgnoreCase))
      TRKh = false;
    if (detlist.Contains("+TRKh", TString::kIgnoreCase))
      TRKh = true;
  };

  if (detlist.Contains("+TRK", TString::kIgnoreCase) && !TRK1 && !TRK2 && !TRKh)
    TRK2 = true;
  if (detlist.Contains("-TRK", TString::kIgnoreCase) && TRK1 && TRK2 && TRKh) {
    TRK2 = false;
    TRK1 = false;
    TRKh = false;
  }
  //  -------------------------------------------------------------------------

  if (detlist.Contains("-TRG", TString::kIgnoreCase))
    TRG = false;
  else if (detlist.Contains("+TRG", TString::kIgnoreCase))
    TRG = true;

  if (detlist.Contains("-TOF", TString::kIgnoreCase))
    TOF = false;
  else if (detlist.Contains("+TOF", TString::kIgnoreCase))
    TOF = true;

  if (detlist.Contains("-TOF0", TString::kIgnoreCase))
    TOF0 = false;
  else if (detlist.Contains("+TOF0", TString::kIgnoreCase))
    TOF0 = true;

  if (detlist.Contains("-S4", TString::kIgnoreCase))
    S4 = false;
  else if (detlist.Contains("+S4", TString::kIgnoreCase))
    S4 = true;

  if (detlist.Contains("-ND", TString::kIgnoreCase))
    ND = false;
  else if (detlist.Contains("+ND", TString::kIgnoreCase))
    ND = true;

  if (detlist.Contains("-AC", TString::kIgnoreCase))
    AC = false;
  else if (detlist.Contains("+AC", TString::kIgnoreCase))
    AC = true;

  if (detlist.Contains("-ORB", TString::kIgnoreCase))
    ORB = false;
  else if (detlist.Contains("+ORB", TString::kIgnoreCase))
    ORB = true;

  if (detlist.Contains("-GP", TString::kIgnoreCase))
    GP = false;
  else if (detlist.Contains("+GP", TString::kIgnoreCase))
    GP = true;

  cout << "tree/branch list from input --> ";
  if (TRK0)
    cout << "TRK0 ";
  if (TRK1)
    cout << "TRK1 ";
  if (TRK2)
    cout << "TRK2 ";
  if (TRKh)
    cout << "TRKH ";
  if (CAL0)
    cout << "CAL0 ";
  if (CAL1)
    cout << "CAL1 ";
  if (CAL2)
    cout << "CAL2 ";
  if (TOF)
    cout << "TOF ";
  if (TRG)
    cout << "TRG ";
  if (AC)
    cout << "AC ";
  if (ND)
    cout << "ND ";
  if (S4)
    cout << "S4 ";
  if (ORB)
    cout << "ORB ";
  if (GP)
    cout << "GP ";
  cout << endl;
  //     cout<< "Set detector list --> ";
  //     if(TRK1)cout<<"TRK1 ";
  //     if(TRK2)cout<<"TRK2 ";
  //     if(TRKh)cout<<"TRKH ";
  //     if(CAL1)cout<<"CAL1 ";
  //     if(CAL2)cout<<"CAL2 ";
  //     if(TOF0)cout<<"TOF0 ";
  //     if(TOF)cout<<"TOF ";
  //     if(TRG)cout<<"TRG ";
  //     if(AC)cout<<"AC ";
  //     if(ND)cout<<"ND ";
  //     if(S4)cout<<"S4 ";
  //     if(ORB)cout<<"ORB ";
  //     cout << endl;

}
;

/**
 * Set tree/branch detector flags from the content of a tree
 */
void PamLevel2::GetWhichTrees(TFile* f) {

  //    cout << "void  PamLevel2::GetWhichTrees(TFile* f) --- WARNING!! --- ...potrebbe non funzionare "<<endl;
  // -----------
  // reset flags
  // -----------
  CAL1 = false;
  CAL2 = false;
  TRK2 = false;
  TRK1 = false;
  TRKh = false;
  TRG = false;
  TOF = false;
  S4 = false;
  ND = false;
  AC = false;
  ORB = false;
  GP = false;

  RUN = false;

  //    cout << "Checking file: "<<f->GetName()<<endl;
  if (!f || f->IsZombie()) {
    cout << "File: " << f->GetName() << " Non valid root file" << endl;
    fDiscarded = true;
    return;
  }

  TList *lk = f->GetListOfKeys();
  if (!lk)
    return;
  TIter next(lk);
  TKey *key = 0;

  Int_t nev = 0;

  while ((key = (TKey*) next())) {

    if (!strcmp(key->GetName(), "Run"))
      RUN = true;

    //=========================================================
    if (!strcmp(key->GetName(), "Trigger")) {
      TRG = true;
      Int_t nevt = ((TTree*) f->Get("Trigger"))->GetEntries();
      if (nev && nevt != nev) {
        cout << "File: " << f->GetName() << " Trigger tree has " << nevt << " events instead of " << nev << endl;
        TRG = false;
      }
      else
        nev = nevt;
    }
    //=========================================================
    if (!strcmp(key->GetName(), "ToF")) {
      TOF = true;
      Int_t nevt = ((TTree*) f->Get("ToF"))->GetEntries();
      if (nev && nevt != nev) {
        cout << "File: " << f->GetName() << "     ToF tree has " << nevt << " events instead of " << nev << endl;
        TOF = false;
      }
      else
        nev = nevt;
    }
    //=========================================================
    if (!strcmp(key->GetName(), "S4")) {
      S4 = true;
      Int_t nevt = ((TTree*) f->Get("S4"))->GetEntries();
      if (nev && nevt != nev) {
        cout << "File: " << f->GetName() << "      S4 tree has " << nevt << " events instead of " << nev << endl;
        S4 = false;
      }
      else
        nev = nevt;
    }
    //=========================================================

    if (!strcmp(key->GetName(), "NeutronD")) {
      ND = true;
      Int_t nevt = ((TTree*) f->Get("NeutronD"))->GetEntries();
      if (nev && nevt != nev) {
        cout << "File: " << f->GetName() << "NeutronD tree has " << nevt << " events instead of " << nev << endl;
        ND = false;
      }
      else
        nev = nevt;
    }
    //=========================================================
    if (!strcmp(key->GetName(), "Anticounter")) {
      AC = true;
      Int_t nevt = ((TTree*) f->Get("Anticounter"))->GetEntries();
      if (nev && nevt != nev) {
        cout << "File: " << f->GetName() << " Anticounter tree has " << nevt << " events instead of " << nev << endl;
        AC = false;
      }
      else
        nev = nevt;
    }
    //=========================================================
    if (!strcmp(key->GetName(), "OrbitalInfo")) {
      ORB = true;
      Int_t nevt = ((TTree*) f->Get("OrbitalInfo"))->GetEntries();
      if (nev && nevt != nev) {
        cout << "File: " << f->GetName() << " OrbitalInfo tree has " << nevt << " events instead of " << nev << endl;
        ORB = false;
      }
      else
        nev = nevt;
    }
    //=========================================================
    if (!strcmp(key->GetName(), "Tracker")) {
      TTree *T = (TTree*) f->Get("Tracker");
      for (Int_t i = 0; i < T->GetListOfBranches()->GetEntries(); i++) {
        TString name = T->GetListOfBranches()->At(i)->GetName();
        if (!name.CompareTo("TrkLevel1"))
          TRK1 = true;
        if (!name.CompareTo("TrkLevel2"))
          TRK2 = true;
        if (!name.CompareTo("TrkHough"))
          TRKh = true;
      };
      Int_t nevt = T->GetEntries();
      if (nev && nevt != nev) {
        cout << "File: " << f->GetName() << " Tracker tree has " << nevt << " events instead of " << nev << endl;
        TRK1 = false;
        TRK2 = false;
        TRKh = false;
      }
      else
        nev = nevt;
      //	    T->Delete();
    };
    //=========================================================
    if (!strcmp(key->GetName(), "Calorimeter")) {
      TTree *T = (TTree*) f->Get("Calorimeter");
      for (Int_t i = 0; i < T->GetListOfBranches()->GetEntries(); i++) {
        TString name = T->GetListOfBranches()->At(i)->GetName();
        if (!name.CompareTo("CaloLevel1"))
          CAL1 = true;
        if (!name.CompareTo("CaloLevel2"))
          CAL2 = true;
      };
      Int_t nevt = T->GetEntries();
      if (nev && nevt != nev) {
        cout << "File: " << f->GetName() << "  Calorimeter tree has " << nevt << " events instead of " << nev << endl;
        CAL1 = false;
        CAL2 = false;
      }
      else
        nev = nevt;
      //	    T->Delete();
    };
    //=========================================================
    if (!strcmp(key->GetName(), "h20")) {
      GP = true;
      Int_t nevt = ((TTree*) f->Get("h20"))->GetEntries();
      if (nev && nevt != nev) {
        cout << "File: " << f->GetName() << " h20 tree has " << nevt << " events instead of " << nev << endl;
        GP = false;
      }
      else
        nev = nevt;
    }

  };

  //    delete lk;

  cout << "tree/branch list from file  --> ";
  if (TRK1)
    cout << "TRK1 ";
  if (TRK2)
    cout << "TRK2 ";
  if (TRKh)
    cout << "TRKH ";
  if (CAL1)
    cout << "CAL1 ";
  if (CAL2)
    cout << "CAL2 ";
  if (TOF)
    cout << "TOF ";
  if (TRG)
    cout << "TRG ";
  if (AC)
    cout << "AC ";
  if (ND)
    cout << "ND ";
  if (S4)
    cout << "S4 ";
  if (ORB)
    cout << "ORB ";
  if (GP)
    cout << "GP ";
  cout << endl;

  return;

}
;

//--------------------------------------
//
//
//--------------------------------------
/**
 * Check if a file contains selected Pamela Level2 trees.
 * @param name File name
 * @return true if the file is ok.
 */
Bool_t PamLevel2::CheckLevel2File(TString name) {

  Bool_t CAL1__ok = false;
  Bool_t CAL2__ok = false;
  Bool_t TRK2__ok = false;
  Bool_t TRK1__ok = false;
  Bool_t TRKh__ok = false;
  Bool_t TRG__ok = false;
  Bool_t TOF__ok = false;
  Bool_t S4__ok = false;
  Bool_t ND__ok = false;
  Bool_t AC__ok = false;
  Bool_t ORB__ok = false;
  Bool_t GP__ok = false;

  Bool_t RUN__ok = false;

  Bool_t SELLI__ok = false;

  //    cout << "Checking file: "<<name<<endl;
  TFile *f = new TFile(name.Data());
  if (!f || f->IsZombie()) {
    cout << "File: " << f->GetName() << " discarded ---- Non valid root file" << endl;
    fDiscarded = true;
    return false;
  }
  //    cout << "Get list of keys: "<<f<<endl;
  TList *lk = f->GetListOfKeys();
  //    lk->Print();
  TIter next(lk);
  TKey *key = 0;

  Int_t nev = 0;

  while ((key = (TKey*) next())) {

    // 	cout << key->GetName() << endl;
    // 	cout << key->GetName() << ""<<key->GetClassName()<<endl;
    //		cout << " Get tree: " << f->Get(key->GetName())<<endl;
    // 	nev_previous = nev;
    // 	cout << " n.entries  "<< nev <<endl;
    // 	if( key->GetClassName()=="TTree" && nev_previous && nev != nev_previous ){
    // 	    nev = ((TTree*)f->Get(key->GetName()))->GetEntries();
    // 	    cout << "File: "<< f->GetName() <<" discarded ---- "<< key->GetName() << " tree: n.entries does not match "<<nev<<" "<<nev_previous<< endl;
    // 	    return false;
    // 	};

    //=========================================================
    // check if the file


    if (!strcmp(key->GetName(), "Run"))
      RUN__ok = true;

    //=========================================================
    if (!strcmp(key->GetName(), "SelectionList")) {
      SELLI__ok = true;
      if (SELLI == 1) {
        Int_t nevt = ((TTree*) f->Get("SelectionList"))->GetEntries();
        if (nev && nevt != nev) {
          cout << "File: " << f->GetName() << " discarded ---- SelectionList tree has " << nevt
              << " events instead of " << nev << endl;
          fDiscarded = true;
          return false;
        }
        nev = nevt;
      }
    }

    //=========================================================
    if (!strcmp(key->GetName(), "Trigger")) {
      TRG__ok = true;
      if (TRG) {
        Int_t nevt = ((TTree*) f->Get("Trigger"))->GetEntries();
        if (nev && nevt != nev) {
          cout << "File: " << f->GetName() << " discarded ---- Trigger tree has " << nevt << " events instead of "
              << nev << endl;
          fDiscarded = true;
          return false;
        }
        nev = nevt;
      }
    }
    //=========================================================
    if (!strcmp(key->GetName(), "ToF")) {
      TOF__ok = true;
      if (TOF) {
        Int_t nevt = ((TTree*) f->Get("ToF"))->GetEntries();
        if (nev && nevt != nev) {
          cout << "File: " << f->GetName() << " discarded ---- ToF tree has " << nevt << " events instead of " << nev
              << endl;
          fDiscarded = true;
          return false;
        }
        nev = nevt;
      }
    }
    //=========================================================
    if (!strcmp(key->GetName(), "S4")) {
      S4__ok = true;
      if (S4) {
        Int_t nevt = ((TTree*) f->Get("S4"))->GetEntries();
        if (nev && nevt != nev) {
          cout << "File: " << f->GetName() << " discarded ---- S4 tree has " << nevt << " events instead of " << nev
              << endl;
          fDiscarded = true;
          return false;
        }
        nev = nevt;
      }
    }
    //=========================================================

    if (!strcmp(key->GetName(), "NeutronD")) {
      ND__ok = true;
      if (ND) {
        Int_t nevt = ((TTree*) f->Get("NeutronD"))->GetEntries();
        if (nev && nevt != nev) {
          cout << "File: " << f->GetName() << " discarded ---- NeutronD tree has " << nevt << " events instead of "
              << nev << endl;
          fDiscarded = true;
          return false;
        }
        nev = nevt;
      }
    }
    //=========================================================
    if (!strcmp(key->GetName(), "Anticounter")) {
      AC__ok = true;
      if (AC) {
        Int_t nevt = ((TTree*) f->Get("Anticounter"))->GetEntries();
        if (nev && nevt != nev) {
          cout << "File: " << f->GetName() << " discarded ---- Anticounter tree has " << nevt << " events instead of "
              << nev << endl;
          fDiscarded = true;
          return false;
        }
        nev = nevt;
      }
    }
    //=========================================================
    if (!strcmp(key->GetName(), "OrbitalInfo")) {
      ORB__ok = true;
      if (ORB) {
        Int_t nevt = ((TTree*) f->Get("OrbitalInfo"))->GetEntries();
        if (nev && nevt != nev) {
          cout << "File: " << f->GetName() << " discarded ---- OrbitalInfo tree has " << nevt << " events instead of "
              << nev << endl;
          fDiscarded = true;
          return false;
        }
        nev = nevt;
      }
    }
    //=========================================================
    if (!strcmp(key->GetName(), "Tracker")) {
      TTree *T = (TTree*) f->Get("Tracker");
      if (TRK1 || TRK2 || TRKh) {
        Int_t nevt = T->GetEntries();
        if (nev && nevt != nev) {
          cout << "File: " << f->GetName() << " discarded ---- Tracker tree has " << nevt << " events instead of "
              << nev << endl;
          fDiscarded = true;
          return false;
        }
        nev = nevt;
      }
      for (Int_t i = 0; i < T->GetListOfBranches()->GetEntries(); i++) {
        TString name = T->GetListOfBranches()->At(i)->GetName();
        if (!name.CompareTo("TrkLevel1"))
          TRK1__ok = true;
        if (!name.CompareTo("TrkLevel2"))
          TRK2__ok = true;
        if (!name.CompareTo("TrkHough"))
          TRKh__ok = true;
      };
      T->Delete();
    };
    //=========================================================
    if (!strcmp(key->GetName(), "Calorimeter")) {
      TTree *T = (TTree*) f->Get("Calorimeter");
      if (CAL1 || CAL2) {
        Int_t nevt = T->GetEntries();
        if (nev && nevt != nev) {
          cout << "File: " << f->GetName() << " discarded ---- Calorimeter tree has " << nevt << " events instead of "
              << nev << endl;
          fDiscarded = true;
          return false;
        }
        nev = nevt;
      }
      for (Int_t i = 0; i < T->GetListOfBranches()->GetEntries(); i++) {
        TString name = T->GetListOfBranches()->At(i)->GetName();
        if (!name.CompareTo("CaloLevel1"))
          CAL1__ok = true;
        if (!name.CompareTo("CaloLevel2"))
          CAL2__ok = true;
      };
      T->Delete();
    };
    //=========================================================
    if (!strcmp(key->GetName(), "h20")) {
      ISGP = true;
      GP__ok = true;
      if (GP) {
        Int_t nevt = ((TTree*) f->Get("h20"))->GetEntries();
        if (nev && nevt != nev) {
          cout << "File: " << f->GetName() << " discarded ---- h20 tree has " << nevt << " events instead of " << nev
              << endl;
          fDiscarded = true;
          return false;
        }
        nev = nevt;
      }
    }

  };

  if (SELLI == -1)
    SELLI = (Int_t) SELLI__ok;
  if (SELLI == 0 && SELLI__ok) {
    cout << "File: " << f->GetName() << " discarded ---- found SelectionList (it is not a full-event file)" << endl;
    fDiscarded = true;
    return false;
  }
  if (SELLI == 1 && !SELLI__ok) {
    cout << "File: " << f->GetName() << " discarded ---- SelectionList missing" << endl;
    fDiscarded = true;
    return false;
  }

  //    cout << "SELLI "<<SELLI<<endl;

  //     cout<< "CheckLevel2File(TString): detector list --> ";
  //     if(TRK1__ok)cout<<"TRK1 ";
  //     if(TRK2__ok)cout<<"TRK2 ";
  //     if(TRKh__ok)cout<<"TRKH ";
  //     if(CAL1__ok)cout<<"CAL1 ";
  //     if(CAL2__ok)cout<<"CAL2 ";
  //     if(TOF__ok)cout<<"TOF ";
  //     if(TRG__ok)cout<<"TRG ";
  //     if(AC__ok)cout<<"AC ";
  //     if(ND__ok)cout<<"ND ";
  //     if(S4__ok)cout<<"S4 ";
  //     if(ORB__ok)cout<<"ORB ";
  //     cout << endl;


  if (TRK2 && TRK1__ok)
    TRK1 = 1;
  // ----------------------------------------------------------------------------
  // NOTA
  // se c'e` il level1, lo devo necessarimente leggere.
  // infatti (non ho capito perche`) i cluster vengono letti e allocati in memoria
  // comunque, ma non vengono disallocati da PamLevel2::Clear()
  // ----------------------------------------------------------------------------


  if (!RUN__ok) {
    cout << "File: " << f->GetName() << " *WARNING* ---- Missing RunInfo tree (NB: RUN infos will not be updated)"
        << endl;
    RUN = false;
  };

  if (CAL1 && !CAL1__ok) {
    cout << "File: " << f->GetName() << " discarded ---- Missing CaloLevel1 branch" << endl;
    fDiscarded = true;
    return false;
  };
  if (CAL2 && !CAL2__ok) {
    cout << "File: " << f->GetName() << " discarded ---- Missing CaloLevel2 branch" << endl;
    fDiscarded = true;
    return false;
  };
  if (TRK2 && !TRK2__ok) {
    cout << "File: " << f->GetName() << " discarded ---- Missing TrkLevel2 branch" << endl;
    fDiscarded = true;
    return false;
  };
  if (TRK1 && !TRK1__ok) {
    cout << "File: " << f->GetName() << " discarded ---- Missing TrkLevel1 branch" << endl;
    fDiscarded = true;
    return false;
  };
  if (TRKh && !TRKh__ok) {
    cout << "File: " << f->GetName() << " discarded ---- Missing TrkHough branch" << endl;
    fDiscarded = true;
    return false;
  };
  if (ORB && !ORB__ok) {
    cout << "File: " << f->GetName() << " discarded ---- Missing ORB tree" << endl;
    fDiscarded = true;
    return false;
  };
  if (AC && !AC__ok) {
    cout << "File: " << f->GetName() << " discarded ---- Missing AC tree" << endl;
    fDiscarded = true;
    return false;
  };
  if (S4 && !S4__ok) {
    cout << "File: " << f->GetName() << " discarded ---- Missing S4 tree" << endl;
    fDiscarded = true;
    return false;
  };
  if (TOF && !TOF__ok) {
    cout << "File: " << f->GetName() << " discarded ---- Missing ToF tree" << endl;
    fDiscarded = true;
    return false;
  };

  if (ND && !ND__ok) {
    cout << "File: " << f->GetName() << " discarded ---- Missing ND tree" << endl;
    fDiscarded = true;
    return false;
  };
  if (TRG && !TRG__ok) {
    cout << "File: " << f->GetName() << " discarded ---- Missing Trigger tree" << endl;
    fDiscarded = true;
    return false;
  };
  if (GP && !GP__ok) {
    cout << "File: " << f->GetName() << " discarded ---- Missing h20 tree" << endl;
    fDiscarded = true;
    return false;
  };

  //    lk->Delete();
  //    delete lk;
  f->Close();

  //     cout<< "CheckLevel2File(TString): detector list --> ";
  //     if(TRK1)cout<<"TRK1 ";
  //     if(TRK2)cout<<"TRK2 ";
  //     if(TRKh)cout<<"TRKH ";
  //     if(CAL1)cout<<"CAL1 ";
  //     if(CAL2)cout<<"CAL2 ";
  //     if(TOF)cout<<"TOF ";
  //     if(TRG)cout<<"TRG ";
  //     if(AC)cout<<"AC ";
  //     if(ND)cout<<"ND ";
  //     if(S4)cout<<"S4 ";
  //     if(ORB)cout<<"ORB ";
  //     if(GP)cout<<"GP ";
  //     cout << endl;

  return true;

}
;

/**
 * Create clone-trees
 */
void PamLevel2::CreateCloneTrees0(TChain *fChain, TFile *ofile) {

  cout << "+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+" << endl;
  cout << "Create clones of PAMELA trees " << endl;

  Int_t i = 0;
  pam_tree_clone[i] = fChain->GetTree()->CloneTree(0);
  TString name = pam_tree_clone[i]->GetName();
  name.Append("_clone");
  //    pam_tree_clone[i]->SetName(name.Data());
  cout << pam_tree_clone[i]->GetName() << endl;
  i++;

  TList *li = fChain->GetListOfFriends();
  TIter next(li);
  TFriendElement* T_friend = 0;
  ofile->cd();
  while ((T_friend = (TFriendElement*) next())) {
    // 	cout<<T_friend->IsA()->GetName()<<" "<<T_friend->GetName()<<hex << T_friend->GetTree() << dec<<endl;
    //	cout<<T_friend->GetTree()->GetName()<< endl;
    pam_tree_clone[i] = T_friend->GetTree()->CloneTree(0);
    pam_tree_clone[i]->SetAutoSave(1000000);
    name = pam_tree_clone[i]->GetName();
    name.Append("_clone");
    //	pam_tree_clone[i]->SetName(name.Data());
    cout << pam_tree_clone[i]->GetName() << endl;
    i++;
  }

  delete li;

  cout << "+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+" << endl;

}

/**
 * Create clone-trees
 */
void PamLevel2::CreateCloneTrees(TFile *ofile) {

  //  if the pointer is null, create a default file
  if (!run_tree)
    return;

  if (!ofile) {
    cout << "void PamLevel2::CreateCloneTrees(TFile*) -- WARNING -- Creating file: clone-tree.root " << endl;
    ofile = new TFile("clone-tree.root", "recreate");
  }

  ofile->cd();

  cout << "+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+" << endl;
  cout << "Create new PAMELA trees " << endl;

  run_tree_clone = new TTree("Run", "PAMELA Level2 data from the GL_RUN table ");
  run_tree_clone->Branch("RunInfo", "GL_RUN", GetPointerTo("RunInfo"));
  cout << "Run          : branch RunInfo" << endl;
  run_tree_clone->Branch("SoftInfo", "SoftInfo", GetPointerTo("SoftInfo"));
  cout << "Run          : branch SoftInfo" << endl;
  // ------------------
  // replicate run tree
  // ------------------
  //    cout << "----------------------------------------------------"<<endl;
  //    cout << "irun\t | RUN\t NEVENTS\t absolute time"<<endl;
  for (Int_t i = 0; i < run_tree->GetEntries(); i++) {
    run_tree->GetEntry(i);
    //	cout << i<< "\t | "<<GetRunInfo()->ID<<"\t "<<GetRunInfo()->NEVENTS<< "\t "<<GetRunInfo()->RUNHEADER_TIME<<" <---> "<<GetRunInfo()->RUNTRAILER_TIME<<endl;
    run_tree_clone->Fill();
  }
  //
  // replicate processinginfo tree
  //
  if ( PROC ){ // EMEMEM
    proc_tree_clone = new TTree("ProcessingInfo","Log of data processing");
    proc_tree_clone->Branch("ProcInfo", "ProcInfo", GetPointerTo("ProcInfo"));
    cout << "ProcessingInfo: branch ProcessingInfo" << endl;  
    // ------------------
    // replicate processinginfo tree
    // ------------------
    //    cout << "----------------------------------------------------"<<endl;
    //    cout << "irun\t | RUN\t NEVENTS\t absolute time"<<endl;
    for (Int_t i = 0; i < proc_tree->GetEntries(); i++) {
      proc_tree->GetEntry(i);
      //      cout << i<< "\t | "<<endl;
      proc_tree_clone->Fill();
    }
    if ( SELLI != 2 ){      
      proc_obj->runID = 0;
      TTimeStamp *dt = new TTimeStamp();
      proc_obj->date = dt->AsString();
      delete dt;
      proc_obj->commandLine = Form("PamelaLevel2 was called: CAL2 %i CAL1 %i CAL0 %i TRK2 %i TRK1 %i TRKh %i TRK0 %i TOF %i TOF0 %i TRG %i \n                                            S4 %i ND %i AC %i ORB %i GP %i EXT %i NUC %i RUN %i ISGP %i SELLI %i \n Custom string   = %s",CAL2,CAL1,CAL0,TRK2,TRK1,TRKh,TRK0,TOF,TOF0,TRG,S4,ND,AC,ORB,GP,EXT,NUC,RUN,ISGP,SELLI,customString.Data());
      proc_obj->outputFilename = ofile->GetName();
      proc_obj->localDir = gSystem->WorkingDirectory();
      proc_obj->uname = gSystem->GetFromPipe("uname -a");
      if (!dbc || (dbc && !dbc->IsConnected())) SetDBConnection(); 
      proc_obj->DB = Form("mysql://%s/%s",dbc->GetHost(),dbc->GetDB());
      dbc->Close();
      proc_tree_clone->Fill();
    }
    cout << "----------------------------------------------------" << endl;
  }
  // ------------------------------------
  // add branch with dead and live times
  // ------------------------------------
  if (SELLI != 2) { // EMILIANO
    run_tree_clone->Branch("DeadLiveTime", totdltime, "dltime[3]/l");
    cout << "Run          : branch DeadLiveTime" << endl;

    sel_tree_clone = new TTree("SelectionList", "List of selected events ");
    //    sel_tree_clone->Branch("RunEntry",&irun,"runentry/L");
    sel_tree_clone->Branch("RunEntry", &irunt, "runentry/L");//NEWNEW
    sel_tree_clone->Branch("EventEntry", &irunentry, "eventry/L");
    //    if ( hasL0EE ) sel_tree_clone->Branch("L0EventEntry", &il0entry, "l0eventry/L");
  };

  Int_t i = 0;
  if (TRK1 || TRK2 || TRKh) {
    pam_tree_clone[i] = new TTree("Tracker", "PAMELA tracker level2 data ");
    if (TRK1) {
      pam_tree_clone[i]->Branch("TrkLevel1", "TrkLevel1", GetPointerTo("TrkLevel1"));
      pam_tree_clone[i]->BranchRef();
      cout << "Tracker      : branch TrkLevel1" << endl;
      //	    cout << "CreateCloneTrees " << GetTrkLevel1()<<endl;
    };
    if (TRK2) {
      pam_tree_clone[i]->Branch("TrkLevel2", "TrkLevel2", GetPointerTo("TrkLevel2"));
      cout << "Tracker      : branch TrkLevel2" << endl;
    };
    if (TRKh) {
      pam_tree_clone[i]->Branch("TrkHough", "TrkHough", GetPointerTo("TrkHough"));
      cout << "Tracker      : branch TrkHough" << endl;
    };
    if(NUC){
	pam_tree_clone[i]->Branch("TrackNuclei","TClonesArray",&trk_nuc_obj);
	cout << "Tracker      : branch TrackNuclei" << endl;	
    }
    if(EXT){
	pam_tree_clone[i]->Branch("extAlgFlag",&extAlgFlag,"extAlgFlag/I");
	pam_tree_clone[i]->Branch("RecoveredTrack","TClonesArray",&trk_ext_obj);
	cout << "Tracker      : branch RecoveredTrack" << endl;	
	if(NUC){
	    pam_tree_clone[i]->Branch("RecoveredTrackNuclei","TClonesArray",&trk_ext_nuc_obj);
	    cout << "Tracker      : branch RecoveredTrackNuclei" << endl;		    
	}
    }

    i++;
  }

  // Calorimeter
  if (CAL1 || CAL2) {
    pam_tree_clone[i] = new TTree("Calorimeter", "PAMELA calorimeter level2 data ");
    if (CAL1) {
      pam_tree_clone[i]->Branch("CaloLevel1", "CaloLevel1", GetPointerTo("CaloLevel1"));
      cout << "Calorimeter  : branch CaloLevel1" << endl;
    };
    if (CAL2) {
      pam_tree_clone[i]->Branch("CaloLevel2", "CaloLevel2", GetPointerTo("CaloLevel2"));
      cout << "Calorimeter  : branch CaloLevel2" << endl;
    };
    if(NUC){
	pam_tree_clone[i]->Branch("TrackNuclei","TClonesArray",&calo_nuc_obj);
	cout << "Calorimeter  : branch TrackNuclei" << endl;	
    }
    if(EXT){
	pam_tree_clone[i]->Branch("RecoveredTrack","TClonesArray",&calo_ext_obj);
	cout << "Calorimeter  : branch RecoveredTrack" << endl;	
	if(NUC){
	    pam_tree_clone[i]->Branch("RecoveredTrackNuclei","TClonesArray",&calo_ext_nuc_obj);
	    cout << "Calorimeter  : branch RecoveredTrackNuclei" << endl;		    
	}
    }
    i++;
  }

  // ToF
  if (TOF) {
    pam_tree_clone[i] = new TTree("ToF", "PAMELA ToF level2 data ");
    pam_tree_clone[i]->Branch("ToFLevel2", "ToFLevel2", GetPointerTo("ToFLevel2"));
    cout << "ToF          : branch ToFLevel2" << endl;
    if(NUC){
	pam_tree_clone[i]->Branch("TrackNuclei","TClonesArray",&tof_nuc_obj);
	cout << "ToF          : branch TrackNuclei" << endl;	
    }
    if(EXT){
	pam_tree_clone[i]->Branch("RecoveredTrack","TClonesArray",&tof_ext_obj);
	cout << "ToF          : branch RecoveredTrack" << endl;	
	if(NUC){
	    pam_tree_clone[i]->Branch("RecoveredTrackNuclei","TClonesArray",&tof_ext_nuc_obj);
	    cout << "ToF          : branch RecoveredTrackNuclei" << endl;		    
	}
    }
    i++;
  };
  // Trigger
  if (TRG) {
    pam_tree_clone[i] = new TTree("Trigger", "PAMELA trigger level2 data ");
    pam_tree_clone[i]->Branch("TrigLevel2", "TrigLevel2", GetPointerTo("TrigLevel2"));
    cout << "Trigger      : branch TrigLevel2" << endl;
    i++;
  };
  // S4
  if (S4) {
    pam_tree_clone[i] = new TTree("S4", "PAMELA S4 level2 data ");
    pam_tree_clone[i]->Branch("S4Level2", "S4Level2", GetPointerTo("S4Level2"));
    cout << "S4           : branch S4Level2" << endl;
    i++;
  };
  // Neutron Detector
  if (ND) {
    pam_tree_clone[i] = new TTree("NeutronD", "PAMELA neutron detector level2 data ");
    pam_tree_clone[i]->Branch("NDLevel2", "NDLevel2", GetPointerTo("NDLevel2"));
    cout << "NeutronD     : branch NDLevel2" << endl;
    i++;
  };
  // Anticounters
  if (AC) {
    pam_tree_clone[i] = new TTree("Anticounter", "PAMELA anticounter detector level2 data ");
    pam_tree_clone[i]->Branch("AcLevel2", "AcLevel2", GetPointerTo("AcLevel2"));
    cout << "Anticounter  : branch AcLevel2" << endl;
    i++;
  };
  // OrbitalInfo
  if (ORB) {
    pam_tree_clone[i] = new TTree("OrbitalInfo", "PAMELA orbital info  ");
    pam_tree_clone[i]->Branch("OrbitalInfo", "OrbitalInfo", GetPointerTo("OrbitalInfo"));
    cout << "OrbitalInfo  : branch OrbitalInfo" << endl;
    if(NUC){
	pam_tree_clone[i]->Branch("TrackNuclei","TClonesArray",&orb_nuc_obj);
	cout << "OrbitalInfo  : branch TrackNuclei" << endl;	
    }
    if(EXT){
	pam_tree_clone[i]->Branch("RecoveredTrack","TClonesArray",&orb_ext_obj);
	cout << "OrbitalInfo  : branch RecoveredTrack" << endl;	
	if(NUC){
	    pam_tree_clone[i]->Branch("RecoveredTrackNuclei","TClonesArray",&orb_ext_nuc_obj);
	    cout << "OrbitalInfo  : branch RecoveredTrackNuclei" << endl;		    
	}
    }
    i++;
  };
  // GPamela
  if (GP) {
    pam_tree_clone[i] = new TTree("h20", "GPAMELA info ");
    pam_tree_clone[i]->Branch("GPamela", "GPamela", GetPointerTo("GPamela"), 32000, 1);//split
    cout << "GPamela  : branch GPamela" << endl;
    i++;
  };


  cout << "+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+" << endl;

}

/**
 * Fill tree (created with CreateCloneTrees)
 *
 */
//void PamLevel2::FillNewPamTree(TTree *T){
void PamLevel2::FillCloneTrees() {

  //    cout << "PamLevel2::FillCloneTrees()" << irunentry << endl;

  for (Int_t i = 0; i < NCLONES; i++) {
    if (pam_tree_clone[i])
      pam_tree_clone[i]->Fill();
  }
  if (sel_tree_clone)
    sel_tree_clone->Fill();

}

TTree* PamLevel2::GetCloneTree(TString name) {

  for (Int_t i = 0; i < NCLONES; i++) {
    if (pam_tree_clone[i]) {
      TString na = pam_tree_clone[i]->GetName();
      if (!name.CompareTo(na))
        return pam_tree_clone[i];
    };
  }
  if (run_tree_clone) {
    TString na = run_tree_clone->GetName();
    if (!name.CompareTo(na))
      return run_tree_clone;
  }
  if (sel_tree_clone) {
    TString na = sel_tree_clone->GetName();
    if (!name.CompareTo(na))
      return sel_tree_clone;
  }
  if (proc_tree_clone && PROC) {
    TString na = proc_tree_clone->GetName();
    if (!name.CompareTo(na))
      return proc_tree_clone;
  }
  return NULL;

}
void PamLevel2::WriteCloneTrees() {
  cout << "+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+" << endl;
  cout << "Write clones of PAMELA trees " << endl;
  cout << run_tree_clone->GetName() << endl;
  if (SELLI != 2) {// Emiliano
    if (run_tree_clone->GetBranch("DeadLiveTime")->GetEntries() < run_tree->GetEntries())
      run_tree_clone->GetBranch("DeadLiveTime")->Fill();
  };
  run_tree_clone->Write();
  if (SELLI != 2) { //Emiliano
    cout << sel_tree_clone->GetName() << endl;
    sel_tree_clone->Write();
  };
  for (Int_t i = 0; i < NCLONES; i++) {
    if (pam_tree_clone[i]) {
      cout << pam_tree_clone[i]->GetName() << endl;
      pam_tree_clone[i]->Write(pam_tree_clone[i]->GetName(),TObject::kOverwrite);
    };
  }
  
  if ( PROC ){//EMEMEMEM
    proc_tree_clone->Write("ProcessingInfo",TObject::kOverwrite);
  }
  cout << "+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+" << endl;

}

/**
 * Method to get level2-trees entry, the corresponding run entry and (if required) the level0 entry.
 */
Int_t PamLevel2::GetEntry(Long64_t iee) {

  if (!pam_tree) {
    cout << " Int_t PamLevel2::GetEntry(Int_t) -- ERROR -- level2 trees not loaded" << endl;
    return 0;
  }

  //
  // This is a sort of bug: if you don't have the run tree you don't want to exit here you want to have loaded the event anyway...
  //
  //    if(!run_tree ){
  //	cout << " Int_t PamLevel2::GetEntry(Int_t) -- ERROR -- run tree not loeaded"<<endl;
  //	return 0;
  //    }

  //-------------------------------
  if (!pam_tree->GetEntry(iee)) {
    cout << " Int_t PamLevel2::GetEntry(Int_t) -- ERROR -- error reading pam tree" << endl;
    return 0;
  }
  //
  // ... that's way I put it here. Notice that nothing change in the code (is backward compatible) since in any case you return with 0.
  // in theory one would like to return 1 if run is not loaded but now I don't have the will to add that 2 lines of code and it is not
  // a problem if you don't check the return code of getentry.
  //
  if (!RUN || !run_tree) {
    if (TRK0 || CAL0 || TOF0 || RUN) { //forse cosi` va bene per tornare 1?
      cout << " Int_t PamLevel2::GetEntry(Int_t) -- ERROR -- run tree not loaded" << endl;
      return 0;
    }
    else {
      return 1; //cosi` se non c'e` run esce qua...
    }
  }

  //-------------------------------
  //
  if ( fUpdateRunInfo ) UpdateRunInfo(iee); // Emiliano
  if (SELLI == 0 || SELLI == 2) irunentry = iee - runfirstentry;

  return 1;

}

TrkLevel0 *PamLevel2::GetTrkLevel0() {
  if (!TRK0)
    return NULL;
  if (!GetYodaEntry()) {
    cout << " Int_t PamLevel2::GetTrkLevel0() -- ERROR -- error reading level0 tree" << endl;
    return 0;
  }
  return trk0_obj;
}
;
CaloLevel0 *PamLevel2::GetCaloLevel0() {
  if (!CAL0)
    return NULL;
  if (!GetYodaEntry()) {
    cout << " Int_t PamLevel2::GetCaloLevel0() -- ERROR -- error reading level0 tree" << endl;
    return 0;
  }
  return calo0_obj;
}
;

/**
 * Method to retrieve the level0 tree (YODA tree) that contains the current event.
 * Given the run ID (...), if needed it query the DB and load the proper file.
 * @return Pointer to the tree
 */

TTree* PamLevel2::GetYodaTree() {

  //    cout << "TTree* PamLevel2::GetYodaTree( )"<<endl;
  //===================================
  // check if iroot has changed
  //===================================
  if (irun < 0) {
    cout << "PamLevel2::GetYodaTree() -- ERROR -- irun = " << irun << endl;
    if (DBG) cout << "In order to use this method you have to first load the RunInfo tree "<<endl;
    return NULL;
  }
  Int_t irootnew = GetRunInfo()->ID_ROOT_L0;
  if (DBG){
    cout << "iroot    "<<iroot<<endl;
    cout << "irootnew "<<irootnew<<endl;
  }

  //===================================
  // load the level0 file
  // (if not already loaded)
  //===================================
  if (iroot != irootnew || !l0_tree) {
    iroot = irootnew;
    //===================================
    // open the DB connection
    // (if not already opened)
    //===================================
    if (!dbc || (dbc && !dbc->IsConnected()))
      SetDBConnection();
    GL_ROOT glroot = GL_ROOT();
    if (glroot.Query_GL_ROOT(iroot, dbc)) {
      cout << "TTree* PamLevel2::GetYodaTree( ) -- ERROR -- level0 file iroot = " << iroot << " does not exists"
          << endl;
      return NULL;
    };
    TString filename = glroot.PATH + glroot.NAME;
    if (l0_file) {
      l0_file->Close();
      l0_file->Delete();
    }
    cout << "Opening LEVEL0 file: " << filename << endl;
    FileStat_t t;
    if (gSystem->GetPathInfo(filename.Data(), t)) {
      cout << " PamLevel2::GetYodaTree() -- ERROR opening file " << endl;
      return NULL;
    }
    l0_file = new TFile(filename);
    if (!l0_file)
      return NULL;
    l0_tree = (TTree*) l0_file->Get("Physics");
    if (!h0_obj)
      h0_obj = new EventHeader();
    l0_tree->SetBranchAddress("Header", &h0_obj);
    yprevshift = 0; // yes, yprevshift is the shift in the level0, prevshift is the shift in the level2
    //---------------------------------------------------
    // TRACKER:
    if (TRK0) {
      if (!trk0_obj) {
        trk0_obj = new TrkLevel0();
        trk0_obj->Set();
      };
      l0_tree->SetBranchAddress("Tracker", trk0_obj->GetPointerToTrackerEvent());
    }
    //--------------------------------------------------
    // CALORIMETER:
    if (CAL0) {
      if (!calo0_obj) {
        calo0_obj = new CaloLevel0();
        calo0_obj->Set();
      };
      l0_tree->SetBranchAddress("Calorimeter", calo0_obj->GetPointerToCalorimeterEvent());
    }
    //---------------------------------------------------
    // TOF:
    if (TOF0) {
      cout << "PamLevel2::GetYodaTree() --- level0 TOF not implemented " << endl;
    }

    dbc->Close(); // EMILIANO, do not leave open connections, open only when needed
    delete dbc;
    dbc=0;

  };

  if (TRK0) {
    if(!dbc || (dbc && !dbc->IsConnected()))SetDBConnection(); 
    TrkParams::SetCalib(run_obj, dbc);
    TrkParams::LoadCalib();
    if (!TrkParams::CalibIsLoaded()) {
      cout << " TTree* PamLevel2::GetYodaTree( ) -- WARNING -- Calibration not loaded" << endl;
    };
    if(dbc){
      dbc->Close(); // EMILIANO, do not leave open connections, open only when needed
      delete dbc;
      dbc=0;
    };
  }
  return l0_tree;
}

/**
 * Method to retrieve the level0 tree (YODA tree) that contains the current event.
 */
Int_t PamLevel2::GetYodaEntry() {

  Long64_t iev = this->GetReadEntry();

  // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-
  // if it is a full file (not preselected)
  // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-
  //  if (SELLI == 0 || SELLI == 2 || !hasL0EE) {

    if (!GetYodaTree()){
      printf(" PamLevel2::GetYodaEntry() : ERROR no level0 file loaded!\n");
      return 0;
    }

    if (irunentry < 0) {
      if (DBG) cout << "Int_t PamLevel2::GetYodaEntry() -- ATTENZIONE -- irunentry negativo?!?! "<<(Int_t)irunentry<<endl;
      //      cout << "Int_t PamLevel2::GetYodaEntry() -- ATTENZIONE -- irunentry negativo?!?! "<<(Int_t)irunentry<<endl; // TOGLITOGLI
      irunentry = 0LL;
    }
    //  ---------------------------------
    //  if file is NOT a preselected file
    //  ---------------------------------
    Long64_t quellagiusta = irunentry + (Long64_t)(run_obj->EV_FROM); // prevshift already included in irunentry

    if (DBG){
      cout << " irun "<< irun << " irunentry "<< irunentry<<" run_obj->EV_FROM "<<run_obj->EV_FROM <<" quella giusta "<<quellagiusta << endl;
      cout << " iroot "<<iroot<<" run_obj->ID_ROOT_L0 "<<run_obj->ID_ROOT_L0<<endl;
      cout << " time "<< abstime << endl;
    }

    ULong64_t obt = 0;
    ULong64_t pktn = 0;
    if (GetOrbitalInfo()) {
      obt = GetOrbitalInfo()->OBT;
      pktn = GetOrbitalInfo()->pkt_num;
    }

    if (!GetOrbitalInfo() && !ISGP) {
      cout << "Int_t PamLevel2::GetYodaEntry() -- ERROR -- missing OrbitalInfo " << endl;
      return 0;
    }
    if (obt == 0 && pktn == 0 && !ISGP) {
      cout << "Int_t PamLevel2::GetYodaEntry() -- ERROR -- level2 event corrupted ?? " << endl;
      return 0;
    }

    // ---------------------------------------------------------------------
    // ATTENTION!!!
    // If data are not pre-processed with cleaner, the level0 tree may contain
    // spurious nested physics packets.
    // The GL_RUN variables EV_FROM, EV_TO and NEVENTS counts also these entries
    // while level2 tree DOES NOT!!
    // This means that "quellagiusta" in these cases is not correct.
    // In order to retrieve the correct level0 event, I implemented a check
    // of the OBT and pkt-number. In case of mismatch, the level0 entry number
    // is shift forward until when the packets match.
    // ---------------------------------------------------------------------
    Long64_t shift = 0LL;
    Long64_t answer = quellagiusta + shift + yprevshift;
    Int_t readl0 = 0;
    readl0 = l0_tree->GetEntry(answer); // prevshift already included in irunentry

    if (DBG){
      printf(" siamo qui shift %lld yprevshift %lld answer %lld \n",shift,yprevshift,answer);
    }


    if (ISGP) {
      obt = (UInt_t)(GetEventHeader()->GetPscuHeader()->GetOrbitalTime()); //BARBATRUCCO
      pktn = (UInt_t)(GetEventHeader()->GetPscuHeader()->GetCounter()); //BARBATRUCCO
    }

    while ( (obt != (UInt_t)(GetEventHeader()->GetPscuHeader()->GetOrbitalTime()) || pktn != (UInt_t)(GetEventHeader()->GetPscuHeader()->GetCounter())) && (quellagiusta + (Long64_t) shift) < GetYodaTree()->GetEntries() && shift < maxshift ){
      if ( isSync && shift == 0LL ){
        printf(" PamLevel2::GetYodaEntry() ERROR! sync file but the level0 entry not found in place!!! \n");
        cout << " OK this is a bug, write to Emiliano, Emiliano.Mocchiutti@ts.infn.it " << endl;
        cout << "\nFor bug reporting instructions, please see for example:\n";
        cout << "     <http://www.ts.infn.it/~mocchiut/bugs/bugs.html>.\n";
        cout << "  " << endl;
      }
      if (shift > 0) {
        if (DBG) cout << " PKTNUM  L2 --- " << pktn << " --- L0 --- " << GetEventHeader()->GetPscuHeader()->GetCounter() << endl;
        if (DBG)
          cout << "         RUN: ID " << GetRunInfo()->ID << " ID_ROOT_L0 " << run_obj->ID_ROOT_L0 << " ID_RUN_FRAG "
               << GetRunInfo()->ID_RUN_FRAG << " EV_FROM " << GetRunInfo()->EV_FROM << endl;
        if (DBG)
          cout << "         L2 <--> L0 mismatch ( irun " << irun << " irunentry " << irunentry << " shift " << shift
               << " prevshift " << prevshift << " )" << endl;
      }
      answer = quellagiusta +  shift+ yprevshift;
      readl0 = l0_tree->GetEntry(answer);
      //      printf(" inside while shift %lld yprevshift %lld answer %lld \n",shift,yprevshift,answer);//TOGLITOGLI

      if (!GetEventHeader()) {
        cout << "Int_t PamLevel2::GetYodaEntry() -- ERROR -- missing EventHeader " << endl;
        return 0;
      }

      //
      if (yprevshift != 0 && (quellagiusta + (Long64_t) shift) == GetYodaTree()->GetEntries()) {
        if (DBG) printf(" reset inside while shift %lld yprevshift %lld answer %lld \n",shift,yprevshift,answer);
        //        printf(" reset inside while shift %lld yprevshift %lld answer %lld \n",shift,yprevshift,answer);//TOGLITOGLI
        yprevshift = 0LL;
        shift = -1LL;
      };
    
      shift++;
    }
                                   

    if ( obt != (UInt_t)(GetEventHeader()->GetPscuHeader()->GetOrbitalTime()) || pktn != (UInt_t)(GetEventHeader()->GetPscuHeader()->GetCounter()) ){
      if ( isSync ){
        printf(" PamLevel2::GetYodaEntry() ERROR! sync file but the level0 entry not found AT ALL!!! \n");
        cout << " OK this is a bug, write to Emiliano, Emiliano.Mocchiutti@ts.infn.it " << endl;
        cout << "\nFor bug reporting instructions, please see for example:\n";
        cout << "     <http://www.ts.infn.it/~mocchiut/bugs/bugs.html>.\n";
        cout << "  " << endl;
      }
      cout << "Int_t PamLevel2::GetYodaEntry() -- WARNING -- " << endl;
      cout << " Big trouble here, no such event in Level0 data! (NB maxshift set to " << maxshift << " )" << endl;    
      cout << " Nested and/or DarthVader skipped packets in fragmented run? checking and trying to fix " <<endl;
      // query the DB for runs containing the event, loop over LEVEL0 files which could contain the level0 event and try to find it
      // ma nel mezzo del cammin per ogni run che pesco devo vedere la posizione relativa di iev rispetto al runheader nel livello2 per andare a cercare nel posto giusto
      // connect to db
      if (!dbc || (dbc && !dbc->IsConnected())) SetDBConnection(); //Emiliano
      //
      if (GetOrbitalInfo()){
        abstime = GetOrbitalInfo()->absTime;
      } else {
        printf(" PamLevel2::GetYodaEntry() ERROR! no OrbitalInfo, cannot get the absolute time for event \n");
        return 0;
      }
      // query DB looking for runs containing the processed event
      TSQLResult *pResult;
      TSQLRow *Row = NULL;
      TString myquery = Form("select ID,NEVENTS from GL_RUN where RUNHEADER_TIME<=%lld and RUNTRAILER_TIME>=%lld;",abstime,abstime);
      if ( DBG ) printf(" query is %s \n",myquery.Data());
      //      printf(" query is %s \n",myquery.Data());// TOGLITOGLI
      pResult = dbc->Query(myquery.Data());     
      if (!pResult->GetRowCount()){
        printf(" PamLevel2::GetYodaEntry() ERROR! event is not included in any run!!! \n");
        cout << " OK this is a bug, write to Emiliano, Emiliano.Mocchiutti@ts.infn.it " << endl;
        cout << "\nFor bug reporting instructions, please see for example:\n";
        cout << "     <http://www.ts.infn.it/~mocchiut/bugs/bugs.html>.\n";
        cout << "  " << endl;
        return 0;
      }
      if ( pResult->GetRowCount() == 1 ){
        if (DBG) printf(" PamLevel2::GetYodaEntry() - WARNING - YodaEntry not found but only one run containing the event, it should not happen \n");
        //        printf(" PamLevel2::GetYodaEntry() - WARNING - YodaEntry not found but only one run containing the event, it should not happen \n");//TOGLITOGLI
      }
      for( Int_t ru=0; ru < pResult->GetRowCount(); ru++){ // loop over runs containing the event
        if (Row) delete Row;
        Row = pResult->Next();   
        if( Row == NULL ) break;
        UInt_t idrun = (UInt_t)atoll(Row->GetField(0));
        UInt_t nev = (UInt_t)atoll(Row->GetField(1));
        if (DBG) printf(" inside loop over runs: ru %i idrun %i nev %i \n",ru,idrun,nev);
        //        printf(" inside loop over runs: ru %i idrun %i nev %i \n",ru,idrun,nev);//TOGLITOGLI

        // now look for this run in the level2 file, it must be present! code is taken from updateruninfo of course
        Bool_t rfound = false;
        totrunentry = 0LL;
        runfirstentry = 0LL;
        for (Int_t r=0; r< run_tree->GetEntries();r++){
          run_tree->GetEntry(r);//update runinfo
          if ( r > 0 ){
            totrunentrymin = totrunentrymax+1;
          } else {
            totrunentrymin = 0LL;
          }
          totrunentry += GetRunInfo()->NEVENTS;
          totrunentrymax = totrunentry - 1 - prevshift; // prevshift is needed to handle nested+DV_skipped packets
          irun = r;        

          if (idrun == GetRunInfo()->ID){
            if ( totrunentrymin > iev ){ // there is a shift (nested+DV_skipped packets)
              if (DBG) printf("PamLevel2::GetYodaEntry - unconsistent iev - nevents, probable DBL0-L2 async\n");
              if (DBG) printf("PamLevel2::GetYodaEntry - totrunentrymin %lld iev %lld prevshift %lld totrunentrymax %lld \n",totrunentrymin,iev,prevshift,totrunentrymax);
              //              printf("PamLevel2::GetYodaEntry - unconsistent iev - nevents, probable DBL0-L2 async\n");
              //              printf("PamLevel2::GetYodaEntry - totrunentrymin %lld iev %lld prevshift %lld totrunentrymax %lld \n",totrunentrymin,iev,prevshift,totrunentrymax);//TOGLITOGLI
              prevshift += (totrunentrymin-iev); // add the new shift to total shift
              totrunentrymin -= (totrunentrymin-iev); // shift run position min
              totrunentrymax -= (totrunentrymin-iev); // shift run position max
              if (DBG) printf("PamLevel2::GetYodaEntry - totrunentrymin %lld iev %lld prevshift %lld totrunentrymax %lld \n",totrunentrymin,iev,prevshift,totrunentrymax);
              //              printf("PamLevel2::GetYodaEntry - totrunentrymin %lld iev %lld prevshift %lld totrunentrymax %lld \n",totrunentrymin,iev,prevshift,totrunentrymax);//TOGLITOGLI
            }
            runfirstentry = totrunentrymin; // first entry of the run in the level2
          

            //
            if (gltsync)
              delete gltsync; // Emiliano
            if (!dbc || (dbc && !dbc->IsConnected()))
              SetDBConnection(); //Emiliano
            gltsync = new GL_TIMESYNC(GetRunInfo()->ID_ROOT_L0, "ID", dbc, false); // Emiliano
            if (dbc){
              dbc->Close(); // Emiliano
              delete dbc;
              dbc=0;
            }          
            if (gltsync->DBobt(GetRunInfo()->RUNHEADER_OBT) > gltsync->DBobt(GetRunInfo()->RUNTRAILER_OBT)) { // Emiliano
              cout << "Bool_t PamLevel2::UpdateRunInfo(Long64_t iev) -- WARNING -- irun " << irun
                   << "  has RUNHEADER_OBT>=RUNTRAILER_OBT " << endl;
              cout
                << "                                                            (NB!! in this case some events could be assigned to a wrong run)"
                << endl;
            }
            //
            if (DBG) printf(" found \n");
            //            printf(" found \n");//TOGLITOGLI
            rfound = true;
            //
            break;
          }
        } // loop over run
        if ( !rfound ){
          printf(" PamLevel2::GetYodaEntry() ERROR! run is not present in the level2 file!!! \n");
          cout << " OK this is a bug, write to Emiliano, Emiliano.Mocchiutti@ts.infn.it " << endl;
          cout << "\nFor bug reporting instructions, please see for example:\n";
          cout << "     <http://www.ts.infn.it/~mocchiut/bugs/bugs.html>.\n";
          cout << "  " << endl;        
          return 0;
        }

        // here we got the first run and we can check if it contains the level0 event
        if (!GetYodaTree()){
          printf(" PamLevel2::GetYodaEntry() : ERROR no level0 file loaded!\n");
          return 0;
        }      

        // get the current run entry
        irunentry = iev - runfirstentry;
        if (irunentry < 0) {
          if (DBG) cout << "Int_t PamLevel2::GetYodaEntry() -- ATTENZIONE -- irunentry negativo?!?! "<<(Int_t)irunentry<<endl;
          //          cout << "Int_t PamLevel2::GetYodaEntry() -- ATTENZIONE -- irunentry negativo?!?! "<<(Int_t)irunentry<<endl; // TOGLITOGLI
          irunentry = 0LL;
        }
        //  ---------------------------------
        //  if file is NOT a preselected file
        //  ---------------------------------
        quellagiusta = irunentry + (Long64_t)(run_obj->EV_FROM); // prevshift already included in irunentry
      
        if (DBG){
          cout << " irun "<< irun << " irunentry "<< irunentry<<" run_obj->EV_FROM "<<run_obj->EV_FROM <<" quella giusta "<<quellagiusta << endl;
          cout << " iroot "<<iroot<<" run_obj->ID_ROOT_L0 "<<run_obj->ID_ROOT_L0<<endl;
          cout << " time "<< abstime << endl;
        }
        //        cout << " irun "<< irun << " irunentry "<< irunentry<<" run_obj->EV_FROM "<<run_obj->EV_FROM <<" quella giusta "<<quellagiusta << endl;
        //        cout << " iroot "<<iroot<<" run_obj->ID_ROOT_L0 "<<run_obj->ID_ROOT_L0<<endl;
        //        cout << " time "<< abstime << endl; // TOGLITOGLI
      
        shift = 0;
        answer = quellagiusta + shift + yprevshift; // prevshift already included in irunentry
        readl0 = l0_tree->GetEntry(answer); // prevshift already included in irunentry

        if (DBG){
          printf(" siamo qua shift %lld yprevshift %lld answer %lld \n",shift,yprevshift,answer);
        }
        //        printf(" siamo qua shift %lld yprevshift %lld answer %lld \n",shift,yprevshift,answer);//TOGLITOGLI
      
        while ( (obt != (UInt_t)(GetEventHeader()->GetPscuHeader()->GetOrbitalTime()) || pktn != (UInt_t)(GetEventHeader()->GetPscuHeader()->GetCounter())) && (quellagiusta + (Long64_t) shift) < GetYodaTree()->GetEntries() && shift < maxshift ){
          if (shift > 0) {
            if (DBG) cout << " PKTNUM  L2 --- " << pktn << " --- L0 --- " << GetEventHeader()->GetPscuHeader()->GetCounter() << endl;
            if (DBG)
              cout << "         RUN: ID " << GetRunInfo()->ID << " ID_ROOT_L0 " << run_obj->ID_ROOT_L0 << " ID_RUN_FRAG "
                   << GetRunInfo()->ID_RUN_FRAG << " EV_FROM " << GetRunInfo()->EV_FROM << endl;
            if (DBG)
              cout << "         L2 <--> L0 mismatch ( irun " << irun << " irunentry " << irunentry << " shift " << shift
                   << " prevshift " << prevshift << " )" << endl;
          }
          answer = quellagiusta +  shift+ yprevshift;
          readl0 = l0_tree->GetEntry(answer);
          //          printf(" inside inside while shift %lld yprevshift %lld answer %lld \n",shift,yprevshift,answer);//TOGLITOGLI
        
          if (!GetEventHeader()) {
            cout << "Int_t PamLevel2::GetYodaEntry() -- ERROR -- missing EventHeader " << endl;
            return 0;
          }
          //
          if (yprevshift != 0 && (quellagiusta + (Long64_t) shift) == GetYodaTree()->GetEntries()) {
            if (DBG) printf(" reset inside while shift %lld yprevshift %lld answer %lld \n",shift,yprevshift,answer);
            //            printf(" reset inside while shift %lld yprevshift %lld answer %lld \n",shift,yprevshift,answer);//TOGLITOGLI
            yprevshift = 0;
            shift = -1;
          };
        
          shift++;
        }
      
        if ( obt != (UInt_t)(GetEventHeader()->GetPscuHeader()->GetOrbitalTime()) || pktn != (UInt_t)(GetEventHeader()->GetPscuHeader()->GetCounter()) ){
          //still not the good run... continue with the nex one!
          printf("still not the good run... continue with the nex one!\n");
        } else {
          if (DBG) cout << "LA ENTRY GIUSTA E`: "<<quellagiusta<<" (spero...)"<<endl;
          //          cout << "LA ENTRY GIUSTA E`: "<<answer<<" (spero...)"<<endl;//TOGLITOGLI
          if (shift > 1) yprevshift = (shift - 1);
          if (Row) delete Row;
          delete pResult;   
          if (dbc){
            dbc->Close(); // Emiliano
            delete dbc;
            dbc=0;
          }     
          il0entry = answer;
          return readl0;
        }
        // perhaps it is all
      }// loop over runs containing the event
      if (Row) delete Row;
      delete pResult;   
      if (dbc){
        dbc->Close(); // Emiliano
        delete dbc;
        dbc=0;
      }          
      // arriving here it means no run found, cannot be! error!
      printf(" PamLevel2::GetYodaEntry() ERROR! run is not present in the level0 files!!! \n");
      cout << " OK this is a bug, write to Emiliano, Emiliano.Mocchiutti@ts.infn.it " << endl;
      cout << "\nFor bug reporting instructions, please see for example:\n";
      cout << "     <http://www.ts.infn.it/~mocchiut/bugs/bugs.html>.\n";
      cout << "  " << endl;        
      return 0;
    } else {
      if (DBG) cout << "=> LA ENTRY GIUSTA E`: "<<answer<<" (spero...)"<<endl;
      //    cout << "=> LA ENTRY GIUSTA E`: "<<answer<<" (spero...)"<<endl;
      //    printf("obt %lld (UInt_t)(GetEventHeader()->GetPscuHeader()->GetOrbitalTime()) %i  pktn %lld (UInt_t)(GetEventHeader()->GetPscuHeader()->GetCounter() %i \n",obt,(UInt_t)(GetEventHeader()->GetPscuHeader()->GetOrbitalTime()), pktn, (UInt_t)(GetEventHeader()->GetPscuHeader()->GetCounter()) ); 
      if (shift > 1) yprevshift = (shift - 1);
      il0entry = answer;
      return readl0;
    }

    /*  } // if selli 0 || 2
  if ( SELLI == 1 && hasL0EE ){
    sel_tree->GetEntry(iev);   
    Long64_t answer = il0entry;
    Int_t readl0 = 0;
    readl0 = l0_tree->GetEntry(answer); 
    return readl0;
    }*/
  printf(" PamLevel2::GetYodaEntry() ERROR! \n");
  cout << " Entry not found! OK this is a bug, write to Emiliano, Emiliano.Mocchiutti@ts.infn.it " << endl;
  cout << "\nFor bug reporting instructions, please see for example:\n";
  cout << "     <http://www.ts.infn.it/~mocchiut/bugs/bugs.html>.\n";
  cout << "  " << endl;
  return 0;
}

/**
 * \Brief Set DB connection
 */
Bool_t PamLevel2::SetDBConnection() {

  //    cout << "PamLevel2::SetDBConnection()" << endl;
  if (DBG) {
    cout << "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~" << endl;
    cout << "Connecting to DB" << endl;
    cout << "HOST " << host << endl;
    cout << "USER " << user << endl;
    cout << "PSW  " << psw << endl;
  }
  Bool_t notconn = true;
  Int_t trials = 0;
  while ( notconn && trials < 10 ){
    //    gSystem->Sleep(500);
    dbc = TSQLServer::Connect(host.Data(), user.Data(), psw.Data());
    //dbc->Connect(host.Data(), user.Data(), psw.Data());
    if ( dbc ) notconn = false;
    if (DBG) printf("<%i> test connection...\n ",trials);
    if (!dbc){
      if (DBG) printf(" :( failed, no pointer \n");
      notconn = true;
      //      return false;
    };
    if (dbc && !dbc->IsConnected()){
      if (DBG) printf(" :( failed, no connection \n");
      notconn = true;
      //      return false;
    }; 
    trials++;
  };
  if ( notconn ) return false;
  //
  if (DBG) printf("=connected!\n");
  stringstream myquery; // EMILIANO
  myquery.str(""); // EMILIANO
  myquery << "SET time_zone='+0:00'"; // EMILIANO
  dbc->Query(myquery.str().c_str()); // EMILIANO
  if ( DBG ) printf("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n");
  return true;

}

/**
 * \Brief Add a friend to the pamela chain.
 * @param cname name of the chain to be added
 */

TChain* PamLevel2::AddFriend(TString cname) {

  if (!GetPamTree()) {
    cout << " TChain* PamLevel2::AddFriend(TString cname) --- a pamela tree must be created first" << endl;
    return NULL;
  }

  TChain *c = new TChain(cname.Data());

  TIter next(GetPamTree()->GetListOfFiles());
  Int_t nf = 0;
  TChainElement* element = 0;
  while ((element = (TChainElement*) next())) {
    c->Add(element->GetTitle());
    nf++;
  }

  GetPamTree()->AddFriend(cname.Data());

  cout << "external chain created and added to pamela friends :" << cname << endl;
  cout << "n.files " << nf << endl;

  return c;

}

/**
 * Returns the current read entry. This method simply returns the result of the call to
 * pam_tree->GetReadEntry(), so it is entirely handled by ROOT.
 */
Long64_t PamLevel2::GetReadEntry() {
  return pam_tree->GetReadEntry();
}

/**
 * Sets the sorting method. If the new method is different from the previous, the issorted
 * flag is set to false, forcing a new sort the next time GetTrack is called.
 * @see GetTrack
 */
void PamLevel2::SetSortingMethod(TString how) {
  if (howtosort != how) {
    issorted = false;
    issorted_new = false;
  }
  howtosort = how;
}
