// Copyright (c) 2012-2013, IGN France.
// Copyright (c) 2012-2024, Oslandia.
// Copyright (c) 2024-2026, SFCGAL team.
// SPDX-License-Identifier: LGPL-2.0-or-later

#include "SFCGAL/algorithm/tessellate.h"
#include "SFCGAL/GeometryCollection.h"
#include "SFCGAL/Solid.h"
#include "SFCGAL/TriangulatedSurface.h"
#include "SFCGAL/algorithm/isValid.h"
#include "SFCGAL/triangulate/triangulatePolygon.h"

namespace SFCGAL::algorithm {

/** Tessellate geometry without validity check
 * @param g Geometry to tessellate
 * @return Tessellated geometry */
auto
tessellate(const Geometry &g, NoValidityCheck /*unused*/)
    -> std::unique_ptr<Geometry>
{
  switch (g.geometryTypeId()) {
  case TYPE_POINT:
  case TYPE_LINESTRING:
  case TYPE_NURBSCURVE:
  case TYPE_TRIANGLE:
  case TYPE_MULTIPOINT:
  case TYPE_MULTILINESTRING:
    return g.clone();

  case TYPE_POLYGON:
  case TYPE_POLYHEDRALSURFACE: {
    auto triSurf = std::make_unique<TriangulatedSurface>();
    triangulate::triangulatePolygon3D(g, *triSurf);
    return triSurf;
  }

  case TYPE_SOLID: {
    auto ret = std::make_unique<GeometryCollection>();

    for (size_t i = 0; i < g.as<Solid>().numShells(); ++i) {
      const PolyhedralSurface &shellN = g.as<Solid>().shellN(i);

      if (!shellN.isEmpty()) {
        ret->addGeometry(tessellate(shellN));
      }
    }

    return ret;
  }

  // multipolygon and multisolid return a geometrycollection
  case TYPE_MULTIPOLYGON:
  case TYPE_MULTISOLID:
  case TYPE_GEOMETRYCOLLECTION: {
    auto ret = std::make_unique<GeometryCollection>();

    for (size_t i = 0; i < g.numGeometries(); ++i) {
      ret->addGeometry(tessellate(g.geometryN(i)));
    }

    return ret;
  }

  default:
    break;
  }

  return g.clone();
}

/** Tessellate geometry
 * @param g Geometry to tessellate
 * @return Tessellated geometry */
auto
tessellate(const Geometry &g) -> std::unique_ptr<Geometry>
{
  SFCGAL_ASSERT_GEOMETRY_VALIDITY(g);

  return tessellate(g, NoValidityCheck());
}

} // namespace SFCGAL::algorithm
