#include "THaEvData.h"
#include "THaCutList.h"
#include "VarDef.h"
#include "VarType.h"
#include "TClonesArray.h"

#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <iostream>

#include "THaApparatus.h"
#include "THcGlobals.h"
#include "THcHodoHit.h"
#include "THcParmList.h"
#include "TrackingEfficiency.h"

namespace hcana {

  using namespace std;

  TrackingEfficiency::TrackingEfficiency(const char* name, const char* description,
                                         const char* hodname)
      : THaPhysicsModule(name, description) {}

  TrackingEfficiency::~TrackingEfficiency() {
    // Destructor
    RemoveVariables();
  }
  //_____________________________________________________________________________
  
  void TrackingEfficiency::Reset(Option_t* opt)
  // Clear event-by-event data
  {
    Clear(opt);
  }

  //_____________________________________________________________________________
  Int_t TrackingEfficiency::Begin(THaRunBase*) {
    // Start of analysis

    //if (!IsOK())
    //  return -1;

    //// Book any special histograms here

    //fNevt = 0;

    //// Clear all the accumulators here
    //for (Int_t ip = 0; ip < fNPlanes; ip++) {
    //  fHitPlane[ip] = 0;
    //  for (Int_t ic = 0; ic < fNCounters[ip]; ic++) {
    //    fStatPosHit[ip][ic] = 0;
    //    fStatNegHit[ip][ic] = 0;
    //    fStatAndHit[ip][ic] = 0;
    //    fStatOrHit[ip][ic]  = 0;
    //    fBothGood[ip][ic]   = 0;
    //    fPosGood[ip][ic]    = 0;
    //    fNegGood[ip][ic]    = 0;
    //    for (Int_t idel = 0; idel < 20; idel++) {
    //      fStatTrkDel[ip][ic][idel]    = 0;
    //      fStatAndHitDel[ip][ic][idel] = 0;
    //    }
    //  }
    //}

    return 0;
  }

  //_____________________________________________________________________________
  Int_t TrackingEfficiency::End(THaRunBase*) {
    //// End of analysis
    //for (Int_t ip = 0; ip < fNPlanes; ip++) {
    //  fStatAndEff[ip] = 0;
    //  for (Int_t ic = 0; ic < fNCounters[ip]; ic++) {
    //    fStatTrkSum[ip] += fStatTrk[fHod->GetScinIndex(ip, ic)];
    //    fStatAndSum[ip] += fHodoAndEffi[fHod->GetScinIndex(ip, ic)];
    //  }
    //  if (fStatTrkSum[ip] != 0)
    //    fStatAndEff[ip] = float(fStatAndSum[ip]) / float(fStatTrkSum[ip]);
    //}
    ////
    //Double_t p1 = fStatAndEff[0];
    //Double_t p2 = fStatAndEff[1];
    //Double_t p3 = fStatAndEff[2];
    //Double_t p4 = fStatAndEff[3];
    //// probability that ONLY the listed planes had triggers
    //Double_t p1234  = p1 * p2 * p3 * p4;
    //Double_t p123   = p1 * p2 * p3 * (1. - p4);
    //Double_t p124   = p1 * p2 * (1. - p3) * p4;
    //Double_t p134   = p1 * (1. - p2) * p3 * p4;
    //Double_t p234   = (1. - p1) * p2 * p3 * p4;
    //fHodoEff_s1     = 1. - ((1. - p1) * (1. - p2));
    //fHodoEff_s2     = 1. - ((1. - p3) * (1. - p4));
    //fHodoEff_tof    = fHodoEff_s1 * fHodoEff_s2;
    //fHodoEff_3_of_4 = p1234 + p123 + p124 + p134 + p234;
    //fHodoEff_4_of_4 = p1234;
    return 0;
  }

  //_____________________________________________________________________________
  THaAnalysisObject::EStatus TrackingEfficiency::Init(const TDatime& run_time) {
    // Initialize TrackingEfficiency physics module

    //  const char* const here = "Init";

    // Standard initialization. Calls ReadDatabase(), ReadRunDatabase(),
    // and DefineVariables() (see THaAnalysisObject::Init)

    //fHod = dynamic_cast<THcHodoscope*>(FindModule(fName.Data(), "THcHodoscope"));

    //fSpectro = static_cast<THaSpectrometer*>(fHod->GetApparatus());

    //if (THaPhysicsModule::Init(run_time) != kOK)
    //  return fStatus;

    //cout << "TrackingEfficiency::Init nplanes=" << fHod->GetNPlanes() << endl;
    //cout << "TrackingEfficiency::Init Apparatus = " << fHod->GetName() << " "
    //     << (fHod->GetApparatus())->GetName() << endl;

    return fStatus = kOK;
  }

