#pragma once

// pybind 11 related includes
#include <pybind11/pybind11.h>
#include <pybind11/stl.h>

namespace py = pybind11;

// Standard Handle
#include <Standard_Handle.hxx>

// user-defined inclusion per module before includes

// includes to resolve forward declarations
#include <Adaptor2d_Curve2d.hxx>
#include <Adaptor3d_Curve.hxx>
#include <Adaptor3d_Surface.hxx>
#include <TopoDS_Vertex.hxx>
#include <IntTools_Curve.hxx>
#include <TopoDS_Edge.hxx>
#include <TopoDS_Face.hxx>
#include <IntTools_Context.hxx>
#include <TopoDS_Solid.hxx>
#include <IntTools_Range.hxx>
#include <TopoDS_Shell.hxx>
#include <Message_Report.hxx>
#include <Adaptor2d_Curve2d.hxx>
#include <Adaptor3d_Curve.hxx>
#include <Adaptor3d_Surface.hxx>
#include <TopoDS_Edge.hxx>
#include <TopoDS_Face.hxx>
#include <gp_Vec.hxx>
#include <Geom2d_Curve.hxx>
#include <Geom_Curve.hxx>
#include <BRepAdaptor_Surface.hxx>
#include <IntTools_Context.hxx>
#include <Adaptor2d_Curve2d.hxx>
#include <Adaptor3d_Curve.hxx>
#include <Adaptor3d_Surface.hxx>
#include <TopoDS_Edge.hxx>
#include <TopoDS_Face.hxx>
#include <gp_Dir.hxx>
#include <Geom_Surface.hxx>
#include <Geom2d_Curve.hxx>
#include <gp_Pnt.hxx>
#include <IntTools_Context.hxx>
#include <gp_Pnt2d.hxx>
#include <TopoDS_Shape.hxx>
#include <Adaptor2d_Curve2d.hxx>
#include <Adaptor3d_Curve.hxx>
#include <Adaptor3d_Surface.hxx>
#include <Adaptor2d_Curve2d.hxx>
#include <Adaptor3d_Curve.hxx>
#include <Adaptor3d_Surface.hxx>
#include <Adaptor2d_Curve2d.hxx>
#include <Adaptor3d_Curve.hxx>
#include <Adaptor3d_Surface.hxx>
#include <Adaptor2d_Curve2d.hxx>
#include <Adaptor3d_Curve.hxx>
#include <Adaptor3d_Surface.hxx>
#include <Adaptor2d_Curve2d.hxx>
#include <Adaptor3d_Curve.hxx>
#include <Adaptor3d_Surface.hxx>
#include <Adaptor2d_Curve2d.hxx>
#include <Adaptor3d_Curve.hxx>
#include <Adaptor3d_Surface.hxx>
#include <Adaptor2d_Curve2d.hxx>
#include <Adaptor3d_Curve.hxx>
#include <Adaptor3d_Surface.hxx>
#include <Adaptor2d_Curve2d.hxx>
#include <Adaptor3d_Curve.hxx>
#include <Adaptor3d_Surface.hxx>
#include <Adaptor2d_Curve2d.hxx>
#include <Adaptor3d_Curve.hxx>
#include <Adaptor3d_Surface.hxx>
#include <Adaptor2d_Curve2d.hxx>
#include <Adaptor3d_Curve.hxx>
#include <Adaptor3d_Surface.hxx>

// module includes
#include <BOPTools_AlgoTools.hxx>
#include <BOPTools_AlgoTools2D.hxx>
#include <BOPTools_AlgoTools3D.hxx>
#include <BOPTools_BoxSelector.hxx>
#include <BOPTools_BoxTree.hxx>
#include <BOPTools_ConnexityBlock.hxx>
#include <BOPTools_CoupleOfShape.hxx>
#include <BOPTools_IndexedDataMapOfSetShape.hxx>
#include <BOPTools_ListOfConnexityBlock.hxx>
#include <BOPTools_ListOfCoupleOfShape.hxx>
#include <BOPTools_MapOfSet.hxx>
#include <BOPTools_Parallel.hxx>
#include <BOPTools_Set.hxx>

