text: #ifndef TrackingTools_DetLayers_GeneralBinFinderInPhi_H
  #define TrackingTools_DetLayers_GeneralBinFinderInPhi_H
  
  /** \class GeneralBinFinderInPhi
   * A phi bin finder for a non-periodic group of detectors.
   *
   *  \author N. Amapane - INFN Torino
   */
  
  #include "Utilities/BinningTools/interface/BaseBinFinder.h"
  #include "TrackingTools/DetLayers/interface/PhiBorderFinder.h"
  #include "DataFormats/GeometryVector/interface/Pi.h"
  #include "FWCore/MessageLogger/interface/MessageLogger.h"
  
  #include <vector>
  
  template <class T>
  class GeneralBinFinderInPhi : public BaseBinFinder<T> {
  public:
    typedef PhiBorderFinder::Det Det;  //FIXME!!!
  
    GeneralBinFinderInPhi() : theNbins(0) {}
  
    /// Construct from an already initialized PhiBorderFinder
    GeneralBinFinderInPhi(const PhiBorderFinder& bf) {
      theBorders = bf.phiBorders();
      theBins = bf.phiBins();
      theNbins = theBins.size();
    }
  
    /// Construct from the list of Det*
    GeneralBinFinderInPhi(std::vector<Det*>::const_iterator first, std::vector<Det*>::const_iterator last)
        : theNbins(last - first) {
      std::vector<const Det*> dets(first, last);
      PhiBorderFinder bf(dets);
      theBorders = bf.phiBorders();
      theBins = bf.phiBins();
      theNbins = theBins.size();
    }
  
    ~GeneralBinFinderInPhi() override{};
  
    /// Returns an index in the valid range for the bin that contains
    /// AND is closest to phi
    int binIndex(T phi) const override {
      const std::string metname = "Muon|RecoMuon|RecoMuonDetLayers|GeneralBinFinderInPhi";
  
      static const T epsilon = 10 * std::numeric_limits<T>::epsilon();
      // Assume -pi, pi range in pi (which is the case for Geom::Phi
  
      LogTrace(metname) << "GeneralBinFinderInPhi::binIndex,"
                        << " Nbins: " << theNbins;
  
      for (int i = 0; i < theNbins; i++) {
        T cur = theBorders[i];
        T next = theBorders[binIndex(i + 1)];
        T phi_ = phi;
  
        LogTrace(metname) << "bin: " << i << " border min " << cur << " border max: " << next << " phi: " << phi_;
  
        if (cur > next)  // we are crossing the pi edge: so move the edge to 0!
        {
          cur = positiveRange(cur);
          next = positiveRange(next);
          phi_ = positiveRange(phi_);
        }
        if (phi_ > cur - epsilon && phi_ < next)
          return i;
      }
      throw cms::Exception("UnexpectedState") << "GeneralBinFinderInPhi::binIndex( T phi) bin not found!";
    }
  
    /// Returns an index in the valid range, modulo Nbins
    int binIndex(int i) const override {
      int ind = i % (int)theNbins;
      return (ind < 0) ? ind + theNbins : ind;
    }
  
    /// the middle of the bin in radians
    T binPosition(int ind) const override { return theBins[binIndex(ind)]; }
  
  private:
    int theNbins;
    std::vector<T> theBorders;
    std::vector<T> theBins;
  
    // returns a positive angle; does NOT reduce the range to 2 pi
    inline T positiveRange(T phi) const { return (phi > 0) ? phi : phi + Geom::twoPi(); }
  };
  #endif
  