/**
 * \file CaloPreSampler.cpp
 * \author Emiliano Mocchiutti (2007/07/18)
 */
//
// headers
//
#include <CaloPreSampler.h>
//--------------------------------------
/**
 * Default constructor 
 */
CaloPreSampler::CaloPreSampler(){
  Clear();
}

void CaloPreSampler::SetCaloLevel2Pointer(CaloLevel2 *cl2p){
  if ( pcalo ) delete pcalo;
  pcalo = cl2p;
}

CaloPreSampler::CaloPreSampler(PamLevel2 *l2p){  
  //
  L2 = l2p;
  //
  if ( !L2->IsORB() ) printf(" WARNING: OrbitalInfo Tree is needed, the plugin could not work properly without it \n");
  //
  OBT = 0;
  PKT = 0;
  atime = 0;
  //
  // Default variables
  //
  event = new CaloLevel0();
  cstrip = new CaloStrip(false);
  //  c1 = new CaloLevel1();
  pcalo = new CaloLevel2();
  N = 4;
  NC = 22-N; 
  debug = false;
  sel = true;
  cont = false;
  emulate18 = true;
  usepl18x = false;
  simulation = false;
  withtrk = true;
  rigdefault = 50.;
  nox = false;
  noy = false;
  forcecalo = false;
  forcefitmode = -1;
  memset(mask,0,2*22*sizeof(Int_t));
  //
  Clear();
  //
  // loading magnetic field...
  //
  TrkLevel2 *trk = new TrkLevel2();
  GL_PARAM *q4 = new GL_PARAM();
  TSQLServer *dbc = 0;
  TString host = "mysql://localhost/pamelaprod";
  TString user = "anonymous";
  TString 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;
  dbc = TSQLServer::Connect(host.Data(),user.Data(),psw.Data());
  //
  q4->Query_GL_PARAM(1,1,dbc);
  printf(" Reading magnetic field maps at %s\n",(q4->PATH+q4->NAME).Data());
  trk->LoadField(q4->PATH+q4->NAME);
  //
}

CaloTrkVar* CaloPreSampler::GetCaloTrack(Int_t t){
  this->Process();
  if ( t < 0 ) return pcalo->GetCaloStoredTrack(t);
  if ( L2->GetTrack(t) ){
    return pcalo->GetCaloStoredTrack(L2->GetTrack(t)->GetTrkTrack()->GetSeqNo());
  };
  return NULL;
}

void CaloPreSampler::SetNoWpreSampler(Int_t n){
  if ( NC+n < 23 ){
    N = n;
  } else {
    printf(" ERROR! Calorimeter is made of 22 W planes\n");
    printf(" you are giving N presampler = %i and N calo = %i \n",n,NC);
    printf(" WARNING: using default values NWpre = 4, NWcalo = 18\n");
    NC = 18;
    N = 4;
  };
}

void CaloPreSampler::SetNoWcalo(Int_t n){
  if ( N+n < 23 ){
    NC = n;
  } else {
    printf(" ERROR! Calorimeter is made of 22 W planes\n");
    printf(" you are giving N W presampler = %i and N W calo = %i \n",N,n);
    printf(" WARNING: using default values NWpre = 4, NWcalo = 18\n");
    NC = 18;
    N = 4;
  };
}

void CaloPreSampler::SplitInto(Int_t NoWpreSampler, Int_t NoWcalo){
  this->SetNoWcalo(0);
  this->SetNoWpreSampler(0);
  if ( NoWpreSampler < NoWcalo ){
	this->SetNoWpreSampler(NoWpreSampler);
	this->SetNoWcalo(NoWcalo);
  } else {
	this->SetNoWcalo(NoWcalo);
	this->SetNoWpreSampler(NoWpreSampler);
  };
}

void CaloPreSampler::Clear(){
  //
  pcalo->Clear();
  //
}

void CaloPreSampler::Print(){
  //
  Process();
  //
  printf("========================================================================\n");
  printf(" OBT: %u PKT: %u ATIME: %u \n",OBT,PKT,atime);
  printf(" debug                [debug flag]:.. %i\n",debug);
  printf(" simulation      [simulation flag]:.. %i\n",simulation);
  printf(" emulate18 [emulate dead plane 18]:.. %i\n",emulate18);
  printf(" selection mode                   :.. %i\n",sel);
  printf(" contamination mode               :.. %i\n",cont);
  printf(" pre-sampler planes               :.. %i\n",N);
  printf(" pcalo->qtot                      :.. %f\n",pcalo->qtot);
  printf(" pcalo->nstrip                    :.. %i\n",pcalo->nstrip);  
  if ( pcalo->ntrk() > 0 ){
    printf(" pcalo->track0->qtrack            :.. %f\n",pcalo->GetCaloTrkVar(0)->qtrack);  
    printf(" pcalo->track0->dX0l              :.. %f\n",pcalo->GetCaloTrkVar(0)->dX0l);  
  };
  printf("========================================================================\n");
  //
}

