#include <TObject.h>
#include <ToFLevel2.h>
#include <iostream>
using namespace std;
ClassImp(ToFPMT);
ClassImp(ToFTrkVar);
ClassImp(ToFLevel2);

ToFPMT::ToFPMT(){
  pmt_id = 0;
  adc = 0.;
  tdc_tw = 0.;
}

ToFPMT::ToFPMT(const ToFPMT &t){
  pmt_id = t.pmt_id;
  adc = t.adc;
  tdc_tw = t.tdc_tw;
}

void ToFPMT::Clear(){
  pmt_id = 0;
  adc = 0.;
  tdc_tw = 0.;
}



ToFTrkVar::ToFTrkVar() {
  trkseqno = 0;
  npmttdc = 0;
  npmtadc = 0;
  pmttdc = TArrayI(48);
  pmtadc = TArrayI(48);
  dedx = TArrayF(48);
  //
  //
  memset(beta,  0, 13*sizeof(Float_t));
  memset(xtofpos,  0, 3*sizeof(Float_t));
  memset(ytofpos,  0, 3*sizeof(Float_t));
  //
};

void ToFTrkVar::Clear() {
  trkseqno = 0;
  npmttdc = 0;
  npmtadc = 0;
  pmttdc.Reset();
  pmtadc.Reset();
  dedx.Reset(); 
  //
  memset(beta,  0, 13*sizeof(Float_t));
  memset(xtofpos,  0, 3*sizeof(Float_t));
  memset(ytofpos,  0, 3*sizeof(Float_t));
  //
};

ToFTrkVar::ToFTrkVar(const ToFTrkVar &t){

  trkseqno = t.trkseqno;  
  //
  npmttdc = t.npmttdc;
  npmtadc = t.npmtadc;
  (t.pmttdc).Copy(pmttdc);
  (t.pmtadc).Copy(pmtadc);
  (t.dedx).Copy(dedx);
  //
  memcpy(beta,t.beta,sizeof(beta));
  memcpy(xtofpos,t.xtofpos,sizeof(xtofpos));
  memcpy(ytofpos,t.ytofpos,sizeof(ytofpos));
  //
};

ToFLevel2::ToFLevel2() {    
  //
  PMT = new TClonesArray("ToFPMT",12);
  ToFTrk = new TClonesArray("ToFTrkVar",2);
  //
  memset(tof_j_flag, 0, 6*sizeof(Int_t));
};

void ToFLevel2::Clear(){
  //
  ToFTrk->Clear();
  PMT->Clear();
  memset(tof_j_flag, 0, 6*sizeof(Int_t));
  // 
};

ToFTrkVar *ToFLevel2::GetToFTrkVar(Int_t itrk){
  //    
  if(itrk >= ntrk()){
    printf(" ToFLevel2 ERROR: track related variables set %i does not exists! \n",itrk);
    printf("                      stored track related variables = %i \n",ntrk());
    return(NULL);
  }  
  //
  TClonesArray &t = *(ToFTrk);
  ToFTrkVar *toftrack = (ToFTrkVar*)t[itrk];
  return toftrack;
}

ToFPMT *ToFLevel2::GetToFPMT(Int_t ihit){
  //    
  if(ihit >= npmt()){
    printf(" ToFLevel2 ERROR: pmt variables set %i does not exists! \n",ihit);
    printf("                  stored pmt variables = %i \n",npmt());
    return(NULL);
  }  
  //
  TClonesArray &t = *(PMT);
  ToFPMT *tofpmt = (ToFPMT*)t[ihit];
  return tofpmt;
}
//--------------------------------------
//
// 
//--------------------------------------
/**
 * Method to get the plane ID (11 12 21 22 31 32) from the plane index (0 1 2 3 4 5)
 */
  Int_t  ToFLevel2::GetToFPlaneID(Int_t ip){ 
      if(ip>=0 && ip<6)return 10*((int)(ip/2+1.1))+(ip%2)+1;
      else return -1;
  };
/**
 * Method to get the plane index (0 1 2 3 4 5) from the plane ID (11 12 21 22 31 32)
 */
  Int_t  ToFLevel2::GetToFPlaneIndex(Int_t plane_id){ 
      if(
	 plane_id == 11 ||
	 plane_id == 12 ||
	 plane_id == 21 ||
	 plane_id == 22 ||
	 plane_id == 31 ||
	 plane_id == 32 ||
	 false)return (Int_t)(plane_id/10)*2-1- plane_id%2;
      else return -1;
  };
