cmake_minimum_required(VERSION 4.0)

project(ninbot
    VERSION 1.0.0
    DESCRIPTION "Ninbot library"
    LANGUAGES CXX
)

if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
    if(CMAKE_CXX_COMPILER_VERSION VERSION_LESS "16")
        message(FATAL_ERROR "GCC >= 16 required (found ${CMAKE_CXX_COMPILER_VERSION})")
    endif()
elseif(CMAKE_CXX_COMPILER_ID STREQUAL "Clang")
    if(CMAKE_CXX_COMPILER_VERSION VERSION_LESS "21")
        message(FATAL_ERROR "Clang >= 21 required (found ${CMAKE_CXX_COMPILER_VERSION})")
    endif()
endif()

# --- Options ---

option(NINBOT_BUILD_TESTS          "Build unit tests"                                 OFF)
option(NINBOT_BUILD_DOCS           "Build Nindocs documentation with Antora"          OFF)
option(NINBOT_BUILD_EXAMPLES       "Compile documentation example programs"           OFF)
option(NINBOT_BUILD_MUJOCO_TESTS   "Build MuJoCo integration tests (requires MuJoCo)" OFF)

if(CMAKE_BUILD_TYPE STREQUAL "Release")
    set(NINBOT_PACKAGE_DEFAULT ON)
else()
    set(NINBOT_PACKAGE_DEFAULT OFF)
endif()
option(NINBOT_BUILD_PACKAGES "Configure CPack package generation (binary and source)" ${NINBOT_PACKAGE_DEFAULT})

set(NINBOT_POS_DEFAULT_HOP_LIMIT "1024" CACHE STRING
    "Override the default coordinate tree traversal hop limit. Leave empty to use the built-in default of 1024.")

