# ==============================================================================
# Course Material (cmat)
# ==============================================================================
# Exercises copied from 397. Each exercise directory holds its own
# CMakeLists.txt (included below) and defines one executable target with the
# directory's name via cmat_add_exercise().
#
# Targets are excluded from the default build; build one by name:
#   cmake --build build --target Ex11
#
# Some exercises intentionally contain bugs that students fix during the
# course. Those targets fail to compile (or misbehave at runtime) until the
# bug is fixed, which is expected.

# ------------------------------------------------------------------------------
# Compile options
# ------------------------------------------------------------------------------
# Legacy course material: keep the project's warning flags but drop -Werror;
# these old sources produce warnings that must not block the build.
set(CMAT_OPTIONS "")
foreach (opt IN LISTS BASE_OPTIONS)
    if (NOT opt STREQUAL "-Werror" AND NOT opt STREQUAL "/WX")
        list(APPEND CMAT_OPTIONS "${opt}")
    endif()
endforeach()

# ------------------------------------------------------------------------------
# Keyboard/Screen support (DOS_Unix/)
# ------------------------------------------------------------------------------
# GUI exercises use the Keyboard/Screen abstraction from DOS_Unix/. The DOS
# variants (Keyboard_DOS.cpp, Screen_DOS.cpp) are Windows-specific and are not
# compiled. On Unix-like systems the curses variants provide the same
# interface instead.

set(CMAT_GUI_LIB "")
if (IS_LINUX OR IS_MACOS)
    find_package(Curses QUIET)
    if (Curses_FOUND)
        add_library(dos_unix STATIC
            DOS_Unix/CursesObj.cpp
            DOS_Unix/Keyboard_Unix.cpp
            DOS_Unix/Screen_Unix.cpp
        )
        set_target_properties(dos_unix PROPERTIES EXCLUDE_FROM_ALL TRUE)
        target_include_directories(dos_unix PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/DOS_Unix")
        if (CURSES_INCLUDE_DIRS)
            target_include_directories(dos_unix SYSTEM PUBLIC ${CURSES_INCLUDE_DIRS})
        endif()
        target_link_libraries(dos_unix PUBLIC ${CURSES_LIBRARIES})
        set(CMAT_GUI_LIB dos_unix)
    else()
        message(STATUS "Curses not found; GUI exercises are unavailable")
    endif()
else()
    # Windows: only the DOS keyboard/screen implementations exist, which are
    # Windows-specific; there is nothing portable to build with.
endif()

# Exercises using Boost.Serialization (system install; not fetched). CONFIG
# mode uses Boost's own CMake package, since the FindBoost module was removed
# in CMake 4.
find_package(Boost CONFIG QUIET COMPONENTS serialization)

# ------------------------------------------------------------------------------
# Target helpers
# ------------------------------------------------------------------------------
# cmat_add_exercise(<name> [GUI] [BOOST] <sources>...)
#
# Creates an executable target from the given sources. GUI links the
# Keyboard/Screen support library; BOOST links Boost.Serialization. If a
# required dependency is missing, the exercise is reported as not available
# and no target is created.
function(cmat_add_exercise name)
    cmake_parse_arguments(ARG "GUI;BOOST" "" "SOURCES" ${ARGN})
    if (ARG_GUI AND NOT CMAT_GUI_LIB)
        cmat_unavailable(${name} "requires the Keyboard/Screen abstraction, which is Windows-specific (DOS_Unix/)")
        return()
    endif()
    if (ARG_BOOST AND NOT Boost_FOUND)
        cmat_unavailable(${name} "requires Boost.Serialization")
        return()
    endif()
    add_executable(${name} ${ARG_SOURCES})
    target_compile_features(${name} PRIVATE cxx_std_23)
    target_compile_options(${name} PRIVATE ${CMAT_OPTIONS})
    set_target_properties(${name} PROPERTIES EXCLUDE_FROM_ALL TRUE)
    if (ARG_GUI)
        target_link_libraries(${name} PRIVATE ${CMAT_GUI_LIB})
    endif()
    if (ARG_BOOST)
        target_link_libraries(${name} PRIVATE Boost::serialization)
    endif()
endfunction()

# cmat_unavailable(<name> <reason>)
#
# Reports that an exercise cannot be built on this platform. A warning (not a
# hard error) is used so the configuration completes and all other exercises
# remain available.
function(cmat_unavailable name reason)
    message(WARNING "Exercise ${name} is not available on this platform: ${reason}")
endfunction()

# ------------------------------------------------------------------------------
# Exercises
# ------------------------------------------------------------------------------
add_subdirectory(Ex11)
add_subdirectory(Ex11bug)
add_subdirectory(Ex21)
add_subdirectory(Ex22)
add_subdirectory(Ex31)
add_subdirectory(Ex32)
add_subdirectory(Ex33)
add_subdirectory(Ex41)
add_subdirectory(Ex42)
add_subdirectory(Ex51)
add_subdirectory(Ex61)
add_subdirectory(Ex62)
add_subdirectory(Ex71)
add_subdirectory(Ex71A)
add_subdirectory(SolutionEx11bug)
add_subdirectory(SolutionEx21)
add_subdirectory(SolutionEx22)
add_subdirectory(SolutionEx22Bonus)
add_subdirectory(SolutionEx31)
add_subdirectory(SolutionEx31Bonus)
add_subdirectory(SolutionEx32)
add_subdirectory(SolutionEx33)
add_subdirectory(SolutionEx33Bonus)
add_subdirectory(SolutionEx41)
add_subdirectory(SolutionEx41Bonus)
add_subdirectory(SolutionEx42)
add_subdirectory(SolutionEx51)
add_subdirectory(SolutionEx51Bonus2)
add_subdirectory(SolutionEx61InterimSolution)
add_subdirectory(SolutionEx61Part1)
add_subdirectory(SolutionEx61Part2)
add_subdirectory(SolutionEx61Part2Bonus)
add_subdirectory(SolutionEx62)
add_subdirectory(SolutionEx62Bonus)
add_subdirectory(SolutionEx62Bonus2)
add_subdirectory(SolutionEx71)
add_subdirectory(SolutionEx71A)
add_subdirectory(SolutionEx71ABonus)
add_subdirectory(SolutionEx71Bonus)
