cmake_minimum_required(VERSION 3.16)
project(KoboDeluxe VERSION 0.5.1 LANGUAGES C CXX)

set(CMAKE_C_STANDARD 99)
set(CMAKE_CXX_STANDARD 14)
set(CMAKE_CXX_EXTENSIONS OFF)

if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES)
    set(CMAKE_BUILD_TYPE Release CACHE STRING "Build type" FORCE)
endif()

option(KOBO_ENABLE_OPENGL "Use OpenGL rendering layer" ON)
option(KOBO_ENABLE_OSS "Build OSS audio backend (Linux)" OFF)
option(KOBO_ENABLE_ALSA "Build ALSA audio backend (Linux)" OFF)
option(KOBO_ENABLE_EPM "Extreme Pickyness Mode (-Wall -Werror)" OFF)

# Emscripten target: SDL renderer maps to WebGL, no desktop GL needed.
if(EMSCRIPTEN)
    set(KOBO_ENABLE_OPENGL OFF CACHE BOOL "Use OpenGL rendering layer" FORCE)
    set(KOBO_ENABLE_OSS    OFF CACHE BOOL "Build OSS audio backend"   FORCE)
    set(KOBO_ENABLE_ALSA   OFF CACHE BOOL "Build ALSA audio backend"  FORCE)
endif()

# ---------------------------------------------------------------------------
# Feature detection
# ---------------------------------------------------------------------------
include(CheckIncludeFile)
include(CheckSymbolExists)
include(CheckLibraryExists)

check_include_file(dirent.h HAVE_DIRENT_H)

check_symbol_exists(getegid       unistd.h HAVE_GETEGID)
check_symbol_exists(setgid        unistd.h HAVE_SETGID)
check_symbol_exists(gettimeofday  "sys/time.h" HAVE_GETTIMEOFDAY)
check_symbol_exists(stat          "sys/stat.h" HAVE_STAT)
check_symbol_exists(snprintf      stdio.h HAVE_SNPRINTF)
check_symbol_exists(vsnprintf     stdio.h HAVE_VSNPRINTF)
check_symbol_exists(_snprintf     stdio.h HAVE__SNPRINTF)
check_symbol_exists(_vsnprintf    stdio.h HAVE__VSNPRINTF)

# ---------------------------------------------------------------------------
# Third-party libraries
# ---------------------------------------------------------------------------
# Migrating to SDL 3. Homebrew: `brew install sdl3 sdl3_image`.
# Emscripten 5.x ships an sdl3 port but no sdl3_image yet — we substitute
# libpng + a small shim (graphics/img_compat.c) for IMG_Load. The
# `--use-port` flags must appear in both compile and link phases.
if(EMSCRIPTEN)
    add_library(SDL3::SDL3 INTERFACE IMPORTED)
    target_compile_options(SDL3::SDL3 INTERFACE --use-port=sdl3)
    target_link_options(SDL3::SDL3    INTERFACE --use-port=sdl3)

    add_library(SDL3_image::SDL3_image INTERFACE IMPORTED)
    target_compile_options(SDL3_image::SDL3_image INTERFACE --use-port=libpng)
    target_link_options(SDL3_image::SDL3_image    INTERFACE --use-port=libpng)
else()
    find_package(SDL3 CONFIG REQUIRED)
    find_package(SDL3_image CONFIG REQUIRED)
    find_package(CURL REQUIRED)
endif()

if(KOBO_ENABLE_OPENGL)
    find_package(OpenGL)
    if(OpenGL_FOUND OR OPENGL_FOUND)
        set(HAVE_OPENGL 1)
    endif()
endif()

if(KOBO_ENABLE_OSS)
    check_include_file("sys/soundcard.h" _has_soundcard_sys)
    check_include_file("soundcard.h"     _has_soundcard)
    if(_has_soundcard_sys OR _has_soundcard)
        set(HAVE_OSS 1)
    endif()
endif()

if(KOBO_ENABLE_ALSA)
    find_library(ALSA_LIB asound)
    check_include_file("sys/asoundlib.h" _has_asoundlib)
    if(ALSA_LIB AND _has_asoundlib)
        set(HAVE_ALSA 1)
    endif()
endif()

# ---------------------------------------------------------------------------
# Platform-specific install layout (matches the old autotools behavior)
# ---------------------------------------------------------------------------
if(EMSCRIPTEN)
    # In the browser, "data" is preloaded into Emscripten's virtual FS at /.
    # Config/scores live under /home which we mount as IDBFS for persistence
    # (see Module.preRun in the HTML shell / build-web.sh).
    set(KOBO_BUNDLE_STYLE "web")
    # index.html so the game can be served from a clean subpath URL
    # (e.g. https://lindholm.dev/kobo/ — no explicit filename).
    set(KOBO_EXEFILE       "index.html")
    set(KOBO_DATA_DIR      "/data")
    set(KOBO_SCORE_DIR     "/home/scores")
    set(KOBO_CONFIG_DIR    "/home")
    set(KOBO_CONFIG_FILE   ".kobodlrc")