if(NINBOT_BUILD_MUJOCO_TESTS AND NINBOT_BUILD_TESTS)
    list(APPEND CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/cmake")
    find_package(MuJoCo)
    if(NOT MuJoCo_FOUND)
        set(NINBOT_BUILD_MUJOCO_TESTS OFF CACHE BOOL "" FORCE)
        set(NINBOT_MUJOCO_DISABLED_REASON "MuJoCo not found (set -DMUJOCO_ROOT=/path/to/mujoco)" CACHE INTERNAL "")
    endif()
endif()

if(NOT CMAKE_BUILD_TYPE)
    set(CMAKE_BUILD_TYPE "Release" CACHE STRING "" FORCE)
endif()

include(GNUInstallDirs)
include(CMakePackageConfigHelpers)

enable_testing()

add_subdirectory(src)
add_subdirectory(doc)

# --- CPack ---

if(NINBOT_BUILD_PACKAGES)
    set(CPACK_PACKAGE_NAME              "ninbot")
    set(CPACK_PACKAGE_VERSION           "${PROJECT_VERSION}")
    set(CPACK_PACKAGE_DESCRIPTION_SHORT "${PROJECT_DESCRIPTION}")
    set(CPACK_PACKAGE_VENDOR            "Ninbot")
    set(CPACK_RESOURCE_FILE_LICENSE     "${CMAKE_SOURCE_DIR}/LICENSE-GPLv3.txt")
    set(CPACK_PACKAGE_FILE_NAME
        "${CPACK_PACKAGE_NAME}-${PROJECT_VERSION}-${CMAKE_SYSTEM_NAME}-${CMAKE_SYSTEM_PROCESSOR}")

    # DEB
    set(CPACK_DEBIAN_PACKAGE_SECTION    "devel")
    set(CPACK_DEBIAN_PACKAGE_PRIORITY   "optional")

    # RPM
    set(CPACK_RPM_PACKAGE_LICENSE       "GPLv3")
    set(CPACK_RPM_PACKAGE_GROUP         "Development/Libraries")
    set(CPACK_RPM_EXCLUDE_FROM_AUTO_FILELIST_ADDITION
        "/usr/lib64"
        "/usr/lib64/cmake"
        "/usr/lib"
        "/usr/lib/cmake"
    )

    find_program(DPKG_FOUND dpkg)
    find_program(RPM_FOUND rpm)

    if(DPKG_FOUND)
        set(CPACK_GENERATOR "TGZ;DEB")
    elseif(RPM_FOUND)
        set(CPACK_GENERATOR "TGZ;RPM")
    else()
        set(CPACK_GENERATOR "TGZ")
    endif()

    # Source packages
    set(CPACK_SOURCE_GENERATOR "TGZ;TBZ2")
    set(CPACK_SOURCE_PACKAGE_FILE_NAME "${CPACK_PACKAGE_NAME}-${CPACK_PACKAGE_VERSION}-src")
    set(CPACK_SOURCE_IGNORE_FILES
        "/\\.git/"
        "/build.*/"
        "\\.swp$"
        "\\.gitignore$"
        # Agent instruction files and directories
        "/\\.claude/"
        "/CLAUDE\\.md$"
        "/AGENTS\\.md$"
        "/GEMINI\\.md$"
        "/COPILOT\\.md$"
        "/\\.cursorrules$"
        "/\\.windsurfrules$"
        # Tags file (generated by ctags/etags)
        "/tags$"
        "/TAGS$"
    )

    include(CPack)

    add_custom_target(pack_source
        COMMAND ${CMAKE_CPACK_COMMAND} --config CPackSourceConfig.cmake
        WORKING_DIRECTORY ${CMAKE_BINARY_DIR}
        COMMENT "Generating source packages (${NINBOT_CPACK_SOURCE_GENERATORS_DISPLAY})"
        VERBATIM
    )
endif()

message(STATUS "")
message(STATUS "Build configuration:")
message(STATUS "  CMAKE_GENERATOR              = ${CMAKE_GENERATOR}")
message(STATUS "  CMAKE_BUILD_TYPE             = ${CMAKE_BUILD_TYPE}")
message(STATUS "  CMAKE_INSTALL_PREFIX         = ${CMAKE_INSTALL_PREFIX}")
if(NINBOT_BUILD_PACKAGES)
    string(REPLACE ";" ", " NINBOT_CPACK_GENERATORS_DISPLAY "${CPACK_GENERATOR}")
    message(STATUS "  CPACK_GENERATOR              = ${NINBOT_CPACK_GENERATORS_DISPLAY}")
    string(REPLACE ";" ", " NINBOT_CPACK_SOURCE_GENERATORS_DISPLAY "${CPACK_SOURCE_GENERATOR}")
    message(STATUS "  CPACK_SOURCE_GENERATOR       = ${NINBOT_CPACK_SOURCE_GENERATORS_DISPLAY}")
endif()
message(STATUS "")
message(STATUS "Conditional compilation flags")
if(NINBOT_BUILD_TESTS)
message(STATUS "  NINBOT_BUILD_TESTS           = ON")
	if(NINBOT_BUILD_MUJOCO_TESTS)
	message(STATUS "  NINBOT_BUILD_MUJOCO_TESTS    = ON")
	elseif(NINBOT_MUJOCO_DISABLED_REASON)
	message(STATUS "  NINBOT_BUILD_MUJOCO_TESTS    = DISABLED - ${NINBOT_MUJOCO_DISABLED_REASON}")
	else()
	message(STATUS "  NINBOT_BUILD_MUJOCO_TESTS    = OFF")
	endif()
else()
message(STATUS "  NINBOT_BUILD_TESTS           = OFF")
endif()
if(NINBOT_BUILD_DOCS)
message(STATUS "  NINBOT_BUILD_DOCS            = ON")
else()
message(STATUS "  NINBOT_BUILD_DOCS            = OFF")
endif()
if(NINBOT_BUILD_EXAMPLES)
message(STATUS "  NINBOT_BUILD_EXAMPLES        = ON")
else()
message(STATUS "  NINBOT_BUILD_EXAMPLES        = OFF")
endif()
if(NINBOT_BUILD_PACKAGES)
message(STATUS "  NINBOT_BUILD_PACKAGES        = ON")
else()
message(STATUS "  NINBOT_BUILD_PACKAGES        = OFF")
endif()
message(STATUS "")
message(STATUS "Configurable parameters:")
message(STATUS "  NINBOT_POS_DEFAULT_HOP_LIMIT = ${NINBOT_POS_DEFAULT_HOP_LIMIT}")
message(STATUS "")
message(STATUS "Hint: Change the options with -D<option>=<ON/OFF/value>")
if(NINBOT_BUILD_PACKAGES)
message(STATUS "Hint: Generate source packages by running `ninja pack_source`")
endif()
message(STATUS "")

