/**
 * \file src/CaloLevel1.cpp
 * \author Emiliano Mocchiutti
 *
**/
#include <TObject.h>
#include <TMath.h>
#include <CaloLevel1.h>
//
ClassImp(CaloStrip);
ClassImp(CaloLevel1);

/**
 * CaloStrip default constructor
**/
CaloStrip::CaloStrip() {
  c1 = 0;
  this->Clear();
};

/**
 * CaloStrip default constructor
**/
CaloStrip::CaloStrip(CaloLevel1 *calo) {
  c1 = calo->GetCaloLevel1();
  this->Clear();
};

/**
 * Clear variables
**/
void CaloStrip::Clear() {
  fE = 0.;
  fX = 0.;
  fY = 0.;
  fZ = 0.;
  fView = 0;  
  fPlane = 0;
  fStrip = 0;
};

/**
 * Given a strip returns its position in the PAMELA reference system
**/
void CaloStrip::Set(Int_t view, Int_t plane, Int_t strip) {
  //
  this->Clear();
  //
  if ( view < 0 || view > 1 ){
    printf(" ERROR: 0 =< view =< 1 \n");
    return;
  };
  if ( plane < 0 || plane > 21 ){
    printf(" ERROR: 0 =< plane =< 21 \n");
    return;
  };
  if ( strip < 0 || strip > 95 ){
    printf(" ERROR: 0 =< strip =< 95 \n");
    return;
  };
  //
  Float_t lShift = 0.;
  Float_t lPos = 0.;
  extern struct shift shift_;
  //
  // Find MIPs for that strip
  //
  if ( c1 ) fE = c1->GetEstrip(view, plane, strip);
  //
  fView = view + 1;
  fPlane = plane + 1;
  fStrip = strip + 1;
  if ( fPlane%2 ){
    lShift = -0.5;
  } else {
    lShift = 0.5;
  };
  //
  shift_.shift = lShift;
  //
  Float_t zplane[22];
  zplane[0] = 0.;
  Int_t ii = 0;
  for ( Int_t i = 2; i < 23; i++){
    ii = i-1;
    if ( i%2 ){
      zplane[ii] = zplane[ii-1] - 10.09;
    } else {
      zplane[ii] = zplane[ii-1] - 8.09;
    };
  };
  //
  millim_(&fStrip,&lPos);
  //
  if ( fView == 1 ){
    //
    // X view
    //
    fX = (lPos - CTX)/10.;
    fY = 0.;
    fZ = (zplane[fPlane-1] - 5.81 + CTZ)/10.;    
  } else {
    //
    // Y view
    //
    fX = 0;
    fY = (lPos - CTY)/10.;
    fZ = (zplane[fPlane-1] + CTZ)/10.;
  };
  //  
};

/**
 * Given a point in the space (PAMELA ref system) returns the closest strip
**/
void CaloStrip::Set(Float_t X, Float_t Y, Float_t Z) {
  //
  fX = X;
  fY = Y;
  fZ = Z;
  //
  Float_t zplane[22];
  zplane[0] = 0.;
  Int_t ii = 0;
  for ( Int_t i = 2; i < 23; i++){
    ii = i-1;
    if ( i%2 ){
      zplane[ii] = zplane[ii-1] - 10.09;
    } else {
      zplane[ii] = zplane[ii-1] - 8.09;
    };
  };
  //
  Float_t dzx[22];
  Float_t dzy[22];
  for ( Int_t i=0; i < 22; i++){
    dzx[i] = fabs(fZ*10. - (zplane[i] - 5.81 + CTZ));
    dzy[i] = fabs(fZ*10. - (zplane[i] + CTZ));    
  };
  //
  Float_t minx = TMath::MinElement(22,dzx);
  Float_t miny = TMath::MinElement(22,dzy);
  //
  // find view
  //
  if ( minx < miny ){
    fView = 1;
  } else {
    fView = 2;
  };
  //
  // find plane
  //
  Float_t pos = 0.;
  //
  for ( Int_t i=0; i < 22; i++){
    if ( fView == 1 ){
      if ( dzx[i] == minx ){
	fPlane = i+1;
	pos = fX*10. + CTX;
      };
    } else {
      if ( dzy[i] == miny ){
	fPlane = i+1;
	pos = fY*10. + CTY;
    };
    };
  };
  //
  // find strip
  //
  Float_t dxy[96];
  Float_t stpos = 0.;
  //
  CaloStrip *ca = new CaloStrip();
  //
  for ( Int_t i=0; i < 96; i++){
    ca->Set(fView-1,fPlane-1,i);
    if ( fView == 1 ){
      stpos = ca->GetX()*10. + CTX;
    } else {
      stpos = ca->GetY()*10. + CTY;
    };
    dxy[i] = fabs(pos - stpos);
  };
  //
  delete ca;
  //  
  Float_t mins =  TMath::MinElement(96,dxy);
  //
  for ( Int_t i=0; i < 96; i++){
    if ( dxy[i] == mins ) fStrip = i+1; 
  };
};

