#pragma once
// Copyright (c) 2024-2026 Tarik Moussa.
// SPDX-License-Identifier: MIT

// conformal_mesh.hpp
//
// Central mesh type for the discrete conformal mapping algorithms.
// Replaces the Java CoHDS (de.varylab.discreteconformal.heds.CoHDS)
// and its associated vertex/edge/face types (CoVertex, CoEdge, CoFace).
//
// Design
// ------
//   Java                         │  C++ (this file)
//   ─────────────────────────────┼──────────────────────────────────────────
//   CoHDS                        │  ConformalMesh   (CGAL::Surface_mesh)
//   CoVertex / CoEdge / CoFace   │  Vertex_index / Edge_index / Face_index
//   HyperIdealRadiusAdapter      │  property_map<Vertex_index, double>
//   HalfedgeInterface adapters   │  named property maps ("v:lambda", …)
//
// Property-map naming convention
// ───────────────────────────────
//   "v:lambda"    per-vertex log scale factor  (conformal variable u_i)
//   "v:theta"     per-vertex target cone angle
//   "v:idx"       per-vertex solver DOF index  (-1 = pinned / boundary)
//   "e:alpha"     per-edge intersection angle  (α_ij, hyperbolic geometry)
//   "f:type"      per-face geometry type       (0=Euclidean, 1=Hyperbolic, 2=Spherical)
//
// All property maps are optional; add only what a given algorithm needs.
//
// Note on descriptor types (CGAL 6.x)
// ────────────────────────────────────
// CGAL::Surface_mesh exposes its index types as nested types:
//   Surface_mesh::Vertex_index, ::Halfedge_index, ::Edge_index, ::Face_index
// The BGL graph_traits aliases expose the same types as vertex_descriptor etc.,
// but those live in boost::graph_traits<Surface_mesh>, not in Surface_mesh itself.
// We use the Surface_mesh member names throughout for clarity.

#include <CGAL/Simple_cartesian.h>
#include <CGAL/Surface_mesh.h>
#include <cstdint>
#include <string>

namespace conformallab {

// ── Kernel ──────────────────────────────────────────────────────────────────
// Simple double-precision Cartesian.  Conformal mapping algorithms never
// need exact arithmetic — they operate on floating-point lengths and angles.

/// CGAL kernel used by all conformallab algorithms (double precision).
using Kernel = CGAL::Simple_cartesian<double>;
/// 3-D point type (vertex coordinates).
using Point3 = Kernel::Point_3;
/// 2-D point type (UV-domain layout coordinates).
using Point2 = Kernel::Point_2;

// ── Mesh type ────────────────────────────────────────────────────────────────
/// Triangle mesh carrying all conformal-map data as property maps.
using ConformalMesh = CGAL::Surface_mesh<Point3>;

// ── Index/descriptor aliases (CGAL 6.x naming) ───────────────────────────────
/// Vertex descriptor of `ConformalMesh`.
using Vertex_index   = ConformalMesh::Vertex_index;
/// Half-edge descriptor of `ConformalMesh`.
using Halfedge_index = ConformalMesh::Halfedge_index;
/// Edge descriptor of `ConformalMesh`.
using Edge_index     = ConformalMesh::Edge_index;
/// Face descriptor of `ConformalMesh`.
using Face_index     = ConformalMesh::Face_index;

// ── Geometry type constant (replaces Java CoFace.type enum) ─────────────────
/// Discrete geometry type that a face/mesh is interpreted in.
/// Replaces the original Java `CoFace.type` enum.
enum class GeometryType : int {
    Euclidean  = 0, ///< Flat metric (ℝ²).
    Hyperbolic = 1, ///< Hyperbolic metric (ℍ²).
    Spherical  = 2  ///< Spherical metric (S²).
};

// ── Standard property-map bundles ────────────────────────────────────────────

/// Register and return the vertex-side property maps used by all five
/// DCE functionals: `v:lambda` (log conformal factor), `v:theta` (target
/// cone angle), `v:idx` (contiguous integer index).
inline auto add_vertex_properties(ConformalMesh& mesh)
{
    auto [lambda, ok1] = mesh.add_property_map<Vertex_index, double>("v:lambda", 0.0);
    auto [theta,  ok2] = mesh.add_property_map<Vertex_index, double>("v:theta",  0.0);
    auto [idx,    ok3] = mesh.add_property_map<Vertex_index, int>   ("v:idx",   -1);
    (void)ok1; (void)ok2; (void)ok3;
    return std::make_tuple(lambda, theta, idx);
}

/// Register and return the edge intersection-angle property `e:alpha`
/// (used by the hyper-ideal functional).
inline auto add_edge_properties(ConformalMesh& mesh)
{
    auto [alpha, ok] = mesh.add_property_map<Edge_index, double>("e:alpha", 0.0);
    (void)ok;
    return alpha;
}

/// Register and return the per-face geometry-type property `f:type`.
inline auto add_face_properties(ConformalMesh& mesh)
{
    auto [ftype, ok] = mesh.add_property_map<Face_index, int>(
        "f:type", static_cast<int>(GeometryType::Euclidean));
    (void)ok;
    return ftype;
}

// ── Half-edge index helper ────────────────────────────────────────────────────
//
// Convert a Halfedge_index to std::size_t for use as a vector subscript.
// Each functional previously duplicated this one-liner under a name like
// eucl_hidx / spher_hidx / hidx.  Centralised here (MINOR-4 fix).
//
// Implementation: the double-cast uint32_t → size_t is intentional.  CGAL 6.x
// Surface_mesh stores half-edge indices internally as 32-bit unsigned integers.
// Casting directly to size_t on a 64-bit system would produce the same result
// because CGAL index types use non-negative values, but the explicit intermediate
// cast documents the assumption and silences spurious sign-conversion warnings.

/// Convert a `Halfedge_index` to `std::size_t` for vector subscript use.
/// Replaces the duplicated `eucl_hidx`, `spher_hidx`, `hidx` helpers.
inline std::size_t halfedge_to_index(Halfedge_index h) noexcept
{
    return static_cast<std::size_t>(static_cast<std::uint32_t>(h));
}

} // namespace conformallab
