/*
 * \file L1TRPCTF.cc
 *
 * \author J. Berryhill
 *
 */
#include "DQM/L1TMonitor/interface/L1TRPCTF.h"
#include "DQMServices/Core/interface/DQMStore.h"

#include "DataFormats/RPCDigi/interface/RPCDigi.h"
#include "DataFormats/RPCDigi/interface/RPCDigiCollection.h"
#include "DataFormats/MuonDetId/interface/RPCDetId.h"

#include <sstream>
using namespace std;
using namespace edm;

L1TRPCTF::L1TRPCTF(const ParameterSet& ps)
    : rpctfSource_(consumes<L1MuGMTReadoutCollection>(ps.getParameter<InputTag>("rpctfSource"))),
      //    digiSource_( ps.getParameter< InputTag >("rpctfRPCDigiSource") ),
      //   m_rpcDigiFine(false),
      //    m_useRpcDigi(true),
      m_lastUsedBxInBxdiff(0),
      output_dir_(ps.getUntrackedParameter<string>("output_dir"))
//    m_rpcDigiWithBX0(0),
//    m_rpcDigiWithBXnon0(0)

{
  // verbosity switch
  verbose_ = ps.getUntrackedParameter<bool>("verbose", false);

  if (verbose_)
    cout << "L1TRPCTF: constructor...." << endl;
}

L1TRPCTF::~L1TRPCTF() {}

