// Copyright (c) 2006,2007,2009,2010,2011 Tel-Aviv University (Israel).
// All rights reserved.
//
// This file is part of CGAL (www.cgal.org).
//
// $URL: https://github.com/CGAL/cgal/blob/v6.0.3/Surface_sweep_2/include/CGAL/Surface_sweep_2/Surface_sweep_2_utils.h $
// $Id: include/CGAL/Surface_sweep_2/Surface_sweep_2_utils.h cefe3007d59 $
// SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-Commercial
//
//
// Author(s)     : Baruch Zukerman <baruchzu@post.tau.ac.il>
//                 Ron Wein        <wein@post.tau.ac.il>
//                 Efi Fogel       <efif@post.tau.ac.il>

#ifndef CGAL_SURFACE_SWEEP_2_UTILS_H
#define CGAL_SURFACE_SWEEP_2_UTILS_H

#include <CGAL/license/Surface_sweep_2.h>

/*! \file
 *
 * Auxiliary functions for the usage of the various sweep-line visitors.
 */

#include <vector>
#include <algorithm>

#include <CGAL/basic.h>
#include <CGAL/assertions.h>
#include <CGAL/Arr_enums.h>

namespace CGAL {
namespace Surface_sweep_2 {

/*! Subdivide a range of input curves into x-monotone objects.
 * \param begin The first input curve (of type Curve_2).
 * \param end A part-the-end iterator for the input curves.
 * \param x_curves Output: The x-monotone subcurves
 *                         (of type X_monotone_curve_2).
 * \param iso_points Output: The isolated points (of type Point_2).
 * \param tr A geometry-traits class.
 */
template <typename Traits,
          typename CurveInputIter,
          typename XCurveOutIter,
          typename PointOutIter>
void make_x_monotone(CurveInputIter begin, CurveInputIter end,
                     XCurveOutIter x_curves,
                     PointOutIter iso_points,
                     const Traits* tr)
{
  typedef typename Traits::Point_2                      Point_2;
  typedef typename Traits::X_monotone_curve_2           X_monotone_curve_2;
  typedef std::variant<Point_2, X_monotone_curve_2>   Make_x_monotone_result;

  // Split the input curves into x-monotone objects.
  std::size_t num_of_curves = std::distance(begin, end);
  std::vector<Make_x_monotone_result> object_vec;
  object_vec.reserve(num_of_curves);
  for (auto iter = begin; iter != end; ++iter) {
    tr->make_x_monotone_2_object()(*iter, std::back_inserter(object_vec));
  }

  // Transform each object to either a point or an x-monotone curve.
  for (const auto& obj : object_vec) {
    const X_monotone_curve_2* xcv = std::get_if<X_monotone_curve_2>(&obj);
    if (xcv != nullptr) {
      // The object is an x-monotone curve.
      *x_curves++ = *xcv;
      continue;
    }
    // The object is an isolated point.
    const Point_2* pt = std::get_if<Point_2>(&obj);
    CGAL_assertion(pt != nullptr);
    *iso_points++ = *pt;
  }
}

/*! Given an arrangement and two ranges of x-monotone curves and isolated
 * points, representing objects that should be inserted into the arrangement,
 * create two output sets of extended x-monotone curves and isolated points,
 * including the arrangement edges and isolated vertices.
 * \param arr The input arrangement.
 * \param xcvs_begin The first input x-monotone curve
 *                   (of type Arrangement::X_monotone_Curve_2).
 * \param xcvs_end A past-the-end iterator for the input x-monotone curves.
 * \param pts_begin The first isolated input point
 *                   (of type Arrangement::Point_2).
 * \param pts_end A past-the-end iterator for the isolated input points.
 * \param x_curves Output: The extended x-monotone subcurves
 *                         (of type ExTraits::X_monotone_curve_2).
 * \param iso_points Output: The extended isolated points
 *                           (of type ExTraits::Point_2).
 * \param ex_tr An extended geometry-traits class.
 *              This parameter is not actually in use, but is needed in order
 *              to instantiate the template parameter ExTraits.
 */
template <typename Arrangement,
          typename ExTraits,
          typename XCurveInputIter,
          typename PointInputIter,
          typename XCurveOutIter,
          typename PointOutIter>
void prepare_for_sweep(Arrangement& arr,
                       XCurveInputIter xcvs_begin, XCurveInputIter xcvs_end,
                       PointInputIter pts_begin, PointInputIter pts_end,
                       XCurveOutIter x_curves,
                       PointOutIter iso_points,
                       const ExTraits * /* ex_tr */)
{
  typedef typename Arrangement::Vertex_iterator       Vertex_iterator;
  typedef typename Arrangement::Edge_iterator         Edge_iterator;
  typedef typename Arrangement::Vertex_handle         Vertex_handle;
  typedef typename Arrangement::Halfedge_handle       Halfedge_handle;

  typedef typename ExTraits::X_monotone_curve_2       Ex_x_monotone_curve_2;
  typedef typename ExTraits::Point_2                  Ex_point_2;

  // Go over the input objects and copy them to the output iterators.
  XCurveInputIter xcv_it;
  PointInputIter pt_it;

  for (xcv_it = xcvs_begin; xcv_it != xcvs_end; ++xcv_it) {
    *x_curves = Ex_x_monotone_curve_2 (*xcv_it);
    ++x_curves;
  }

  for (pt_it = pts_begin; pt_it != pts_end; ++pt_it) {
    *iso_points = Ex_point_2 (*pt_it);
    ++iso_points;
  }

  // Go over the arrangement edges and insert their associated x-monotone
  // curves into the output iterator. To each curve we attach a handle to the
  // halfedge that goes from right to left.
  Edge_iterator     eit;
  Halfedge_handle   he;

  for (eit = arr.edges_begin(); eit != arr.edges_end(); ++eit) {
    if (eit->direction() == ARR_LEFT_TO_RIGHT) he = eit->twin();
    else he = eit;

    *x_curves = Ex_x_monotone_curve_2 (he->curve(), he);
    ++x_curves;
  }

  // Go over the isolated arrangement vertices and insert their associated
  // points into the output iterator. To each point we attach a handle to its
  // vertex.
  Vertex_iterator   vit;
  Vertex_handle     v;

   for (vit = arr.vertices_begin(); vit != arr.vertices_end(); ++vit) {
     v = vit;
     if (v->is_isolated()) {
       *iso_points = Ex_point_2 (v->point(), v);
       ++iso_points;
     }
   }
}

} // namespace CGAL
} // namespace Surface_sweep_2

#endif