/**
 * Method to know if a given ToF paddle was hit, that is there is a TDC signal from both PMTs
 * @param plane Plane ID (11, 12, 21, 22, 31, 32) or Plane index (0,1,2,3,4,5).
 * @param paddle_id Paddle ID.
 * @return 1 if the paddle was hit.
 */
  Bool_t ToFLevel2::HitPaddle(Int_t plane, Int_t paddle_id){  //<<< NEW
    Int_t ip = -1;
    if     (plane>=6             ) ip = GetToFPlaneIndex(plane);
    else if(plane>=0 && plane < 6) ip = plane;
    Int_t flag=0;
    if(ip != -1)flag = tof_j_flag[ip] & (int)pow(2.,(double)paddle_id);
    if(
       (ip == 0 && paddle_id < 8 && flag) ||
       (ip == 1 && paddle_id < 6 && flag) ||
       (ip == 2 && paddle_id < 2 && flag) ||
       (ip == 3 && paddle_id < 2 && flag) ||
       (ip == 4 && paddle_id < 3 && flag) ||
       (ip == 5 && paddle_id < 3 && flag) ||
       false) return true;
    else return false;
};
/**
 * Method to get the number of hit paddles on a ToF plane.
 * @param plane Plane ID (11, 12, 21, 22, 31, 32) or Plane index (0,1,2,3,4,5).
 */
Int_t ToFLevel2::GetNHitPaddles(Int_t plane){
    Int_t npad=0;
    for(Int_t i=0; i<8; i++)npad = npad + (int)HitPaddle(plane,i);
    return npad;
};


Float_t ToFLevel2::GetdEdx(Int_t notrack, Int_t plane){
  Float_t dedx = 0.;
  Int_t ip = 0;
  Int_t pmt_id = 0;
  Int_t pl = 0;
  if ( plane >= 6 ){
    ip = GetToFPlaneIndex(plane);
  } else {
    ip = plane;
  };
  //
  ToFTrkVar *trk = GetToFTrkVar(notrack);
  //
  for (Int_t i=0; i<trk->npmtadc; i++){
    //
    pmt_id = (trk->pmtadc).At(i);
    //
    pl = GetPlaneIndex(pmt_id);
    //
    if ( pl == ip ) dedx += (trk->dedx).At(i);   
    //
  };
  //
  return(dedx);
};


void ToFLevel2::GetMatrix(Int_t notrack, Float_t adc[4][12], Float_t tdc[4][12]){
  //
  for (Int_t aa=0; aa<4;aa++){
    for (Int_t bb=0; bb<12;bb++){
      adc[aa][bb] = 1000.;
      tdc[aa][bb] = 4095.;
    };
  };
  //
  Int_t pmt_id = 0;
  Int_t hh = 0;
  Int_t kk = 0;
  //
  ToFTrkVar *trk = GetToFTrkVar(notrack);
  //
  for (Int_t i=0; i<trk->npmtadc; i++){
    //
    pmt_id = (trk->pmtadc).At(i);
    //
    GetPMTIndex(pmt_id,hh,kk);
    adc[kk][hh] = (trk->dedx).At(i);   
    //
  };
  //
  for (Int_t i=0; i<npmt(); i++){
    //
    ToFPMT *pmt = GetToFPMT(i);
    //
    GetPMTIndex(pmt->pmt_id,hh,kk);
    //
    tdc[kk][hh] = pmt->tdc_tw;   
    //
  };
  //
  return;
};



Int_t ToFLevel2::GetPlaneIndex(Int_t pmt_id){
  TString pmtname = GetPMTName(pmt_id);
  pmtname.Resize(3);
  if ( !strcmp(pmtname,"S11") ) return(0);
  if ( !strcmp(pmtname,"S12") ) return(1);
  if ( !strcmp(pmtname,"S21") ) return(2);
  if ( !strcmp(pmtname,"S22") ) return(3);
  if ( !strcmp(pmtname,"S31") ) return(4);
  if ( !strcmp(pmtname,"S32") ) return(5);
  return(-1);
};


Int_t ToFLevel2::GetPMTid(Int_t hh, Int_t kk){
  //
  short tof[4][24] = {
    {4, 4,  4,  4,  1,  1, 2, 2,  3,  3, 3, 3,  3,  3, 1, 1,  1,  1, 2, 3,  3, 3, 3,  4},
    {1, 3,  5,  7, 10, 12, 2, 4,  2,  4, 6, 8, 10, 12, 1, 5,  3,  9, 7, 9, 11, 1, 5,  9},
    {2, 2,  2,  2,  1,  1, 1, 1,  4,  4, 4, 4,  4,  4, 2, 1,  2,  1, 2, 2,  2, 3, 3,  4},
    {6, 8, 12, 10,  8,  6, 4, 2, 12, 10, 8, 6,  4,  2, 9, 7, 11, 11, 5, 3,  1, 3, 7, 11}
  };
  //
  Int_t ind = 0;
  Int_t k = 0;
  while (k < 24){
    Int_t j = 0;
    while (j < 2){
      Int_t ch = tof[2*j][k]     - 1;
      Int_t hb = tof[2*j + 1][k] - 1;      
      /* tofEvent->tdc[ch][hb] */      
      if( ch == hh && hb == kk ){	
	ind = 2*k + j;
	break;
      };
      j++;
    };
    k++;
  };
  return ind;
};

