#
# Copyright (c) 2015-2024 CNRS INRIA
#

# Compute flags outside the macro to avoid recomputing it for each tests
cxx_flags_by_compiler_frontend(MSVC _USE_MATH_DEFINES OUTPUT EXAMPLE_PRIVATE_DEFINITIONS)

function(ADD_PINOCCHIO_CPP_EXAMPLE EXAMPLE)
    if(NOT BUILD_STANDALONE_PYTHON_INTERFACE)
        set(options PARSERS CPPAD CPPADCG CASADI)
        set(oneValueArgs)
        set(multiValueArgs)
        cmake_parse_arguments(
            example
            "${options}"
            "${oneValueArgs}"
            "${multiValueArgs}"
            ${ARGN}
        )

        get_filename_component(EXAMPLE_NAME ${EXAMPLE} NAME)
        set(EXAMPLE_NAME "${PROJECT_NAME}-example-cpp-${EXAMPLE_NAME}")
        add_unit_test(${EXAMPLE_NAME} "${EXAMPLE}.cpp")
        target_link_libraries(${EXAMPLE_NAME} PUBLIC ${PROJECT_NAME})

        if(example_PARSERS)
            target_link_libraries(
                ${EXAMPLE_NAME}
                PUBLIC ${PROJECT_NAME}_parsers
            )
        endif()

        if(example_CPPAD)
            target_link_libraries(${EXAMPLE_NAME} PUBLIC ${PROJECT_NAME}_cppad)
        endif()

        if(example_CPPADCG)
            target_link_libraries(
                ${EXAMPLE_NAME}
                PUBLIC ${PROJECT_NAME}_cppadcg
            )
        endif()

        if(example_CASADI)
            target_link_libraries(${EXAMPLE_NAME} PUBLIC ${PROJECT_NAME}_casadi)
        endif()

        target_compile_definitions(
            ${EXAMPLE_NAME}
            PRIVATE ${EXAMPLE_PRIVATE_DEFINITIONS}
        )

        modernize_target_link_libraries(
          ${EXAMPLE_NAME}
          SCOPE PRIVATE
          TARGETS Boost::filesystem
          LIBRARIES ${Boost_FILESYSTEM_LIBRARY}}
          INCLUDE_DIRS ${Boost_INCLUDE_DIRS}
        )

        # There is no RPATH in Windows, then we must use the PATH to find the DLL
        if(WIN32)
            string(REPLACE ";" "\\\;" _PATH "$ENV{PATH}")
            set(ENV_VARIABLES
                "PATH=${_PATH}\\\;${PROJECT_BINARY_DIR}/src\\\;${PROJECT_BINARY_DIR}/bindings/python/pinocchio"
            )
            set_tests_properties(
                ${EXAMPLE_NAME}
                PROPERTIES ENVIRONMENT "${ENV_VARIABLES}"
            )
        endif()
        if(TARGET example-robot-data::example-robot-data)
            target_link_libraries(
                ${EXAMPLE_NAME}
                PRIVATE example-robot-data::example-robot-data
            )
        else()
            target_compile_definitions(
                ${EXAMPLE_NAME}
                PRIVATE
                    "EXAMPLE_ROBOT_DATA_MODEL_DIR=\"${EXAMPLE_ROBOT_DATA_MODEL_DIR}\""
            )
        endif()
    endif()
endfunction()

add_pinocchio_cpp_example(inverse-kinematics)
add_pinocchio_cpp_example(inverse-kinematics-3d)
add_pinocchio_cpp_example(overview-simple)
add_pinocchio_cpp_example(overview-lie)
add_pinocchio_cpp_example(overview-SE3)
add_pinocchio_cpp_example(interpolation-SE3)
add_pinocchio_cpp_example(model-graph PARSERS)
add_pinocchio_cpp_example(model-configuration-converter PARSERS)

if(BUILD_WITH_URDF_SUPPORT)
    add_pinocchio_cpp_example(overview-urdf PARSERS)
    add_pinocchio_cpp_example(build-reduced-model PARSERS)
    add_pinocchio_cpp_example(geometry-models PARSERS)
    add_pinocchio_cpp_example(kinematics-derivatives PARSERS)
    add_pinocchio_cpp_example(forward-dynamics-derivatives PARSERS)
    add_pinocchio_cpp_example(inverse-dynamics-derivatives PARSERS)
    if(BUILD_ADVANCED_TESTING)
        add_pinocchio_cpp_example(multiprecision PARSERS)
    endif()
endif()

if(BUILD_WITH_COLLISION_SUPPORT)
    if(BUILD_WITH_URDF_SUPPORT)
        add_pinocchio_cpp_example(collisions PARSERS)
    endif()
endif()

if(BUILD_PYTHON_INTERFACE)
    set(${PROJECT_NAME}_PYTHON_EXAMPLES
        inverse-kinematics
        inverse-kinematics-3d
        overview-simple
        kinematics-derivatives
        forward-dynamics-derivatives
        inverse-dynamics-derivatives
        model-graph
        model-configuration-converter
        ellipsoid-joint-kinematics
        admm-constraint-solver
    )

    if(BUILD_WITH_URDF_SUPPORT)
        list(
            APPEND ${PROJECT_NAME}_PYTHON_EXAMPLES
            overview-urdf
            gepetto-viewer
            build-reduced-model
            robot-wrapper-viewer
            geometry-models
            constraint-cholesky
        )
        if(BUILD_ADVANCED_TESTING)
            # Set as advanced testing because it need a new
            # example_robot_data release (> 4.4)
            # and because computation is long in Debug
            list(
                APPEND ${PROJECT_NAME}_PYTHON_EXAMPLES
                g1-constraint-simulation
            )
        endif()
    endif()

    if(BUILD_WITH_COLLISION_SUPPORT)
        list(
            APPEND ${PROJECT_NAME}_PYTHON_EXAMPLES
            sample-model-viewer
            display-shapes
            simulation-pendulum
            simulation-closed-kinematic-chains
            simulation-lcaba
            model-graph-geometry
        )
        if(BUILD_WITH_URDF_SUPPORT)
            list(
                APPEND ${PROJECT_NAME}_PYTHON_EXAMPLES
                meshcat-viewer
                meshcat-viewer-dae
                viser-viewer
                collisions
                collision-with-point-clouds
                append-urdf-model-with-another-model
                simulation-contact-dynamics
                # talos-simulation
                static-contact-dynamics
            )
        endif()
    endif()

    if(BUILD_WITH_OPENMP_SUPPORT)
        list(APPEND ${PROJECT_NAME}_PYTHON_EXAMPLES run-algo-in-parallel)
    endif()

    foreach(EXAMPLE ${${PROJECT_NAME}_PYTHON_EXAMPLES})
        set(EXAMPLE_NAME "${PROJECT_NAME}-example-py-${EXAMPLE}")
        add_python_unit_test("${EXAMPLE_NAME}" "examples/${EXAMPLE}.py" "bindings/python")
        get_test_property(${EXAMPLE_NAME} ENVIRONMENT _ENVIRONMENT)
        set_tests_properties(
            "${EXAMPLE_NAME}"
            PROPERTIES
                ENVIRONMENT
                    "${_ENVIRONMENT};EXAMPLE_ROBOT_DATA_MODEL_DIR=${EXAMPLE_ROBOT_DATA_MODEL_DIR}"
        )
        add_windows_dll_path_to_test(${EXAMPLE_NAME})
    endforeach()
endif()

add_subdirectory(casadi)
add_subdirectory(cppad)
add_subdirectory(codegen)
