// Copyright (c) 2014  GeometryFactory (France).  All rights reserved.
//
// This file is part of CGAL (www.cgal.org)
//
// $URL: https://github.com/CGAL/cgal/blob/v6.1.1/BGL/include/CGAL/boost/graph/iterator.h $
// $Id: include/CGAL/boost/graph/iterator.h 08b27d3db14 $
// SPDX-License-Identifier: LGPL-3.0-or-later OR LicenseRef-Commercial
//
//
// Author(s)     : Andreas Fabri

#ifndef CGAL_BGL_ITERATORS_H
#define CGAL_BGL_ITERATORS_H

#include <stdexcept>

#include <boost/graph/graph_traits.hpp>
#include <boost/iterator/iterator_adaptor.hpp>

#include <CGAL/Iterator_range.h>
#include <CGAL/assertions.h>
#include <CGAL/circulator_bases.h>
#include <CGAL/boost/graph/internal/helpers.h>

namespace CGAL {

/// \cond SKIP_IN_MANUAL

namespace internal {

template <typename G>
struct Edge {
  const G* g;

  Edge()
    : g(nullptr)
  {}

  Edge(const G& g)
    : g(&g)
  {}

  typedef typename boost::graph_traits<G>::edge_descriptor result_type;
  typedef typename boost::graph_traits<G>::halfedge_descriptor argument_type;

  result_type operator()(argument_type h) const
  {
    return edge(h, *g);
  }
};

template <typename G>
struct Opposite_edge {
  const G* g;

  Opposite_edge()
    : g(nullptr)
  {}

  Opposite_edge(const G& g)
    : g(&g)
  {}

  typedef typename boost::graph_traits<G>::edge_descriptor result_type;
  typedef typename boost::graph_traits<G>::halfedge_descriptor argument_type;

  result_type operator()(argument_type h) const
  {
    return edge(opposite(h,*g), *g);
  }
};

template <typename G>
struct Opposite_halfedge {
  const G* g;

  Opposite_halfedge()
    : g(nullptr)
  {}

  Opposite_halfedge(const G& g)
    : g(&g)
  {}

  typedef typename boost::graph_traits<G>::halfedge_descriptor result_type;
  typedef typename boost::graph_traits<G>::halfedge_descriptor argument_type;

  result_type operator()(argument_type h) const
  {
    return opposite(h,*g);
  }
};

template <typename G>
struct Target {
  const G* g;

  Target()
    : g(nullptr)
  {}

  Target(const G& g)
    : g(&g)
  {}

  typedef typename boost::graph_traits<G>::vertex_descriptor result_type;
  typedef typename boost::graph_traits<G>::halfedge_descriptor argument_type;

  result_type operator()(argument_type h) const
  {
    return target(h,*g);
  }
};

template <typename G>
struct Source {
  const G* g;

  Source()
    : g(nullptr)
  {}

  Source(const G& g)
    : g(&g)
  {}

  typedef typename boost::graph_traits<G>::vertex_descriptor result_type;
  typedef typename boost::graph_traits<G>::halfedge_descriptor argument_type;

  result_type operator()(argument_type h) const
  {
    return source(h,*g);
  }
};

template <typename G>
struct Face {
  const G* g;

  Face()
    : g(nullptr)
  {}

  Face(const G& g)
    : g(&g)
  {}

  typedef typename boost::graph_traits<G>::face_descriptor result_type;
  typedef typename boost::graph_traits<G>::halfedge_descriptor argument_type;

  result_type operator()(argument_type h) const
  {
    return face(h,*g);
  }
};
template <typename G>
struct Opposite_face {
  const G* g;

  Opposite_face()
    : g(nullptr)
  {}

  Opposite_face(const G& g)
    : g(&g)
  {}

  typedef typename boost::graph_traits<G>::face_descriptor result_type;
  typedef typename boost::graph_traits<G>::halfedge_descriptor argument_type;

  result_type operator()(argument_type h) const
  {
    return face(opposite(h,*g),*g);
  }
};
} // namespace internal
/// \endcond

/**
 * \ingroup PkgBGLIterators
 * A bidirectional iterator with value type `boost::graph_traits<Graph>::%halfedge_descriptor` over all halfedges having the same vertex as source.
 * Let `h` be a halfedge of graph `g`. For a `Halfedge_around_source_iterator` `havi` with `h = *havi;`
 * the following holds: Either `++havi` is the past the end iterator, or `next(opposite(h,g),g) == *++havi`.
 * \tparam Graph must be a model of the concept `HalfedgeGraph`
 * \cgalModels{BidirectionalIterator}
 */
template <typename Graph>
class Halfedge_around_source_iterator {
  typedef Halfedge_around_source_iterator Self;
public:
#ifndef DOXYGEN_RUNNING
  typedef typename boost::graph_traits<Graph>::halfedge_descriptor halfedge_descriptor;
  typedef typename boost::graph_traits<Graph>::halfedge_descriptor vertex_descriptor;
  typedef std::bidirectional_iterator_tag     iterator_category;
  typedef halfedge_descriptor                 value_type;
  typedef value_type*                         pointer;
  typedef const value_type&                   reference;
  typedef std::ptrdiff_t                      difference_type;

private:
  halfedge_descriptor anchor, pos;
  const Graph* g;
  int      winding;
#endif

public:
  Halfedge_around_source_iterator()
    : anchor(), pos(), g(nullptr), winding(0)
  {}

