// Copyright (c) 2025 GeometryFactory (France).
// All rights reserved.
//
// This file is part of CGAL (www.cgal.org).
//
// $URL: https://github.com/CGAL/cgal/blob/v6.2-beta1/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/Three_point_cut_plane_traits.h $
// $Id: include/CGAL/Polygon_mesh_processing/internal/Three_point_cut_plane_traits.h 431cfb5357d $
// SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-Commercial
//
//
// Author(s)     : Léo Valque

#ifndef CGAL_THREE_POINT_CUT_PLANE_TRAITS_H
#define CGAL_THREE_POINT_CUT_PLANE_TRAITS_H

#include <CGAL/license/Polygon_mesh_processing/corefinement.h>

#include <CGAL/Origin.h>
#include <CGAL/enum.h>

namespace CGAL {
namespace Polygon_mesh_processing {
namespace internal {

template <class Kernel>
struct Three_point_cut_plane_traits
{
  using FT = typename Kernel::FT;
  using Point_3 = typename Kernel::Point_3;
  using Vector_3 = typename Kernel::Vector_3;

  struct Plane_3: public std::array<typename Kernel::Point_3, 3>{
    using Base = std::array<typename Kernel::Point_3, 3>;

    Plane_3(const Point_3 &a, const Point_3 &b, const Point_3 &c): Base({a, b, c}){}
    Plane_3(const std::array<Point_3, 3> &arr): Base(arr){}

    bool is_degenerate() const{
      return collinear((*this)[0], (*this)[1], (*this)[2]);
    }
  };

  struct Does_not_support_CDT2{};

  struct Oriented_side_3
  {
    Oriented_side operator()(const Plane_3& plane, const Point_3& p)  const
    {
      return orientation(plane[0], plane[1], plane[2], p);
    }
  };

  struct Construct_plane_line_intersection_point_3
  {
    Point_3 operator()(const Plane_3& plane, const Point_3& p, const Point_3& q)
    {
      typename Kernel::Construct_plane_line_intersection_point_3 construction;
      return construction(plane[0], plane[1], plane[2], p, q);
    }
  };

  struct Construct_orthogonal_vector_3{
    Vector_3 operator()(const Plane_3& plane)
    {
      return typename Kernel::Plane_3(plane[0], plane[1], plane[2]).orthogonal_vector();
    }
  };

  struct Construct_point_on_3{
    Point_3 operator()(const Plane_3& plane)
    {
      return plane[0];
    }
  };

  Oriented_side_3 oriented_side_3_object() const { return Oriented_side_3(); }
  Construct_plane_line_intersection_point_3 construct_plane_line_intersection_point_3_object() const { return Construct_plane_line_intersection_point_3(); }
  Construct_orthogonal_vector_3 construct_orthogonal_vector_3_object() const { return Construct_orthogonal_vector_3(); }
  Construct_point_on_3 construct_point_on_3_object() const { return Construct_point_on_3(); }

  using Compute_scalar_product_3 = typename Kernel::Compute_scalar_product_3;
  using Construct_vector_3 = typename Kernel::Construct_vector_3;

  Compute_scalar_product_3 compute_scalar_product_3_object(){ return Kernel().compute_scalar_product_3_object(); }
  Construct_vector_3 construct_vector_3_object(){ return Kernel().construct_vector_3_object(); }

#ifndef CGAL_PLANE_CLIP_DO_NOT_USE_BOX_INTERSECTION_D
// for does self-intersect
  using Segment_3 = typename Kernel::Segment_3;
  using Triangle_3 = typename Kernel::Triangle_3;
  using Construct_segment_3 = typename Kernel::Construct_segment_3;
  using Construct_triangle_3 =typename  Kernel::Construct_triangle_3;
  using Do_intersect_3 = typename Kernel::Do_intersect_3;
  Construct_segment_3 construct_segment_3_object() const { return Construct_segment_3(); }
  Construct_triangle_3 construct_triangle_3_object() const { return Construct_triangle_3(); }
  Do_intersect_3 do_intersect_3_object() const { return Do_intersect_3(); }
#endif
};

} } } // end of CGAL::Polygon_mesh_processing

#endif // CGAL_THREE_POINT_CUT_PLANE_TRAITS_H
