namespace CGAL {

/*! \ingroup PkgArrangementOnSurface2TraitsClasses
 *
 * The class `Arr_circle_segment_traits_2` is a model of the
 * `AosTraits_2` concept and can be used to construct and maintain
 * arrangements of circular arcs and line segments.
 *
 * The traits class must be instantiated with a geometric kernel, such that the
 * supporting circles of the circular arcs are of type `Kernel::Circle_2` and
 * the supporting lines of the line segments are of type `Kernel::Line_2`.
 * Thus, the coordinates of the center of supporting circles, and its squared
 * radius are of type `Kernel::FT`, which should be an exact rational
 * number-type; similarly, the coefficients of each supporting line
 * \f$ax + by + c = 0\f$ are also of type `Kernel::FT`. Note however that the
 * intersection point between two such arcs do not have rational coordinates in
 * general. For this reason, we do not require the endpoints of the input arcs
 * and segments to have rational coordinates.
 *
 * The nested `Point_2` type defined by the traits class is therefore
 * <I>different</I> than the `Kernel::Point_2` type. Its coordinates are of type
 * `CoordNT`, which an instantiation of `Sqrt_extension<NT,ROOT>` where
 * `NT` = `ROOT` = `Kernel::FT`.  Moreover, the third and fourth (hidden)
 * template parameters of `Sqrt_extension<NT,ROOT>` are set to `CGAL::Tag_true`,
 * which enables efficient comparison among different extensions.
 *
 * For more details see the documentation of `Sqrt_extension<NT,ROOT>`.
 *
 * While `Arr_circle_segment_traits_2` models the concept
 * `AosDirectionalXMonotoneTraits_2`, the implementation of the
 * `Are_mergeable_2` operation does not enforce the input curves to have the
 * same direction as a precondition. Moreover, `Arr_circle_segment_traits_2`
 * supports the merging of curves of opposite directions.
 *
 * \cgalModels{AosTraits_2,AosApproximateTraits_2,AosDirectionalXMonotoneTraits_2}
 *
 */
template <typename Kernel>
class Arr_circle_segment_traits_2 {
public:
  /*! The `Curve_2` class nested within the traits class can represent
   * arbitrary circular arcs, full circles and line segments and support their
   * construction in various ways.  The copy and default constructor as well as
   * the assignment operator are provided. In addition, an `operator<<` for the
   * curves is defined for standard output streams.
   */
  class Curve_2 {
  public:

    /// \name Creation
    /// @{

    /*! constructs an curve corresponding to the line segment `seg`.
     */
    Curve_2(const typename Kernel::Segment_2& seg);

    /*! constructs an curve corresponding to the line segment directed
     * from `source` to `target`, both having rational coordinates.
     */
    Curve_2(const typename Kernel::Point_2& source,
            const typename Kernel::Point_2& target);

    /*! constructs an curve corresponding to the line segment supported by
     * the given line, directed from `source` to `target`. Note that the two
     * endpoints may have one-root coordinates.
     *
     * \pre Both endpoints must lie on the given supporting line.
     */
    Curve_2(const typename Kernel::Line_2& line,
            const Point_2& source,
            const Point_2& target);

    /*! constructs an curve corresponding to the given circle. `circ`
     * has a center point with rational coordinates and its <I>squared</I>
     * radius is rational.
     */
    Curve_2(const typename Kernel::Circle_2& circ);

    /*! constructs an curve corresponding to a circle centered at the rational
     * point `c` whose radius `r` is rational.
     */
    Curve_2(const typename Kernel::Point_2& c,
            const typename Kernel::FT& r,
            Orientation orient = COUNTERCLOCKWISE);

    /*! constructs a circular arc supported by `circ`, which has a
     * center point with rational coordinates and whose <I>squared</I> radius is
     * rational, with the given endpoints. The orientation of the arc is the
     * same as the orientation of `circ`.
     *
     * \pre Both endpoints must lie on the given supporting circle.
     */
    Curve_2(const typename Kernel::Circle_2& circ,
            const Point_2& source, const Point_2& target);

    /*! constructs a circular arc supported by a circle centered at the rational
     * point `c` whose radius `r` is rational, directed from `source` to
     * `target` with the given orientation.
     *
     * \pre Both endpoints must lie on the supporting circle.
     */
    Curve_2(const typename Kernel::Point_2& c,
            const typename Kernel::FT& r,
            Orientation orient,
            const Point_2& source, const Point_2& target);

    /*! constructs an circular arc whose endpoints are `source` and
     * `target` that passes through `mid`. All three points have
     * rational coordinates.
     *
     * \pre The three points must not be collinear.
     */
    Curve_2(const typename Kernel::Point_2& source,
            const typename Kernel::Point_2& mid,
            const typename Kernel::Point_2& target);

    /// @}

    /// \name Access Functions
    /// @{

    /*! indicates whether the curve represents a full circle.
     */
    bool is_full() const;

    /*! returns the source point.
     *
     * \pre `cv` is not a full circle.
     */
    const Point_2& source() const;

    /*! returns the target point.
     *
     * \pre `cv` is not a full circle.
     */
    const Point_2& target() const;