  Halfedge_around_source_iterator(halfedge_descriptor hd, const Graph& g, int n=0)
    : anchor(hd), pos(hd), g(&g), winding((hd==halfedge_descriptor())?1:n)
  {}

#ifndef DOXYGEN_RUNNING

  bool operator==( const Self& i) const {
    CGAL_assertion( anchor == anchor);
    return  ( g == i.g) && ( pos == i.pos) && ( winding == i.winding);
  }

  bool operator!=( const Self& i) const {
    return !(*this == i);
  }

  bool operator== (void* ) const
  {
    return g == nullptr;
  }

  reference operator*() const
  {
    return pos;
  }

  pointer operator->() const
  {
    return &pos;
  }

  Self& operator++() {
    pos = next(opposite(pos,*g),*g);
    if ( pos == anchor)
      ++winding;
    return *this;
  }
  Self  operator++(int) {
    Self tmp = *this;
    ++*this;
    return tmp;
  }
  Self& operator--() {
    if ( pos == anchor)
      --winding;
    pos = opposite(prev(pos,*g),*g);
    return *this;
  }
  Self  operator--(int) {
    Self tmp = *this;
    --*this;
    return tmp;
  }
#endif
};

/**
 * \ingroup PkgBGLIterators
 * A bidirectional iterator with value type `boost::graph_traits<Graph>::%halfedge_descriptor` over all halfedges having the same vertex as target.
 * Let `h` be a halfedge of graph `g`. For a `Halfedge_around_target_iterator` `havi` with `h = *havi;`
 * the following holds: Either `++havi` is the past the end iterator, or `opposite(next(h,g),g) == *++havi`.
 * \tparam Graph must be a model of the concept `HalfedgeGraph`
 * \cgalModels{BidirectionalIterator}
 */

template <typename Graph>
class Halfedge_around_target_iterator {
  typedef Halfedge_around_target_iterator Self;

public:
#ifndef DOXYGEN_RUNNING
  typedef typename boost::graph_traits<Graph>::halfedge_descriptor halfedge_descriptor;
  typedef typename boost::graph_traits<Graph>::halfedge_descriptor vertex_descriptor;
  typedef std::bidirectional_iterator_tag     iterator_category;
  typedef halfedge_descriptor                 value_type;
  typedef value_type*                         pointer;
  typedef const value_type&                   reference;
  typedef std::ptrdiff_t                      difference_type;

private:
  halfedge_descriptor anchor, pos;
  const Graph* g;
  int      winding;
#endif

public:
  Halfedge_around_target_iterator()
    : anchor(), pos(), g(nullptr), winding(0)
  {}

  Halfedge_around_target_iterator(halfedge_descriptor hd, const Graph& g, int n=0)
    : anchor(hd), pos(hd), g(&g), winding((hd==halfedge_descriptor())?1:n)
  {}

#ifndef DOXYGEN_RUNNING

  bool operator==( const Self& i) const {
    CGAL_assertion( anchor == anchor);
    return  ( g == i.g) && ( pos == i.pos) && ( winding == i.winding);
  }

  bool operator!=( const Self& i) const {
    return !(*this == i);
  }

  bool operator== (void* ) const
  {
    return g == nullptr;
  }

  reference operator*() const
  {
    return pos;
  }

  pointer operator->() const
  {
    return &pos;
  }

  Self& operator++() {
    pos = opposite(next(pos,*g),*g);
    if ( pos == anchor)
      ++winding;
    return *this;
  }
  Self  operator++(int) {
    Self tmp = *this;
    ++*this;
    return tmp;
  }
  Self& operator--() {
    if ( pos == anchor)
      --winding;
    pos = prev(opposite(pos,*g),*g);
    return *this;
  }
  Self  operator--(int) {
    Self tmp = *this;
    --*this;
    return tmp;
  }
#endif
};


/**
 * \ingroup PkgBGLIterators
 * A bidirectional iterator  with value type `boost::graph_traits<Graph>::%halfedge_descriptor` over all halfedges incident to the same face or border.
 * Let `h` be a halfedge of graph `g`. For a `Halfedge_around_face_iterator` `hafi` with  `h = *hafi`
 * the following holds: Either `++hafi` is the past the end iterator, or `next(h,g) == *++hafi`.
 * \tparam Graph must be a model of the concept `HalfedgeGraph`
 * \cgalModels{BidirectionalIterator}
 */

template <typename Graph>
class Halfedge_around_face_iterator {
#ifndef DOXYGEN_RUNNING
  typedef Halfedge_around_face_iterator Self;

public:
  typedef typename boost::graph_traits<Graph>::halfedge_descriptor halfedge_descriptor;
  typedef std::bidirectional_iterator_tag      iterator_category;
  typedef halfedge_descriptor                 value_type;
  typedef value_type*                         pointer;
  typedef value_type&                         reference;
  typedef std::ptrdiff_t                      difference_type;

#endif

  Halfedge_around_face_iterator()
    : pos(), g(0)
  {}

  Halfedge_around_face_iterator(halfedge_descriptor hd, const Graph& g, int n=0)
    : anchor(hd), pos(hd), g(&g), winding((hd == halfedge_descriptor())?1:n)
  {}
#ifndef DOXYGEN_RUNNING
  reference         operator *  ( )       { return  pos; }
  const value_type& operator *  ( ) const { return  pos; }
  pointer           operator -> ( )       { return &pos; }
  const value_type* operator -> ( ) const { return &pos; }