TString ToFLevel2::GetPMTName(Int_t ind){
  
  TString pmtname = " ";
  
  TString photoS[48] = {
    "S11_1A", "S11_1B", "S11_2A", "S11_2B", "S11_3A", "S11_3B", "S11_4A", "S11_4B", 
    "S11_5A", "S11_5B", "S11_6A", "S11_6B", "S11_7A", "S11_7B", "S11_8A", "S11_8B", 
    "S12_1A", "S12_1B", "S12_2A", "S12_2B", "S12_3A", "S12_3B", "S12_4A", "S12_4B", "S12_5A",  "S12_5B", "S12_6A", "S12_6B",
    "S21_1A", "S21_1B", "S21_2A", "S21_2B", 
    "S22_1A", "S22_1B", "S22_2A", "S22_2B",
    "S31_1A", "S31_1B", "S31_2A", "S31_2B", "S31_3A", "S31_3B", 
    "S32_1A", "S32_1B", "S32_2A", "S32_2B", "S32_3A", "S32_3B"
  };
  

  pmtname = photoS[ind].Data();

  return pmtname;
};


void ToFLevel2::GetPMTIndex(Int_t ind, Int_t &hb, Int_t &ch){
  //
  short tof[4][24] = {
    {4, 4,  4,  4,  1,  1, 2, 2,  3,  3, 3, 3,  3,  3, 1, 1,  1,  1, 2, 3,  3, 3, 3,  4},
    {1, 3,  5,  7, 10, 12, 2, 4,  2,  4, 6, 8, 10, 12, 1, 5,  3,  9, 7, 9, 11, 1, 5,  9},
    {2, 2,  2,  2,  1,  1, 1, 1,  4,  4, 4, 4,  4,  4, 2, 1,  2,  1, 2, 2,  2, 3, 3,  4},
    {6, 8, 12, 10,  8,  6, 4, 2, 12, 10, 8, 6,  4,  2, 9, 7, 11, 11, 5, 3,  1, 3, 7, 11}
  };
  //
  Int_t k = 0;
  while (k < 24){
    Int_t j = 0;
    while (j < 2){
      /* tofEvent->tdc[ch][hb] */            
      if( ind == 2*k + j ){
 	ch = tof[2*j][k]     - 1;
 	hb = tof[2*j + 1][k] - 1;      
	return;
      };
      j++;
    };
    k++;
  };
  return;
};

/**
 * Fills a struct cToFLevel2 with values from a ToFLevel2 object (to put data into a F77 common).
 */
void ToFLevel2::GetLevel2Struct(cToFLevel2 *l2) const{

  for(Int_t i=0;i<6;i++)
    l2->tof_j_flag[i]=tof_j_flag[i];

  l2->ntoftrk = ToFTrk->GetEntries();
  for(Int_t j=0;j<l2->ntoftrk;j++){
    l2->toftrkseqno[j]= ((ToFTrkVar*)ToFTrk->At(j))->trkseqno;
    l2->npmttdc[j]= ((ToFTrkVar*)ToFTrk->At(j))->npmttdc;
    for(Int_t i=0;i<l2->npmttdc[j];i++)
      l2->pmttdc[i][j] = ((ToFTrkVar*)ToFTrk->At(j))->pmttdc.At(i);
    for(Int_t i=0;i<13;i++)
      l2->beta[i][j] = ((ToFTrkVar*)ToFTrk->At(j))->beta[i];

    l2->npmtadc[j]= ((ToFTrkVar*)ToFTrk->At(j))->npmtadc;
    for(Int_t i=0;i<l2->npmtadc[j];i++){
      l2->pmtadc[i][j] = ((ToFTrkVar*)ToFTrk->At(j))->pmtadc.At(i);
      l2->dedx[i][j] = ((ToFTrkVar*)ToFTrk->At(j))->dedx.At(i);
    }
    for(Int_t i=0;i<3;i++){
      l2->xtofpos[i][j]=((ToFTrkVar*)ToFTrk->At(j))->xtofpos[i];
      l2->ytofpos[i][j]=((ToFTrkVar*)ToFTrk->At(j))->ytofpos[i];
    }
  }
    
  l2->npmt = PMT->GetEntries();
   for(Int_t j=0;j<l2->npmt;j++){
     l2->pmt_id[j] = ((ToFPMT*)PMT->At(j))->pmt_id;
     l2->adc[j] =((ToFPMT*)PMT->At(j))->adc;
     l2->tdc_tw[j] =((ToFPMT*)PMT->At(j))->tdc_tw;
   }
}
