cmake_minimum_required(VERSION 3.10)
project(akgl LANGUAGES C)

include(CTest)

if(CMAKE_SOURCE_DIR STREQUAL CMAKE_CURRENT_SOURCE_DIR)

# Vendored projects own their test suites. Suppress their CTest registration
# while embedded so the top-level suite contains only targets built here.
set(AKGL_SUPPRESS_DEPENDENCY_TESTS TRUE)
function(add_test)
  if(NOT AKGL_SUPPRESS_DEPENDENCY_TESTS)
    _add_test(${ARGV})
  endif()
endfunction()
function(set_tests_properties)
  if(NOT AKGL_SUPPRESS_DEPENDENCY_TESTS)
    _set_tests_properties(${ARGV})
  endif()
endfunction()

set(JANSSON_WITHOUT_TESTS ON CACHE BOOL "Do not build vendored Jansson tests" FORCE)
set(JANSSON_EXAMPLES OFF CACHE BOOL "Do not build vendored Jansson examples" FORCE)
set(JANSSON_BUILD_DOCS OFF CACHE BOOL "Do not build vendored Jansson docs" FORCE)

add_subdirectory(deps/jansson EXCLUDE_FROM_ALL)
add_subdirectory(deps/libakerror EXCLUDE_FROM_ALL)
add_subdirectory(deps/libakstdlib EXCLUDE_FROM_ALL)
add_subdirectory(deps/SDL EXCLUDE_FROM_ALL)
add_subdirectory(deps/SDL_image EXCLUDE_FROM_ALL)
add_subdirectory(deps/SDL_mixer EXCLUDE_FROM_ALL)
add_subdirectory(deps/SDL_ttf EXCLUDE_FROM_ALL)

# Reserve error-name table entries for libakgl-specific status codes.
target_compile_definitions(akerror PUBLIC
  AKERR_MAX_ERR_VALUE=256
)

set(AKGL_SUPPRESS_DEPENDENCY_TESTS FALSE)

else()

  find_package(PkgConfig REQUIRED)

  if(NOT TARGET SDL3::SDL3)
    find_package(SDL3 REQUIRED)
  endif()
  if(NOT TARGET SDL3_image::SDL3_image)
    find_package(SDL3_image REQUIRED)
  endif()
  if(NOT TARGET SDL3_mixer::SDL3_mixer)
    find_package(SDL3_mixer REQUIRED)
  endif()
  if(NOT TARGET SDL3_ttf::SDL3_ttf)
    find_package(SDL3_ttf REQUIRED)
  endif()
  if(NOT TARGET akerror::akerror)
    find_package(akerror REQUIRED)
  endif()
  if(NOT TARGET akstdlib::akstdlib)
    find_package(akstdlib REQUIRED)
  endif()
  if(NOT TARGET jansson::jansson)
    find_package(jansson)
  endif()
  
endif()

set(GAMECONTROLLERDB_H "include/akgl/SDL_GameControllerDB.h")
set(prefix      ${CMAKE_INSTALL_PREFIX})
set(exec_prefix "\${prefix}")
set(libdir      "\${exec_prefix}/lib")
set(includedir  "\${prefix}/include")
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/akgl.pc.in ${CMAKE_CURRENT_BINARY_DIR}/akgl.pc @ONLY)

# Tests use both relative paths and SDL_GetBasePath(), so stage fixtures beside
# test executables in every out-of-tree build.
file(COPY "${CMAKE_CURRENT_SOURCE_DIR}/tests/assets"
     DESTINATION "${CMAKE_CURRENT_BINARY_DIR}")

add_custom_command(
  OUTPUT ${GAMECONTROLLERDB_H}
  COMMAND ${CMAKE_CURRENT_SOURCE_DIR}/mkcontrollermappings.sh ${CMAKE_CURRENT_SOURCE_DIR}
  COMMENT "Generating controller mappings ..."
)

# Add include directories
include_directories(${SDL3_INCLUDE_DIRS})
add_library(akgl SHARED
  deps/semver/semver.c
  src/actor.c
  src/actor_state_string_names.c
  src/text.c
  src/assets.c
  src/character.c
  src/draw.c
  src/game.c
  src/controller.c
  src/heap.c
  src/json_helpers.c
  src/registry.c
  src/renderer.c
  src/physics.c
  src/sprite.c
  src/staticstring.c
  src/tilemap.c
  src/util.c
  ${GAMECONTROLLERDB_H}
)

add_library(akgl::akgl ALIAS akgl)

add_executable(charviewer util/charviewer.c)
add_executable(test_actor tests/actor.c)
add_executable(test_bitmasks tests/bitmasks.c)
add_executable(test_character tests/character.c)
add_executable(test_registry tests/registry.c)
add_executable(test_sprite tests/sprite.c)
add_executable(test_staticstring tests/staticstring.c)
add_executable(test_tilemap tests/tilemap.c)
add_executable(test_util tests/util.c)
add_executable(test_semver_unit deps/semver/semver_unit.c)
add_test(NAME actor COMMAND test_actor)
add_test(NAME bitmasks COMMAND test_bitmasks)
add_test(NAME character COMMAND test_character)
add_test(NAME registry COMMAND test_registry)
add_test(NAME sprite COMMAND test_sprite)
add_test(NAME staticstring COMMAND test_staticstring)
add_test(NAME tilemap COMMAND test_tilemap)
add_test(NAME util COMMAND test_util)
add_test(NAME semver_unit COMMAND test_semver_unit)

set_tests_properties(
  actor bitmasks character registry sprite staticstring tilemap util semver_unit
  PROPERTIES WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/tests" TIMEOUT 30
)

