/* -*- C++ -*- */
#ifndef HcalUnpacker_h_included
#define HcalUnpacker_h_included 1

#include "DataFormats/HcalDigi/interface/HBHEDataFrame.h"
#include "DataFormats/HcalDigi/interface/HODataFrame.h"
#include "DataFormats/HcalDigi/interface/HFDataFrame.h"
#include "DataFormats/HcalDigi/interface/ZDCDataFrame.h"
#include "DataFormats/HcalDigi/interface/HcalCalibDataFrame.h"
#include "DataFormats/HcalDigi/interface/HcalTriggerPrimitiveDigi.h"
#include "DataFormats/HcalDigi/interface/HOTriggerPrimitiveDigi.h"
#include "DataFormats/HcalDigi/interface/HcalHistogramDigi.h"
#include "DataFormats/HcalDigi/interface/HcalUnpackerReport.h"
#include "DataFormats/FEDRawData/interface/FEDRawData.h"
#include "CondFormats/HcalObjects/interface/HcalElectronicsMap.h"
#include "DataFormats/HcalDigi/interface/HcalTTPDigi.h"
#include "DataFormats/HcalDigi/interface/HcalDigiCollections.h"
#include "DataFormats/HcalDigi/interface/HcalUMNioDigi.h"
#include <set>

class HcalUnpacker {
public:
  struct Collections {
    Collections();
    std::vector<HBHEDataFrame>* hbheCont;
    std::vector<HODataFrame>* hoCont;
    std::vector<HFDataFrame>* hfCont;
    std::vector<HcalCalibDataFrame>* calibCont;
    std::vector<ZDCDataFrame>* zdcCont;
    std::vector<HcalTriggerPrimitiveDigi>* tpCont;
    std::vector<HOTriggerPrimitiveDigi>* tphoCont;
    std::vector<HcalTTPDigi>* ttp;
    QIE10DigiCollection* qie10;
    QIE10DigiCollection* qie10ZDC;
    QIE10DigiCollection* qie10Lasermon;
    QIE11DigiCollection* qie11;
    // additional qie10 and qie11 data collections
    std::unordered_map<int, QIE10DigiCollection*> qie10Addtl;
    std::unordered_map<int, QIE11DigiCollection*> qie11Addtl;
    HcalUMNioDigi* umnio;
  };

  /// for normal data
  HcalUnpacker(int sourceIdOffset, int beg, int end)
      : sourceIdOffset_(sourceIdOffset),
        startSample_(beg),
        endSample_(end),
        expectedOrbitMessageTime_(-1),
        mode_(0),
        nPrinted_(0) {}
  /// For histograms, no begin and end
  HcalUnpacker(int sourceIdOffset)
      : sourceIdOffset_(sourceIdOffset),
        startSample_(-1),
        endSample_(-1),
        expectedOrbitMessageTime_(-1),
        mode_(0),
        nPrinted_(0) {}
  void setExpectedOrbitMessageTime(int time) { expectedOrbitMessageTime_ = time; }
  void unpack(const FEDRawData& raw, const HcalElectronicsMap& emap, std::vector<HcalHistogramDigi>& histoDigis);
  void unpack(const FEDRawData& raw,
              const HcalElectronicsMap& emap,
              Collections& conts,
              HcalUnpackerReport& report,
              bool silent = false);
  void setMode(int mode) { mode_ = mode; }

private:
  void unpackVME(const FEDRawData& raw,
                 const HcalElectronicsMap& emap,
                 Collections& conts,
                 HcalUnpackerReport& report,
                 bool silent = false);
  void unpackUTCA(const FEDRawData& raw,
                  const HcalElectronicsMap& emap,
                  Collections& conts,
                  HcalUnpackerReport& report,
                  bool silent = false);
  void unpackUMNio(const FEDRawData& raw, int slot, Collections& colls);

  void printInvalidDataMessage(const std::string& coll_type, int default_ns, int conflict_ns, bool extended = false);

  int sourceIdOffset_;            ///< number to subtract from the source id to get the dcc id
  int startSample_;               ///< first sample from fed raw data to copy
  int endSample_;                 ///< last sample from fed raw data to copy (if present)
  int expectedOrbitMessageTime_;  ///< Expected orbit bunch time (needed to evaluate time differences)
  int mode_;
  std::set<HcalElectronicsId> unknownIds_,
      unknownIdsTrig_;  ///< Recorded to limit number of times a log message is generated

  int nPrinted_;
};

#endif  // HcalUnpacker_h_included
