// -*- C++ -*-
//
// Package:    SourceCardTextToRctDigi
// Class:      SourceCardTextToRctDigi
//
/**\class SourceCardTextToRctDigi SourceCardTextToRctDigi.cc
L1Trigger/TextToDigi/src/SourceCardTextToRctDigi.cc

Description: Input text file to be loaded into the source cards and output RCT
digis for pattern tests.

*/
//
// Original Author:  Alex Tapper
//         Created:  Fri Mar  9 19:11:51 CET 2007
//
//

#include "FWCore/MessageLogger/interface/MessageLogger.h"  // Logger
#include "FWCore/ServiceRegistry/interface/Service.h"      // Framework services
#include "SourceCardTextToRctDigi.h"

using namespace edm;
using namespace std;

// Set constants
const static unsigned NUM_LINES_PER_EVENT = 63;
const static int NUM_RCT_CRATES = 18;

SourceCardTextToRctDigi::SourceCardTextToRctDigi(const edm::ParameterSet &iConfig)
    : m_textFileName(iConfig.getParameter<std::string>("TextFileName")),
      m_fileEventOffset(iConfig.getParameter<int>("fileEventOffset")),
      m_nevt(0) {
  // Produces collections
  produces<L1CaloEmCollection>();
  produces<L1CaloRegionCollection>();

  // Open the input file
  m_file.open(m_textFileName.c_str(), std::ios::in);

  if (!m_file.good()) {
    throw cms::Exception("SourceCardTextToRctDigiTextFileOpenError")
        << "SourceCardTextToRctDigi::SourceCardTextToRctDigi : "
        << " couldn't open the file " << m_textFileName << " for reading" << std::endl;
  }

  // Make a SC routing object
  SourceCardRouting m_scRouting;
}

SourceCardTextToRctDigi::~SourceCardTextToRctDigi() {
  // Close the input file
  m_file.close();
}

/// Append empty digi collection
void SourceCardTextToRctDigi::putEmptyDigi(edm::Event &iEvent) {
  std::unique_ptr<L1CaloEmCollection> em(new L1CaloEmCollection);
  std::unique_ptr<L1CaloRegionCollection> rgn(new L1CaloRegionCollection);
  for (int i = 0; i < NUM_RCT_CRATES; i++) {
    for (int j = 0; j < 4; j++) {
      em->push_back(L1CaloEmCand(0, i, true));
      em->push_back(L1CaloEmCand(0, i, false));
    }
    for (int j = 0; j < 14; j++)
      rgn->push_back(L1CaloRegion(0, false, false, false, false, i, j / 2, j % 2));
    for (unsigned j = 0; j < 8; j++)
      rgn->push_back(L1CaloRegion(0, true, i, j));
  }
  iEvent.put(std::move(em));
  iEvent.put(std::move(rgn));
}

