text: /**
   * \class L1GlobalTriggerReadoutRecord
   *
   *
   * Description: see header file.
   *
   * Implementation:
   *    <TODO: enter implementation details>
   *
   * \author: Vasile Mihai Ghete - HEPHY Vienna
   *
   *
   */
  
  // this class header
  #include "DataFormats/L1GlobalTrigger/interface/L1GlobalTriggerReadoutRecord.h"
  
  // system include files
  #include <iomanip>
  
  // user include files
  
  #include "FWCore/MessageLogger/interface/MessageLogger.h"
  
  // constructors
  L1GlobalTriggerReadoutRecord::L1GlobalTriggerReadoutRecord() {
    // empty GTFE
    m_gtfeWord = L1GtfeWord();
  
    // no FDL, no PSB
  }
  
  L1GlobalTriggerReadoutRecord::L1GlobalTriggerReadoutRecord(int numberBxInEvent) {
    m_gtfeWord = L1GtfeWord();
  
    m_gtFdlWord.reserve(numberBxInEvent);
    m_gtFdlWord.assign(numberBxInEvent, L1GtFdlWord());
  
    // min value of bxInEvent
    int minBxInEvent = (numberBxInEvent + 1) / 2 - numberBxInEvent;
    //int maxBxInEvent = (numberBxInEvent + 1)/2 - 1; // not needed
  
    // matrix index [0, numberBxInEvent) -> bxInEvent [minBxInEvent, maxBxInEvent]
    // warning: matrix index != bxInEvent
    for (int iFdl = 0; iFdl < numberBxInEvent; ++iFdl) {
      int iBxInEvent = minBxInEvent + iFdl;
      m_gtFdlWord[iFdl].setBxInEvent(iBxInEvent);
    }
  
    // PSBs
    int numberPsb = L1GlobalTriggerReadoutSetup::NumberPsbBoards;
    int totalNumberPsb = numberPsb * numberBxInEvent;
  
    m_gtPsbWord.reserve(totalNumberPsb);
    m_gtPsbWord.assign(totalNumberPsb, L1GtPsbWord());
  }
  
  L1GlobalTriggerReadoutRecord::L1GlobalTriggerReadoutRecord(const int numberBxInEvent,
                                                             const int numberFdlBoards,
                                                             const int numberPsbBoards) {
    // GTFE board
    m_gtfeWord = L1GtfeWord();
  
    // FDL board
    if (numberFdlBoards > 0) {
      m_gtFdlWord.reserve(numberBxInEvent);
    }
  
    // PSB boards
    if (numberPsbBoards > 0) {
      m_gtPsbWord.reserve(numberPsbBoards * numberBxInEvent);
    }
  }
  
  // copy constructor
  L1GlobalTriggerReadoutRecord::L1GlobalTriggerReadoutRecord(const L1GlobalTriggerReadoutRecord& result) {
    m_gtfeWord = result.m_gtfeWord;
    m_gtFdlWord = result.m_gtFdlWord;
    m_gtPsbWord = result.m_gtPsbWord;
  
    m_muCollRefProd = result.m_muCollRefProd;
  }
  
  // destructor
  L1GlobalTriggerReadoutRecord::~L1GlobalTriggerReadoutRecord() {
    // empty now
  }
  
  // assignment operator
  L1GlobalTriggerReadoutRecord& L1GlobalTriggerReadoutRecord::operator=(const L1GlobalTriggerReadoutRecord& result) {
    if (this != &result) {
      m_gtfeWord = result.m_gtfeWord;
      m_gtFdlWord = result.m_gtFdlWord;
      m_gtPsbWord = result.m_gtPsbWord;
  
      m_muCollRefProd = result.m_muCollRefProd;
    }
  
    return *this;
  }
  
  // equal operator
  bool L1GlobalTriggerReadoutRecord::operator==(const L1GlobalTriggerReadoutRecord& result) const {
    if (m_gtfeWord != result.m_gtfeWord) {
      return false;
    }
  
    if (m_gtFdlWord != result.m_gtFdlWord) {
      return false;
    }
  
    if (m_gtPsbWord != result.m_gtPsbWord) {
      return false;
    }
  
    if (m_muCollRefProd != result.m_muCollRefProd) {
      return false;
    }
  
    // all members identical
    return true;
  }
  
  // unequal operator
  bool L1GlobalTriggerReadoutRecord::operator!=(const L1GlobalTriggerReadoutRecord& result) const {
    return !(result == *this);
  }
  // methods
  
  // get Global Trigger decision
  //    general bxInEvent
  const bool L1GlobalTriggerReadoutRecord::decision(int bxInEventValue) const {
    for (std::vector<L1GtFdlWord>::const_iterator itBx = m_gtFdlWord.begin(); itBx != m_gtFdlWord.end(); ++itBx) {
      if ((*itBx).bxInEvent() == bxInEventValue) {
        return (*itBx).finalOR();
      }
    }
  
    // if bunch cross not found, throw exception (action: SkipEvent)
    // TODO re-evaluate action
  
    //    throw cms::Exception("NotFound")
    LogTrace("L1GlobalTriggerReadoutRecord")
        << "\nError: requested GtFdlWord for bxInEvent = " << bxInEventValue << " does not exist.\n"
        << "Can not return global decision for this bx!\n"
        << std::endl;
  
    return false;
  }
  
  //    bxInEvent = 0
  const bool L1GlobalTriggerReadoutRecord::decision() const {
    int bxInEventL1Accept = 0;
    return decision(bxInEventL1Accept);
  }
  
  // get final OR for all DAQ partitions
  //    general bxInEvent
  const cms_uint16_t L1GlobalTriggerReadoutRecord::finalOR(int bxInEventValue) const {
    for (std::vector<L1GtFdlWord>::const_iterator itBx = m_gtFdlWord.begin(); itBx != m_gtFdlWord.end(); ++itBx) {
      if ((*itBx).bxInEvent() == bxInEventValue) {
        return (*itBx).finalOR();
      }
    }
  
    // if bunch cross not found, throw exception (action: SkipEvent)
    // TODO re-evaluate action
  
    //    throw cms::Exception("NotFound")
    LogTrace("L1GlobalTriggerReadoutRecord")
        << "\nError: requested GtFdlWord for bxInEvent = " << bxInEventValue << " does not exist.\n"
        << "Can not return finalOR for this bx!\n"
        << std::endl;
  
    return 0;
  }
  
  //    bxInEvent = 0
  const cms_uint16_t L1GlobalTriggerReadoutRecord::finalOR() const {
    int bxInEventL1Accept = 0;
    return finalOR(bxInEventL1Accept);
  }
  
  // get Global Trigger decision word
  
  const DecisionWord& L1GlobalTriggerReadoutRecord::decisionWord(int bxInEventValue) const {
    const static DecisionWord emptyDecisionWord;
  
    for (std::vector<L1GtFdlWord>::const_iterator itBx = m_gtFdlWord.begin(); itBx != m_gtFdlWord.end(); ++itBx) {
      if ((*itBx).bxInEvent() == bxInEventValue) {
        return (*itBx).gtDecisionWord();
      }
    }
  
    // if bunch cross not found, throw exception (action: SkipEvent)
    // TODO re-evaluate action
  
    //    throw cms::Exception("NotFound")
    LogTrace("L1GlobalTriggerReadoutRecord")
        << "\nError: requested GtFdlWord for bxInEvent = " << bxInEventValue << " does not exist.\n"
        << "Can not return decision word for this bx!\n"
        << std::endl;
  
    return emptyDecisionWord;
  }
  
  const DecisionWord& L1GlobalTriggerReadoutRecord::decisionWord() const {
    int bxInEventL1Accept = 0;
    return decisionWord(bxInEventL1Accept);
  }
  
  const TechnicalTriggerWord& L1GlobalTriggerReadoutRecord::technicalTriggerWord(int bxInEventValue) const {
    const static TechnicalTriggerWord emptyTechnicalTriggerWord;
  
    for (std::vector<L1GtFdlWord>::const_iterator itBx = m_gtFdlWord.begin(); itBx != m_gtFdlWord.end(); ++itBx) {
      if ((*itBx).bxInEvent() == bxInEventValue) {
        return (*itBx).gtTechnicalTriggerWord();
      }
    }
  
    // if bunch cross not found, throw exception (action: SkipEvent)
    // TODO re-evaluate action
  
    //    throw cms::Exception("NotFound")
    LogTrace("L1GlobalTriggerReadoutRecord")
        << "\nError: requested GtFdlWord for bxInEvent = " << bxInEventValue << " does not exist.\n"
        << "Can not return technical trigger word for this bx!\n"
        << std::endl;
  
    return emptyTechnicalTriggerWord;
  }
  
  const TechnicalTriggerWord& L1GlobalTriggerReadoutRecord::technicalTriggerWord() const {
    int bxInEventL1Accept = 0;
    return technicalTriggerWord(bxInEventL1Accept);
  }
  
  // set global decision
  //    general
  void L1GlobalTriggerReadoutRecord::setDecision(const bool& t, int bxInEventValue) {
    for (std::vector<L1GtFdlWord>::iterator itBx = m_gtFdlWord.begin(); itBx != m_gtFdlWord.end(); ++itBx) {
      if ((*itBx).bxInEvent() == bxInEventValue) {
        // TODO FIXME when manipulating partitions
        (*itBx).setFinalOR(static_cast<uint16_t>(t));
        return;
      }
    }
  
    // if bunch cross not found, throw exception (action: SkipEvent)
  
    //    throw cms::Exception("NotFound")
    LogTrace("L1GlobalTriggerReadoutRecord")
        << "\nError: requested GtFdlWord for bxInEvent = " << bxInEventValue << " does not exist.\n"
        << "Can not set global decision for this bx!\n"
        << std::endl;
  }
  
  //    bxInEvent = 0
  void L1GlobalTriggerReadoutRecord::setDecision(const bool& t) {
    int bxInEventL1Accept = 0;
    setDecision(t, bxInEventL1Accept);
  }
  
  // set decision word
  void L1GlobalTriggerReadoutRecord::setDecisionWord(const DecisionWord& decisionWordValue, int bxInEventValue) {
    for (std::vector<L1GtFdlWord>::iterator itBx = m_gtFdlWord.begin(); itBx != m_gtFdlWord.end(); ++itBx) {
      if ((*itBx).bxInEvent() == bxInEventValue) {
        (*itBx).setGtDecisionWord(decisionWordValue);
        return;
      }
    }
  
    // if bunch cross not found, throw exception (action: SkipEvent)
  
    //    throw cms::Exception("NotFound")
    LogTrace("L1GlobalTriggerReadoutRecord")
        << "\nError: requested GtFdlWord for bxInEvent = " << bxInEventValue << " does not exist.\n"
        << "Can not set decision word for this bx!\n"
        << std::endl;
  }
  
  void L1GlobalTriggerReadoutRecord::setDecisionWord(const DecisionWord& decisionWordValue) {
    int bxInEventL1Accept = 0;
    setDecisionWord(decisionWordValue, bxInEventL1Accept);
  }
  
  void L1GlobalTriggerReadoutRecord::setTechnicalTriggerWord(const TechnicalTriggerWord& ttWordValue,
                                                             int bxInEventValue) {
    for (std::vector<L1GtFdlWord>::iterator itBx = m_gtFdlWord.begin(); itBx != m_gtFdlWord.end(); ++itBx) {
      if ((*itBx).bxInEvent() == bxInEventValue) {
        (*itBx).setGtTechnicalTriggerWord(ttWordValue);
        return;
      }
    }
  
    // if bunch cross not found, throw exception (action: SkipEvent)
  
    //    throw cms::Exception("NotFound")
    LogTrace("L1GlobalTriggerReadoutRecord")
        << "\nError: requested GtFdlWord for bxInEvent = " << bxInEventValue << " does not exist.\n"
        << "Can not set technical trigger word for this bx!\n"
        << std::endl;
  }
  
  void L1GlobalTriggerReadoutRecord::setTechnicalTriggerWord(const TechnicalTriggerWord& ttWordValue) {
    int bxInEventL1Accept = 0;
    setTechnicalTriggerWord(ttWordValue, bxInEventL1Accept);
  }
  
  // print global decision and algorithm decision word
  void L1GlobalTriggerReadoutRecord::printGtDecision(std::ostream& myCout, int bxInEventValue) const {
    for (std::vector<L1GtFdlWord>::const_iterator itBx = m_gtFdlWord.begin(); itBx != m_gtFdlWord.end(); ++itBx) {
      if ((*itBx).bxInEvent() == bxInEventValue) {
        myCout << "\nL1 Global Trigger Record: " << std::endl;
  
        myCout << "  Bunch cross " << bxInEventValue << std::endl
               << "  Global Decision = " << std::setw(5) << (*itBx).globalDecision() << std::endl;
  
        (*itBx).printGtDecisionWord(myCout);
      }
    }
  
    myCout << std::endl;
  }
  
  void L1GlobalTriggerReadoutRecord::printGtDecision(std::ostream& myCout) const {
    int bxInEventL1Accept = 0;
    printGtDecision(myCout, bxInEventL1Accept);
  }
  
  // print technical trigger word (reverse order for vector<bool>)
  void L1GlobalTriggerReadoutRecord::printTechnicalTrigger(std::ostream& myCout, int bxInEventValue) const {
    for (std::vector<L1GtFdlWord>::const_iterator itBx = m_gtFdlWord.begin(); itBx != m_gtFdlWord.end(); ++itBx) {
      if ((*itBx).bxInEvent() == bxInEventValue) {
        myCout << "\nL1 Global Trigger Record: " << std::endl;
  
        myCout << "  Bunch cross " << bxInEventValue << std::endl;
  
        (*itBx).printGtTechnicalTriggerWord(myCout);
      }
    }
  
    myCout << std::endl;
  }
  
  void L1GlobalTriggerReadoutRecord::printTechnicalTrigger(std::ostream& myCout) const {
    int bxInEventL1Accept = 0;
    printTechnicalTrigger(myCout, bxInEventL1Accept);
  }
  
  // get / set reference to L1MuGMTReadoutCollection
  const edm::RefProd<L1MuGMTReadoutCollection> L1GlobalTriggerReadoutRecord::muCollectionRefProd() const {
    return m_muCollRefProd;
  }
  
  void L1GlobalTriggerReadoutRecord::setMuCollectionRefProd(edm::Handle<L1MuGMTReadoutCollection>& muHandle) {
    m_muCollRefProd = edm::RefProd<L1MuGMTReadoutCollection>(muHandle);
  }
  
  void L1GlobalTriggerReadoutRecord::setMuCollectionRefProd(const edm::RefProd<L1MuGMTReadoutCollection>& refProdMuGMT) {
    m_muCollRefProd = refProdMuGMT;
  }
  
  // get/set hardware-related words
  
  // get / set GTFE word (record) in the GT readout record
  const L1GtfeWord L1GlobalTriggerReadoutRecord::gtfeWord() const { return m_gtfeWord; }
  
  void L1GlobalTriggerReadoutRecord::setGtfeWord(const L1GtfeWord& gtfeWordValue) { m_gtfeWord = gtfeWordValue; }
  
  // get / set FDL word (record) in the GT readout record
  const L1GtFdlWord L1GlobalTriggerReadoutRecord::gtFdlWord(int bxInEventValue) const {
    for (std::vector<L1GtFdlWord>::const_iterator itBx = m_gtFdlWord.begin(); itBx != m_gtFdlWord.end(); ++itBx) {
      if ((*itBx).bxInEvent() == bxInEventValue) {
        return (*itBx);
      }
    }
  
    // if bunch cross not found, throw exception (action: SkipEvent)
  
    //    throw cms::Exception("NotFound")
    LogTrace("L1GlobalTriggerReadoutRecord")
        << "\nError: requested L1GtFdlWord for bxInEvent = " << bxInEventValue << " does not exist.\n"
        << std::endl;
  
    // return empty record - actually does not arrive here
    return L1GtFdlWord();
  }
  
  const L1GtFdlWord L1GlobalTriggerReadoutRecord::gtFdlWord() const {
    int bxInEventL1Accept = 0;
    return gtFdlWord(bxInEventL1Accept);
  }
  
  void L1GlobalTriggerReadoutRecord::setGtFdlWord(const L1GtFdlWord& gtFdlWordValue, int bxInEventValue) {
    // if a L1GtFdlWord exists for bxInEventValue, replace it
    for (std::vector<L1GtFdlWord>::iterator itBx = m_gtFdlWord.begin(); itBx != m_gtFdlWord.end(); ++itBx) {
      if ((*itBx).bxInEvent() == bxInEventValue) {
        *itBx = gtFdlWordValue;
        LogTrace("L1GlobalTriggerReadoutRecord")
            << "L1GlobalTriggerReadoutRecord: replacing L1GtFdlWord for bxInEvent = " << bxInEventValue << "\n"
            << std::endl;
        return;
      }
    }
  
    // if bunch cross not found, throw exception (action: SkipEvent)
    // all L1GtFdlWord are created in the record constructor for allowed bunch crosses
  
    //    throw cms::Exception("NotFound")
    LogTrace("L1GlobalTriggerReadoutRecord")
        << "\nError: Cannot set L1GtFdlWord for bxInEvent = " << bxInEventValue << std::endl;
  }
  
  void L1GlobalTriggerReadoutRecord::setGtFdlWord(const L1GtFdlWord& gtFdlWordValue) {
    // just push back the new FDL block
    m_gtFdlWord.push_back(gtFdlWordValue);
  }
  
  // get / set PSB word (record) in the GT readout record
  const L1GtPsbWord L1GlobalTriggerReadoutRecord::gtPsbWord(cms_uint16_t boardIdValue, int bxInEventValue) const {
    for (std::vector<L1GtPsbWord>::const_iterator itBx = m_gtPsbWord.begin(); itBx != m_gtPsbWord.end(); ++itBx) {
      if (((*itBx).bxInEvent() == bxInEventValue) && ((*itBx).boardId() == boardIdValue)) {
        return (*itBx);
      }
    }
  
    // if bunch cross or boardId not found, throw exception (action: SkipEvent)
  
    //    throw cms::Exception("NotFound")
    LogTrace("L1GlobalTriggerReadoutRecord")
        << "\nError: requested L1GtPsbWord for boardId = " << std::hex << boardIdValue << std::dec
        << " and bxInEvent = " << bxInEventValue << " does not exist.\n"
        << std::endl;
  
    // return empty record - actually does not arrive here
    return L1GtPsbWord();
  }
  
  const L1GtPsbWord L1GlobalTriggerReadoutRecord::gtPsbWord(cms_uint16_t boardIdValue) const {
    int bxInEventL1Accept = 0;
    return gtPsbWord(boardIdValue, bxInEventL1Accept);
  }
  
  void L1GlobalTriggerReadoutRecord::setGtPsbWord(const L1GtPsbWord& gtPsbWordValue,
                                                  cms_uint16_t boardIdValue,
                                                  int bxInEventValue) {
    // if a L1GtPsbWord with the same bxInEventValue and boardIdValue exists, replace it
    for (std::vector<L1GtPsbWord>::iterator itBx = m_gtPsbWord.begin(); itBx != m_gtPsbWord.end(); ++itBx) {
      if (((*itBx).bxInEvent() == bxInEventValue) && ((*itBx).boardId() == boardIdValue)) {
        *itBx = gtPsbWordValue;
  
        LogTrace("L1GlobalTriggerReadoutRecord")
            << "\nL1GlobalTriggerReadoutRecord: replacing L1GtPsbWord with boardId = " << std::hex << boardIdValue
            << std::dec << " and bxInEvent = " << bxInEventValue << "\n"
            << std::endl;
        return;
      }
    }
  
    // otherwise, write in the first empty PSB
    // empty means: PSB with bxInEvent = 0, boardId = 0
  
    for (std::vector<L1GtPsbWord>::iterator itBx = m_gtPsbWord.begin(); itBx != m_gtPsbWord.end(); ++itBx) {
      if (((*itBx).bxInEvent() == 0) && ((*itBx).boardId() == 0)) {
        *itBx = gtPsbWordValue;
  
        LogTrace("L1GlobalTriggerReadoutRecord") << "\nL1GlobalTriggerReadoutRecord: filling an empty L1GtPsbWord"
                                                 << " for PSB with boardId = " << std::hex << boardIdValue << std::dec
                                                 << " and bxInEvent = " << bxInEventValue << "\n"
                                                 << std::endl;
        return;
      }
    }
  
    // no PSB to replace, no empty PSB: throw exception (action: SkipEvent)
    // all L1GtPsbWord are created in the record constructor
  
    //    throw cms::Exception("NotFound")
    LogTrace("L1GlobalTriggerReadoutRecord")
        << "\nError: Cannot set L1GtPsbWord for PSB with boardId = " << std::hex << boardIdValue << std::dec
        << " and bxInEvent = " << bxInEventValue << "\n  No PSB to replace and no empty PSB found!\n"
        << std::endl;
  }
  
  void L1GlobalTriggerReadoutRecord::setGtPsbWord(const L1GtPsbWord& gtPsbWordValue, cms_uint16_t boardIdValue) {
    int bxInEventL1Accept = 0;
    setGtPsbWord(gtPsbWordValue, boardIdValue, bxInEventL1Accept);
  }
  
  void L1GlobalTriggerReadoutRecord::setGtPsbWord(const L1GtPsbWord& gtPsbWordValue) {
    // just push back the new PSB block
    m_gtPsbWord.push_back(gtPsbWordValue);
  }
  
  // other methods
  
  // clear the record
  // it resets the content of the members only!
  void L1GlobalTriggerReadoutRecord::reset() {
    m_gtfeWord.reset();
  
    for (std::vector<L1GtFdlWord>::iterator itFdl = m_gtFdlWord.begin(); itFdl != m_gtFdlWord.end(); ++itFdl) {
      itFdl->reset();
    }
  
    for (std::vector<L1GtPsbWord>::iterator itPsb = m_gtPsbWord.begin(); itPsb != m_gtPsbWord.end(); ++itPsb) {
      itPsb->reset();
    }
  
    // TODO FIXME reset m_muCollRefProd
  }
  
  /// pretty print the content of a L1GlobalTriggerReadoutRecord
  void L1GlobalTriggerReadoutRecord::print(std::ostream& myCout) const {
    myCout << "\n L1GlobalTriggerReadoutRecord::print \n" << std::endl;
  
    m_gtfeWord.print(myCout);
  
    for (std::vector<L1GtFdlWord>::const_iterator itFdl = m_gtFdlWord.begin(); itFdl != m_gtFdlWord.end(); ++itFdl) {
      itFdl->print(myCout);
    }
  
    for (std::vector<L1GtPsbWord>::const_iterator itPsb = m_gtPsbWord.begin(); itPsb != m_gtPsbWord.end(); ++itPsb) {
      itPsb->print(myCout);
    }
  
    // FIXME add  L1MuGMTReadoutCollection printing
    //    edm::RefProd<L1MuGMTReadoutCollection> m_muCollRefProd;
  }
  
  // output stream operator
  std::ostream& operator<<(std::ostream& s, const L1GlobalTriggerReadoutRecord& result) {
    // TODO FIXME put together all prints
    s << "Not available yet - sorry";
  
    return s;
  }
  