  bool operator==( const Self& i) const {
    CGAL_assertion( anchor == anchor);
    return  ( g == i.g) && ( pos == i.pos) && ( winding == i.winding);
  }

  bool operator!=( const Self& i) const {
    return !(*this == i);
  }

  Self& operator++()
  {
    CGAL_assertion(g != nullptr);
    pos = next(pos,*g);
    if ( pos == anchor)
      ++winding;
    return *this;
  }

  Self operator++(int)
  {
    CGAL_assertion(g != nullptr);
    Self tmp = *this;
    ++*this;
    return tmp;
  }

  Self& operator--()
  {
    CGAL_assertion(g != nullptr);
    if ( pos == anchor)
      --winding;

    pos = prev(pos,*g);
    return *this;
  }

  Self operator--(int)
  {
    CGAL_assertion(g != nullptr);
    Self tmp = *this;
    --*this;
    return tmp;
  }
#endif
private:
  halfedge_descriptor anchor, pos;
  const Graph* g;
  int      winding;
};


template <typename Graph>
class Halfedge_around_target_circulator;

/**
 * \ingroup PkgBGLIterators
 * A bidirectional circulator  with value type `boost::graph_traits<Graph>::%halfedge_descriptor` over all halfedges having the same vertex as source.
 * Let `h` be a halfedge of graph `g`. For a `Halfedge_around_source_circulator` `havc` with `h = *havc;`
 * the following holds: `next(opposite(h,g),g) == *++havc`.
 * \tparam Graph must be a model of the concept `HalfedgeGraph`
 * \cgalModels{BidirectionalCirculator}
 */
template <typename Graph>
class Halfedge_around_source_circulator
#ifndef DOXYGEN_RUNNING
 : public boost::iterator_adaptor<
             Halfedge_around_source_circulator<Graph>                    // Derived
             , Halfedge_around_target_circulator<Graph>                  // Base
             , typename boost::graph_traits<Graph>::halfedge_descriptor  // Value
             , Bidirectional_circulator_tag                              // CategoryOrTraversal
             , typename boost::graph_traits<Graph>::halfedge_descriptor  // Reference
             >
#endif
{
private:
  internal::Opposite_halfedge<Graph> opp;

#ifndef DOXYGEN_RUNNING
  typedef typename boost::graph_traits<Graph>::halfedge_descriptor halfedge_descriptor;
  typedef typename boost::graph_traits<Graph>::vertex_descriptor vertex_descriptor;
#endif

public:

#ifndef DOXYGEN_RUNNING
  typedef std::size_t size_type;
#endif

  Halfedge_around_source_circulator()
  {}

  Halfedge_around_source_circulator(halfedge_descriptor hd, const Graph& g)
    : Halfedge_around_source_circulator::iterator_adaptor_(Halfedge_around_target_circulator<Graph>(opposite(hd,g),g)), opp(g)
  {}

  Halfedge_around_source_circulator(vertex_descriptor vd, const Graph& g)
    : Halfedge_around_source_circulator::iterator_adaptor_(Halfedge_around_target_circulator<Graph>(halfedge(vd,g),g)), opp(g)
  {}

  explicit operator bool() const
  {
    return (! (this->base_reference() == nullptr));
  }

  bool operator== (void*) const
  {
    return this->base_reference() == nullptr;
  }

  bool operator!= (void*) const
  {
    return this->base_reference() != nullptr;
  }

private:
  friend class boost::iterator_core_access;
  typename  boost::graph_traits<Graph>::halfedge_descriptor dereference() const { return opp(*this->base_reference()); }
};


/**
 * \ingroup PkgBGLIterators
 * A bidirectional circulator  with value type `boost::graph_traits<Graph>::%face_descriptor` over all faces incident to the same vertex.
 * It circulates over the same halfedges as the `Halfedge_around_target_circulator`.
 *
 * \tparam Graph must be a model of the concept `HalfedgeGraph`
 * \cgalModels{BidirectionalCirculator}
 */

template <typename Graph>
class Face_around_target_circulator
#ifndef DOXYGEN_RUNNING
  : public boost::iterator_adaptor<
             Face_around_target_circulator<Graph>                    // Derived
             , Halfedge_around_target_circulator<Graph>                  // Base
             , typename boost::graph_traits<Graph>::face_descriptor  // Value
             , Bidirectional_circulator_tag                              // CategoryOrTraversal
             , typename boost::graph_traits<Graph>::face_descriptor  // Reference
             >
#endif
{
  typedef typename boost::graph_traits<Graph>::halfedge_descriptor halfedge_descriptor;
  internal::Face<Graph> fct;

public:

  Face_around_target_circulator()
  {}

  Face_around_target_circulator(halfedge_descriptor hd, const Graph& g)
    : Face_around_target_circulator::iterator_adaptor_(Halfedge_around_target_circulator<Graph>(hd,g)), fct(g)
  {}
#ifndef DOXYGEN_RUNNING
  typedef std::size_t size_type;

  explicit operator bool() const
  {
    return (! (this->base_reference() == nullptr));
  }

  bool operator== (void*) const
  {
    return this->base_reference() == nullptr;
  }

  bool operator!= (void*) const
  {
    return this->base_reference() != nullptr;
  }


private:
  friend class boost::iterator_core_access;
  typename  boost::graph_traits<Graph>::face_descriptor dereference() const { return fct(*this->base_reference()); }
#endif

};


/**
 * \ingroup PkgBGLIterators
 * A bidirectional circulator  with value type `boost::graph_traits<Graph>::%halfedge_descriptor` over all halfedges having the same vertex as target.
 * Let `h` be a halfedge of graph `g`. For a `Halfedge_around_target_circulator` `havc` with `h = *havc;`
 * the following holds: `opposite(next(h,g),g) == *++havc`.
 * \tparam Graph must be a model of the concept `HalfedgeGraph`
 * \cgalModels{BidirectionalCirculator}
 */



template <typename Graph>
class Halfedge_around_target_circulator {
  typedef Halfedge_around_target_circulator Self;

public:
#ifndef DOXYGEN_RUNNING
  typedef typename boost::graph_traits<Graph>::halfedge_descriptor halfedge_descriptor;
  typedef typename boost::graph_traits<Graph>::vertex_descriptor vertex_descriptor;
  typedef Bidirectional_circulator_tag        iterator_category;
  typedef halfedge_descriptor                 value_type;
  typedef value_type*                         pointer;
  typedef value_type&                         reference;
  typedef std::ptrdiff_t                      difference_type;
  typedef std::size_t                         size_type;
#endif