elseif(APPLE)
    set(KOBO_BUNDLE_STYLE "macosx")
    set(KOBO_EXEFILE       "kobodl")
    set(KOBO_DATA_DIR      "EXE>>../Resources")
    set(KOBO_SCORE_DIR     "/Library/Preferences/KoboDeluxe/scores")
    set(KOBO_CONFIG_DIR    "HOME>>Library/Preferences")
    set(KOBO_CONFIG_FILE   "KoboDeluxe Preferences")
elseif(WIN32)
    set(KOBO_BUNDLE_STYLE "simple")
    set(KOBO_EXEFILE       "kobodl.exe")
    set(KOBO_DATA_DIR      "EXE>>")
    set(KOBO_SCORE_DIR     "EXE>>scores")
    set(KOBO_CONFIG_DIR    "EXE>>")
    set(KOBO_CONFIG_FILE   "kobodl.cfg")
else()
    set(KOBO_BUNDLE_STYLE "unix")
    set(KOBO_EXEFILE       "kobodl")
    set(KOBO_DATA_DIR      "${CMAKE_INSTALL_PREFIX}/share/kobo-deluxe")
    set(KOBO_SCORE_DIR     "${CMAKE_INSTALL_PREFIX}/var/lib/kobo-deluxe/scores")
    set(KOBO_CONFIG_DIR    "HOME>>")
    set(KOBO_CONFIG_FILE   ".kobodlrc")
endif()

# ---------------------------------------------------------------------------
# Generated headers
# ---------------------------------------------------------------------------
configure_file(
    ${CMAKE_CURRENT_SOURCE_DIR}/aconfig.h.cmake.in
    ${CMAKE_CURRENT_BINARY_DIR}/aconfig.h
    @ONLY
)

if(APPLE)
    configure_file(
        ${CMAKE_CURRENT_SOURCE_DIR}/Info.plist.cmake.in
        ${CMAKE_CURRENT_BINARY_DIR}/Info.plist
        @ONLY
    )
endif()

# ---------------------------------------------------------------------------
# Shared interface target — every component links this for flags/defines/SDL
# ---------------------------------------------------------------------------
add_library(kobo_deps INTERFACE)
target_compile_definitions(kobo_deps INTERFACE
    HAVE_CONFIG_H
    KOBO_DATA_DIR="${KOBO_DATA_DIR}"
    KOBO_SCORE_DIR="${KOBO_SCORE_DIR}"
    KOBO_CONFIG_DIR="${KOBO_CONFIG_DIR}"
    KOBO_CONFIG_FILE="${KOBO_CONFIG_FILE}"
    SYSCONF_DIR="${CMAKE_INSTALL_PREFIX}/etc"
)
target_include_directories(kobo_deps INTERFACE
    ${CMAKE_CURRENT_BINARY_DIR}    # for generated aconfig.h
    ${CMAKE_CURRENT_SOURCE_DIR}    # for config.h
)
target_link_libraries(kobo_deps INTERFACE SDL3::SDL3 SDL3_image::SDL3_image)

if(HAVE_OPENGL)
    target_compile_definitions(kobo_deps INTERFACE HAVE_OPENGL)
    target_link_libraries(kobo_deps INTERFACE OpenGL::GL)
endif()
if(HAVE_OSS)
    target_compile_definitions(kobo_deps INTERFACE HAVE_OSS)
endif()
if(HAVE_ALSA)
    target_compile_definitions(kobo_deps INTERFACE HAVE_ALSA)
    target_link_libraries(kobo_deps INTERFACE ${ALSA_LIB})
endif()

if(UNIX AND NOT APPLE)
    target_link_libraries(kobo_deps INTERFACE m)
endif()

if(EMSCRIPTEN)
    # -pthread enables wasm atomics+bulk-memory; every TU must agree on it or
    # wasm-ld rejects --shared-memory.
    target_compile_options(kobo_deps INTERFACE -pthread)
    target_link_options(kobo_deps    INTERFACE -pthread)
endif()

if(KOBO_ENABLE_EPM)
    target_compile_options(kobo_deps INTERFACE
        -Wall -Werror -Wwrite-strings -fno-builtin
    )
endif()

# ---------------------------------------------------------------------------
# Subprojects
# ---------------------------------------------------------------------------
add_subdirectory(graphics)
add_subdirectory(sound)
add_subdirectory(eel)

# ---------------------------------------------------------------------------
# Main executable
# ---------------------------------------------------------------------------
set(KOBO_SOURCES
    enemies.cpp enemy.cpp pfile.cpp gamectl.cpp manage.cpp map.cpp
    myship.cpp radar.cpp random.cpp scenes.cpp score.cpp screen.cpp
    filemap.cpp prefs.cpp cfgform.cpp options.cpp gamestate.cpp
    states.cpp form.cpp cfgparse.cpp game.cpp kobo.cpp logger.c
    dashboard.cpp sound.cpp prof.cpp bench.cpp leaderboard.cpp
)

if(EMSCRIPTEN)
    list(APPEND KOBO_SOURCES httpclient_web.cpp)