  //_____________________________________________________________________________
  Int_t TrackingEfficiency::ReadDatabase(const TDatime& date) {
    //// Read database. Gets variable needed for efficiency calculation
    //// Get # of planes and their z positions here.

    //fNPlanes     = fHod->GetNPlanes();
    //fPlanes      = new THcScintillatorPlane*[fNPlanes];
    //fPosZ        = new Double_t[fNPlanes];
    //fSpacing     = new Double_t[fNPlanes];
    //fCenterFirst = new Double_t[fNPlanes];
    //fNCounters   = new Int_t[fNPlanes];
    //fHodoSlop    = new Double_t[fNPlanes];
    //fStatTrkSum  = new Int_t[fNPlanes];
    //fStatAndSum  = new Int_t[fNPlanes];
    //fStatAndEff  = new Double_t[fNPlanes];

    //Int_t maxcountersperplane = 0;
    //for (Int_t ip = 0; ip < fNPlanes; ip++) {
    //  fStatTrkSum[ip]     = 0.;
    //  fStatAndSum[ip]     = 0.;
    //  fStatAndEff[ip]     = 0.;
    //  fPlanes[ip]         = fHod->GetPlane(ip);
    //  fPosZ[ip]           = fPlanes[ip]->GetZpos() + 0.5 * fPlanes[ip]->GetDzpos();
    //  fSpacing[ip]        = fPlanes[ip]->GetSpacing();
    //  fCenterFirst[ip]    = fPlanes[ip]->GetPosCenter(0) + fPlanes[ip]->GetPosOffset();
    //  fNCounters[ip]      = fPlanes[ip]->GetNelem();
    //  maxcountersperplane = TMath::Max(maxcountersperplane, fNCounters[ip]);
    //}
    //Int_t totalpaddles = fNPlanes * maxcountersperplane;
    //fHodoPosEffi       = new Int_t[totalpaddles];
    //fHodoNegEffi       = new Int_t[totalpaddles];
    //fHodoOrEffi        = new Int_t[totalpaddles];
    //fHodoAndEffi       = new Int_t[totalpaddles];
    //fStatTrk           = new Int_t[totalpaddles];

    //char prefix[2];
    //prefix[0] = tolower((fHod->GetApparatus())->GetName()[0]);
    //prefix[1] = '\0';

    //DBRequest list[]       = {{"stat_slop", &fStatSlop, kDouble},
    //                    {"stat_maxchisq", &fMaxChisq, kDouble},
    //                    {"HodoEff_CalEnergy_Cut", &fHodoEff_CalEnergy_Cut, kDouble, 0, 1},
    //                    {"hodo_slop", fHodoSlop, kDouble, (UInt_t)fNPlanes},
    //                    {0}};
    //fHodoEff_CalEnergy_Cut = 0.050; // set default value
    //gHcParms->LoadParmValues((DBRequest*)&list, prefix);
    //cout << "\n\nTrackingEfficiency::ReadDatabase nplanes=" << fHod->GetNPlanes() << endl;
    //// Setup statistics arrays
    //// Better method to put this in?
    //// These all need to be cleared in Begin
    //fHitPlane = new Int_t[fNPlanes];
    //fStatTrkDel.resize(fNPlanes);
    //fStatAndHitDel.resize(fNPlanes);
    //fStatPosHit.resize(fNPlanes);
    //fStatNegHit.resize(fNPlanes);
    //fStatAndHit.resize(fNPlanes);
    //fStatOrHit.resize(fNPlanes);
    //fBothGood.resize(fNPlanes);
    //fPosGood.resize(fNPlanes);
    //fNegGood.resize(fNPlanes);

    //for (Int_t ip = 0; ip < fNPlanes; ip++) {

    //  cout << "Plane = " << ip + 1 << "    counters = " << fNCounters[ip] << endl;

    //  fStatTrkDel[ip].resize(fNCounters[ip]);
    //  fStatAndHitDel[ip].resize(fNCounters[ip]);
    //  fStatPosHit[ip].resize(fNCounters[ip]);
    //  fStatNegHit[ip].resize(fNCounters[ip]);
    //  fStatAndHit[ip].resize(fNCounters[ip]);
    //  fStatOrHit[ip].resize(fNCounters[ip]);
    //  fBothGood[ip].resize(fNCounters[ip]);
    //  fPosGood[ip].resize(fNCounters[ip]);
    //  fNegGood[ip].resize(fNCounters[ip]);
    //  for (Int_t ic = 0; ic < fNCounters[ip]; ic++) {
    //    fStatTrkDel[ip][ic].resize(20);    // Max this settable
    //    fStatAndHitDel[ip][ic].resize(20); // Max this settable

    //    fHodoPosEffi[fHod->GetScinIndex(ip, ic)] = 0;
    //    fHodoNegEffi[fHod->GetScinIndex(ip, ic)] = 0;
    //    fHodoOrEffi[fHod->GetScinIndex(ip, ic)]  = 0;
    //    fHodoAndEffi[fHod->GetScinIndex(ip, ic)] = 0;
    //    fStatTrk[fHod->GetScinIndex(ip, ic)]     = 0;
    //  }
    //}

    //// Int_t fHodPaddles = fNCounters[0];
    //// gHcParms->Define(Form("%shodo_pos_hits[%d][%d]",fPrefix,fNPlanes,fHodPaddles),
    //// 		        "Golden track's pos pmt hit",*&fStatPosHit);

    //gHcParms->Define(Form("%shodo_pos_eff[%d]", prefix, totalpaddles), "Hodo positive effi",
    //                 *fHodoPosEffi);
    //gHcParms->Define(Form("%shodo_neg_eff[%d]", prefix, totalpaddles), "Hodo negative effi",
    //                 *fHodoNegEffi);
    //gHcParms->Define(Form("%shodo_or_eff[%d]", prefix, totalpaddles), "Hodo or effi", *fHodoOrEffi);
    //gHcParms->Define(Form("%shodo_and_eff[%d]", prefix, totalpaddles), "Hodo and effi",
    //                 *fHodoAndEffi);
    //gHcParms->Define(Form("%shodo_plane_AND_eff[%d]", prefix, fNPlanes), "Hodo plane AND eff",
    //                 *fStatAndEff);
    //gHcParms->Define(Form("%shodo_gold_hits[%d]", prefix, totalpaddles), "Hodo golden hits",
    //                 *fStatTrk);
    //gHcParms->Define(Form("%shodo_s1XY_eff", prefix), "Efficiency for S1XY", fHodoEff_s1);
    //gHcParms->Define(Form("%shodo_s2XY_eff", prefix), "Efficiency for S2XY", fHodoEff_s2);
    //gHcParms->Define(Form("%shodo_stof_eff", prefix), "Efficiency for STOF", fHodoEff_tof);
    //gHcParms->Define(Form("%shodo_3_of_4_eff", prefix), "Efficiency for 3 of 4", fHodoEff_3_of_4);
    //gHcParms->Define(Form("%shodo_4_of_4_eff", prefix), "Efficiency for 4 of 4", fHodoEff_4_of_4);

    return kOK;
  }