# Specify include directories for the library's headers (if applicable)
target_include_directories(akgl PUBLIC
  include/
  deps/semver/
  )

target_link_libraries(akgl
  PUBLIC
    SDL3::SDL3
    SDL3_image::SDL3_image
    SDL3_mixer::SDL3_mixer
    SDL3_ttf::SDL3_ttf
    akstdlib::akstdlib
    akerror::akerror
    jansson::jansson
)
  
target_link_libraries(test_actor PRIVATE akstdlib::akstdlib akerror::akerror akgl SDL3::SDL3 SDL3_ttf::SDL3_ttf SDL3_image::SDL3_image SDL3_mixer::SDL3_mixer  jansson::jansson -lm)
target_link_libraries(test_bitmasks PRIVATE akstdlib::akstdlib akerror::akerror akgl SDL3::SDL3 SDL3_ttf::SDL3_ttf SDL3_image::SDL3_image SDL3_mixer::SDL3_mixer  jansson::jansson -lm)
target_link_libraries(test_character PRIVATE akstdlib::akstdlib akerror::akerror akgl SDL3::SDL3 SDL3_ttf::SDL3_ttf SDL3_image::SDL3_image SDL3_mixer::SDL3_mixer  jansson::jansson -lm)
target_link_libraries(test_registry PRIVATE akstdlib::akstdlib akerror::akerror akgl SDL3::SDL3 SDL3_ttf::SDL3_ttf SDL3_image::SDL3_image SDL3_mixer::SDL3_mixer  jansson::jansson -lm)
target_link_libraries(test_sprite PRIVATE akstdlib::akstdlib akerror::akerror akgl SDL3::SDL3 SDL3_ttf::SDL3_ttf SDL3_image::SDL3_image SDL3_mixer::SDL3_mixer  jansson::jansson -lm)
target_link_libraries(test_staticstring PRIVATE akstdlib::akstdlib akerror::akerror akgl SDL3::SDL3 SDL3_ttf::SDL3_ttf SDL3_image::SDL3_image SDL3_mixer::SDL3_mixer  jansson::jansson -lm)
target_link_libraries(test_tilemap PRIVATE akstdlib::akstdlib akerror::akerror akgl SDL3::SDL3 SDL3_ttf::SDL3_ttf SDL3_image::SDL3_image SDL3_mixer::SDL3_mixer  jansson::jansson -lm)
target_link_libraries(test_util PRIVATE akstdlib::akstdlib akerror::akerror akgl SDL3::SDL3 SDL3_ttf::SDL3_ttf SDL3_image::SDL3_image SDL3_mixer::SDL3_mixer  jansson::jansson -lm)

target_link_libraries(charviewer PRIVATE akstdlib::akstdlib akerror::akerror akgl SDL3::SDL3 SDL3_ttf::SDL3_ttf SDL3_image::SDL3_image SDL3_mixer::SDL3_mixer  jansson::jansson -lm)

# Mutation testing copies the repository to scratch space, applies one small
# source change at a time, and verifies that the passing tests detect it. The
# intentionally failing character test is excluded by the harness.
find_package(Python3 COMPONENTS Interpreter)
if(Python3_FOUND)
  if(CMAKE_SOURCE_DIR STREQUAL CMAKE_CURRENT_SOURCE_DIR)
    set(AKGL_MUTATION_TARGET mutation)
  else()
    set(AKGL_MUTATION_TARGET akgl_mutation)
  endif()
  add_custom_target(${AKGL_MUTATION_TARGET}
    COMMAND ${Python3_EXECUTABLE}
            ${CMAKE_CURRENT_SOURCE_DIR}/scripts/mutation_test.py
            --source-root ${CMAKE_CURRENT_SOURCE_DIR}
    WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
    USES_TERMINAL
    COMMENT "Running mutation tests (breaks a scratch copy, expects tests to fail)"
  )
endif()

set(main_lib_dest "lib/akgl-${MY_LIBRARY_VERSION}")
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/akgl.pc DESTINATION "lib/pkgconfig/")
install(TARGETS akgl DESTINATION "lib/")
install(FILES "deps/semver/semver.h" DESTINATION "include/")
install(FILES "include/akgl/actor.h" DESTINATION "include/akgl/")
install(FILES "include/akgl/types.h" DESTINATION "include/akgl/")
install(FILES "include/akgl/text.h" DESTINATION "include/akgl/")
install(FILES "include/akgl/assets.h" DESTINATION "include/akgl/")
install(FILES "include/akgl/character.h" DESTINATION "include/akgl/")
install(FILES "include/akgl/error.h" DESTINATION "include/akgl/")
install(FILES "include/akgl/draw.h" DESTINATION "include/akgl/")
install(FILES "include/akgl/game.h" DESTINATION "include/akgl/")
install(FILES "include/akgl/controller.h" DESTINATION "include/akgl/")
install(FILES "include/akgl/heap.h" DESTINATION "include/akgl/")
install(FILES "include/akgl/iterator.h" DESTINATION "include/akgl/")
install(FILES "include/akgl/json_helpers.h" DESTINATION "include/akgl/")
install(FILES "include/akgl/renderer.h" DESTINATION "include/akgl/")
install(FILES "include/akgl/physics.h" DESTINATION "include/akgl/")
install(FILES "include/akgl/registry.h" DESTINATION "include/akgl/")
install(FILES "include/akgl/sprite.h" DESTINATION "include/akgl/")
install(FILES "include/akgl/staticstring.h" DESTINATION "include/akgl/")
install(FILES "include/akgl/tilemap.h" DESTINATION "include/akgl/")
install(FILES "include/akgl/util.h" DESTINATION "include/akgl/")
install(FILES ${GAMECONTROLLERDB_H} DESTINATION "include/akgl/")