// ------------ method called to produce the data  ------------
void SourceCardTextToRctDigi::produce(edm::Event &iEvent, const edm::EventSetup &iSetup) {
  // Skip event if required
  if (m_nevt < m_fileEventOffset) {
    //    std::string tmp;
    // for (unsigned i=0;i<NUM_LINES_PER_EVENT;i++){
    // getline(m_file,tmp);
    //}
    putEmptyDigi(iEvent);
    m_nevt++;
    return;
  } else if (m_nevt == 0 && m_fileEventOffset < 0) {
    // skip first fileEventOffset input events
    std::string tmp;
    for (int i = 0; i < abs(m_fileEventOffset); i++)
      for (unsigned line = 0; line < NUM_LINES_PER_EVENT; line++)
        if (!getline(m_file, tmp)) {
          throw cms::Exception("SourceCardTextToRctDigiTextFileReadError")
              << "SourceCardTextToRctDigi::produce() : "
              << " couldn't read from the file " << m_textFileName << std::endl;
        }
  }

  // New collections
  std::unique_ptr<L1CaloEmCollection> em(new L1CaloEmCollection);
  std::unique_ptr<L1CaloRegionCollection> rgn(new L1CaloRegionCollection);

  // General variables
  unsigned long VHDCI[2][2];
  int routingMode;
  int crate;
  std::string dataString;
  unsigned short eventNumber;
  unsigned short logicalCardID;

  // Arrays to hold electron variables
  unsigned short eIsoRank[18][4];
  unsigned short eIsoCardId[18][4];
  unsigned short eIsoRegionId[18][4];
  unsigned short eNonIsoRank[18][4];
  unsigned short eNonIsoCardId[18][4];
  unsigned short eNonIsoRegionId[18][4];

  // Arrays to hold region variables
  unsigned short RC[18][7][2];
  unsigned short RCof[18][7][2];
  unsigned short RCtau[18][7][2];
  unsigned short MIPbits[18][7][2];
  unsigned short Qbits[18][7][2];
  unsigned short HF[18][4][2];
  unsigned short HFQ[18][4][2];

  // Check we're not at the end of the file
  if (m_file.eof()) {
    throw cms::Exception("SourceCardTextToRctDigiTextFileReadError")
        << "SourceCardTextToRctDigi::produce : "
        << " unexpected end of file " << m_textFileName << std::endl;
  }

  int thisEventNumber = -1;
  // Read in file one line at a time
  for (unsigned line = 0; line < NUM_LINES_PER_EVENT; line++) {
    if (!getline(m_file, dataString)) {
      throw cms::Exception("SourceCardTextToRctDigiTextFileReadError")
          << "SourceCardTextToRctDigi::SourceCardTextToRctDigi : "
          << " couldn't read from the file " << m_textFileName << std::endl;
    }

    // Convert the string to useful info
    m_scRouting.STRINGtoVHDCI(logicalCardID, eventNumber, dataString, VHDCI);

    // Check crossing number
    if (line != 0)
      assert(eventNumber == thisEventNumber);
    thisEventNumber = eventNumber;

    // Are we looking at electrons or regions
    m_scRouting.LogicalCardIDtoRoutingMode(logicalCardID, routingMode, crate);

    if (routingMode == 0) {
      // Electrons
      m_scRouting.VHDCItoEMU(eIsoRank[crate],
                             eIsoCardId[crate],
                             eIsoRegionId[crate],
                             eNonIsoRank[crate],
                             eNonIsoCardId[crate],
                             eNonIsoRegionId[crate],
                             MIPbits[crate],
                             Qbits[crate],
                             VHDCI);

    } else if (routingMode == 1) {
      // Regions
      m_scRouting.VHDCItoRC56HF(RC[crate], RCof[crate], RCtau[crate], HF[crate], HFQ[crate], VHDCI);

    } else if (routingMode == 2) {
      // Regions
      m_scRouting.VHDCItoRC012(RC[crate], RCof[crate], RCtau[crate], VHDCI);

    } else if (routingMode == 3) {
      // Regions
      m_scRouting.VHDCItoRC234(
          RC[crate], RCof[crate], RCtau[crate], RC[crate + 9], RCof[crate + 9], RCtau[crate + 9], VHDCI);

    } else {
      // Something went wrong
      throw cms::Exception("SourceCardtextToRctDigiError") << "SourceCardTextToRctDigi::produce : "
                                                           << " unknown routing mode=" << routingMode << std::endl;
    }
  }

  // Make RCT digis
  for (crate = 0; crate < NUM_RCT_CRATES; crate++) {
    // Make EM collections
    for (int i = 0; i < 4; i++) {
      em->push_back(L1CaloEmCand(eIsoRank[crate][i], eIsoRegionId[crate][i], eIsoCardId[crate][i], crate, true, i, 0));
      em->push_back(
          L1CaloEmCand(eNonIsoRank[crate][i], eNonIsoRegionId[crate][i], eNonIsoCardId[crate][i], crate, false, i, 0));
    }

    // Make region collections
    for (int i = 0; i < 7; i++) {    // Receiver card
      for (int j = 0; j < 2; j++) {  // Region
        rgn->push_back(L1CaloRegion::makeHBHERegion(RC[crate][i][j],
                                                    RCof[crate][i][j],
                                                    RCtau[crate][i][j],
                                                    MIPbits[crate][i][j],
                                                    Qbits[crate][i][j],
                                                    crate,
                                                    i,
                                                    j));
      }
    }

    // Make HF region collections
    for (int i = 0; i < 4; i++) {    // Eta bin
      for (int j = 0; j < 2; j++) {  // HF0, HF1
        rgn->push_back(L1CaloRegion::makeHFRegion(HF[crate][i][j],
                                                  HFQ[crate][i][j],
                                                  crate,
                                                  i + (4 * j)));  // region=eta+4*phi for eta 0-3
      }
    }
  }

  // Debug info
  for (L1CaloEmCollection::const_iterator iem = em->begin(); iem != em->end(); iem++) {
    LogDebug("Electrons") << (*iem);
  }

  for (L1CaloRegionCollection::const_iterator irgn = rgn->begin(); irgn != rgn->end(); irgn++) {
    LogDebug("HFRegions") << (*irgn);
  }

  iEvent.put(std::move(em));
  iEvent.put(std::move(rgn));

  m_nevt++;
}