void CaloPreSampler::Delete(){
  Clear();
  delete pcalo;
  //delete this;
}


void CaloPreSampler::Process(){
  //  
  if ( !L2 ){
    printf(" ERROR: cannot find PamLevel2 object, use the correct constructor or check your program!\n");
    printf(" ERROR: CaloPreSampler variables _NOT_ filled \n");
    return;
  };
  //
  // Clear structures used to communicate with fortran
  //
  event->ClearStructs();//ELENA
  if ( forcefitmode > 0 ){
    if ( forcefitmode != 1000 && forcefitmode != 1001 && forcefitmode != 1002 ){
      printf(" ERROR! forcefitmode=%i \n Use forcefitmode = 1000 for fit mode 0, 1001 fit mode 1, 1002 fit mode 3\n",forcefitmode);
      forcefitmode = -1;
    } else {
      event->clevel2->fmode[0] = forcefitmode;
      event->clevel2->fmode[1] = forcefitmode;
    };
  };
  //
  Bool_t newentry = false;
  //
  if ( L2->IsORB() ){
    if ( debug ) printf(" I am here, we have orbital infos \n");
    if ( L2->GetOrbitalInfo()->pkt_num != PKT || L2->GetOrbitalInfo()->OBT != OBT || L2->GetOrbitalInfo()->absTime != atime || sel != ssel ){
      newentry = true;
      OBT = L2->GetOrbitalInfo()->OBT;
      PKT = L2->GetOrbitalInfo()->pkt_num;
      atime = L2->GetOrbitalInfo()->absTime;
      ssel = sel;
    };
  } else {
    newentry = true;
  };
  //
  if ( !newentry ) return;
  //
  // Some variables
  //
  Int_t S3 = 0;
  Int_t S2 = 0;
  Int_t S12 = 0;
  Int_t S11 = 0;
  Float_t tmptrigty = -1.; 
  Bool_t trackanyway = true;
  //  Float_t rigdefault = 50.;
  Bool_t hZn = true;
  //  Bool_t withtrk = true;
  Bool_t st = true;
  Int_t ntrkentry = 0;
  TrkLevel2 *trk = L2->GetTrkLevel2();
  //  Bool_t filled = false;
  //
  if ( debug ) printf(" Processing event at OBT %u PKT %u time %u \n",OBT,PKT,atime);
  //
  // find out if we have trkseqno = -1, -2 or -3
  //
  Bool_t m1 = false;
  Bool_t m2 = false;
  Bool_t m3 = false;
  for (Int_t mm=0; mm < L2->GetCaloLevel2()->ntrk(); mm++ ){
    if ( L2->GetCaloLevel2()->GetCaloTrkVar(mm)->trkseqno == -1 ) m1 = true;
    if ( L2->GetCaloLevel2()->GetCaloTrkVar(mm)->trkseqno == -2 ) m2 = true;
    if ( L2->GetCaloLevel2()->GetCaloTrkVar(mm)->trkseqno == -3 ) m3 = true;
  };
  if ( !withtrk ) m3 = true;
  //
  // copy variables calculated during calibration process which is skipped here... this has been moved before this->Clear() for reprocessing purpose
  //
  event->clevel2->good = L2->GetCaloLevel2()->good;
  memcpy(event->clevel2->perr,L2->GetCaloLevel2()->perr,sizeof(L2->GetCaloLevel2()->perr));
  memcpy(event->clevel2->swerr,L2->GetCaloLevel2()->swerr,sizeof(L2->GetCaloLevel2()->swerr));
  memcpy(event->clevel2->crc,L2->GetCaloLevel2()->crc,sizeof(L2->GetCaloLevel2()->crc));
  event->clevel2->selftrigger = L2->GetCaloLevel2()->selftrigger;
  //
  //
  this->Clear(); // moved after all calls to L2->GetCaloLevel2() since pcalo could be the same as L2->GetCaloLevel2() !!!
  //
  //
  if ( debug ) printf(" Fill estrip matrix needed to calculate variables \n");
  //
  // Fill the estrip matrix
  //
  memset(event->clevel1->estrip, 0, 2*22*96*sizeof(Float_t));
  Int_t view = 0;
  Int_t plane = 0;
  Int_t strip = 0;
  Float_t mip = 0.;
  for ( Int_t i=0; i<L2->GetCaloLevel1()->istrip; i++ ){
    //
    mip = L2->GetCaloLevel1()->DecodeEstrip(i,view,plane,strip);
    //
    if ( !usepl18x && view==0 && plane==18 ) mip = 0.;
    //
    // Mask x or y view if nox and/or noy are true (default false)
    //
    if ( mask[view][plane] ) mip = 0.;
    if ( nox && view == 0 ) mip = 0.; 
    if ( noy && view == 1 ) mip = 0.; 
    //
    if ( emulate18 && view == 0 && plane == 18 ) mip = 0.;
    //
    // Selection mode: fill the matrix only for plane < (22 - N) REMEMBER N = number of W planes to be used as presampler, ie if N = 2 then we want to use planes from 0 to 19
    //                 included so plane < (22 - 2)
    //
    if ( sel ){
      if ( plane < (22 - N) ){
	//
	if ( emulate18 && plane == (18 - N) && view == 0 ) mip = 0.;
	if ( plane >= NC ) mip = 0.;
	event->clevel1->estrip[strip][plane][view] = mip;
	//
      };
    };
    //
    // Contamination mode: fill the matrix only for planes from N to 22 but shift all planes up to the first one
    //
    if ( cont ){
      if ( plane >= N ){
	//
	if ( emulate18 && plane == (18 + N) && view == 0 ) mip = 0.;
	if ( (plane-N) >= NC ) mip = 0.;
	event->clevel1->estrip[strip][(plane-N)][view] = mip;
	//
      };
    };    
    //
  };
  //
  // if data comes from the simulation we must use mechanical alignment parameters (default is flight parameters)
  //
  if ( simulation ){
    cstrip->UseMechanicalAlig();
  };
  //
  // Set alignment parameter 
  //
  event->clevel1->xalig = cstrip->GetXalig();
  event->clevel1->yalig = cstrip->GetYalig();
  event->clevel1->zalig = cstrip->GetZalig();
  //
  event->clevel1->emin = 0.7;
  //
  // in case of the contamination mode we must play with the Z alignment in order to have the correct track in the calo since we have moved the planes up...
  //
  if ( cont ){
    if ( !(N%2) ){
      event->clevel1->reverse = 0; // if the number of planes is even we have taken away a full module no need to do anything strange...
      event->clevel1->zalig -= (N/2) * (8.09 + 10.09);
    } else {
      event->clevel1->reverse = 1; // if the number of planes is odd we have taken away half a module, we need to reverse silicon planes shifting
      event->clevel1->zalig -= ((N+1)/2) * 8.09 + ((N-1)/2) * 10.09;
    };
  };
  if ( debug ) printf(" xalig = %f \n",event->clevel1->xalig);
  if ( debug ) printf(" yalig = %f \n",event->clevel1->yalig);
  if ( debug ) printf(" zalig = %f \n",event->clevel1->zalig);
  //
  if ( debug ) printf(" Calculate variables as done in CaloCore, N = %i \n",N);
  //
  // Calculate variables
  //
  //
  // use only N W planes
  //
  //  event->clevel1->npla = 22-N;
  event->clevel1->npla = NC;
  //
  S3 = 0;
  S2 = 0;
  S12 = 0;
  S11 = 0;
  S3 = L2->GetTrigLevel2()->patterntrig[2];
  S2 = L2->GetTrigLevel2()->patterntrig[3];
  S12 = L2->GetTrigLevel2()->patterntrig[4];
  S11 = L2->GetTrigLevel2()->patterntrig[5];
  if ( L2->GetTrigLevel2()->patterntrig[1] & (1<<0) ) tmptrigty = 1.;
  if ( L2->GetTrigLevel2()->patterntrig[0] ) tmptrigty = 2.;
  if ( S3 || S2 || S12 || S11 )  tmptrigty = 0.;    
  if ( !(L2->GetTrigLevel2()->patterntrig[1] & (1<<0)) && !L2->GetTrigLevel2()->patterntrig[0] && !S3 && !S2 && !S12 && !S11 ) tmptrigty = 1.;
  event->clevel2->trigty = tmptrigty;
  //
  // do we have at least one track from the tracker? this check has been disabled
  //
  event->clevel1->good2 = 1;
  //
  // copy variables calculated during calibration process which is skipped here... this has to be moved before this->Clear() for reprocessing purpose
  //
//  event->clevel2->good = L2->GetCaloLevel2()->good;
//  memcpy(event->clevel2->perr,L2->GetCaloLevel2()->perr,sizeof(L2->GetCaloLevel2()->perr));
//  memcpy(event->clevel2->swerr,L2->GetCaloLevel2()->swerr,sizeof(L2->GetCaloLevel2()->swerr));
//  memcpy(event->clevel2->crc,L2->GetCaloLevel2()->crc,sizeof(L2->GetCaloLevel2()->crc));
//  event->clevel2->selftrigger = L2->GetCaloLevel2()->selftrigger;
  //
  // Calculate variables common to all tracks (qtot, nstrip, etc.)
  //
  if ( debug ) printf("1 Call GetCommonVar() \n");
  event->GetCommonVar();
  //
  // Fill common variables
  //
  if ( debug ) printf("1 Call FillCommonVar() \n");
  event->FillCommonVar(NULL,pcalo);
  //
  // Calculate variables related to tracks only if we have at least one track (from selftrigger and/or tracker)
  //
  ntrkentry = 0;
  //
  //  filled = false;
  //
  // Run over tracks (tracker or calorimeter )
  //
  if ( withtrk ){
    //
    for (Int_t nt=0; nt < trk->ntrk(); nt++){  
      //
      event->clevel1->good2 = 1;
      //
      TrkTrack *ptt = trk->GetStoredTrack(nt); 
      //
      event->clevel1->trkchi2 = 0;
      //
      // Copy the alpha vector in the input structure
      //
      for (Int_t e = 0; e < 5 ; e++){
	event->clevel1->al_p[e][0] = ptt->al[e];
      };	  
      //
      // Get tracker related variables for this track
      //
      if ( debug ) printf("track %i Call GetTrkVar() \n",nt);
      event->GetTrkVar();
      if ( debug ) printf(" event->clevel2->dX0l %f \n",event->clevel2->dX0l);
      //
      // Save tracker track sequence number
      //	
      event->trkseqno = nt;
      //
      // Copy values in the class ca from the structure clevel2
      //
      if ( debug ) printf("track %i Call FillTrkVar() \n",nt);
      event->FillTrkVar(pcalo,ntrkentry);


      ntrkentry++;	
      //      filled = true;
      //
    }; // loop on all the tracks
  };
  // 
  // if no tracks found but there is the possibility to have a good track we should try to calculate anyway the track related variables using the calorimeter 
  // fit of the track (to be used for example when TRK is off due to any reason like IPM3/5 off).
  // here we make an event selection so it must be done very carefully...
  //
  // conditions are: 0) no track from the tracker 1) we have a track fit both in x and y 2) no problems with calo for this event 3) no selftrigger event
  //
  //  if ( trackanyway && !filled && event->clevel2->npcfit[0] >= 2 && event->clevel2->npcfit[1] >= 2 && event->clevel2->good != 0 && event->clevel2->trigty < 2. ){
  if ( (trackanyway && m3) || forcecalo ){
    if ( debug ) printf(" Event with a track not fitted by the tracker \n");
    //
    // Disable "track mode" in the fortran routine
    //
    event->clevel1->good2 = 0;
    event->clevel1->riginput = rigdefault;
    if ( debug ) printf(" Using as default rigidity: %f \n",event->clevel1->riginput);
    //
    // We have a selftrigger event to analyze.
    //
    for (Int_t e = 0; e < 5 ; e++){
      event->clevel1->al_p[e][0] = 0.;
      event->clevel1->al_p[e][1] = 0.;
    };
    event->clevel1->trkchi2 = 0;
    //
    if ( debug ) printf("-3 a Call GetTrkVar() \n");
    event->GetTrkVar();
    //
    // if we had no problem (clevel1->good2 = 0, NOTICE zero, not one in this mode!), fill and go on
    //
    if ( event->clevel1->good2 == 0 ) {
      //
      // In selftrigger mode the trkentry variable is set to -1
      //
      event->trkseqno = -3;
      //
      // Copy values in the class ca from the structure clevel2
      //
      if ( debug ) printf("-3 a Call FillTrkVar() \n");
      event->FillTrkVar(pcalo,ntrkentry);
      ntrkentry++;
      //      filled = true;
      //
    } else {
      if ( debug ) printf(" Selftrigger: problems with event \n");
    };
    //
  };
  //
  // Call high energy nuclei routine
  //
  //  if ( hZn && event->clevel2->trigty >= 2. ){
  if ( hZn && m2 ){
    if ( debug ) printf(" Calling selftrigger high energy nuclei routine \n");
    //
    // Disable "track mode" in the fortran routine
    //
    event->clevel1->good2 = 0;
    //
    // Set high energy nuclei flag to one
    // 
    event->clevel1->hzn = 1; 
    event->clevel1->riginput = rigdefault;
    //
    // We have a selftrigger event to analyze.
    //
    for (Int_t e = 0; e < 5 ; e++){
      event->clevel1->al_p[e][0] = 0.;
      event->clevel1->al_p[e][1] = 0.;
    };
    event->clevel1->trkchi2 = 0;
    //
    if ( debug ) printf("-2 a Call GetTrkVar() \n");
    event->GetTrkVar();
    //
    // if we had no problem (clevel1->good2 = 0, NOTICE zero, not one in this mode!), fill and go on
    //
    if ( event->clevel1->good2 == 0 ) {
      //
      // In selftrigger mode the trkentry variable is set to -1
      //
      event->trkseqno = -2;
      //
      // Copy values in the class ca from the structure clevel2
      //
      if ( debug ) printf("-2 a Call FillTrkVar() \n");
      event->FillTrkVar(pcalo,ntrkentry);
      ntrkentry++;
      //      filled = true;
      //
    } else {
      if ( debug ) printf(" Selftrigger: problems with event \n");
    };
    //
  };
  //
  // self trigger event
  //
  //  if ( st && event->clevel2->trigty >= 2. ){
  if ( st && m1 ){
    if ( debug ) printf(" Selftrigger event  \n");
    //
    // Disable "track mode" in the fortran routine
    //
    event->clevel1->good2 = 0;
    //
    // disable high enery nuclei flag;
    //
    event->clevel1->hzn = 0; 
    //
    // We have a selftrigger event to analyze.
    //
    for (Int_t e = 0; e < 5 ; e++){
      event->clevel1->al_p[e][0] = 0.;
      event->clevel1->al_p[e][1] = 0.;
    };
    event->clevel1->trkchi2 = 0;
    //
    if ( debug ) printf("-1 a Call GetTrkVar() \n");
    event->GetTrkVar();
    //
    // if we had no problem (clevel2->good = 0, NOTICE zero, not one in selftrigger mode!), fill and go on
    //
    if ( event->clevel1->good2 == 0 ) {
      //
      // In selftrigger mode the trkentry variable is set to -1
      //
      event->trkseqno = -1;
      //
      // Copy values in the class ca from the structure clevel2
      //
      if ( debug ) printf("-1 a Call FillTrkVar() \n");
      event->FillTrkVar(pcalo,ntrkentry);
      ntrkentry++;
      //      filled = true;
      //
    } else {
      if ( debug ) printf(" Selftrigger: problems with event \n");
    };
  };
//   //
//   // Clear structures used to communicate with fortran
//   //
//   event->ClearStructs();
// ELENA: moved @ beginning
  //
  //
  //
  if ( debug ) this->Print();
  if ( debug ) printf(" exit \n");
  //
}