// user-defined pre
#include "OCP_specific.inc"

// Class template handling functions

template <typename NumType,int Dimension,typename DataType>
void preregister_template_BOPTools_BoxSet(py::object &m, const char *name){
    py::class_<BOPTools_BoxSet<NumType,Dimension,DataType> , shared_ptr<BOPTools_BoxSet<NumType,Dimension,DataType>> >(m,name,R"#(Redefines BoxSet to use the Linear builder by default)#");
}

template <typename NumType,int Dimension,typename DataType>
void register_template_BOPTools_BoxSet(py::object &m, const char *name){
    static_cast<py::class_<BOPTools_BoxSet<NumType,Dimension,DataType> , shared_ptr<BOPTools_BoxSet<NumType,Dimension,DataType>> >>(m.attr(name))
        .def(py::init<  const handle<BVH_Builder<NumType, Dimension>> & >() ,py::arg("theBuilder")=static_cast< const handle<BVH_Builder<NumType, Dimension>> &>(NULL) )
    ;
};

template <int Dimension>
void preregister_template_BOPTools_BoxSelector(py::object &m, const char *name){
    py::class_<BOPTools_BoxSelector<Dimension> , shared_ptr<BOPTools_BoxSelector<Dimension>> >(m,name,R"#(Template Selector for elements selection from BVH tree.)#");
}

template <int Dimension>
void register_template_BOPTools_BoxSelector(py::object &m, const char *name){
    static_cast<py::class_<BOPTools_BoxSelector<Dimension> , shared_ptr<BOPTools_BoxSelector<Dimension>> >>(m.attr(name))
        .def(py::init<  >()  )
        .def("Clear",
             (void (BOPTools_BoxSelector<Dimension>::*)() ) &BOPTools_BoxSelector<Dimension>::Clear,
             R"#(Clears the indices)#" )
        .def("SetBox",
             (void (BOPTools_BoxSelector<Dimension>::*)(  const BVH_Box<Standard_Real, Dimension> &  ) ) &BOPTools_BoxSelector<Dimension>::SetBox,
             R"#(Sets the box)#" ,py::arg("theBox"))
        .def("Indices",
             ( const TColStd_ListOfInteger & (BOPTools_BoxSelector<Dimension>::*)() const) &BOPTools_BoxSelector<Dimension>::Indices,
             R"#(Returns the list of accepted indices)#" )
        .def("RejectNode",
             (Standard_Boolean (BOPTools_BoxSelector<Dimension>::*)(  const typename BOPTools_BoxSelector<Dimension>::BVH_VecNd & ,   const typename BOPTools_BoxSelector<Dimension>::BVH_VecNd & ,  Standard_Boolean &  ) const) &BOPTools_BoxSelector<Dimension>::RejectNode,
             R"#(Checks if the box should be rejected)#" ,py::arg("theCMin"), py::arg("theCMax"), py::arg("theIsInside"))
        .def("RejectElement",
             (Standard_Boolean (BOPTools_BoxSelector<Dimension>::*)(  const Standard_Integer  ) ) &BOPTools_BoxSelector<Dimension>::RejectElement,
             R"#(Checks if the element should be rejected)#" ,py::arg("theIndex"))
        .def("AcceptMetric",
             (Standard_Boolean (BOPTools_BoxSelector<Dimension>::*)(  const Standard_Boolean &  ) const) &BOPTools_BoxSelector<Dimension>::AcceptMetric,
             R"#(Checks if the metric of the node may be accepted)#" ,py::arg("theIsInside"))
        .def("Accept",
             (Standard_Boolean (BOPTools_BoxSelector<Dimension>::*)(  const Standard_Integer ,   const Standard_Boolean &  ) ) &BOPTools_BoxSelector<Dimension>::Accept,
             R"#(Accepts the element with the index <theIndex> in BVH tree)#" ,py::arg("theIndex"), py::arg("theIsInside"))
    ;
};


// user-defined post

