cmake_minimum_required(VERSION 3.16)
project(salmanoff VERSION 0.01.000 LANGUAGES CXX)

include(CMakeDependentOption)
include(${CMAKE_CURRENT_SOURCE_DIR}/cmake/DAPSS.cmake)
include(${CMAKE_CURRENT_SOURCE_DIR}/cmake/DebugOpts.cmake)

# Set C++ standard
set(CMAKE_CXX_STANDARD 20)
set(CMAKE_CXX_STANDARD_REQUIRED ON)

# Build type
if(NOT CMAKE_BUILD_TYPE)
    set(CMAKE_BUILD_TYPE Debug FORCE)
endif()

# Compiler flags
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wextra -pedantic")

# Mind oscillator configuration
set(MIND_VOSCILLATOR_PERIOD_MS 33 CACHE STRING "Mind's virtual osc clock rate (ms)")
if(NOT MIND_VOSCILLATOR_PERIOD_MS GREATER 0)
    message(FATAL_ERROR "MIND_VOSCILLATOR_PERIOD_MS must be a positive integer > 0")
endif()
math(EXPR MIND_VOSCILLATOR_FREQ_MS "1000 / ${MIND_VOSCILLATOR_PERIOD_MS}")

# Device manager reattacher configuration
set(MRNTT_DEVMGR_REATTACHER_PERIOD_MS 2000
	CACHE STRING "Device manager reattacher period (ms)")
if(NOT MRNTT_DEVMGR_REATTACHER_PERIOD_MS GREATER 0)
    message(FATAL_ERROR
		"MRNTT_DEVMGR_REATTACHER_PERIOD_MS must be a positive integer > 0")
endif()

# World thread configuration
option(WORLD_USE_BODY_THREAD
	"Use body thread for world component instead of separate world thread" OFF)

# Test configuration
option(ENABLE_TESTS "Enable building tests" OFF)

# Set the debug locks variable for config.h
if(ENABLE_DEBUG_LOCKS)
    set(CONFIG_ENABLE_DEBUG_LOCKS TRUE)
endif()

# Set the world thread variable for config.h
if(WORLD_USE_BODY_THREAD)
    set(CONFIG_WORLD_USE_BODY_THREAD TRUE)
endif()

# Set the timeout variable for config.h
set(CONFIG_DEBUG_QUTEX_DEADLOCK_TIMEOUT_MS ${DEBUG_QUTEX_DEADLOCK_TIMEOUT_MS})

# Configure config.h
configure_file(
    ${CMAKE_CURRENT_SOURCE_DIR}/include/config.h.in
    ${CMAKE_CURRENT_BINARY_DIR}/include/config.h
    @ONLY
)

# Include directories
include_directories(
    ${CMAKE_CURRENT_SOURCE_DIR}/include
    ${CMAKE_CURRENT_SOURCE_DIR}/smocore/include
    ${CMAKE_CURRENT_BINARY_DIR}/include
)

# Find core dependencies
# Boost 1.72.0 is required to ensure that a certain bug where boost::asio
# objects depend on specific copies of symbols, and boost will cause a segfault
# if boost::asio objects are used inside of a dlopen()'d library, is fixed.
find_package(Boost 1.73.0 REQUIRED COMPONENTS system)
find_package(PkgConfig REQUIRED)
find_package(FLEX REQUIRED)
find_package(BISON REQUIRED)

# Need dlopen() and dlsym()
find_library(DL_LIBRARY NAMES dl ldl)
if(NOT DL_LIBRARY)
    message(FATAL_ERROR "Dynamic linking library (libdl/libldl) not found")
endif()

# Add third-party dependencies
if(ENABLE_TESTS)
    add_subdirectory(third_party)
endif()
# Add core components
add_subdirectory(smocore)
add_subdirectory(commonLibs)
add_subdirectory(stimBuffApis)
add_subdirectory(wilzorApis)
add_subdirectory(devices)

# Main executable
add_executable(salmanoff main.cpp)
target_link_libraries(salmanoff
    smocore
    ${Boost_LIBRARIES}
    ${DL_LIBRARY}
)

# Add all registered DAPSS targets as dependencies
add_all_daps_dependencies()

# Add tests if enabled
if(ENABLE_TESTS)
    enable_testing()
    add_subdirectory(tests)
endif()

install(TARGETS salmanoff DESTINATION bin)

# Install device configuration files (preprocessed .daps files)
install(DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/devices/
    DESTINATION share/salmanoff/devices
    FILES_MATCHING PATTERN "*.daps"
)

# Install documentation
install(FILES README.md DESTINATION share/doc/salmanoff)
install(FILES LICENSE DESTINATION share/doc/salmanoff)

# Install example configurations if they exist
if(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/examples")
    install(DIRECTORY examples/ DESTINATION share/salmanoff/examples)
endif()

# Include CPack configuration
include(${CMAKE_CURRENT_SOURCE_DIR}/cmake/CPackConfig.cmake)
include(CPack)