void L1TRPCTF::bookHistograms(DQMStore::IBooker& ibooker, const edm::Run&, const edm::EventSetup&) {
  nev_ = 0;
  nevRPC_ = 0;

  ostringstream oDir;
  oDir << output_dir_ << "/CrateSynchroHistograms/";
  ibooker.setCurrentFolder(oDir.str());
  for (unsigned int i = 0; i < 12; i++) {
    ostringstream o;
    o << "RPCTF_crate_" << i << "_synchro";
    rpctfcratesynchro[i] = ibooker.book2D(o.str(), o.str(), 5, -2.5, 2.5, 33, -16.5, 16.5);
    for (int bx = -2; bx < 3; ++bx) {
      ostringstream b;
      b << "BX=" << bx;
      rpctfcratesynchro[i]->setBinLabel(bx + 3, b.str(), 1);
    }
    rpctfcratesynchro[i]->setAxisTitle("Tower", 2);
  }
  ibooker.setCurrentFolder(output_dir_);

  rpctfetavalue[1] = ibooker.book1D("RPCTF_eta_value_bx0", "RPCTF eta value bx=0", 33, -16.5, 16.5);
  rpctfetavalue[2] = ibooker.book1D("RPCTF_eta_value_bx+", "RPCTF eta value bx>0", 33, -16.5, 16.5);
  rpctfetavalue[0] = ibooker.book1D("RPCTF_eta_value_bx-", "RPCTF eta value bx<0", 33, -16.5, 16.5);

  rpctfphivalue[1] = ibooker.book1D("RPCTF_phi_value_bx0", "RPCTF phi value bx=0", 144, -0.5, 143.5);
  rpctfphivalue[2] = ibooker.book1D("RPCTF_phi_value_bx+", "RPCTF phi value bx>0", 144, -0.5, 143.5);
  rpctfphivalue[0] = ibooker.book1D("RPCTF_phi_value_bx-", "RPCTF phi value bx<0", 144, -0.5, 143.5);

  rpctfptvalue[1] = ibooker.book1D("RPCTF_pt_value_bx0", "RPCTF pt value bx=0", 160, -0.5, 159.5);
  rpctfptvalue[2] = ibooker.book1D("RPCTF_pt_value_bx+", "RPCTF pt value bx>0", 160, -0.5, 159.5);
  rpctfptvalue[0] = ibooker.book1D("RPCTF_pt_value_bx-", "RPCTF pt value bx<0", 160, -0.5, 159.5);

  rpctfchargevalue[1] = ibooker.book1D("RPCTF_charge_value_bx0", "RPCTF charge value bx=0", 3, -1.5, 1.5);
  rpctfchargevalue[2] = ibooker.book1D("RPCTF_charge_value_bx+", "RPCTF charge value bx>0", 3, -1.5, 1.5);
  rpctfchargevalue[0] = ibooker.book1D("RPCTF_charge_value_bx-", "RPCTF charge value bx<01", 3, -1.5, 1.5);

  rpctfquality[1] = ibooker.book1D("RPCTF_quality", "RPCTF quality bx=0", 6, -0.5, 5.5);
  rpctfquality[2] = ibooker.book1D("RPCTF_quality_bx+", "RPCTF quality bx>0", 6, -0.5, 5.5);
  rpctfquality[0] = ibooker.book1D("RPCTF_quality_bx-", "RPCTF quality bx<0", 6, -0.5, 5.5);

  rpctfntrack_b[1] = ibooker.book1D("RPCTF_ntrack_brl_bx0", "RPCTF number of tracks - barrel, bx=0", 5, -0.5, 4.5);
  rpctfntrack_b[2] = ibooker.book1D("RPCTF_ntrack_brl_bx+", "RPCTF number of tracks - barrel, bx>0", 5, -0.5, 4.5);
  rpctfntrack_b[0] = ibooker.book1D("RPCTF_ntrack_brl_bx-", "RPCTF number of tracks - barrel, bx<0", 5, -0.5, 4.5);

  rpctfntrack_e[1] = ibooker.book1D("RPCTF_ntrack_fwd_bx0", "RPCTF number of tracks - endcap, bx=0", 5, -0.5, 4.5);
  rpctfntrack_e[2] = ibooker.book1D("RPCTF_ntrack_fwd_bx+", "RPCTF number of tracks - endcap, bx>0", 5, -0.5, 4.5);
  rpctfntrack_e[0] = ibooker.book1D("RPCTF_ntrack_fwd_bx-", "RPCTF number of tracks - endcap, bx<0", 5, -0.5, 4.5);

  m_qualVsEta[1] = ibooker.book2D("RPCTF_quality_vs_eta_bx0",
                                  "RPCTF quality vs eta, bx=0",
                                  33,
                                  -16.5,
                                  16.5,
                                  6,
                                  -0.5,
                                  5.5);  // Currently only 0...3 quals are possible
  m_qualVsEta[2] = ibooker.book2D("RPCTF_quality_vs_eta_bx+",
                                  "RPCTF quality vs eta, bx>0",
                                  33,
                                  -16.5,
                                  16.5,
                                  6,
                                  -0.5,
                                  5.5);  // Currently only 0...3 quals are possible
  m_qualVsEta[0] = ibooker.book2D("RPCTF_quality_vs_eta_bx-",
                                  "RPCTF quality vs eta, bx<0",
                                  33,
                                  -16.5,
                                  16.5,
                                  6,
                                  -0.5,
                                  5.5);  // Currently only 0...3 quals are possible

  m_muonsEtaPhi[1] =
      ibooker.book2D("RPCTF_muons_eta_phi_bx0", "RPCTF occupancy(eta,phi), bx=0", 33, -16.5, 16.5, 144, -0.5, 143.5);
  m_muonsEtaPhi[2] =
      ibooker.book2D("RPCTF_muons_eta_phi_bx+", "RPCTF occupancy(eta,phi), bx>0", 33, -16.5, 16.5, 144, -0.5, 143.5);
  m_muonsEtaPhi[0] =
      ibooker.book2D("RPCTF_muons_eta_phi_bx-", "RPCTF occupancy(eta,phi), bx<0", 33, -16.5, 16.5, 144, -0.5, 143.5);

  rpctfbx = ibooker.book1D("RPCTF_bx", "RPCTF bx distribiution", 7, -3.5, 3.5);

  //axis labels
  for (int l = 0; l < 3; ++l) {
    m_muonsEtaPhi[l]->setAxisTitle("tower", 1);
    m_qualVsEta[l]->setAxisTitle("tower");
    rpctfetavalue[l]->setAxisTitle("tower");

    m_muonsEtaPhi[l]->setAxisTitle("phi", 2);
    rpctfphivalue[l]->setAxisTitle("phi");
  }

  // set phi bin labels
  for (int i = 0; i < 12; ++i) {
    //float lPhi  = (30./360)*i*2*3.14;
    int lPhi = 30 * i;
    int lBin = int((30. / 360) * i * 144) + 1;
    std::stringstream ss;
    ss << "phi=" << lPhi;
    for (int l = 0; l < 3; ++l) {
      rpctfphivalue[l]->setBinLabel(lBin, ss.str());
      m_muonsEtaPhi[l]->setBinLabel(lBin, ss.str(), 2);
    }
  }

  /*
    // set TC numbers on phi axis
    for (int tc = 0; tc < 12 ; ++tc ){
      int lBin  = (tc*12+3+1)%144;
      std::stringstream ss;
      ss << "TC" <<tc;
      for (int l = 0; l<3; ++l){
        rpctfphivalue[l]->setBinLabel(lBin,ss.str());
        m_muonsEtaPhi[l]->setBinLabel(lBin,ss.str(), 2);
      }
  }*/

  // set eta bin labels
  for (int i = -16; i < 17; ++i) {
    std::stringstream ss;
    ss << i;
    for (int l = 0; l < 3; ++l) {
      rpctfetavalue[l]->setBinLabel(i + 17, ss.str());
      m_muonsEtaPhi[l]->setBinLabel(i + 17, ss.str(), 1);
      m_qualVsEta[l]->setBinLabel(i + 17, ss.str());
    }
  }

  m_bxDiff = ibooker.book1D("RPCTF_bx_diff", "RPCTrigger - bx difference", 12000, -.5, 11999.5);
}