  Halfedge_around_target_circulator()
    : g(0)
  {}

  Halfedge_around_target_circulator(halfedge_descriptor pos, const Graph& g)
    : pos(pos), g(&g)
  {}

  Halfedge_around_target_circulator(vertex_descriptor vd, const Graph& g)
    : pos(halfedge(vd,g)), g(&g)
  {}

#ifndef DOXYGEN_RUNNING
  reference         operator *  ( )       { return  pos; }
  const value_type& operator *  ( ) const { return  pos; }
  pointer           operator -> ( )       { return &pos; }
  const value_type* operator -> ( ) const { return &pos; }

  bool       operator == ( const Self& other) const { return  g == other.g && pos == other.pos; }
  bool       operator != ( const Self& other) const { return  g != other.g || pos != other.pos; }

  explicit operator bool() const
  {
    return (! (g == nullptr));
  }


  bool operator== (void* ) const
  {
    return g == nullptr;
  }

  bool operator!= (void* ) const
  {
    return g != nullptr;
  }


  Self& operator++()
  {
    CGAL_assertion(g != nullptr);
    pos = opposite(next(pos,*g),*g);
    return *this;
  }

  Self operator++(int)
  {
    CGAL_assertion(g != nullptr);
    Self tmp = *this;
    ++*this;
    return tmp;
  }

  Self& operator--()
  {
    CGAL_assertion(g != nullptr);
    pos = prev(opposite(pos,*g),*g);
    return *this;
  }

  Self operator--(int)
  {
    CGAL_assertion(g != nullptr);
    Self tmp = *this;
    --*this;
    return tmp;
  }
#endif

private:
  halfedge_descriptor pos;
  const Graph* g;
};


/**
 * \ingroup PkgBGLIterators
 * A bidirectional circulator  with value type `boost::graph_traits<Graph>::%halfedge_descriptor` over all halfedges incident to the same face or border.
 * Let `h` be a halfedge of graph `g`. For a `Halfedge_around_face_circulator` `hafc` with  `h = *hafc`
 * the following holds:  `next(h,g) == *++hafc`.
 * \tparam Graph must be a model of the concept `HalfedgeGraph`
 * \cgalModels{BidirectionalCirculator}
 */

template <typename Graph>
class Halfedge_around_face_circulator {
  typedef Halfedge_around_face_circulator Self;

public:
#ifndef DOXYGEN_RUNNING
  typedef typename boost::graph_traits<Graph>::halfedge_descriptor halfedge_descriptor;
  typedef Bidirectional_circulator_tag        iterator_category;
  typedef halfedge_descriptor                 value_type;
  typedef value_type*                         pointer;
  typedef value_type&                         reference;
  typedef std::ptrdiff_t                      difference_type;
  typedef std::size_t                         size_type;
#endif

  Halfedge_around_face_circulator()
    : pos(), g(0)
  {}

  Halfedge_around_face_circulator(halfedge_descriptor pos, const Graph& g)
    : pos(pos), g(&g)
  {}
#ifndef DOXYGEN_RUNNING
  reference         operator *  ( )       { return  pos; }
  const value_type& operator *  ( ) const { return  pos; }
  pointer           operator -> ( )       { return &pos; }
  const value_type* operator -> ( ) const { return &pos; }

  bool       operator == ( const Self& other) const { return  g == other.g && pos == other.pos; }
  bool       operator != ( const Self& other) const { return  g != other.g || pos != other.pos; }

  explicit operator bool() const
  {
    return (! (g == nullptr));
  }

  bool operator== (void* ) const
  {
    return g == nullptr;
  }

  bool operator!= (void* ) const
  {
    return g != nullptr;
  }

  Self& operator++()
  {
    CGAL_assertion(g != nullptr);
    pos = next(pos,*g);
    return *this;
  }

  Self operator++(int)
  {
    CGAL_assertion(g != nullptr);
    Self tmp = *this;
    ++*this;
    return tmp;
  }

  Self& operator--()
  {
    CGAL_assertion(g != nullptr);
    pos = prev(pos,*g);
    return *this;
  }

