// Copyright (c) 2006 Foundation for Research and Technology-Hellas (Greece).
// All rights reserved.
//
// This file is part of CGAL (www.cgal.org).
//
// $URL: https://github.com/CGAL/cgal/blob/v6.1.1/Voronoi_diagram_2/include/CGAL/Voronoi_diagram_2/Connected_components.h $
// $Id: include/CGAL/Voronoi_diagram_2/Connected_components.h 08b27d3db14 $
// SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-Commercial
//
//
// Author(s)     : Menelaos Karavelas <mkaravel@iacm.forth.gr>

#ifndef CGAL_VORONOI_DIAGRAM_2_CONNECTED_COMPONENTS_H
#define CGAL_VORONOI_DIAGRAM_2_CONNECTED_COMPONENTS_H 1

#include <CGAL/license/Voronoi_diagram_2.h>


#include <CGAL/Voronoi_diagram_2/basic.h>

namespace CGAL {

namespace VoronoiDiagram_2 { namespace Internal {

//========================================================================
//========================================================================

template<class VD_t>
class Connected_components
{
 private:
  typedef VD_t                                            VD;
  typedef typename VD::Halfedge_iterator                  Halfedge_iterator;
  typedef typename VD::Halfedge_handle                    Halfedge_handle;
  typedef typename VD::Halfedge                           Halfedge;
  typedef typename VD::Halfedge_around_vertex_circulator  HAVC;

  typedef HAVC Halfedge_around_vertex_circulator;

 public:
  typedef VD  Voronoi_diagram_2;

  typedef typename Voronoi_diagram_2::size_type          size_type;
  typedef size_type                                      result_type;
  typedef Voronoi_diagram_2                              argument_type;

 private:
  struct Halfedge_handle_less {
    bool operator()(const Halfedge_handle& e1,
                    const Halfedge_handle& e2) const {
      typename Halfedge::Delaunay_edge de1 = e1->dual();
      typename Halfedge::Delaunay_edge de2 = e2->dual();

      if ( de1.first != de2.first ) { return de1.first < de2.first; }
      return de1.second < de2.second;
    }
  };

  typedef std::map<Halfedge_handle,bool,Halfedge_handle_less>
  Halfedge_handle_map;

  void mark(const Halfedge_handle& e, Halfedge_handle_map& e_map) const
  {
    e_map[e] = true;
    e_map[e->opposite()] = true;
  }

  bool is_unmarked(const Halfedge_handle& e,
                   const Halfedge_handle_map& e_map) const
  {
    return e_map.find(e) == e_map.end();
  }

  void dfs(const Voronoi_diagram_2& vd, const Halfedge_handle& e,
           Halfedge_handle_map& e_map) const
  {
    CGAL_precondition( !vd.dual().is_infinite(e->dual()) );

    Halfedge_handle e_opp = e->opposite();
    mark(e, e_map);

    if ( e->has_source() ) {
      HAVC ec =        vd.incident_halfedges(e->source());
      HAVC ec_start = ec;

      do {
        if ( e != ec && e_opp != ec && is_unmarked(ec, e_map) ) {
          dfs(vd, ec, e_map);
        }
        ec++;
      } while (ec != ec_start);
    }

    if ( e->has_target() ) {
      HAVC ec = vd.incident_halfedges(e->target());
      HAVC ec_start = ec;

      do {
        if ( e != ec && e_opp != ec && is_unmarked(ec, e_map) ) {
          dfs(vd, ec, e_map);
        }
        ec++;
      } while (ec != ec_start);
    }
  }

 public:
  size_type operator()(const Voronoi_diagram_2& vd) const
  {
    Halfedge_handle_map e_map;

    size_type n_components = 0;
    for(Halfedge_iterator eit = vd.halfedges_begin();
        eit != vd.halfedges_end(); ++eit) {
      if ( is_unmarked(eit, e_map) ) {
        n_components++;
        dfs(vd, eit, e_map);
      }
    }
    return n_components;
  }
};

//========================================================================
//========================================================================

} } //namespace VoronoiDiagram_2::Internal

} //namespace CGAL

#endif // CGAL_VORONOI_DIAGRAM_2_CONNECTED_COMPONENTS