void L1TRPCTF::analyze(const Event& e, const EventSetup& c) {
  nev_++;
  if (verbose_)
    cout << "L1TRPCTF: analyze...." << endl;

  edm::Handle<L1MuGMTReadoutCollection> pCollection;
  e.getByToken(rpctfSource_, pCollection);

  if (!pCollection.isValid()) {
    edm::LogInfo("DataNotFound") << "can't find L1MuGMTReadoutCollection";
    return;
  }

  L1MuGMTReadoutCollection const* gmtrc = pCollection.product();
  vector<L1MuGMTReadoutRecord> gmt_records = gmtrc->getRecords();
  vector<L1MuGMTReadoutRecord>::const_iterator RRItr;

  std::vector<int> nrpctftrack_b(3, 0);
  std::vector<int> nrpctftrack_e(3, 0);

  vector<L1TRPCTF::BxDelays> all_bxdelays;

  for (RRItr = gmt_records.begin(); RRItr != gmt_records.end(); RRItr++) {
    if (verbose_)
      cout << "Readout Record " << RRItr->getBxInEvent() << endl;

    vector<vector<L1MuRegionalCand> > brlAndFwdCands;
    brlAndFwdCands.push_back(RRItr->getBrlRPCCands());
    brlAndFwdCands.push_back(RRItr->getFwdRPCCands());

    int beIndex = 0;
    vector<vector<L1MuRegionalCand> >::iterator RPCTFCands = brlAndFwdCands.begin();
    for (; RPCTFCands != brlAndFwdCands.end(); ++RPCTFCands) {
      for (vector<L1MuRegionalCand>::const_iterator ECItr = RPCTFCands->begin(); ECItr != RPCTFCands->end(); ++ECItr) {
        int bxindex = 1;  // bx == 0
        if (ECItr->bx() > 0)
          bxindex = 2;
        if (ECItr->bx() < 0)
          bxindex = 0;

        if (!ECItr->empty()) {
          if (beIndex == 0)
            ++nrpctftrack_b[bxindex];
          if (beIndex == 1)
            ++nrpctftrack_e[bxindex];

          if (verbose_)
            cout << "RPCTFCand bx " << ECItr->bx() << endl;

          int tower = ECItr->eta_packed();
          if (tower > 16) {
            tower = -((~tower & 63) + 1);
          }

          rpctfbx->Fill(ECItr->bx());

          rpctfetavalue[bxindex]->Fill(tower);
          if (verbose_)
            cout << "\tRPCTFCand eta value " << ECItr->etaValue() << endl;

          rpctfphivalue[bxindex]->Fill(ECItr->phi_packed());
          if (verbose_)
            cout << "\tRPCTFCand phi value " << ECItr->phiValue() << endl;

          rpctfptvalue[bxindex]->Fill(ECItr->ptValue());
          if (verbose_)
            cout << "\tRPCTFCand pt value " << ECItr->ptValue() << endl;

          rpctfchargevalue[bxindex]->Fill(ECItr->chargeValue());
          if (verbose_)
            cout << "\tRPCTFCand charge value " << ECItr->chargeValue() << endl;

          rpctfquality[bxindex]->Fill(ECItr->quality());
          if (verbose_)
            cout << "\tRPCTFCand quality " << ECItr->quality() << endl;

          m_qualVsEta[bxindex]->Fill(tower, ECItr->quality());
          m_muonsEtaPhi[bxindex]->Fill(tower, ECItr->phi_packed());

          BxDelays bx_del;
          bx_del.bx = ECItr->bx();
          bx_del.eta_t = tower;
          bx_del.phi_p = ECItr->phi_packed();
          all_bxdelays.push_back(bx_del);

        }  // if !empty
      }    // end candidates iteration
      ++beIndex;
    }  // end brl/endcap iteration
  }    // end GMT records iteration

  for (int bxI = 0; bxI < 3; ++bxI) {
    rpctfntrack_b[bxI]->Fill(nrpctftrack_b[bxI]);
    rpctfntrack_e[bxI]->Fill(nrpctftrack_e[bxI]);
  }

  for (unsigned int i = 0; i < all_bxdelays.size(); i++) {
    int sector = ((all_bxdelays[i].phi_p + 142) % 144) / 12;
    if (sector > 11 || sector < 0)
      continue;
    int eta_tower = all_bxdelays[i].eta_t;
    for (unsigned int j = 0; j < all_bxdelays.size(); j++) {
      if (i == j)
        continue;
      int sector2 = ((all_bxdelays[j].phi_p + 142) % 144) / 12;

      int distance_cut = 1;
      int distance = ((sector + 12) - sector2) % 12;
      distance = min(distance, 11 - distance);
      if (distance < distance_cut)
        continue;

      int bxDiff = all_bxdelays[i].bx - all_bxdelays[j].bx;
      rpctfcratesynchro[sector]->Fill(bxDiff, eta_tower);
    }
  }

  while (m_globBX.begin() != m_globBX.end()) {
    long long int diff = *m_globBX.begin() - m_lastUsedBxInBxdiff;  // first entry will go to overflow bin, ignore
    m_bxDiff->Fill(diff);
    m_lastUsedBxInBxdiff = *m_globBX.begin();
    m_globBX.erase(m_globBX.begin());
  }

  if (verbose_)
    cout << "L1TRPCTF: end job...." << endl;
  LogInfo("EndJob") << "analyzed " << nev_ << " events";
}