else()
    list(APPEND KOBO_SOURCES httpclient_native.cpp)
endif()

add_executable(kobodl ${KOBO_SOURCES})
target_include_directories(kobodl PRIVATE ${CMAKE_SOURCE_DIR}/data/sfx)
target_link_libraries(kobodl PRIVATE graphics sound eel kobo_deps)
set_target_properties(kobodl PROPERTIES OUTPUT_NAME ${KOBO_EXEFILE})

if(EMSCRIPTEN)
    target_link_options(kobodl PRIVATE -sFETCH=1)
else()
    target_link_libraries(kobodl PRIVATE CURL::libcurl)
endif()

if(EMSCRIPTEN)
    # ASYNCIFY lets the existing blocking main loop (gengine->run(), SDL_Delay)
    # yield to the browser without rewriting it around emscripten_set_main_loop.
    # pthread (atomics+bulk-memory) is applied via kobo_deps for every TU.
    # The data directory is baked into the .data sidecar via --preload-file.
    target_link_options(kobodl PRIVATE
        -sASYNCIFY=1
        -sALLOW_MEMORY_GROWTH=1
        -sINITIAL_MEMORY=128MB
        -sMAXIMUM_MEMORY=1gb
        -sPTHREAD_POOL_SIZE=4
        -sEXIT_RUNTIME=1
        -sFORCE_FILESYSTEM=1
        -sEXPORTED_RUNTIME_METHODS=FS,callMain
        -lidbfs.js
        --preload-file ${CMAKE_SOURCE_DIR}/data@/data
    )
    # Generate index.html alongside kobodl.html so it can be served as the
    # default document. The shell file mounts /home as IDBFS for persistence.
    if(EXISTS ${CMAKE_SOURCE_DIR}/web/shell.html)
        target_link_options(kobodl PRIVATE
            --shell-file ${CMAKE_SOURCE_DIR}/web/shell.html)
    endif()
    set_target_properties(kobodl PROPERTIES SUFFIX "")
endif()

# ---------------------------------------------------------------------------
# Install rules
# ---------------------------------------------------------------------------
if(KOBO_BUNDLE_STYLE STREQUAL "macosx")
    # Build a .app bundle alongside the binary.
    set(KOBO_APP_DIR ${CMAKE_BINARY_DIR}/KoboDeluxe.app)
    add_custom_command(TARGET kobodl POST_BUILD
        COMMAND ${CMAKE_COMMAND} -E make_directory ${KOBO_APP_DIR}/Contents/MacOS
        COMMAND ${CMAKE_COMMAND} -E make_directory ${KOBO_APP_DIR}/Contents/Resources
        COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_BINARY_DIR}/Info.plist ${KOBO_APP_DIR}/Contents/Info.plist
        COMMAND ${CMAKE_COMMAND} -E copy $<TARGET_FILE:kobodl> ${KOBO_APP_DIR}/Contents/MacOS/
        COMMAND ${CMAKE_COMMAND} -E copy_directory ${CMAKE_SOURCE_DIR}/data/gfx ${KOBO_APP_DIR}/Contents/Resources/gfx
        COMMAND ${CMAKE_COMMAND} -E copy_directory ${CMAKE_SOURCE_DIR}/data/sfx ${KOBO_APP_DIR}/Contents/Resources/sfx
        COMMENT "Assembling KoboDeluxe.app bundle"
        VERBATIM
    )
    install(DIRECTORY ${KOBO_APP_DIR} DESTINATION /Applications USE_SOURCE_PERMISSIONS)
elseif(KOBO_BUNDLE_STYLE STREQUAL "simple")
    install(TARGETS kobodl RUNTIME DESTINATION KoboDeluxe)
    install(DIRECTORY data/gfx data/sfx DESTINATION KoboDeluxe)
    install(FILES COPYING COPYING.LIB README ChangeLog TODO DESTINATION KoboDeluxe)
elseif(KOBO_BUNDLE_STYLE STREQUAL "web")
    # Emscripten emits index.html / .js / .wasm / .data — install all four.
    install(TARGETS kobodl RUNTIME DESTINATION web)
    install(FILES
        ${CMAKE_CURRENT_BINARY_DIR}/index.js
        ${CMAKE_CURRENT_BINARY_DIR}/index.wasm
        ${CMAKE_CURRENT_BINARY_DIR}/index.data
        DESTINATION web OPTIONAL)
else()
    include(GNUInstallDirs)
    install(TARGETS kobodl RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR})
    install(FILES kobodl.6 DESTINATION ${CMAKE_INSTALL_MANDIR}/man6)
    install(DIRECTORY data/gfx data/sfx
            DESTINATION ${CMAKE_INSTALL_DATADIR}/kobo-deluxe)
    install(DIRECTORY DESTINATION ${KOBO_SCORE_DIR}
            DIRECTORY_PERMISSIONS
                OWNER_READ OWNER_WRITE OWNER_EXECUTE
                GROUP_READ GROUP_WRITE GROUP_EXECUTE
                WORLD_READ WORLD_WRITE WORLD_EXECUTE)
endif()