/**
 * CaloLevel1 constructor
**/
CaloLevel1::CaloLevel1() {    
  //
  estrip = TArrayI(0,NULL);
  //
  this->Clear();
  //
};

/**
 * Clear the CaloLevel1 object
 **/
void CaloLevel1::Clear() {    
  //
  istrip = 0;
  estrip.Reset();
  //
};

/**
 * Returns the detected energy for the given strip once loaded the event
**/
Float_t CaloLevel1::GetEstrip(Int_t sview, Int_t splane, Int_t sstrip){
  Int_t view = -1;
  Int_t plane = -1;
  Int_t strip = -1;
  Float_t mip = 0.;
  //
  if ( istrip == 0 ) return(0.);
  //
  for (Int_t i = 0; i<istrip; i++ ){
    //
    mip = DecodeEstrip(i,view,plane,strip);
    //
    if ( view == sview && splane == plane && sstrip == strip ) return(mip);
    //
    // entry are ordered by strip, plane and view number. Go out if you pass the input strip
    //
    if ( view == sview && plane == splane && strip > sstrip ) return(0.);
    if ( view == sview && plane > splane ) return(0.);
    if ( view > sview ) return(0.);
    //
  };
  return(0.);
};

/**
 * Given estrip entry returns energy plus view, plane and strip numbers
**/
Float_t CaloLevel1::DecodeEstrip(Int_t entry, Int_t &view, Int_t &plane, Int_t &strip){
  //
  if ( entry>istrip ) return(0.);
  //
  //  printf(" num lim %f \n",std::numeric_limits<Float_t>::max());
  //  printf(" estrip.At(%i) = %i \n",entry,estrip.At(entry));
  //
  Int_t eval = 0;
  if ( estrip.At(entry) > 0. ){
    view = 0;
    eval = estrip.At(entry);
  } else {
    view = 1;
    eval = -estrip.At(entry);
  };
  //
  Int_t fbi = 0;
  fbi = (Int_t)truncf((Float_t)(eval/1000000000));
  //
  Int_t plom = 0;
  plom = (Int_t)truncf((Float_t)((eval-fbi*1000000000)/10000000));
  //
  Float_t tim = 100000.;
  plane = plom;
  if ( fbi == 1 ) tim = 10000.;
  if ( plom > 21 ){
    plane = plom - 22;
    if ( fbi == 1 ){
      tim = 1000.;
    } else {
      tim = 100.;
    };
  };
  if ( plom > 43 ){
    plane = plom - 44;
    tim = 10.;
  };
  if ( plom > 65 ){
    plane = plom - 66;
    tim = 1.;
  };
  //
  strip = (Int_t)truncf((Float_t)((eval - fbi*1000000000 -plom*10000000)/100000));
  //
  Float_t mip = ((Float_t)(eval - fbi*1000000000 -plom*10000000 -strip*100000))/tim;
  //
  if ( mip > 0. && mip < 99999. ) return(mip);
  //
  printf(" WARNING: problems decoding value %i at entry %i \n",estrip.At(entry),entry);
  //
  view = -1;
  plane = -1;
  strip = -1;
  return(0.);  
}

/*
 * Returns energy released on plane nplane (where 0<= nplane <= 43, 0 = 1Y, 1 = 1X, 2 = 2Y, 3 = 2X, etc. etc.).
 */
Float_t CaloLevel1::qtotpl(Int_t nplane){
  //
  Int_t sview = 1;
  if ( nplane%2 ) sview = 0;
  //
  Int_t splane = nplane-(sview+1)/2;
  //
  Float_t totmip = qtotpl(sview,splane);
  //
  return(totmip);
  //
};

/*
 * Returns energy released on view "view" (0 = X, 1 = Y) and plane "plane" ( 0 <= plane <= 21 ).
 */
Float_t CaloLevel1::qtotpl(Int_t sview, Int_t splane){
  //
  Int_t view = -1;
  Int_t plane = -1;
  Int_t strip = -1;
  //
  Float_t mip = 0.;
  Float_t totmip = 0.;
  //
  if ( istrip == 0 ) return(0.);
  //
  for (Int_t i = 0; i<istrip; i++ ){
    //
    mip = DecodeEstrip(i,view,plane,strip);
    //
    if ( view == sview && splane == plane ) totmip += mip;
    //
    // entry are ordered by strip, plane and view number. Go out if you pass the input strip
    //
    if ( view == sview && plane > splane ) return(totmip);
    if ( view > sview ) return(totmip);
    //
  };
  //
  return(totmip);
  //
};