  //_____________________________________________________________________________
  Int_t TrackingEfficiency::DefineVariables(EMode mode) {

    //if (mode == kDefine && fIsSetup)
    //  return kOK;
    //fIsSetup = (mode == kDefine);

    ////  fEffiTest = 0;
    ////  gHcParms->Define(Form("hodoeffi"),"Testing effi",fEffiTest);

    //const RVarDef vars[] = {// Move these into THcHallCSpectrometer using track fTracks
    //                        // {"effitestvar",    "efficiency test var",      "fEffiTest"},
    //                        // {"goldhodposhit",    "pos pmt hit in hodo",      "fStatPosHit"},
    //                        {0}};
    //return DefineVarsFromList(vars, mode);
    return kOK;
  }

  //_____________________________________________________________________________
  Int_t TrackingEfficiency::Process(const THaEvData& evdata) {
    // Accumulate statistics for efficiency

    // const char* const here = "Process";

    if (!IsOK())
      return -1;

    //// Project the golden track to each
    //// plane.  Need to get track at Focal Plane, not tgt.
    ////
    //// Assumes that planes are X, Y, X, Y
    //THaTrack* theTrack = fSpectro->GetGoldenTrack();
    //// Since fSpectro knows the index of the golden track, we can
    //// get other information about the track from fSpectro.
    //// Need to remove the specialized stuff from fGoldenTrack

    //if (!theTrack)
    //  return 0;
    //Int_t trackIndex = theTrack->GetTrkNum() - 1;

    //// May make these member variables
    //Double_t hitPos[fNPlanes];
    //Double_t hitDistance[fNPlanes];
    //Int_t    hitCounter[fNPlanes];
    //Int_t    checkHit[fNPlanes];
    //// Bool_t goodTdcBothSides[fNPlanes];
    //// Bool_t goodTdcOneSide[fNPlanes];

    //for (Int_t ip = 0; ip < fNPlanes; ip++) {
    //  // Should really have plane object self identify as X or Y
    //  if (ip % 2 == 0) { // X Plane
    //    hitPos[ip] = theTrack->GetX() + theTrack->GetTheta() * fPosZ[ip];
    //    hitCounter[ip] =
    //        TMath::Max(TMath::Min(TMath::Nint((hitPos[ip] - fCenterFirst[ip]) / fSpacing[ip] + 1),
    //                              fNCounters[ip]),
    //                   1);
    //    hitDistance[ip] = hitPos[ip] - (fSpacing[ip] * (hitCounter[ip] - 1) + fCenterFirst[ip]);
    //  } else { // Y Plane
    //    hitPos[ip] = theTrack->GetY() + theTrack->GetPhi() * fPosZ[ip];
    //    hitCounter[ip] =
    //        TMath::Max(TMath::Min(TMath::Nint((fCenterFirst[ip] - hitPos[ip]) / fSpacing[ip] + 1),
    //                              fNCounters[ip]),
    //                   1);
    //    hitDistance[ip] = hitPos[ip] - (fCenterFirst[ip] - fSpacing[ip] * (hitCounter[ip] - 1));
    //  }
    //}

    //// Fill dpos histograms and set checkHit for each plane.
    //// dpos stuff not implemented
    //// Why do dpos stuff here, does any other part need the dpos historgrams
    //// Look to VDCEff code to see how to create and fill histograms

    //for (Int_t ip = 0; ip < fNPlanes; ip++) {
    //  Int_t hitcounter = hitCounter[ip];
    //  // goodTdcBothSides[ip] = kFALSE;
    //  // goodTdcOneSide[ip] = kFALSE;
    //  checkHit[ip]           = 2;
    //  Int_t         nphits   = fPlanes[ip]->GetNScinHits();
    //  TClonesArray* hodoHits = fPlanes[ip]->GetHits();
    //  for (Int_t ihit = 0; ihit < nphits; ihit++) {
    //    THcHodoHit* hit     = (THcHodoHit*)hodoHits->At(ihit);
    //    Int_t       counter = hit->GetPaddleNumber();
    //    if (counter == hitcounter) {
    //      checkHit[ip] = 0;
    //    } else {
    //      if (TMath::Abs(counter - hitcounter) == 1 && checkHit[ip] != 0) {
    //        checkHit[ip] = 1;
    //      }
    //    }
    //  }
    //}

    //// Record position differences between track and center of scin
    //// and increment 'should have hit' counters
    //for (Int_t ip = 0; ip < fNPlanes; ip++) {
    //  // Int_t hitcounter = hitCounter[ip];
    //  Double_t dist = hitDistance[ip];
    //  if (TMath::Abs(dist) <= fStatSlop && theTrack->GetChi2() / theTrack->GetNDoF() <= fMaxChisq &&
    //      theTrack->GetEnergy() >= fHodoEff_CalEnergy_Cut) {
    //    fStatTrk[fHod->GetScinIndex(ip, hitCounter[ip] - 1)]++;
    //    // Double_t delta = theTrack->GetDp();
    //    // Int_t idel = TMath::Floor(delta+10.0);
    //    // Should
    //    // if(idel >=0 && idel < 20) {
    //    //   fStatTrkDel[ip][hitcounter][idel]++;
    //    // }
    //    // lookat[ip] = TRUE;
    //  }
    //  fHitPlane[ip] = 0;
    //}
    //// Is there a hit on or adjacent to paddle that track
    //// passes through?

    //// May collapse this loop into last

    //// record the hits as a "didhit" if track is near center of
    //// scintillator, the chisqared of the track is good and it is the
    //// first "didhit" in that plane.

    //for (Int_t ip = 0; ip < fNPlanes; ip++) {
    //  Int_t hitcounter = hitCounter[ip];
    //  if (hitcounter >= fNCounters[ip])
    //    hitcounter = fNCounters[ip] - 1;
    //  if (hitcounter < 0)
    //    hitcounter = 0;
    //  Double_t      dist     = hitDistance[ip];
    //  Int_t         nphits   = fPlanes[ip]->GetNScinHits();
    //  TClonesArray* hodoHits = fPlanes[ip]->GetHits();
    //  for (Int_t ihit = 0; ihit < nphits; ihit++) {
    //    THcHodoHit* hit     = (THcHodoHit*)hodoHits->At(ihit);
    //    Int_t       counter = hit->GetPaddleNumber();
    //    // Finds first best hit
    //    Bool_t onTrack, goodScinTime, goodTdcNeg, goodTdcPos;
    //    fHod->GetFlags(trackIndex, ip, ihit, onTrack, goodScinTime, goodTdcNeg, goodTdcPos);
    //    if (TMath::Abs(dist) <= fStatSlop && TMath::Abs(hitcounter - counter) <= checkHit[ip] &&
    //        fHitPlane[ip] == 0 && theTrack->GetChi2() / theTrack->GetNDoF() <= fMaxChisq &&
    //        theTrack->GetEnergy() >= fHodoEff_CalEnergy_Cut) {
    //      fHitPlane[ip]++;

    //      // Need to find out hgood_tdc_pos(igoldentrack,ihit) and neg
    //      if (goodTdcPos) {
    //        if (goodTdcNeg) { // Both fired
    //          fStatPosHit[ip][hitcounter]++;
    //          fStatNegHit[ip][hitcounter]++;
    //          fStatAndHit[ip][hitcounter]++;
    //          fStatOrHit[ip][hitcounter]++;

    //          fHodoPosEffi[fHod->GetScinIndex(ip, hitCounter[ip] - 1)]++;
    //          fHodoNegEffi[fHod->GetScinIndex(ip, hitCounter[ip] - 1)]++;
    //          fHodoAndEffi[fHod->GetScinIndex(ip, hitCounter[ip] - 1)]++;
    //          fHodoOrEffi[fHod->GetScinIndex(ip, hitCounter[ip] - 1)]++;

    //          // Double_t delta = theTrack->GetDp();
    //          // Int_t idel = TMath::Floor(delta+10.0);
    //          // if(idel >=0 && idel < 20) {
    //          //   fStatAndHitDel[ip][hitcounter][idel]++;
    //          // }
    //        } else {
    //          fStatPosHit[ip][hitcounter]++;
    //          fStatOrHit[ip][hitcounter]++;
    //          fHodoPosEffi[fHod->GetScinIndex(ip, hitCounter[ip] - 1)]++;
    //          fHodoOrEffi[fHod->GetScinIndex(ip, hitCounter[ip] - 1)]++;
    //        }
    //      } else if (goodTdcNeg) {
    //        fStatNegHit[ip][hitcounter]++;
    //        fStatOrHit[ip][hitcounter]++;
    //        fHodoNegEffi[fHod->GetScinIndex(ip, hitCounter[ip] - 1)]++;
    //        fHodoOrEffi[fHod->GetScinIndex(ip, hitCounter[ip] - 1)]++;
    //      }

    //      // Increment pos/neg/both fired.  Track independent, so
    //      // no chisquared cut, but note that only scintillators on the
    //      // track are examined.
    //      if (goodTdcPos) {
    //        if (goodTdcNeg) {
    //          fBothGood[ip][hitcounter]++;
    //        } else {
    //          fPosGood[ip][hitcounter]++;
    //        }
    //      } else if (goodTdcNeg) {
    //        fNegGood[ip][hitcounter]++;
    //      }
    //      // Determine if one or both PMTs had a good tdc

    //      // if(goodTdcPos && goodTdcNeg) {
    //      //  goodTdcBothSides[ip] = kTRUE;
    //      // }
    //      // if(goodTdcPos || goodTdcNeg) {
    //      //  goodTdcOneSide[ip] = kTRUE;
    //      // }
    //    }

    //    /*
    //      For each plane, see of other 3 fired.  This means that they were enough
    //      to form a 3/4 trigger, and so the fraction of times this plane fired is
    //      the plane trigger efficiency.  NOTE: we only require a TDC hit, not a
    //      TDC hit within the SCIN 3/4 trigger window, so high rates will make
    //      this seem better than it is.  Also, make sure we're not near the edge
    //      of the hodoscope (at the last plane), using the same hhodo_slop param.
    //      as for h_tof.f
    //      NOTE ALSO: to make this check simpler, we are assuming that all planes
    //      have identical active areas.  y_scin = y_cent + y_offset, so shift track
    //      position by offset for comparing to edges.
    //    */

    //    // Need to add calculation and cuts on
    //    // xatback and yatback in order to set the
    //    // htrig_hododidflag, htrig_hodoshouldflag and otherthreehit flags
    //    //

    //    ++fNevt;
    //  }
    //}
    return 0;
  }

} // namespace hcana