//
// Method to add a calorimeter track, evaluated around a tracker track defined by a status vector.
// (can be used to evaluate the calorimeter track around an arbitrary axis, by setting the status vector with zero deflection )
// 
//
CaloTrkVar* CaloPreSampler::AddCaloTrkVar(float *al,int trktag){

    int ntrkentry = pcalo->ntrk();
    //
    for (Int_t nt=0; nt < ntrkentry; nt++){  
	if( pcalo->GetCaloTrkVar(nt)->trkseqno == trktag){
	    cout << " CaloTrkVar* CaloPreSampler::AddCaloTrkVar(float *al,int trktag)"<<endl;
	    cout << " --> trktag = "<<trktag<<" already defined "<<endl;
	    return NULL;
	}
    }
    //
    event->clevel1->good2 = 1; //is a trk track
    event->clevel1->trkchi2 = 0;
    event->clevel1->hzn = 0; 
    //
    // Copy the alpha vector in the input structure
    //
    for (Int_t e = 0; e < 5 ; e++){
	event->clevel1->al_p[e][0] = al[e];
    };	  
    //
    // Get tracker related variables for this track
    //
    if ( debug ) printf("track %i Call GetTrkVar() \n",trktag);
    event->GetTrkVar();
    if ( debug ) printf(" event->clevel2->dX0l %f \n",event->clevel2->dX0l);
    //
    // Save tracker track sequence number
    //	
    event->trkseqno = trktag;
    //
    // Copy values in the class ca from the structure clevel2
    //
    if ( debug ) printf("track %i Call FillTrkVar() \n",trktag);
    event->FillTrkVar(pcalo,ntrkentry);

    return pcalo->GetCaloTrkVar(ntrkentry);
    

};//ELENA
