// -*- C++ -*-
//
// Package:    SiPixelOfflineCalibAnalysisBase
// Class:      SiPixelOfflineCalibAnalysisBase
//
/**\class SiPixelOfflineCalibAnalysisBase SiPixelOfflineCalibAnalysisBase.h CalibTracker/SiPixelTools/src/SiPixelOfflineCalibAnalysisBase.h

 Description: Base class for Pixel calibrations

 Implementation:
     <Notes on implementation>
*/
//
// Original Author:  Evan Klose Friis
//    additions by:  Freya Blekman
//         Created:  Tue Nov  6 17:27:19 CET 2007
//
//

// system include files
#include <memory>

// user include files
#include "FWCore/Framework/interface/Frameworkfwd.h"
#include "FWCore/Framework/interface/one/EDAnalyzer.h"

#include "FWCore/Framework/interface/Event.h"
#include "FWCore/ServiceRegistry/interface/Service.h"

#include "DataFormats/Common/interface/DetSetVector.h"
#include "DataFormats/DetId/interface/DetId.h"

#include "DataFormats/SiPixelDigi/interface/SiPixelCalibDigifwd.h"
#include "DataFormats/SiPixelDigi/interface/SiPixelCalibDigi.h"

#include "CondFormats/SiPixelObjects/interface/SiPixelCalibConfiguration.h"
#include "CondFormats/DataRecord/interface/SiPixelCalibConfigurationRcd.h"
#include "CondFormats/DataRecord/interface/SiPixelFedCablingMapRcd.h"

#include "DataFormats/TrackerCommon/interface/PixelEndcapName.h"
#include "DataFormats/TrackerCommon/interface/PixelBarrelName.h"

#include "TF1.h"

#include "DQMServices/Core/interface/DQMStore.h"
#include "DQM/SiPixelCommon/interface/SiPixelHistogramId.h"
#include "DQM/SiPixelCommon/interface/SiPixelFolderOrganizer.h"
#include "Geometry/TrackerGeometryBuilder/interface/TrackerGeometry.h"
#include "Geometry/Records/interface/TrackerDigiGeometryRecord.h"
#include "CondFormats/SiPixelObjects/interface/SiPixelFedCablingMap.h"

#include <map>
#include <vector>
#include <iostream>
#include <string>
//
// class decleration
//

class SiPixelOfflineCalibAnalysisBase : public edm::one::EDAnalyzer<edm::one::WatchRuns> {
public:
  typedef dqm::legacy::MonitorElement MonitorElement;
  typedef dqm::legacy::DQMStore DQMStore;
  explicit SiPixelOfflineCalibAnalysisBase(const edm::ParameterSet&);
  ~SiPixelOfflineCalibAnalysisBase() override;

  //no argument constructor only used to throw exception in the case of derived
  //class constructor not calling SiPixelOfflineCalibAnalysisBase(const edm::ParameterSet&)
  SiPixelOfflineCalibAnalysisBase();

  //pure virtual function, called after each DetID loaded
  virtual bool doFits(uint32_t detid, std::vector<SiPixelCalibDigi>::const_iterator ipix);

  //translate DetID to human readable string
  std::string translateDetIdToString(uint32_t detid);

  //booking DQM histograms (for dynamic histogram creation)

  MonitorElement* bookDQMHistogram1D(
      uint32_t detid, std::string name, std::string title, int nchX, double lowX, double highX);
  MonitorElement* bookDQMHistogram1D(
      uint32_t detid, std::string name, std::string title, int nchX, float* xbinsize);  //variable size bins
  MonitorElement* bookDQMHistogram2D(uint32_t detid,
                                     std::string name,
                                     std::string title,
                                     int nchX,
                                     double lowX,
                                     double highX,
                                     int nchY,
                                     double lowY,
                                     double highY);

  MonitorElement* bookDQMHistoPlaquetteSummary2D(
      uint32_t detid,
      std::string name,
      std::string
          title);  // take the detid to determine the size of rows and columns, this saves looking up everything in the cabling map by the user.
  void addTF1ToDQMMonitoringElement(MonitorElement* ele, TF1* func);

  bool setDQMDirectory(std::string dirName);
  bool setDQMDirectory(uint32_t detID);  //automatically create directory hierachy based on DetID
  static TF1* fitFunction_;
  static const std::vector<short>* getVcalValues();
  std::vector<uint32_t>& getRunNumbers() { return runnumbers_; }

protected:
  //calibration parameters from calib.dat/DB
  edm::ESHandle<SiPixelCalibConfiguration> calib_;
  edm::ESHandle<TrackerGeometry> geom_;
  edm::ESHandle<SiPixelFedCablingMap> theCablingMap_;

  edm::ESGetToken<SiPixelCalibConfiguration, SiPixelCalibConfigurationRcd> calibTokenBeginRun_;
  edm::ESGetToken<SiPixelCalibConfiguration, SiPixelCalibConfigurationRcd> calibToken_;
  edm::ESGetToken<TrackerGeometry, TrackerDigiGeometryRecord> trackerGeomToken_;
  edm::ESGetToken<SiPixelFedCablingMap, SiPixelFedCablingMapRcd> cablingMapToken_;

  std::string calibrationMode_;
  short nTriggers_;
  static std::vector<short> vCalValues_;
  uint32_t& EventNumber() { return eventCounter_; }

private:
  SiPixelFolderOrganizer* folderMaker_;
  DQMStore* daqBE_;
  SiPixelHistogramId* theHistogramIdWorker_;
  std::string outputFileName_;
  bool createOutputFile_;

  std::vector<uint32_t> runnumbers_;
  uint32_t eventCounter_;

  //store set of detIDs that have been encountered
  //second int argument can be a derived class result flag
  std::map<uint32_t, int> detIdsEntered_;
  std::map<uint32_t, std::string> detIdNames_;

  edm::InputTag siPixelCalibDigiProducer_;

  edm::EDGetTokenT<edm::DetSetVector<SiPixelCalibDigi> > tPixelCalibDigi;

  //the beginJob is used to load the calib database.  It then calls the pure
  //virtual calibrationSetup() function.  Derived classes should put beginJob functionality there.
  void beginRun(const edm::Run&, const edm::EventSetup&) override;
  void endRun(const edm::Run&, const edm::EventSetup&) override;
  void beginJob() override;

  //calibrationSetup will be used by derived classes
  virtual void calibrationSetup(const edm::EventSetup& iSetup);

  // pure virtual function, checks if the calibration analyzer is of the right type wrt the calibration information in the database (as defined in the calibrationMode_ variable). Should be implemented in each analyzer, if false will not do anything in analyze loop. default returns true.
  virtual bool checkCorrectCalibrationType();

  //called when new DetID discovered
  virtual void newDetID(uint32_t detid);

  void analyze(const edm::Event&, const edm::EventSetup&) override;
  // the endJob method is used to save things like histograms etc.
  // for additional actions derived classes should use the calibrationEnd() method for endJob functionality.
  void endJob() override;
  // calibrationEnd() will be used by derived classes
  virtual void calibrationEnd();

  // checkPixel returns whether a particular pixel is to be expected during the entire run..
  bool checkPixel(uint32_t detid, short row, short column);
};