    /*! returns the orientation of the curve (`COLLINEAR` in case of line
     * segments).
     */
    Orientation orientation() const;

    /*! determines whether `cv` is a line segment.
     */
    bool is_linear() const;

    /*! determines whether `cv` is a circular arc.
     */
    bool is_circular() const;

    /*! returns the supporting line of `cv`.
     *
     * \pre `cv` is a line segment.
     */
    typename Kernel::Line_2 supporting_line() const;

    /*! returns the supporting circle of `cv`.
     *
     * \pre `cv` is a circular arc.
     */
    typename Kernel::Circle_2 supporting_circle() const;

    /// @}
  }; /* end Arr_circle_segment_traits_2::Curve_2 */


  /*! The `Point_2` number-type nested within the traits class represents
   * a %Cartesian point whose coordinates are algebraic numbers of type
   * `CoordNT`.
   */
  class Point_2 {
  public:
    /// \name Types
    /// @{

    /// the `Kernel::FT` type.
    typedef unspecified_type Rational;

    /// the algebraic number-type.
    typedef unspecified_type CoordNT;

    /// @}

    /// \name Creation
    /// @{

    /*! constructs default
     */
    Point_2();

    /*! creates the point \f$(x,y)\f$.
     */
    Point_2(const Rational& x, const Rational& y);

    /*! creates the point \f$(x,y)\f$.
     */
    Point_2(const CoordNT& x, const CoordNT& y);

    /// @}

    /// \name Access Functions
    /// @{

    /*! returns the \f$x\f$-coordinate.
     */
    CoordNT x() const;

    /*! returns the \f$y\f$-coordinate.
     */
    CoordNT y() const;

    /// @}
  }; /* end Arr_circle_segment_traits_2::Point_2 */


  /*! The `X_monotone_curve_2` class nested within the traits class can
   * represent \f$x\f$-monotone and line segments (which are always weakly
   * \f$x\f$-monotone).  The copy and default constructor as well as the
   * assignment operator are provided. In addition, an `operator<<` for the
   * curves is defined for standard output streams.
   */
  class X_monotone_curve_2 {
  public:
    /// \name Creation
    /// @{

    /*! constructs an curve corresponding to the line segment directed
     * from `source` to `target`, both having rational coordinates.
     */
    X_monotone_curve_2(const typename Kernel::Point_2& source,
                       const typename Kernel::Point_2& target);

    /*! constructs an curve corresponding to the line segment supported by
     * the given line, directed from `source` to `target`.  Note that the two
     * endpoints may have one-root coordinates.
     *
     * \pre Both endpoints must lie on the given supporting line.
     */
    X_monotone_curve_2(const typename Kernel::Line_2& line,
                       const Point_2& source,
                       const Point_2& target);

    /*! constructs a circular arc supported by `circ`, which has a
     * center point with rational coordinates and whose <I>squared</I>
     * radius is rational, with the given endpoints. The orientation of the
     * arc is determined by `orient`.
     *
     * \pre Both endpoints must lie on the given supporting circle.
     *
     * \pre The circular arc is \f$x\f$-monotone.
     */
    X_monotone_curve_2(const typename Kernel::Circle_2& circ,
                       const Point_2& source, const Point_2& target,
                       Orientation orient);

    /// @}

    /// \name Access Functions
    /// @{

    /*! returns the source point of `xcv`.
     */
    const Point_2& source() const;

    /*! returns the target point of `xcv`.
     */
    const Point_2& target() const;

    /*! returns true if `xcv` is directed right, false otherwise.
     */
    bool is_directed_right() const;

    /*! returns the left (lexicographically smaller) endpoint of `xcv`.
     */
    const Point_2& left() const;

    /*! returns the right (lexicographically larger) endpoint of `xcv`.
     */
    const Point_2& right() const;

    /*! returns the orientation of the curve (`COLLINEAR` in case of line
     * segments).
     */
    Orientation orientation() const;

    /*! determines whether `xcv` is a line segment.
     */
    bool is_linear() const;

    /*! determines whether `xcv` is a circular arc.
     */
    bool is_circular() const;

    /*! returns the supporting line of `xcv`.
     *
     * \pre `xcv` is a line segment.
     */
    typename Kernel::Line_2 supporting_line() const;

    /*! returns the supporting circle of `xcv`.
     *
     * \pre `xcv` is a circular arc.
     */
    typename Kernel::Circle_2 supporting_circle() const;

    /*! returns a bounding box of the arc `xcv`.
     */
    Bbox_2 bbox() const;

    /// @}
  }; /* end Arr_circle_segment_traits_2::X_monotone_curve_2 */

  class Trim_2 {
  public:
    /// \name Creation
    /// @{

    /*! trims the given \f$x\f$-monotone curve to an from `src` to `tgt`.
     * \ pre `src` and `tgt` lies on the curve
     */
    X_monotone_curve_2(const X_monotone_curve_2& xcv,
                       const Point_2& src,
                       const Point_2& tgt) const

    /// @}
  } /* end Arr_circle_segment_traits_2::Trim_2 */
}; /* end Arr_circle_segment_traits_2 */

} /* end namespace CGAL */