  Self operator--(int)
  {
    CGAL_assertion(g != nullptr);
    Self tmp = *this;
    --*this;
    return tmp;
  }
#endif

private:
  halfedge_descriptor pos;
  const Graph* g;
};


/**
 * \ingroup PkgBGLIterators
 * returns an iterator range over all halfedges with vertex `source(h,g)` as source.
 */
template<typename Graph>
Iterator_range<Halfedge_around_source_iterator<Graph> >
halfedges_around_source(typename boost::graph_traits<Graph>::halfedge_descriptor h, const Graph& g)
{
  typedef Halfedge_around_source_iterator<Graph> I;
  return make_range(I(h,g), I(h,g,1));
}

/**
 * \ingroup PkgBGLIterators
 * returns an iterator range over all halfedges with vertex `v` as source.
 */
template<typename Graph>
Iterator_range<Halfedge_around_source_iterator<Graph> >
halfedges_around_source(typename boost::graph_traits<Graph>::vertex_descriptor v, const Graph& g)
{
  return halfedges_around_source(opposite(halfedge(v,g),g),g);
}

/**
 * \ingroup PkgBGLIterators
 * returns an iterator range over all halfedges with vertex `target(h,g)` as target.
 */
template<typename Graph>
Iterator_range<Halfedge_around_target_iterator<Graph> >
halfedges_around_target(typename boost::graph_traits<Graph>::halfedge_descriptor h, const Graph& g)
{
  typedef Halfedge_around_target_iterator<Graph> I;
  return make_range(I(h,g), I(h,g,1));
}

/**
 * \ingroup PkgBGLIterators
 * returns an iterator range over all halfedges with vertex `v` as target.
 */
template<typename Graph>
Iterator_range<Halfedge_around_target_iterator<Graph> >
halfedges_around_target(typename boost::graph_traits<Graph>::vertex_descriptor v, const Graph& g)
{
  return halfedges_around_target(halfedge(v,g),g);
}

/**
 * \ingroup PkgBGLIterators
 * returns an iterator range over all halfedges incident to the same face or border as `h`.
 */
template<typename Graph>
Iterator_range<Halfedge_around_face_iterator<Graph> >
halfedges_around_face(typename boost::graph_traits<Graph>::halfedge_descriptor h, const Graph& g)
{
  typedef Halfedge_around_face_iterator<Graph> I;
  return make_range(I(h,g), I(h,g,1));
}

/**
 * \ingroup PkgBGLIterators
 * A bidirectional iterator with value type `boost::graph_traits<Graph>::%face_descriptor`.
 * It iterates over the same halfedges as the `Halfedge_around_face_iterator`,
 * and provides the face descriptor associated to the opposite halfedge.  The face descriptor
 * may be the null face, and it may be several times the same face descriptor.
 *
 * \tparam Graph must be a model of the concept `HalfedgeGraph`
 * \cgalModels{BidirectionalCirculator}
 */
template <typename Graph>
class Face_around_face_iterator
#ifndef DOXYGEN_RUNNING
  : public boost::iterator_adaptor<
            Face_around_face_iterator<Graph>                       // Derived
             , Halfedge_around_face_iterator<Graph>                // Base
             , typename boost::graph_traits<Graph>::face_descriptor  // Value
             , std::bidirectional_iterator_tag                       // CategoryOrTraversal
             , typename boost::graph_traits<Graph>::face_descriptor  // Reference
             >
#endif
{
  typedef typename boost::graph_traits<Graph>::halfedge_descriptor halfedge_descriptor;
  internal::Opposite_face<Graph> fct;
public:

  Face_around_face_iterator()
  {}

  Face_around_face_iterator(halfedge_descriptor h, const Graph& g, int n = 0)
    : Face_around_face_iterator::iterator_adaptor_(Halfedge_around_face_iterator<Graph>(h,g,(h==halfedge_descriptor())?1:n)), fct(g)
  {}
private:
  friend class boost::iterator_core_access;
  typename  boost::graph_traits<Graph>::face_descriptor dereference() const { return fct(*this->base_reference()); }
};


/**
 * \ingroup PkgBGLIterators
 * A bidirectional circulator  with value type `boost::graph_traits<Graph>::%face_descriptor`.
 * It circulates over the same halfedges as the `Halfedge_around_face_circulator`,
 * and provides the face descriptor associated to the opposite halfedge.  The face descriptor
 * may be the null face, and it may be several times the same face descriptor.
 *
 * \tparam Graph must be a model of the concept `HalfedgeGraph`
 * \cgalModels{BidirectionalCirculator}
 */
template <typename Graph>
class Face_around_face_circulator
{};

/**
 * \ingroup PkgBGLIterators
 * A bidirectional iterator with value type `boost::graph_traits<Graph>::%face_descriptor`.
 * It iterates over the same halfedges as the `Halfedge_around_face_iterator`,
 * and provides the face descriptor associated to the opposite halfedge.  The face descriptor
 * may be the null face, and it may be several times the same face descriptor.
 *
 * \tparam Graph must be a model of the concept `HalfedgeGraph`
 * \cgalModels{BidirectionalIterator}
 */
template <typename Graph>
class Face_around_target_iterator
#ifndef DOXYGEN_RUNNING
  : public boost::iterator_adaptor<
            Face_around_target_iterator<Graph>                       // Derived
             , Halfedge_around_target_iterator<Graph>                // Base
             , typename boost::graph_traits<Graph>::face_descriptor  // Value
             , std::bidirectional_iterator_tag                       // CategoryOrTraversal
             , typename boost::graph_traits<Graph>::face_descriptor  // Reference
             >
#endif
{
  typedef typename boost::graph_traits<Graph>::halfedge_descriptor halfedge_descriptor;

  internal::Face<Graph> fct;

public:

  Face_around_target_iterator()
  {}

  Face_around_target_iterator(halfedge_descriptor h, const Graph& g, int n = 0)
    : Face_around_target_iterator::iterator_adaptor_(Halfedge_around_target_iterator<Graph>(h,g,(h==halfedge_descriptor())?1:n)), fct(g)
  {}

private:
  friend class boost::iterator_core_access;
  typename  boost::graph_traits<Graph>::face_descriptor dereference() const { return fct(*this->base_reference()); }
};

/**
 * \ingroup PkgBGLIterators
 * returns an iterator range over all faces around  vertex `target(h,g)`.
 */
template<typename Graph>
Iterator_range<Face_around_target_iterator<Graph> >
faces_around_target(typename boost::graph_traits<Graph>::halfedge_descriptor h, const Graph& g)
{
  typedef Face_around_target_iterator<Graph> I;
  return make_range(I(h,g), I(h,g,1));
}

/**
 * \ingroup PkgBGLIterators
 * returns an iterator range over all edge-adjacent faces to the same face `face(h,g)`.
 */
template<typename Graph>
Iterator_range<Face_around_face_iterator<Graph> >
faces_around_face(typename boost::graph_traits<Graph>::halfedge_descriptor h, const Graph& g)
{
  typedef Face_around_face_iterator<Graph> I;
  return make_range(I(h,g), I(h,g,1));
}

/**
 * \ingroup PkgBGLIterators
 * A bidirectional circulator with value type `boost::graph_traits<Graph>::%vertex_descriptor` over all vertices incident to the same face or border.
 * \tparam Graph must be a model of the concept `HalfedgeGraph`
 * \cgalModels{BidirectionalIterator}
 */
template <typename Graph>
class Vertex_around_face_circulator
#ifndef DOXYGEN_RUNNING
  : public boost::iterator_adaptor<
             Vertex_around_face_circulator<Graph>                    // Derived
             , Halfedge_around_face_circulator<Graph>                  // Base
             , typename boost::graph_traits<Graph>::vertex_descriptor  // Value
             , Bidirectional_circulator_tag                              // CategoryOrTraversal
             , typename boost::graph_traits<Graph>::vertex_descriptor  // Reference
             >
#endif
{
  internal::Target<Graph> fct;
  typedef typename boost::graph_traits<Graph>::halfedge_descriptor halfedge_descriptor;

public:
#ifndef DOXYGEN_RUNNING
  typedef std::size_t size_type;
#endif

  Vertex_around_face_circulator()
  {}

  Vertex_around_face_circulator(halfedge_descriptor h, const Graph& g)
    : Vertex_around_face_circulator::iterator_adaptor_(Halfedge_around_face_circulator<Graph>(h,g)), fct(g)
  {}

#ifndef DOXYGEN_RUNNING

  explicit operator bool() const
  {
    return (! (this->base_reference() == nullptr));
  }

  bool operator== (void*) const
  {
    return this->base_reference()== nullptr;
  }

  bool operator!= (void*) const
  {
    return this->base_reference()!= nullptr;
  }

private:
  friend class boost::iterator_core_access;
  typename  boost::graph_traits<Graph>::vertex_descriptor dereference() const { return fct(*this->base_reference()); }
#endif
};

/**
 * \ingroup PkgBGLIterators
 * A bidirectional iterator  with value type `boost::graph_traits<Graph>::%vertex_descriptor`
 *  over all vertices incident to the same face or border.
 * \tparam Graph must be a model of the concept `HalfedgeGraph`
 * \cgalModels{BidirectionalIterator}
 */
template <typename Graph>
class Vertex_around_face_iterator
#ifndef DOXYGEN_RUNNING
   : public boost::iterator_adaptor<
            Vertex_around_face_iterator<Graph>                       // Derived
             , Halfedge_around_face_iterator<Graph>                // Base
             , typename boost::graph_traits<Graph>::vertex_descriptor  // Value
             , std::bidirectional_iterator_tag                       // CategoryOrTraversal
             , typename boost::graph_traits<Graph>::vertex_descriptor  // Reference
             >
#endif
{
  typedef typename boost::graph_traits<Graph>::halfedge_descriptor halfedge_descriptor;

  internal::Target<Graph> fct;
public:

  Vertex_around_face_iterator()
  {}

  Vertex_around_face_iterator(halfedge_descriptor h, const Graph& g, int n = 0)
    : Vertex_around_face_iterator::iterator_adaptor_(Halfedge_around_face_iterator<Graph>(h,g,(h==halfedge_descriptor())?1:n)), fct(g)
  {}

#ifndef DOXYGEN_RUNNING

  explicit operator bool() const
  {
    return (! (this->base_reference() == nullptr));
  }

  bool operator== (void*) const
  {
    return this->base_reference()== nullptr;
  }
private:
  friend class boost::iterator_core_access;
  typename  boost::graph_traits<Graph>::vertex_descriptor dereference() const { return fct(*this->base_reference()); }
#endif
};


template <typename Graph>
class Opposite_edge_around_face_iterator
#ifndef DOXYGEN_RUNNING
  : public boost::iterator_adaptor<
            Opposite_edge_around_face_iterator<Graph>                       // Derived
             , Halfedge_around_face_iterator<Graph>                // Base
             , typename boost::graph_traits<Graph>::edge_descriptor  // Value
             , std::bidirectional_iterator_tag                       // CategoryOrTraversal
             , typename boost::graph_traits<Graph>::edge_descriptor  // Reference
             >
#endif
{
  typedef typename boost::graph_traits<Graph>::halfedge_descriptor halfedge_descriptor;
  internal::Opposite_edge<Graph> fct;
public:

  Opposite_edge_around_face_iterator()
  {}

  Opposite_edge_around_face_iterator(halfedge_descriptor h, const Graph& g, int n = 0)
    : Opposite_edge_around_face_iterator::iterator_adaptor_(Halfedge_around_face_iterator<Graph>(h,g,(h==halfedge_descriptor())?1:n)), fct(g)
  {}
private:
  friend class boost::iterator_core_access;
  typename  boost::graph_traits<Graph>::edge_descriptor dereference() const { return fct(*this->base_reference()); }
};

template<typename Graph>
Iterator_range<Opposite_edge_around_face_iterator<Graph> >
opposite_edges_around_face(typename boost::graph_traits<Graph>::halfedge_descriptor h, const Graph& g)
{
  typedef Opposite_edge_around_face_iterator<Graph> I;
  return make_range(I(h,g), I(h,g,1));
}

template <typename Graph>
class Edge_around_face_iterator
#ifndef DOXYGEN_RUNNING
  : public boost::iterator_adaptor<
            Edge_around_face_iterator<Graph>                       // Derived
             , Halfedge_around_face_iterator<Graph>                // Base
             , typename boost::graph_traits<Graph>::edge_descriptor  // Value
             , std::bidirectional_iterator_tag                       // CategoryOrTraversal
             , typename boost::graph_traits<Graph>::edge_descriptor  // Reference
             >
#endif
{
  typedef typename boost::graph_traits<Graph>::halfedge_descriptor halfedge_descriptor;
  internal::Edge<Graph> fct;
public:

  Edge_around_face_iterator()
  {}

  Edge_around_face_iterator(halfedge_descriptor h, const Graph& g, int n = 0)
    : Edge_around_face_iterator::iterator_adaptor_(Halfedge_around_face_iterator<Graph>(h,g,(h==halfedge_descriptor())?1:n)), fct(g)
  {}
private:
  friend class boost::iterator_core_access;
  typename  boost::graph_traits<Graph>::edge_descriptor dereference() const { return fct(*this->base_reference()); }
};

template<typename Graph>
Iterator_range<Edge_around_face_iterator<Graph> >
edges_around_face(typename boost::graph_traits<Graph>::halfedge_descriptor h, const Graph& g)
{
  typedef Edge_around_face_iterator<Graph> I;
  return make_range(I(h,g), I(h,g,1));
}



/**
 * \ingroup PkgBGLIterators
 * A bidirectional circulator with value type `boost::graph_traits<Graph>::%vertex_descriptor` over all vertices adjacent to the same vertex.
 * It circulates over the same halfedges as the `Halfedge_around_target_circulator`.
 *
 * \tparam Graph must be a model of the concept `HalfedgeGraph`
 * \cgalModels{BidirectionalCirculator}
 */
template <typename Graph>
class Vertex_around_target_circulator
#ifndef DOXYGEN_RUNNING
  : public boost::iterator_adaptor<
            Vertex_around_target_circulator<Graph>                       // Derived
             , Halfedge_around_target_circulator<Graph>                // Base
             , typename boost::graph_traits<Graph>::vertex_descriptor  // Value
             , Bidirectional_circulator_tag                       // CategoryOrTraversal
             , typename boost::graph_traits<Graph>::vertex_descriptor  // Reference
             >
#endif
{
  internal::Source<Graph> fct;
public:
#ifndef DOXYGEN_RUNNING
  typedef typename boost::graph_traits<Graph>::halfedge_descriptor halfedge_descriptor;
  typedef std::size_t size_type;
#endif

  Vertex_around_target_circulator()
  {}

  Vertex_around_target_circulator(halfedge_descriptor h, const Graph& g)
    : Vertex_around_target_circulator::iterator_adaptor_(Halfedge_around_target_circulator<Graph>(h,g)), fct(g)
  {}

#ifndef DOXYGEN_RUNNING

  explicit operator bool() const
  {
    return (! (this->base_reference() == nullptr));
  }

  bool operator== (void*) const
  {
    return this->base_reference()== nullptr;
  }

  bool operator!= (void*) const
  {
    return this->base_reference()!= nullptr;
  }

private:
  friend class boost::iterator_core_access;
  typename  boost::graph_traits<Graph>::vertex_descriptor dereference() const { return fct(*this->base_reference()); }
#endif
};



/**
 * \ingroup PkgBGLIterators
 * A bidirectional iterator with value type `boost::graph_traits<Graph>::%vertex_descriptor` over all vertices adjacent to the same vertex.
 * It iterates over the same halfedges as the `Halfedge_around_target_iterator`.
 *
 * \tparam Graph must be a model of the concept `HalfedgeGraph`
 * \cgalModels{BidirectionalIterator}
 */
template <typename Graph>
class Vertex_around_target_iterator
#ifndef DOXYGEN_RUNNING
  : public boost::iterator_adaptor<
            Vertex_around_target_iterator<Graph>                       // Derived
             , Halfedge_around_target_iterator<Graph>                // Base
             , typename boost::graph_traits<Graph>::vertex_descriptor  // Value
             , std::bidirectional_iterator_tag                       // CategoryOrTraversal
             , typename boost::graph_traits<Graph>::vertex_descriptor  // Reference
             >
#endif
{
  typedef typename boost::graph_traits<Graph>::halfedge_descriptor halfedge_descriptor;
  internal::Source<Graph> fct;

public:

  Vertex_around_target_iterator()
  {}

  Vertex_around_target_iterator(halfedge_descriptor h, const Graph& g, int n = 0)
    : Vertex_around_target_iterator::iterator_adaptor_(Halfedge_around_target_iterator<Graph>(h,g,(h==halfedge_descriptor())?1:n)), fct(g)
  {}

#ifndef DOXYGEN_RUNNING

  explicit operator bool() const
  {
    return (! (this->base_reference() == nullptr));
  }
private:
  friend class boost::iterator_core_access;
  typename  boost::graph_traits<Graph>::vertex_descriptor dereference() const { return fct(*this->base_reference()); }
#endif
};


template <typename Graph>
Iterator_range<Vertex_around_target_iterator<Graph> >
adjacent_vertices(typename boost::graph_traits<Graph>::halfedge_descriptor h, const Graph& g)
{
  typedef Vertex_around_target_iterator<Graph> I;
  return make_range(I(h,g), I(h,g,1));
}


template <typename Graph>
Iterator_range<Vertex_around_target_iterator<Graph> >
adjacent_vertices(typename boost::graph_traits<Graph>::vertex_descriptor v, const Graph& g)
{
  typedef Vertex_around_target_iterator<Graph> I;
  return make_range(I(halfedge(v,g),g), I(halfedge(v,g),g,1));
}

/**
 * \ingroup PkgBGLIterators
 * returns an iterator range over all vertices adjacent to the vertex `target(h,g)`.
 */
template <typename Graph>
Iterator_range<Vertex_around_target_iterator<Graph> >
vertices_around_target(typename boost::graph_traits<Graph>::halfedge_descriptor h, const Graph& g)
{
  typedef Vertex_around_target_iterator<Graph> I;
  return make_range(I(h,g), I(h,g,1));
}

template <typename Graph>
Iterator_range<Vertex_around_target_iterator<Graph> >
vertices_around_target(typename boost::graph_traits<Graph>::vertex_descriptor v, const Graph& g)
{
  typedef Vertex_around_target_iterator<Graph> I;
  return make_range(I(halfedge(v,g),g), I(halfedge(v,g),g,1));
}
/**
 * \ingroup PkgBGLIterators
 * returns an iterator range over all vertices adjacent to the face `face(h,g)`.
 */
template <typename Graph>
Iterator_range<Vertex_around_face_iterator<Graph> >
vertices_around_face(typename boost::graph_traits<Graph>::halfedge_descriptor h, const Graph& g)
{
  typedef Vertex_around_face_iterator<Graph> I;
  return make_range(I(h,g), I(h,g,1));
}


template <class Graph>
class Out_edge_iterator
  : public boost::iterator_adaptor<
             Out_edge_iterator<Graph>                                // Derived
             , Halfedge_around_target_iterator<Graph>                // Base
             , typename boost::graph_traits<Graph>::edge_descriptor  // Value
             , std::bidirectional_iterator_tag                       // CategoryOrTraversal
             , typename boost::graph_traits<Graph>::edge_descriptor  // Reference
             >
{
  typedef typename boost::graph_traits<Graph>::halfedge_descriptor halfedge_descriptor;
private:
  internal::Opposite_edge<Graph> opp;
public:
  Out_edge_iterator()
  {}

  Out_edge_iterator(halfedge_descriptor h, const Graph& g, int n = 0)
    : Out_edge_iterator::iterator_adaptor_(Halfedge_around_target_iterator<Graph>(h,g,(h==halfedge_descriptor())?1:n)), opp(g) {}

  explicit operator bool() const
  {
    return (! (this->base_reference() == nullptr));
  }


private:
  friend class boost::iterator_core_access;
  typename  boost::graph_traits<Graph>::edge_descriptor dereference() const { return opp(*this->base_reference()); }
};




template <class Graph>
class In_edge_iterator
  : public boost::iterator_adaptor<
             In_edge_iterator<Graph>                                 // Derived
             , Halfedge_around_target_iterator<Graph>                // Base
             , typename boost::graph_traits<Graph>::edge_descriptor  // Value
             , std::bidirectional_iterator_tag                       // CategoryOrTraversal
             , typename boost::graph_traits<Graph>::edge_descriptor  // Reference
             >
{
  typedef typename boost::graph_traits<Graph>::halfedge_descriptor halfedge_descriptor;
private:
  internal::Edge<Graph> fct;
public:
  In_edge_iterator()
  {}

  In_edge_iterator(halfedge_descriptor h, const Graph& g, int n = 0)
    : In_edge_iterator::iterator_adaptor_(Halfedge_around_target_iterator<Graph>(h,g,(h==halfedge_descriptor())?1:n)), fct(g)
  {}

  explicit operator bool() const
  {
    return (! (this->base_reference() == nullptr));
  }

 private:
    friend class boost::iterator_core_access;
  typename  boost::graph_traits<Graph>::edge_descriptor dereference() const { return fct(*this->base_reference()); }
};






} // CGAL


#endif /* CGAL_BGL_ITERATORS_H */
