#ifndef PhysicsTools_IsolationAlgos_EventDependentAbsVetos_h
#define PhysicsTools_IsolationAlgos_EventDependentAbsVetos_h

#include "FWCore/Framework/interface/ConsumesCollector.h"
#include "PhysicsTools/IsolationAlgos/interface/EventDependentAbsVeto.h"
#include "FWCore/Utilities/interface/InputTag.h"
#include "DataFormats/Common/interface/View.h"
#include "DataFormats/Common/interface/AssociationMap.h"
#include "DataFormats/Candidate/interface/Candidate.h"
#include "DataFormats/JetReco/interface/PFJet.h"

namespace reco {
 namespace isodeposit {
    class OtherCandidatesDeltaRVeto : public EventDependentAbsVeto {
      public:
          //! Create a veto specifying the input collection of the candidates, and the deltaR
          OtherCandidatesDeltaRVeto(const edm::InputTag& candidates, double deltaR, edm::ConsumesCollector& iC) :
            src_(iC.consumes<edm::View<reco::Candidate> >(candidates)), deltaR2_(deltaR*deltaR) { }

          // Virtual destructor (should always be there)
          ~OtherCandidatesDeltaRVeto() override {}

          //! Return "true" if a deposit at specific (eta,phi) with that value must be vetoed in the sum
          //! This is true if the deposit is within the configured deltaR from any item of the source collection
          bool veto(double eta, double phi, float value) const override ;

          //! Nothing to do for this
          void centerOn(double eta, double phi) override { }

          //! Picks up the directions of the given candidates
          void setEvent(const edm::Event &iEvent, const edm::EventSetup &iSetup) override ;

      private:
          edm::EDGetTokenT<edm::View<reco::Candidate> > src_;
          float         deltaR2_;
          std::vector<Direction> items_;
    };

    class OtherCandVeto : public EventDependentAbsVeto {
      public:
          //! Create a veto specifying the input collection of the candidates, and the deltaR
          OtherCandVeto(const edm::InputTag& candidates, AbsVeto *veto, edm::ConsumesCollector& iC) :
            src_(iC.consumes<edm::View<reco::Candidate> >(candidates)), veto_(veto) { }

          // Virtual destructor (should always be there)
          ~OtherCandVeto() override {}

          //! Return "true" if a deposit at specific (eta,phi) with that value must be vetoed in the sum
          //! This is true if the deposit is within the stored AbsVeto of any item of the source collection
          bool veto(double eta, double phi, float value) const override ;

          //! Nothing to do for this
          void centerOn(double eta, double phi) override { }

          //! Picks up the directions of the given candidates
          void setEvent(const edm::Event &iEvent, const edm::EventSetup &iSetup) override ;

      private:
          edm::EDGetTokenT<edm::View<reco::Candidate> > src_;
          std::vector<Direction> items_;
          std::unique_ptr<AbsVeto> veto_;
    };

    class OtherJetConstituentsDeltaRVeto : public EventDependentAbsVeto {
      public:
          //! Create a veto specifying the input collection of the jets, the candidates, and the deltaR
          OtherJetConstituentsDeltaRVeto(Direction dir, const edm::InputTag& jets, double dRjet, const edm::InputTag& pfCandAssocMap, double dRconstituent, edm::ConsumesCollector& iC)
	    : evt_(nullptr),
	      vetoDir_(dir),
	      srcJets_(iC.consumes<reco::PFJetCollection>(jets)),
	      dR2jet_(dRjet*dRjet),
	      srcPFCandAssocMap_(iC.consumes<JetToPFCandidateAssociation>(pfCandAssocMap)),
	      dR2constituent_(dRconstituent*dRconstituent)
	  {
	    //std::cout << "<OtherJetConstituentsDeltaRVeto::OtherJetConstituentsDeltaRVeto>:" << std::endl;
	    //std::cout << " vetoDir: eta = " << vetoDir_.eta() << ", phi = " << vetoDir_.phi() << std::endl;
	    //std::cout << " srcJets = " << srcJets_.label() << ":" << srcJets_.instance() << std::endl;
	    //std::cout << " dRjet = " << sqrt(dR2jet_) << std::endl;
	    //std::cout << " srcPFCandAssocMap = " << srcPFCandAssocMap_.label() << ":" << srcPFCandAssocMap_.instance() << std::endl;
	    //std::cout << " dRconstituent = " << sqrt(dR2constituent_) << std::endl;
	  }

          // Virtual destructor (should always be there)
          ~OtherJetConstituentsDeltaRVeto() override {}

          //! Return "true" if a deposit at specific (eta,phi) with that value must be vetoed in the sum
          //! This is true if the deposit is within the stored AbsVeto of any item of the source collection
          bool veto(double eta, double phi, float value) const override;

          //! Set axis for matching jets
          void centerOn(double eta, double phi) override;

          //! Picks up the directions of the given candidates
          void setEvent(const edm::Event& evt, const edm::EventSetup& es) override;

      private:
          typedef edm::AssociationMap<edm::OneToMany<std::vector<reco::PFJet>, std::vector<reco::PFCandidate>, unsigned int> > JetToPFCandidateAssociation;

	  void initialize();

	  const edm::Event* evt_;

	  Direction vetoDir_;
          edm::EDGetTokenT<reco::PFJetCollection> srcJets_;
	  double dR2jet_;
	  edm::EDGetTokenT<JetToPFCandidateAssociation> srcPFCandAssocMap_;
	  double dR2constituent_;
          std::vector<Direction> items_;
    };
 }
}
#endif
