// Copyright (c) 2014  INRIA Sophia-Antipolis (France).
// All rights reserved.
//
// This file is part of CGAL (www.cgal.org).
//
// $URL: https://github.com/CGAL/cgal/blob/v6.2/Triangulation_2/include/CGAL/Triangulation_2/insert_constraints.h $
// $Id: include/CGAL/Triangulation_2/insert_constraints.h cac3e9d75e2 $
// SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-Commercial
//
//
// Author(s)     : Andreas Fabri, Mariette Yvinec

#ifndef CGAL_INTERNAL_TRIANGULATION_2_IMSERT_CONSTRAINTS_H
#define CGAL_INTERNAL_TRIANGULATION_2_IMSERT_CONSTRAINTS_H

#include <CGAL/license/Triangulation_2.h>


#include <CGAL/Spatial_sort_traits_adapter_2.h>
#include <CGAL/property_map.h>
#include <CGAL/boost/iterator/counting_iterator.hpp>
#include <boost/functional/hash.hpp>

#include <iterator>
#include <unordered_set>
#include <vector>

namespace CGAL {
  namespace internal {



    template <class T, class IndicesIterator, bool check_duplicates = false>
    std::size_t insert_constraints( T& t,
                                    const std::vector<typename T::Point>& points,
                                    IndicesIterator indices_first,
                                    IndicesIterator indices_beyond)
  {
    if(indices_first == indices_beyond){
      return t.insert(points.begin(), points.end());
    }
    typedef typename T::Vertex_handle Vertex_handle;
    typedef typename T::Face_handle Face_handle;
    typedef typename T::Geom_traits Geom_traits;
    typedef typename T::Point Point;
    typedef std::vector<std::size_t> Vertex_indices;
    typedef std::vector<Vertex_handle> Vertices;

    Vertex_indices vertex_indices(boost::counting_iterator<std::ptrdiff_t>(0),
                                  boost::counting_iterator<std::ptrdiff_t>(points.size()));

    typename T::size_type n = t.number_of_vertices();
    CGAL::Spatial_sort_traits_adapter_2<
      Geom_traits,
      typename Pointer_property_map<Point>::const_type >
        sort_traits(make_property_map(points),t.geom_traits());

    spatial_sort(vertex_indices.begin(), vertex_indices.end(), sort_traits);

    Vertices vertices;
    vertices.resize(points.size());

    Face_handle hint;
    for(typename Vertex_indices::const_iterator
          it_pti = vertex_indices.begin(), end = vertex_indices.end();
          it_pti != end; ++it_pti)
    {
      vertices[*it_pti] = t.insert(points[*it_pti], hint);
      hint=vertices[*it_pti]->face();
    }

    typedef std::unordered_set< std::pair<Vertex_handle,Vertex_handle>, boost::hash<std::pair<Vertex_handle,Vertex_handle> > >  Inserted;
    Inserted inserted;
    for(IndicesIterator it_cst=indices_first, end=indices_beyond;
        it_cst!=end; ++it_cst)
    {
      Vertex_handle v1 = vertices[it_cst->first];
      Vertex_handle v2 = vertices[it_cst->second];
      if(v1 != v2){
        if constexpr(check_duplicates){
          std::pair<Vertex_handle,Vertex_handle> p = (v1 < v2)? std::make_pair(v1,v2): std::make_pair(v2,v1);
          if(inserted.insert(p).second){
            t.insert_constraint(v1, v2);
          }
        }else{
          t.insert_constraint(v1, v2);
        }
      }
    }
    return t.number_of_vertices() - n;
  }


    template <class T, class ConstraintIterator, bool check_duplicates = false>
    std::size_t insert_constraints(T& t,
                                   ConstraintIterator first,
                                   ConstraintIterator beyond)
  {
    typedef typename T::Point Point;
    typedef std::vector< std::pair<std::size_t, std::size_t> >::iterator IndicesIterator;

    std::vector<Point> points;
    for (ConstraintIterator s_it=first; s_it!=beyond; ++s_it)
    {
      points.push_back( T::get_source(*s_it) );
      points.push_back( T::get_target(*s_it) );
    }

    std::vector< std::pair<std::size_t, std::size_t> > segment_indices;
    std::size_t nb_segments = points.size() / 2;
    segment_indices.reserve( nb_segments );
    for (std::size_t k=0; k < nb_segments; ++k)
      segment_indices.push_back( std::make_pair(2*k,2*k+1) );

    return insert_constraints<T, IndicesIterator,check_duplicates>(t,
                                                                   points,
                                                                   segment_indices.begin(),
                                                                   segment_indices.end());
  }


  }
}

#endif // CGAL_INTERNAL_TRIANGULATION_2_IMSERT_CONSTRAINTS_H
