#include <Rcpp.h>
// Copyright (c) 2020 GeometryFactory (France) and Telecom Paris (France).
// All rights reserved.
//
// This file is part of CGAL (www.cgal.org)
//
// $URL: https://github.com/CGAL/cgal/blob/v6.1/Tetrahedral_remeshing/include/CGAL/Tetrahedral_remeshing/internal/peel_slivers.h $
// $Id: include/CGAL/Tetrahedral_remeshing/internal/peel_slivers.h b26b07a1242 $
// SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-Commercial
//
//
// Author(s)     : Jane Tournois, Noura Faraj, Jean-Marc Thiery, Tamy Boubekeur

#ifndef CGAL_INTERNAL_PEEL_SLIVERS_H
#define CGAL_INTERNAL_PEEL_SLIVERS_H

#include <CGAL/license/Tetrahedral_remeshing.h>

#include <CGAL/Tetrahedral_remeshing/internal/tetrahedral_remeshing_helpers.h>
#include <CGAL/Tetrahedral_remeshing/internal/property_maps.h>

#include <optional>

namespace CGAL
{
namespace Tetrahedral_remeshing
{
template<typename C3T3>
std::size_t peel_slivers(C3T3& c3t3,
                         const typename C3T3::Triangulation::Geom_traits::FT& sliver_angle);

template<typename C3T3, typename CellSelector>
std::size_t peel_slivers(C3T3& c3t3,
                         const typename C3T3::Triangulation::Geom_traits::FT& sliver_angle,
                         const CellSelector& cell_selector)
{
  using FT = typename C3T3::Triangulation::Geom_traits::FT;
  using Cell_handle = typename C3T3::Triangulation::Cell_handle;
  using Surface_patch_index = typename C3T3::Surface_patch_index;

  auto& tr = c3t3.triangulation();

  std::size_t nb_slivers_peel = 0;
  std::vector<std::pair<Cell_handle, std::array<bool, 4> > > peelable_cells;

#ifdef CGAL_TETRAHEDRAL_REMESHING_VERBOSE
  FT mindh = FT(180);
#endif
  for (Cell_handle cit : c3t3.cells_in_complex())
  {
    const bool selected = get(cell_selector, cit);
    if(!selected)
      continue;

    std::array<bool, 4> facets_on_surface;

    const FT dh = min_dihedral_angle(tr, cit);
    if (dh < sliver_angle && is_peelable(c3t3, cit, facets_on_surface))
      peelable_cells.push_back(std::make_pair(cit, facets_on_surface));

#ifdef CGAL_TETRAHEDRAL_REMESHING_VERBOSE
    mindh = (std::min)(dh, mindh);
#endif
  }

#ifdef CGAL_TETRAHEDRAL_REMESHING_VERBOSE
  Rcpp::Rcout << "Min dihedral angle : " << mindh << std::endl;
  Rcpp::Rcout << "Peelable cells : " << peelable_cells.size() << std::endl;
#endif

  for (auto c_i : peelable_cells)
  {
    Cell_handle c = c_i.first;
    const std::array<bool, 4>& f_on_surface = c_i.second;

    std::optional<Surface_patch_index> patch;
    for (int i = 0; i < 4; ++i)
    {
      if (f_on_surface[i])
      {
        Surface_patch_index spi = c3t3.surface_patch_index(c, i);
        if (patch.has_value() && patch.value() != spi)
        {
          //there are 2 different patches
          patch.reset();
          break;
        }
        else
        {
          patch = spi;
        }
      }
    }
    if (!patch.has_value())
      continue;

    for (int i = 0; i < 4; ++i)
    {
      if (f_on_surface[i])
        c3t3.remove_from_complex(c, i);
      else
        c3t3.add_to_complex(c, i, patch.value());
    }

    c3t3.remove_from_complex(c);
    ++nb_slivers_peel;
  }

#ifdef CGAL_TETRAHEDRAL_REMESHING_VERBOSE
  mindh = FT(180);
  for (Cell_handle cit : c3t3.cells_in_complex())
  {
    if(get(cell_selector, cit))
      mindh = (std::min)(min_dihedral_angle(tr, cit), mindh);
  }
  Rcpp::Rcout << "Peeling done (removed " << nb_slivers_peel << " slivers, "
    << "min dihedral angle = " << mindh << ")." << std::endl;
#endif

  return nb_slivers_peel;
}

template<typename C3T3>
std::size_t peel_slivers(C3T3 & c3t3,
  const typename C3T3::Triangulation::Geom_traits::FT & sliver_angle)
{
  using Tr = typename C3T3::Triangulation;
  return peel_slivers(c3t3, sliver_angle,
    CGAL::Tetrahedral_remeshing::internal::All_cells_selected<Tr>());
}


} // end namespace Tetrahedral_remeshing
} // end namespace CGAL

#endif // CGAL_INTERNAL_PEEL_SLIVERS_H

