// Copyright (c) 2014
// INRIA Saclay-Ile de France (France)
//
// This file is part of CGAL (www.cgal.org)
//
// $URL: https://github.com/CGAL/cgal/blob/v6.1.1/NewKernel_d/include/CGAL/NewKernel_d/Cartesian_filter_NT.h $
// $Id: include/CGAL/NewKernel_d/Cartesian_filter_NT.h 08b27d3db14 $
// SPDX-License-Identifier: LGPL-3.0-or-later OR LicenseRef-Commercial
//
// Author(s)     : Marc Glisse

#ifndef CGAL_KERNEL_D_CARTESIAN_FILTER_NT_H
#define CGAL_KERNEL_D_CARTESIAN_FILTER_NT_H

#include <CGAL/basic.h>
#include <CGAL/NewKernel_d/Cartesian_change_FT.h>
#include <CGAL/Number_types/internal/Exact_type_selector.h>

namespace CGAL {

template < typename Base_ >
struct Cartesian_filter_NT : public Base_
{
    constexpr Cartesian_filter_NT(){}
    constexpr Cartesian_filter_NT(int d):Base_(d){}
    typedef Base_ Kernel_base;
    typedef Cartesian_change_FT<Kernel_base,Interval_nt_advanced> K1;
    typedef typename internal::Exact_field_selector<typename Get_type<Kernel_base, FT_tag>::type>::Type  Exact_nt;
    typedef Cartesian_change_FT<Kernel_base,Exact_nt> K2;

    template<class T,class D=void,class=typename Get_functor_category<Cartesian_filter_NT,T>::type> struct Functor :
       Inherit_functor<Kernel_base,T,D> {};
    template<class T,class D> struct Functor<T,D,Predicate_tag> {
            struct type {
                    //TODO: use compression (derive from a compressed_pair?)
                    typedef typename Get_functor<K1, T>::type P1; P1 p1;
                    typedef typename Get_functor<K2, T>::type P2; P2 p2;
                    typedef typename P2::result_type result_type;
                    type(){}
                    type(Cartesian_filter_NT const&k):p1(reinterpret_cast<K1 const&>(k)),p2(reinterpret_cast<K2 const&>(k)){}
                    //FIXME: if predicate's constructor takes a kernel as argument, how do we translate that? reinterpret_cast is really ugly and possibly unsafe.

                    template<class...U> result_type operator()(U&&...u)const{
                            {
                                  Protect_FPU_rounding<true> p;
                                  try {
                                          typename P1::result_type res=p1(u...); // don't forward as u may be reused
                                          if(is_certain(res)) return get_certain(res);
                                  } catch (Uncertain_conversion_exception&) {}
                            }
                            CGAL_expensive_assertion(FPU_get_cw() == CGAL_FE_TONEAREST);
                            return p2(std::forward<U>(u)...);
                    }
            };
    };
};

} //namespace CGAL

#endif // CGAL_KERNEL_D_CARTESIAN_FILTER_NT_H
