#
# Haupt CMakeLists.txt für das Projekt TDS
#
# $Id$
# $HeadURL$
# $Author$
#
# Setzen von CMAKE_INSTALL_PREFIX auf "/shd/CTC" falls nicht über Kommandozeile angegeben
#

CMAKE_MINIMUM_REQUIRED(VERSION 3.16)
IF(POLICY CMP0069)
  CMAKE_POLICY(SET CMP0069 NEW) # cmake >= 3.9.0 - INTERPROCEDURAL_OPTIMIZATION behavior
ENDIF()
IF(POLICY CMP0071)
  CMAKE_POLICY(SET CMP0071 NEW) # cmake >= 3.10.0 - automatically process generated sources with AUTOMOC
ENDIF()
IF(POLICY CMP0072)
  CMAKE_POLICY(SET CMP0072 NEW) # cmake >= 3.11.0 - prefer libOpenGL.so over legacy libGL.so
ENDIF()


IF(NOT DEFINED CMAKE_INSTALL_PREFIX)
  SET(CMAKE_INSTALL_PREFIX "/shd/CTC" CACHE STRING "Install path prefix, prepended onto install directories." FORCE)
ENDIF()
#
# # Setzen von CMAKE_BUILD_TYPE auf "Debug" falls nicht über Kommandozeile angegeben
#
IF(NOT DEFINED CMAKE_BUILD_TYPE)
  SET(CMAKE_BUILD_TYPE "Debug" CACHE STRING "Choose the type of build, options are: None(CMAKE_CXX_FLAGS or CMAKE_C_FLAGS used) Debug Release RelWithDebInfo MinSizeRel." FORCE)
ENDIF()
ADD_DEFINITIONS(-DEXPORT_BDV_TOPIC_AS_JSON)
SET(_ver "1.2.0")
IF(DEFINED LTS_VERSION_MAJOR AND DEFINED LTS_VERSION_MINOR AND DEFINED LTS_VERSION_PATCH)
  SET(_ver "${LTS_VERSION_MAJOR}.${LTS_VERSION_MINOR}.${LTS_VERSION_PATCH}")
ENDIF()
PROJECT(LTS VERSION ${_ver})
MESSAGE(STATUS "LTS Version: ${LTS_VERSION_MAJOR}.${LTS_VERSION_MINOR}.${LTS_VERSION_PATCH}")

# Enable CTest integration for unit tests
include(CTest)

function(NGL_ADD_SUBDIR_GUARDED subdir)
  if(MIGRATE_MODULE STREQUAL "")
    add_subdirectory(${subdir})
  else()
    # normalize to forward slashes
    string(REPLACE "\\" "/" _mig "${MIGRATE_MODULE}")
    string(REPLACE "\\" "/" _sub "${subdir}")
    # also compare basenames so MIGRATE_MODULE=Lts/DDS matches subdir 'DDS' when called from Lts
    get_filename_component(_mig_base "${_mig}" NAME)
    get_filename_component(_sub_base "${_sub}" NAME)
    # If MIGRATE_MODULE either starts with the subdir, equals it, contains it as a path component,
    # or the basename matches, include the subdir. This makes nested paths like
    # 'Lts/Proxies/TrainingAreaBase' include both 'Lts' and its child 'Proxies'.
    if(_mig MATCHES "^${_sub}(/|$)" OR _sub MATCHES "^${_mig}(/|$)" OR _mig MATCHES ".*/${_sub}(/|$)" OR _sub MATCHES ".*/${_mig}(/|$)" OR _mig_base STREQUAL _sub OR _sub_base STREQUAL _mig)
      message(STATUS "Including subdir ${subdir} because MIGRATE_MODULE=${MIGRATE_MODULE}")
      add_subdirectory(${subdir})
    else()
      message(STATUS "Skipping subdir ${subdir} because MIGRATE_MODULE=${MIGRATE_MODULE}")
    endif()
  endif()
endfunction()

SET(LTS_VERSION_DATE  "01.01.2018" CACHE STRING "The date when this software was compiled")
ADD_DEFINITIONS(-DLTS_VERSION_MAJOR=\"${LTS_VERSION_MAJOR}\")
ADD_DEFINITIONS(-DLTS_VERSION_MINOR=\"${LTS_VERSION_MINOR}\")
ADD_DEFINITIONS(-DLTS_VERSION_PATCH=\"${LTS_VERSION_PATCH}\")
ADD_DEFINITIONS(-DLTS_VERSION_DATE=\"${LTS_VERSION_DATE}\")
IF(JENKINS_BUILD_NUMBER)
  ADD_DEFINITIONS(-DJENKINS_BUILD_NUMBER=\"${JENKINS_BUILD_NUMBER}\")
ELSE()
  ADD_DEFINITIONS(-DJENKINS_BUILD_NUMBER=\"unknown\")
ENDIF()

ADD_DEFINITIONS(-DAPP6C)
SET(CMAKE_INCLUDE_CURRENT_DIR ON)
# Resolve <DDS/...> and other framework includes to the real headers under
# Lts/ BEFORE the migration stub tree in include/. The stub tree shadows them
# otherwise and opens namespace DDSGeneric around framework includes, which
# pulls Qt/std definitions into that namespace and breaks every consumer.
# (The qt5 legacy has no include/ tree; Lts/ is the real include root.)
include_directories(BEFORE ${CMAKE_SOURCE_DIR})
include_directories(${CMAKE_SOURCE_DIR}/include)
# Include directory for generated export headers
include_directories(${CMAKE_BINARY_DIR})
include_directories(${CMAKE_SOURCE_DIR}/Z/src)
# Include directories for external dependencies and internal modules
include_directories(${CMAKE_SOURCE_DIR}/Z/src)
include_directories(${CMAKE_SOURCE_DIR}/Z/src/ngltools)
# Lts/Viewer is outside the release scope; only add the include paths when
# present to avoid -Wmissing-include-dirs warnings on validation-scope trees
if(EXISTS "${CMAKE_SOURCE_DIR}/Lts/Viewer/SituationMap/Symbology")
  include_directories(${CMAKE_SOURCE_DIR}/Lts/Viewer/SituationMap/Symbology)
  include_directories(${CMAKE_SOURCE_DIR}/Lts/Viewer/LtsDataView)
endif()
include_directories(${CMAKE_SOURCE_DIR}/Lts/Proxies/TrainingAreaBase)
# Release scope: exclude Services, DDS, and Plugins include paths
IF(NOT RELEASE_BUILD)
include_directories(${CMAKE_BINARY_DIR}/Lts/Services/ProjectDataManagement)
include_directories(${CMAKE_SOURCE_DIR}/Lts/Services)
include_directories(${CMAKE_SOURCE_DIR}/include/ProjectDataManagement)
include_directories(${CMAKE_BINARY_DIR}/Lts/Services/InfrastructureManagement)
include_directories(${CMAKE_SOURCE_DIR}/include/InfrastructureManagement)
include_directories(${CMAKE_BINARY_DIR}/Lts/Plugins/InfrastructureManagement/Shared)
include_directories(${CMAKE_BINARY_DIR}/Lts/Services/AssetManagement)
include_directories(${CMAKE_SOURCE_DIR}/include/AssetManagement)
include_directories(${CMAKE_BINARY_DIR}/Lts/Services/AudioVideoManagement)
include_directories(${CMAKE_SOURCE_DIR}/include/AudioVideoManagement)
include_directories(${CMAKE_BINARY_DIR}/Lts/Services/ExerciseEventManagement)
include_directories(${CMAKE_SOURCE_DIR}/include/ExerciseEventManagement)
include_directories(${CMAKE_BINARY_DIR}/Lts/Services/ExerciseManagement)
include_directories(${CMAKE_SOURCE_DIR}/include/ExerciseManagement)
include_directories(${CMAKE_BINARY_DIR}/Lts/Services/FileManagement)
include_directories(${CMAKE_BINARY_DIR}/Lts/Services/NotificationManagement)
include_directories(${CMAKE_SOURCE_DIR}/include/NotificationManagement)
include_directories(${CMAKE_BINARY_DIR}/Lts/Services/ParticipantManagement)
include_directories(${CMAKE_SOURCE_DIR}/include/ParticipantManagement)
include_directories(${CMAKE_BINARY_DIR}/Lts/Services/ReportManagement)
include_directories(${CMAKE_SOURCE_DIR}/include/ReportManagement)
include_directories(${CMAKE_BINARY_DIR}/Lts/Services/SituationReplay)
include_directories(${CMAKE_SOURCE_DIR}/include/SituationReplay)
# Evaluations' generated evl_db_structs.h includes <evl_enums.hpp> by bare name, and that
# header is consumed from OcBaseDownload as well, so its build dir must be visible tree-wide
# like the services above. There is no include/Evaluations stub tree, so only the build dir
# is added (same shape as FileManagement above, which has no stub tree either).
include_directories(${CMAKE_BINARY_DIR}/Lts/Services/Evaluations)
include_directories(${CMAKE_SOURCE_DIR}/Lts/Proxies/GuezNasat)
include_directories(${CMAKE_SOURCE_DIR}/Lts/DDS)
include_directories(${CMAKE_SOURCE_DIR}/Lts/DDS/QosProfile)
# Generated DDS headers (BUILD_RTI=ON)
include_directories(${CMAKE_BINARY_DIR}/Lts)
# <Core/core.hpp> consumers (LtsCoordinate, AES/CES, HLA proxies) resolve the
# rtiddsgen-generated core.hpp from the DDS build dir (the qt5 include order);
# the OFF-era stub copies in include/Core/ have been removed.
include_directories(${CMAKE_BINARY_DIR}/Lts/DDS)
include_directories(${CMAKE_BINARY_DIR}/Lts/DDS/DDSConnector)
include_directories(${CMAKE_BINARY_DIR}/Lts/Services/Messaging)
include_directories(${CMAKE_SOURCE_DIR}/include/OperatorManagement)
include_directories(${CMAKE_BINARY_DIR}/Lts/Services/OperatorManagement)
include_directories(${CMAKE_SOURCE_DIR}/Lts/Plugins)
ENDIF()
# Release scope: include path for ProjectDataManagement stub headers
IF(RELEASE_BUILD)
  include_directories(${CMAKE_SOURCE_DIR}/Lts/Services/ProjectDataManagement/stubs)
ENDIF()
include_directories(${CMAKE_SOURCE_DIR}/Lts/Common)
include_directories(${CMAKE_SOURCE_DIR}/Lts/Common/LtsUtils)
include_directories(${CMAKE_BINARY_DIR}/Lts/Common/LtsUtils/LtsUtilsCore)
# LtsUtilsSettings's generated ltsutilssettings_export.h is included by bare name from
# settings.h. Consumer targets that reach settings.h transitively (without linking
# LtsUtilsSettings themselves) cannot see it through the target's PUBLIC interface, so the
# directory holding the generated header has to be visible tree-wide. The directory contains
# only that generated header, so appending it cannot shadow an existing include.
include_directories(${CMAKE_BINARY_DIR}/Lts/Common/LtsUtils/LtsUtilsSettings)
include_directories(${CMAKE_SOURCE_DIR}/Z/src/NGLLogger)
include_directories(${CMAKE_SOURCE_DIR}/include/Viewer/SituationMap)
SET(CMAKE_CXX_STANDARD 17)
SET(CMAKE_CXX_STANDARD_REQUIRED ON)
SET(CMAKE_VISIBILITY_INLINES_HIDDEN ON)
SET(CMAKE_CXX_VISIBILITY_PRESET hidden)
# Qt6 Migration: Removed CMAKE_POSITION_INDEPENDENT_CODE - Qt6 handles PIC automatically
# and this setting conflicts with Qt6's reduce_relocations feature
# SET(CMAKE_POSITION_INDEPENDENT_CODE ON)

IF(CMAKE_VERSION VERSION_GREATER 3.15.9)
  OPTION(USE_UNITY_BUILDS "Use Unity builds to speed up compilation (cmake 3.16 or newer required!)" OFF)
  IF (USE_UNITY_BUILDS)
    SET(CMAKE_UNITY_BUILD ON)
    SET(CMAKE_UNITY_BUILD_BATCH_SIZE 40)
  ENDIF()
ENDIF()

# Qt6 Migration: Options to disable modules with missing dependencies (WebEngine, XmlPatterns, ArcGIS)
# These can be enabled once the required system dependencies are available in the build environment
OPTION(BUILD_PLUGINS_PLANEDITOR "Build PlanEditor plugin (requires Qt6 WebEngine + ArcGIS SDK)" OFF)
OPTION(BUILD_PLUGINS_ONLINEHELP "Build OnlineHelp plugin (requires Qt6 WebEngine)" OFF)
OPTION(BUILD_PLUGINS_SERVICEMONITOR "Build ServiceMonitor plugin (requires Qt6 WebEngine)" OFF)
OPTION(BUILD_PLUGINS_PARTICIPANT_ORG_CHART "Build ParticipantOrgChart (requires Qt6 WebEngine)" OFF)
OPTION(BUILD_PLUGINS_MSDL "Build MSDL module (requires Qt6 XmlPatterns)" OFF)
OPTION(BUILD_PLUGINS_SAAB "Build Saab module (requires Qt6 XmlPatterns)" OFF)
OPTION(BUILD_RTI "Build RTI Connext DDS dependent modules" OFF)
OPTION(BUILD_VIEWER_ONLY "Build only Viewer module (no RTI required)" OFF)
# Add Lts/ include path globally for QosProfile and other Lts headers
INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR}/Lts)
IF(BUILD_RTI)
  # Define BUILD_RTI as preprocessor macro for all targets
  ADD_COMPILE_DEFINITIONS(BUILD_RTI)
ENDIF()
OPTION(BUILD_ARCGIS "Build ArcGIS SDK dependent modules" ON)
OPTION(BUILD_FILTERMANAGEMENT "Build FilterManagement plugins (temporarily disabled for migration)" OFF)
OPTION(BUILD_CODIFICATION "Build CodificationManagement plugins (requires KDReports)" OFF)
OPTION(BUILD_GRANTLEE "Build CodeGen SQL files using KTextTemplate parser (KF6::TextTemplate)" ON)

# If BUILD_GRANTLEE is OFF but ngl_codegen is needed (for IDL codegen),
# provide it as an imported executable target from pre-built location
# Skip this for RELEASE_BUILD since CodeGen is excluded and ngl_codegen is not needed
IF(NOT BUILD_GRANTLEE AND NOT RELEASE_BUILD)
  # ngl_codegen is copied to build/bin/ by run_final_migration.sh
  # Create an imported target so MacroCodeGenIdl.cmake can find it
  IF(NOT TARGET ngl_codegen)
    ADD_EXECUTABLE(ngl_codegen IMPORTED GLOBAL)
    SET_TARGET_PROPERTIES(ngl_codegen PROPERTIES
      IMPORTED_LOCATION "${CMAKE_BINARY_DIR}/bin/ngl_codegen"
    )
    MESSAGE(STATUS "Using pre-built ngl_codegen from ${CMAKE_BINARY_DIR}/bin/ngl_codegen")
  ENDIF()
ENDIF()

OPTION(BUILD_LTSWEBSOCKET "Build LtsWebSocket module (requires NGLLogger)" ON)

IF(WIN32)
  SET(EXTERNAL_LIBRARY_DIR "C:/Development/Projekte/SituationMap/ExtFw" CACHE STRING "Library dir with all external dependencies")
  LIST(APPEND CMAKE_PREFIX_PATH "${EXTERNAL_LIBRARY_DIR}")
  LIST(APPEND CMAKE_PROGRAM_PATH "${EXTERNAL_LIBRARY_DIR}/bin;${EXTERNAL_LIBRARY_DIR}/dev-utils/bin")
ELSE()
  # Linux: ArcGIS SDK Pfad konfigurieren (nur wenn BUILD_ARCGIS=ON)
  IF(BUILD_ARCGIS)
    # Use environment variable ARCGIS_ROOT if set, otherwise default to /workspace/external/... (Docker) or host path
    IF(DEFINED ENV{ARCGIS_ROOT})
      SET(ARCGIS_SDK_DIR "$ENV{ARCGIS_ROOT}" CACHE STRING "ArcGIS Runtime SDK for Qt directory")
    ELSEIF(EXISTS "/workspace/external/ArcGIS/MapsSDK_Qt_300.0.0/ArcGIS_Maps_SDK_Qt_300.0.0/qt300.0.0/sdk")
      SET(ARCGIS_SDK_DIR "/workspace/external/ArcGIS/MapsSDK_Qt_300.0.0/ArcGIS_Maps_SDK_Qt_300.0.0/qt300.0.0/sdk" CACHE STRING "ArcGIS Runtime SDK for Qt directory")
    ELSE()
      SET(ARCGIS_SDK_DIR "/repo/external/ArcGIS/MapsSDK_Qt_300.0.0/ArcGIS_Maps_SDK_Qt_300.0.0/qt300.0.0/sdk" CACHE STRING "ArcGIS Runtime SDK for Qt directory")
    ENDIF()
    IF(EXISTS "${ARCGIS_SDK_DIR}")
      LIST(APPEND CMAKE_PREFIX_PATH "${ARCGIS_SDK_DIR}")
      MESSAGE(STATUS "ArcGIS SDK found at: ${ARCGIS_SDK_DIR}")
    ELSE()
      MESSAGE(WARNING "ArcGIS SDK not found at: ${ARCGIS_SDK_DIR}")
    ENDIF()
  ENDIF()
ENDIF()

# Set CMAKE_MODULE_PATH early so FIND_PACKAGE can find our custom Find modules
SET(CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/cmake")
INCLUDE(FindLibraryWithDebug)

# Find ArcGIS SDK globally if BUILD_ARCGIS is enabled
# This creates ArcGIS::ArcGIS target for all modules to use
IF(BUILD_ARCGIS)
  FIND_PACKAGE(ArcGIS REQUIRED)
ENDIF()

ENABLE_TESTING()
INCLUDE(CTest)
CONFIGURE_FILE(CTestCustom.ctest ${CMAKE_BINARY_DIR}/CTestCustom.ctest COPYONLY)
CONFIGURE_FILE(lts-cc.conf ${CMAKE_BINARY_DIR}/lts-cc.conf.distrib COPYONLY)

# Add bundled GeographicLib cmake config to find modern targets (GeographicLib::GeographicLib_SHARED)
LIST(APPEND CMAKE_PREFIX_PATH "${CMAKE_SOURCE_DIR}/include/GeographicLib/lib/cmake")
SET(EXECUTABLE_OUTPUT_PATH ${CMAKE_BINARY_DIR}/bin)
IF(WIN32)
  SET(LIBRARY_OUTPUT_PATH ${CMAKE_BINARY_DIR}/bin)
ELSE(WIN32)
  SET(LIBRARY_OUTPUT_PATH ${CMAKE_BINARY_DIR}/lib)
ENDIF()

#
# Disallow in-source build
#
INCLUDE(MacroEnsureOutOfSourceBuild)

macro_ensure_out_of_source_build("In-Source build nicht erlaubt!")

#
# Qt ist wichtig - zuerst suchen
#
SET(CMAKE_AUTOMOC TRUE)
SET(CMAKE_AUTOUIC TRUE)
SET(QT_USE_IMPORTED_TARGETS TRUE)

# Check for OpenGL first (required by Qt6Gui)
find_package(OpenGL)

# Prefer Qt6, fallback to Qt5. Create Qt6::*-aliases when Qt6 is found so existing CMakeLists continue to work.
# Try to find Qt6 with GUI components first
set(QT6_GUI_AVAILABLE FALSE)
set(QT6_FOUND FALSE)
set(QT6_CORE5COMPAT_AVAILABLE FALSE)

# First check if Core5Compat is available
find_package(Qt6 6.2 COMPONENTS Core5Compat QUIET)
if(Qt6Core5Compat_FOUND)
  set(QT6_CORE5COMPAT_AVAILABLE TRUE)
  message(STATUS "Found Qt6Core5Compat")
endif()

# Find Qt6 core components first (without OpenGL which may not be available)
# WebSockets is required by the migrated services (FileManagement's THP script
# server uses QWebSocketServer; LtsWebSocket/httq enable their real websocket
# paths via QT6_WEBSOCKETS_AVAILABLE when the module is found).
find_package(Qt6 6.2 COMPONENTS Concurrent Core LinguistTools Network
  Multimedia Sql SerialPort Test Xml Positioning Svg WebSockets PrintSupport OpenGL QUIET)

if(Qt6_FOUND)
  # Check if OpenGL was found (GUI support available)
  if(OpenGL_FOUND)
    set(QT6_GUI_AVAILABLE TRUE)
    message(STATUS "Found Qt6 with GUI support (OpenGL): ${Qt6Core_VERSION}")
  else()
    # Skip GUI find_package - it fails without OpenGL. We'll create manual targets below.
    set(QT6_GUI_AVAILABLE FALSE)
    message(STATUS "Found Qt6 (GUI will be manually configured): ${Qt6Core_VERSION}")
  endif()
endif()

# If Qt6 not found yet, try with full component list including OpenGL
if(NOT Qt6_FOUND)
  find_package(Qt6 6.2 COMPONENTS Concurrent Core LinguistTools Network OpenGL PrintSupport
    Multimedia Sql Svg SerialPort Test UiTools WebSockets WebEngineCore WebEngineWidgets
    Widgets Xml Positioning QUIET)
  if(Qt6_FOUND AND OpenGL_FOUND)
    set(QT6_GUI_AVAILABLE TRUE)
    message(STATUS "Found Qt6 with GUI support (OpenGL): ${Qt6Core_VERSION}")
  endif()
endif()

if(NOT Qt6_FOUND)
  # Final fallback - try to find Qt6 with minimum required components
  find_package(Qt6 6.2 COMPONENTS Core REQUIRED)
  message(STATUS "Found Qt6 (minimal): ${Qt6Core_VERSION}")
endif()

# Manual Qt6 configuration - create imported targets for available libraries
if(NOT TARGET Qt6::Core)
  find_package(Qt6 6.2 COMPONENTS Core REQUIRED)
endif()

# Create imported targets for all available Qt6 libraries
# Use Qt6 installation path from find_package or fall back to system paths
if(Qt6Core_DIR)
  # <Qt6Core_DIR> is the cmake package dir: <prefix>/lib/cmake/Qt6Core in the
  # standard Qt layout and <prefix>/<multiarch>/cmake/Qt6Core in the Debian/
  # Ubuntu layout — so the library dir is two levels up in both. (Going three
  # levels up and appending /lib only matches the standard layout; in the
  # Debian validation container it resolved to /usr/lib/lib and every manual
  # target below was silently skipped, breaking all targets linking
  # Qt6::Sql / Qt6::Xml / Qt6::Test.)
  get_filename_component(QT6_LIB_DIR "${Qt6Core_DIR}/../.." ABSOLUTE)
  get_filename_component(QT6_ARCH_DIR "${QT6_LIB_DIR}" NAME)
  # The standard layout keeps headers in <prefix>/include; Debian/Ubuntu keeps
  # them in <prefix>/include/<multiarch>/qt6 — probe the multiarch form first.
  if(EXISTS "${QT6_LIB_DIR}/../../include/${QT6_ARCH_DIR}/qt6")
    get_filename_component(QT6_INC_DIR "${QT6_LIB_DIR}/../../include/${QT6_ARCH_DIR}/qt6" ABSOLUTE)
  else()
    get_filename_component(QT6_INC_DIR "${QT6_LIB_DIR}/../include" ABSOLUTE)
  endif()
elseif(DEFINED ENV{QT_BASE_DIR} AND DEFINED ENV{QT_VERSION} AND DEFINED ENV{QT_ARCH_DIR})
  set(QT6_LIB_DIR "$ENV{QT_BASE_DIR}/$ENV{QT_VERSION}/$ENV{QT_ARCH_DIR}/lib")
  set(QT6_INC_DIR "$ENV{QT_BASE_DIR}/$ENV{QT_VERSION}/$ENV{QT_ARCH_DIR}/include")
else()
  set(QT6_LIB_DIR "/usr/lib/x86_64-linux-gnu")
  set(QT6_INC_DIR "/usr/include/x86_64-linux-gnu/qt6")
endif()

# Qt6::DBus
if(NOT TARGET Qt6::DBus AND EXISTS "${QT6_LIB_DIR}/libQt6DBus.so.6")
  add_library(Qt6::DBus SHARED IMPORTED)
  set_target_properties(Qt6::DBus PROPERTIES
    IMPORTED_LOCATION "${QT6_LIB_DIR}/libQt6DBus.so.6"
    INTERFACE_INCLUDE_DIRECTORIES "${QT6_INC_DIR}/QtDBus;${QT6_INC_DIR}"
    INTERFACE_LINK_LIBRARIES "Qt6::Core"
  )
endif()

# Qt6::Gui (needs OpenGL libs, X11, EGL)
if(NOT TARGET Qt6::Gui AND EXISTS "${QT6_LIB_DIR}/libQt6Gui.so.6")
  add_library(Qt6::Gui SHARED IMPORTED)
  set_target_properties(Qt6::Gui PROPERTIES
    IMPORTED_LOCATION "${QT6_LIB_DIR}/libQt6Gui.so.6"
    INTERFACE_INCLUDE_DIRECTORIES "${QT6_INC_DIR}/QtGui;${QT6_INC_DIR}"
    INTERFACE_LINK_LIBRARIES "Qt6::Core;Qt6::DBus;${QT6_LIB_DIR}/libQt6OpenGL.so.6;${QT6_LIB_DIR}/libEGL.so.1;${QT6_LIB_DIR}/libGLX.so.0;${QT6_LIB_DIR}/libX11.so.6;${CMAKE_DL_LIBS};pthread"
  )
endif()

# Set variable for legacy code that uses ${Qt6_Gui} — like Qt6_Widgets below,
# subdirectory CMakeLists contain `set(Qt6_Gui ${Qt6_Gui})` optional-guard
# no-ops that keep this root-scope value.
if(TARGET Qt6::Gui)
  set(Qt6_Gui Qt6::Gui)
endif()

# Qt6::Widgets - create manual target (find_package fails without OpenGL)
if(EXISTS "${QT6_LIB_DIR}/libQt6Widgets.so.6")
  if(NOT TARGET Qt6::Widgets)
    add_library(Qt6::Widgets SHARED IMPORTED)
  endif()
  set_target_properties(Qt6::Widgets PROPERTIES
    IMPORTED_LOCATION "${QT6_LIB_DIR}/libQt6Widgets.so.6"
    INTERFACE_INCLUDE_DIRECTORIES "/usr/include/x86_64-linux-gnu/qt6/QtWidgets;/usr/include/x86_64-linux-gnu/qt6"
    INTERFACE_LINK_LIBRARIES "Qt6::Core;Qt6::Gui"
  )
  # Set variable for legacy code that uses ${Qt6_Widgets}
  set(Qt6_Widgets Qt6::Widgets)
  set(QT6_GUI_AVAILABLE TRUE)
  message(STATUS "Manually configured Qt6 Widgets target")
endif()

# Qt6::Sql - create manual target if not found
if(NOT TARGET Qt6::Sql AND EXISTS "${QT6_LIB_DIR}/libQt6Sql.so.6")
  add_library(Qt6::Sql SHARED IMPORTED)
  set_target_properties(Qt6::Sql PROPERTIES
    IMPORTED_LOCATION "${QT6_LIB_DIR}/libQt6Sql.so.6"
    INTERFACE_INCLUDE_DIRECTORIES "${QT6_INC_DIR}/QtSql;${QT6_INC_DIR}"
    INTERFACE_LINK_LIBRARIES "Qt6::Core"
  )
  message(STATUS "Manually configured Qt6 Sql target")
endif()

# Qt6::Xml - create manual target if not found
if(NOT TARGET Qt6::Xml AND EXISTS "${QT6_LIB_DIR}/libQt6Xml.so.6")
  add_library(Qt6::Xml SHARED IMPORTED)
  set_target_properties(Qt6::Xml PROPERTIES
    IMPORTED_LOCATION "${QT6_LIB_DIR}/libQt6Xml.so.6"
    INTERFACE_INCLUDE_DIRECTORIES "${QT6_INC_DIR}/QtXml;${QT6_INC_DIR}"
    INTERFACE_LINK_LIBRARIES "Qt6::Core"
  )
  message(STATUS "Manually configured Qt6 Xml target")
endif()

# Qt6::Network - create manual target if not found
if(NOT TARGET Qt6::Network AND EXISTS "${QT6_LIB_DIR}/libQt6Network.so.6")
  add_library(Qt6::Network SHARED IMPORTED)
  set_target_properties(Qt6::Network PROPERTIES
    IMPORTED_LOCATION "${QT6_LIB_DIR}/libQt6Network.so.6"
    INTERFACE_INCLUDE_DIRECTORIES "${QT6_INC_DIR}/QtNetwork;${QT6_INC_DIR}"
    INTERFACE_LINK_LIBRARIES "Qt6::Core"
  )
  message(STATUS "Manually configured Qt6 Network target")
endif()

# Qt6::Test - create manual target if not found
if(NOT TARGET Qt6::Test AND EXISTS "${QT6_LIB_DIR}/libQt6Test.so.6")
  add_library(Qt6::Test SHARED IMPORTED)
  set_target_properties(Qt6::Test PROPERTIES
    IMPORTED_LOCATION "${QT6_LIB_DIR}/libQt6Test.so.6"
    INTERFACE_INCLUDE_DIRECTORIES "${QT6_INC_DIR}/QtTest;${QT6_INC_DIR}"
    INTERFACE_LINK_LIBRARIES "Qt6::Core"
  )
  message(STATUS "Manually configured Qt6 Test target")
endif()

# Qt6::Multimedia - create manual target if not found
if(NOT TARGET Qt6::Multimedia AND EXISTS "${QT6_LIB_DIR}/libQt6Multimedia.so.6")
  add_library(Qt6::Multimedia SHARED IMPORTED)
  set_target_properties(Qt6::Multimedia PROPERTIES
    IMPORTED_LOCATION "${QT6_LIB_DIR}/libQt6Multimedia.so.6"
    INTERFACE_INCLUDE_DIRECTORIES "${QT6_INC_DIR}/QtMultimedia;${QT6_INC_DIR}"
    INTERFACE_LINK_LIBRARIES "Qt6::Core;Qt6::Gui"
  )
  message(STATUS "Manually configured Qt6 Multimedia target")
endif()

# Stub Qt6::Multimedia target if not available (needed by OscSystemGuiPlugin, etc.)
if(NOT TARGET Qt6::Multimedia)
  add_library(Qt6::Multimedia INTERFACE IMPORTED)
  set_target_properties(Qt6::Multimedia PROPERTIES
    INTERFACE_COMPILE_DEFINITIONS "QT_NO_MULTIMEDIA"
  )
  message(STATUS "Created stub target for Qt6::Multimedia (library not available)")
endif()

# Qt6::Svg - create manual target if not found. Also require the headers:
# the container can ship the runtime library (libqt6svg6 via Recommends)
# without qt6-svg-dev, and an imported target with a non-existent
# INTERFACE_INCLUDE_DIRECTORIES entry fails the CMake generate step for
# every Svg consumer. Without headers the stub below is used instead.
if(NOT TARGET Qt6::Svg AND EXISTS "${QT6_LIB_DIR}/libQt6Svg.so.6" AND EXISTS "${QT6_INC_DIR}/QtSvg")
  add_library(Qt6::Svg SHARED IMPORTED)
  set_target_properties(Qt6::Svg PROPERTIES
    IMPORTED_LOCATION "${QT6_LIB_DIR}/libQt6Svg.so.6"
    INTERFACE_INCLUDE_DIRECTORIES "${QT6_INC_DIR}/QtSvg;${QT6_INC_DIR}"
    INTERFACE_LINK_LIBRARIES "Qt6::Core;Qt6::Gui"
  )
  message(STATUS "Manually configured Qt6 Svg target")
endif()

# Stub Qt6::Svg target if not available (needed by various plugins)
if(NOT TARGET Qt6::Svg)
  add_library(Qt6::Svg INTERFACE IMPORTED)
  message(STATUS "Created stub target for Qt6::Svg (library not available)")
endif()

# Qt6::SerialPort - create manual target if not found
if(NOT TARGET Qt6::SerialPort AND EXISTS "${QT6_LIB_DIR}/libQt6SerialPort.so.6")
  add_library(Qt6::SerialPort SHARED IMPORTED)
  set_target_properties(Qt6::SerialPort PROPERTIES
    IMPORTED_LOCATION "${QT6_LIB_DIR}/libQt6SerialPort.so.6"
    INTERFACE_INCLUDE_DIRECTORIES "${QT6_INC_DIR}/QtSerialPort;${QT6_INC_DIR}"
    INTERFACE_LINK_LIBRARIES "Qt6::Core"
  )
  message(STATUS "Manually configured Qt6 SerialPort target")
endif()

# Stub Qt6::SerialPort target if not available (needed by TrainingAreaBaseOC)
if(NOT TARGET Qt6::SerialPort)
  add_library(Qt6::SerialPort INTERFACE IMPORTED)
  set_target_properties(Qt6::SerialPort PROPERTIES
    INTERFACE_COMPILE_DEFINITIONS "QT_NO_SERIALPORT"
  )
  message(STATUS "Created stub target for Qt6::SerialPort (library not available)")
endif()

# Stub Qt6::WebEngineCore target if not available (needed by thp_viewer)
if(NOT TARGET Qt6::WebEngineCore)
  add_library(Qt6::WebEngineCore INTERFACE IMPORTED)
  set_target_properties(Qt6::WebEngineCore PROPERTIES
    INTERFACE_COMPILE_DEFINITIONS "QT_NO_WEBENGINE"
  )
  message(STATUS "Created stub target for Qt6::WebEngineCore (library not available)")
endif()

# Stub Qt6::WebEngineWidgets target if not available (needed by thp_viewer)
if(NOT TARGET Qt6::WebEngineWidgets)
  add_library(Qt6::WebEngineWidgets INTERFACE IMPORTED)
  set_target_properties(Qt6::WebEngineWidgets PROPERTIES
    INTERFACE_COMPILE_DEFINITIONS "QT_NO_WEBENGINE"
  )
  message(STATUS "Created stub target for Qt6::WebEngineWidgets (library not available)")
endif()

# Stub KDReports::KDReports target if not available (needed by LtsReportDisplay)
# UNKNOWN (not INTERFACE) so FindKDReports.cmake can upgrade it with a real
# IMPORTED_LOCATION; an INTERFACE imported target ignores IMPORTED_LOCATION.
if(NOT TARGET KDReports::KDReports)
  add_library(KDReports::KDReports UNKNOWN IMPORTED)
  set_target_properties(KDReports::KDReports PROPERTIES
    INTERFACE_COMPILE_DEFINITIONS "NO_KDREPORTS"
  )
  message(STATUS "Created stub target for KDReports::KDReports (library not available)")
endif()

# Stub Qt6::Core5Compat target if not available (needed by textEditorTest)
if(NOT TARGET Qt6::Core5Compat)
  add_library(Qt6::Core5Compat INTERFACE IMPORTED)
  set_target_properties(Qt6::Core5Compat PROPERTIES
    INTERFACE_COMPILE_DEFINITIONS "QT_NO_CORE5COMPAT"
  )
  message(STATUS "Created stub target for Qt6::Core5Compat (library not available)")
endif()

# Qt6::WebSockets - create manual target if not found (the container's Qt6
# discovery takes the minimal path, so find_package never creates the
# component targets). The migrated FileManagement service (THP script
# server) needs the real module.
if(NOT TARGET Qt6::WebSockets AND EXISTS "${QT6_LIB_DIR}/libQt6WebSockets.so.6")
  add_library(Qt6::WebSockets SHARED IMPORTED)
  set_target_properties(Qt6::WebSockets PROPERTIES
    IMPORTED_LOCATION "${QT6_LIB_DIR}/libQt6WebSockets.so.6"
    INTERFACE_INCLUDE_DIRECTORIES "${QT6_INC_DIR}/QtWebSockets;${QT6_INC_DIR}"
    INTERFACE_LINK_LIBRARIES "Qt6::Core;Qt6::Network"
  )
  set(QT6_WEBSOCKETS_REAL_FOUND TRUE)
  message(STATUS "Manually configured Qt6 WebSockets target")
endif()

# Stub Qt6::WebSockets target if not available (needed by LtsWebSocket, httq, etc.)
if(NOT TARGET Qt6::WebSockets)
  add_library(Qt6::WebSockets INTERFACE IMPORTED)
  set_target_properties(Qt6::WebSockets PROPERTIES
    INTERFACE_COMPILE_DEFINITIONS "QT_NO_WEBSOCKETS"
  )
  message(STATUS "Created stub target for Qt6::WebSockets (library not available)")
endif()

# Qt6::PrintSupport - create manual target if not found
if(NOT TARGET Qt6::PrintSupport AND EXISTS "${QT6_LIB_DIR}/libQt6PrintSupport.so.6")
  add_library(Qt6::PrintSupport SHARED IMPORTED)
  set_target_properties(Qt6::PrintSupport PROPERTIES
    IMPORTED_LOCATION "${QT6_LIB_DIR}/libQt6PrintSupport.so.6"
    INTERFACE_INCLUDE_DIRECTORIES "${QT6_INC_DIR}/QtPrintSupport;${QT6_INC_DIR}"
    INTERFACE_LINK_LIBRARIES "Qt6::Core;Qt6::Gui;Qt6::Widgets"
  )
  message(STATUS "Manually configured Qt6 PrintSupport target")
endif()

# Stub Qt6::PrintSupport target if not available (needed by textEditorTest, thp_viewer)
if(NOT TARGET Qt6::PrintSupport)
  add_library(Qt6::PrintSupport INTERFACE IMPORTED)
  set_target_properties(Qt6::PrintSupport PROPERTIES
    INTERFACE_COMPILE_DEFINITIONS "QT_NO_PRINTSUPPORT"
  )
  message(STATUS "Created stub target for Qt6::PrintSupport (library not available)")
endif()

# Qt6::OpenGL - create manual target if not found
if(NOT TARGET Qt6::OpenGL AND EXISTS "${QT6_LIB_DIR}/libQt6OpenGL.so.6")
  add_library(Qt6::OpenGL SHARED IMPORTED)
  set_target_properties(Qt6::OpenGL PROPERTIES
    IMPORTED_LOCATION "${QT6_LIB_DIR}/libQt6OpenGL.so.6"
    INTERFACE_INCLUDE_DIRECTORIES "${QT6_INC_DIR}/QtOpenGL;${QT6_INC_DIR}"
    INTERFACE_LINK_LIBRARIES "Qt6::Core;Qt6::Gui"
  )
  message(STATUS "Manually configured Qt6 OpenGL target")
endif()

# Stub Qt6::OpenGL target if not available (needed by PwsGuiPlugin)
if(NOT TARGET Qt6::OpenGL)
  add_library(Qt6::OpenGL INTERFACE IMPORTED)
  set_target_properties(Qt6::OpenGL PROPERTIES
    INTERFACE_COMPILE_DEFINITIONS "QT_NO_OPENGL"
  )
  message(STATUS "Created stub target for Qt6::OpenGL (library not available)")
endif()

# Set variable for legacy code that uses ${Qt6_WebSockets} — subdirectory
# CMakeLists contain `set(Qt6_WebSockets ${Qt6_WebSockets})` optional-guard
# no-ops that keep this root-scope value.
if(TARGET Qt6::WebSockets)
  set(Qt6_WebSockets Qt6::WebSockets)
endif()

# The real Qt6 WebSockets module is available (either via find_package or the
# manual import above): enable the real websocket code paths in httq,
# LtsWebSocket and the migrated services (they check this macro; without it
# they fall back to websocket-less operation).
if(Qt6WebSockets_FOUND OR QT6_WEBSOCKETS_REAL_FOUND)
  add_compile_definitions(QT6_WEBSOCKETS_AVAILABLE)
endif()

MESSAGE(STATUS "Qt version is ${Qt6Core_VERSION}, GUI available: ${QT6_GUI_AVAILABLE}")

#
# RTI Connext DDS - manuelle Konfiguration da keine CMake Config Files vorhanden
#
IF(BUILD_RTI)
  # Support environment variable override, otherwise use relative path from repo root
  IF(DEFINED ENV{DDS_PATH})
    SET(RTI_INSTALL_DIR "$ENV{DDS_PATH}" CACHE PATH "RTI Connext DDS installation directory")
  ELSE()
    # In Docker container: /workspace/external/rti_connext_dds-7.7.0
    # On host: ${CMAKE_SOURCE_DIR}/../../../external/rti_connext_dds-7.7.0
    IF(EXISTS "/workspace/external/rti_connext_dds-7.7.0")
      SET(RTI_INSTALL_DIR "/workspace/external/rti_connext_dds-7.7.0" CACHE PATH "RTI Connext DDS installation directory")
    ELSEIF(EXISTS "${CMAKE_SOURCE_DIR}/../../../external/rti_connext_dds-7.7.0")
      SET(RTI_INSTALL_DIR "${CMAKE_SOURCE_DIR}/../../../external/rti_connext_dds-7.7.0" CACHE PATH "RTI Connext DDS installation directory")
    ELSE()
      SET(RTI_INSTALL_DIR "/opt/RTI" CACHE PATH "RTI Connext DDS installation directory")
    ENDIF()
  ENDIF()
  # Also set RTI_DIR for FindRTI.cmake compatibility (used by subdirectories)
  SET(RTI_DIR "${RTI_INSTALL_DIR}" CACHE PATH "RTI base path" FORCE)
  IF(EXISTS "${RTI_INSTALL_DIR}")
    SET(RTI_LIB_DIR "${RTI_INSTALL_DIR}/lib/x64Linux4gcc8.5.0")
    SET(RTI_INCLUDE_DIR "${RTI_INSTALL_DIR}/include/ndds/hpp")
    
    # RTI hat vier Include-Pfade:
    # - include/ für ndds/... und andere Top-Level Headers (z.B. ndds/ndds_config_common.h)
    # - include/ndds/ für osapi/... Headers (z.B. osapi/osapi_platform.h)
    # - include/ndds/hpp für C++ Headers (dds/..., rti/...)
    # - include/rti für rti/... Headers
    SET(RTI_INCLUDE_DIRS 
        "${RTI_INSTALL_DIR}/include"
        "${RTI_INSTALL_DIR}/include/ndds"
        "${RTI_INSTALL_DIR}/include/ndds/hpp"
        "${RTI_INSTALL_DIR}/include/rti"
    )
    
    # RTI Include-Pfade global hinzufügen (auch für Tests die keine RTI Libraries linken)
    INCLUDE_DIRECTORIES(${RTI_INCLUDE_DIRS})
    
    # RTI Include-Pfade auch an MOC weitergeben (für Q_OBJECT Header mit RTI Types)
    SET(CMAKE_AUTOMOC_INCLUDE_DIRECTORIES ${CMAKE_AUTOMOC_INCLUDE_DIRECTORIES} ${RTI_INCLUDE_DIRS})

    # The generated <svc>_topic_type_plugin.h / <svc>_record_replay_plugin.h
    # headers use Q_INTERFACES(DDSGeneric::TopicTypePlugin), so moc must see
    # the Q_DECLARE_INTERFACE in Lts/DDS/... (resolved through the Lts include
    # root). Without this path every <svc>TopicTypePlugin fails with
    # "Undefined interface" even though the compiler sees the header.
    SET(CMAKE_AUTOMOC_INCLUDE_DIRECTORIES ${CMAKE_AUTOMOC_INCLUDE_DIRECTORIES} ${CMAKE_SOURCE_DIR}/Lts)

    # The ElevationMapManager stub header (include/Viewer/SituationMap/ElevationMap/)
    # lives apart from its source (src/...), so moc needs its directory explicitly.
    # NOTE: this must be set at root scope - subdir-scope appends do not reach
    # the AutogenInfo MOC_INCLUDES.
    SET(CMAKE_AUTOMOC_INCLUDE_DIRECTORIES ${CMAKE_AUTOMOC_INCLUDE_DIRECTORIES} ${CMAKE_SOURCE_DIR}/include/Viewer/SituationMap/ElevationMap)

    # The migrated Projects declare Q_INTERFACES(ProjectPlugin::Plugin) and include
    # <PluginInterfaces/project_plugin_interface.h>. That include dir
    # (Lts/Common/PluginInterfaces/..) is only a target-level PUBLIC include of
    # ProjectPluginInterface and is NOT part of the global include_directories that
    # reach the AutogenInfo MOC_INCLUDES, so moc fails with "Undefined interface".
    # Add the Lts/Common root explicitly (mirrors the Lts append above) so moc can
    # resolve the interface. Must be set at root scope - subdir appends do not
    # reach the AutogenInfo MOC_INCLUDES.
    SET(CMAKE_AUTOMOC_INCLUDE_DIRECTORIES ${CMAKE_AUTOMOC_INCLUDE_DIRECTORIES} ${CMAKE_SOURCE_DIR}/Lts/Common)

    # IMPORTED Targets für RTI Libraries erstellen
    # Debug und Release Varianten korrekt konfigurieren
    FOREACH(lib nddsc nddscore nddscpp nddscpp2 nddsctesthelpers)
      ADD_LIBRARY(RTI::${lib} SHARED IMPORTED)
      
      # Debug Library
      IF(EXISTS "${RTI_LIB_DIR}/lib${lib}d.so")
        SET_TARGET_PROPERTIES(RTI::${lib} PROPERTIES
          IMPORTED_LOCATION_DEBUG "${RTI_LIB_DIR}/lib${lib}d.so"
        )
      ENDIF()
      
      # Release Library
      IF(EXISTS "${RTI_LIB_DIR}/lib${lib}.so")
        SET_TARGET_PROPERTIES(RTI::${lib} PROPERTIES
          IMPORTED_LOCATION_RELEASE "${RTI_LIB_DIR}/lib${lib}.so"
          IMPORTED_LOCATION_RELWITHDEBINFO "${RTI_LIB_DIR}/lib${lib}.so"
          IMPORTED_LOCATION_MINSIZEREL "${RTI_LIB_DIR}/lib${lib}.so"
        )
      ENDIF()
      
      # Include Verzeichnisse für alle Varianten
      # RTI_UNIX required for basic types (RTI_INT32, RTI_UINT32, etc.)
      # RTI_POSIX_THREADS required for pthread support
      SET_TARGET_PROPERTIES(RTI::${lib} PROPERTIES
        INTERFACE_INCLUDE_DIRECTORIES "${RTI_INCLUDE_DIRS}"
        INTERFACE_COMPILE_DEFINITIONS "RTI_LINUX;RTI_UNIX;RTI_POSIX_THREADS"
      )
    ENDFOREACH()
  
    MESSAGE(STATUS "RTI Connext DDS found at: ${RTI_INSTALL_DIR}")
    MESSAGE(STATUS "RTI Libraries: ${RTI_LIB_DIR}")
    MESSAGE(STATUS "RTI Platform: RTI_LINUX")
  ELSE()
    MESSAGE(WARNING "RTI Connext DDS not found at: ${RTI_INSTALL_DIR}, BUILD_RTI will fail")
  ENDIF()
ENDIF(BUILD_RTI)

  # Alias Targets für RTI Libraries (für Abwärtskompatibilität)
# Ermöglicht Verwendung von "ddscore" statt "RTI::nddscore" in CMakeLists.txt Files
# HINWEIS: ddscore, ddsftc, ddsfts, ddsconnector werden von Lts/DDS Modulen als echte Targets erstellt
# Daher hier KEINE ALIAS für diese Targets erstellen um Kollisionen zu vermeiden
IF(BUILD_RTI)
  # BUILD_RTI=ON: Targets werden von Lts/DDS/Core/CMakeLists.txt erstellt - hier keine Stubs!
  # Alias-Typen werden später erstellt, wenn RTI:: Targets verfügbar sind
  IF(TARGET RTI::nddsc)
    ADD_LIBRARY(ddsc ALIAS RTI::nddsc)
    # ddscore wird von Lts/DDS/Core/CMakeLists.txt als echtes Target erstellt - kein Alias hier!
    ADD_LIBRARY(ddscpp2 ALIAS RTI::nddscpp2)
    # Optionale Targets nur als ALIAS erstellen wenn verfügbar (RTI 7.x hat nicht alle Legacy-Bibliotheken)
    IF(TARGET RTI::nddscpp)
      ADD_LIBRARY(ddscpp ALIAS RTI::nddscpp)
    ENDIF()
    IF(TARGET RTI::nddsctesthelpers)
      ADD_LIBRARY(nddsctesthelpers ALIAS RTI::nddsctesthelpers)
    ENDIF()
  ENDIF()
  # HINWEIS: ddsftc, ddsfts, ddsconnector werden von Lts/DDS/FTC Modulen als INTERFACE Targets erstellt
  # Hier KEINE ALIAS erstellen um Target-Kollisionen zu vermeiden
ELSE()
  # BUILD_RTI=OFF: Leere Interface-Libraries als Platzhalter
  ADD_LIBRARY(ddsc INTERFACE)
  ADD_LIBRARY(ddscore INTERFACE)
  ADD_LIBRARY(ddscpp INTERFACE)
  ADD_LIBRARY(ddscpp2 INTERFACE)
  ADD_LIBRARY(nddsctesthelpers INTERFACE)
  # HINWEIS: ddsftc, ddsfts, ddsconnector werden von Lts/DDS/FTC Modulen als INTERFACE Targets erstellt
  # Hier KEINE Platzhalter erstellen um Target-Kollisionen zu vermeiden
ENDIF(BUILD_RTI)

ADD_DEFINITIONS(-DQT_USE_QSTRINGBUILDER)
ADD_DEFINITIONS(-DQT_NO_CAST_TO_ASCII)
ADD_DEFINITIONS(-DQT_NO_CAST_FROM_ASCII)
ADD_DEFINITIONS(-DQT_NO_URL_CAST_FROM_STRING)
ADD_DEFINITIONS(-DQT_DEPRECATED_WARNINGS)
ADD_DEFINITIONS(-DQT_NO_CAST_FROM_BYTEARRAY)
#ADD_DEFINITIONS(-DQT_NO_DEPRECATED)
ADD_DEFINITIONS(-DQT_DISABLE_DEPRECATED_BEFORE=0x050900)
ADD_DEFINITIONS(-DQT_NO_FOREACH)
IF(NOT WIN32)
  ADD_DEFINITIONS(-DQT_STRICT_ITERATORS)
ENDIF()

#
# Ein paar NGL-spezifische Macros
#
INCLUDE(NGLMacros)
# Skip MacroCodeGenIdl for release builds as CodeGen module is excluded
IF(NOT RELEASE_BUILD)
  INCLUDE(MacroCodeGenIdl)
ENDIF()

#
# Projektspezifische Einstellungen?
#
NGL_INSTALL(SV AAR WS FILES lts-cc.conf DESTINATION . RENAME lts-cc.conf.distrib)

OPTION(ETS_MODE "Build for ETS (No B-Contamination etc)" OFF)
IF(ETS_MODE)
  ADD_DEFINITIONS(-DETS_MODE)
ENDIF()
OPTION(TABLET_MODE "Build for TABLET " OFF)
IF(TABLET_MODE)
  ADD_DEFINITIONS(-DTABLET_MODE)
ENDIF()

OPTION(GUEZ_MODE "Build for GUEZ " ON)
IF(GUEZ_MODE)
  ADD_DEFINITIONS(-DGUEZ_MODE)
ENDIF()

#
# Doxygen
#
INCLUDE(DoxygenMacros)
IF(NOT DOXYGEN_OUT_DIR)
  SET(DOXYGEN_OUT_DIR ${CMAKE_BINARY_DIR}/doxygen)
ENDIF()
ADD_DOXYGEN_TARGET(TDS ${CMAKE_SOURCE_DIR}/doxygen/Doxyfile.in ${CMAKE_BINARY_DIR}/Doxyfile
                       ${CMAKE_SOURCE_DIR}/doxygen/rheinmetall_defence_logo.jpg
                       ${DOXYGEN_OUT_DIR})

IF(NOT DOXYGEN_OUT_DIR_2025)
  SET(DOXYGEN_OUT_DIR_2025 ${CMAKE_BINARY_DIR}/doxygen2025)
ENDIF()
ADD_DOXYGEN_TARGET(TDS2025 ${CMAKE_SOURCE_DIR}/doxygen/Doxyfile2025.in ${CMAKE_BINARY_DIR}/Doxyfile
                           ${CMAKE_SOURCE_DIR}/doxygen/rheinmetall_defence_logo.jpg
                           ${DOXYGEN_OUT_DIR_2025})

#
# Compilerflags
#
IF(WIN32)
  ADD_DEFINITIONS(-DWIN32 -D_USE_MATH_DEFINES -D_WIN32_WINNT=0x0501 -DUNICODE)
ELSE()
  ADD_DEFINITIONS(-D_LINUX)
ENDIF()

IF(MSVC)
  # C4250: 'class1' : inherits 'class2::member' via dominance
  # C4251: 'identifier' : class 'type' needs to have dll-interface to be used by clients of class 'type2'
  # C4290: C++ exception specification ignored except to indicate a function is not __declspec(nothrow)
  # C4496: 'function': was declared deprecated
  # C4267: 'var' : conversion from 'size_t' to 'type', possible loss of data
  ADD_DEFINITIONS(-wd4250
                  -wd4251
                  -wd4290
                  -wd4496
                  -wd4267
                  -D_CRT_SECURE_NO_DEPRECATE
                  -D_CRT_NONSTDC_NO_DEPRECATE
                  -D_SCL_SECURE_NO_WARNINGS
                  -D_WINSOCK_DEPRECATED_NO_WARNINGS
                  /bigobj
                  )
  # komplette Programmoptimierung
  SET(CMAKE_C_FLAGS   "${CMAKE_C_FLAGS} /MP")
  SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /MP")
  # .pdb - Datei nicht gefunden
  SET(CMAKE_EXE_LINKER_FLAGS    "${CMAKE_EXE_LINKER_FLAGS} /IGNORE:4099")
  SET(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} /IGNORE:4099")
  # min() und max() nicht als Macros
  ADD_DEFINITIONS(-DNOMINMAX)
  SET(CMAKE_MSVCIDE_RUN_PATH "" CACHE PATH "Run path to use when starting programs from MSVC")
ENDIF()

IF(UNIX)
  # Alle Warnungen aktivieren
  SET(CMAKE_C_FLAGS   "${CMAKE_C_FLAGS} -Wall")
  SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall")
  SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wextra -Wmissing-include-dirs")
  # disable
  SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-overloaded-virtual")
  IF("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU")
    IF(CMAKE_CXX_COMPILER_VERSION VERSION_LESS 4.8.0)
      MESSAGE(FATAL_ERROR "gcc 4.8 or higher is required to build TDS: ${CMAKE_CXX_COMPILER_VERSION}")
    ENDIF()
    IF(CMAKE_CXX_COMPILER_VERSION VERSION_GREATER 4.9.99)
      SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-strict-aliasing")
#      SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wsuggest-attribute=const")
#      SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wsuggest-final-types")
#      SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wsuggest-final-methods")
#      SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wsuggest-override")
    ENDIF()
  ENDIF()
ENDIF()

OPTION(USE_IPO "Use interprocedural optimizations (cmake 3.9 or higher required)" OFF)
IF (USE_IPO AND CMAKE_VERSION VERSION_GREATER 3.8.9)
  INCLUDE(CheckIPOSupported)
  check_ipo_supported(RESULT result OUTPUT output)
  IF(result)
    SET(CMAKE_INTERPROCEDURAL_OPTIMIZATION TRUE)
  ELSE()
    MESSAGE(WARNING "IPO is not supported: ${output}")
  ENDIF()
ENDIF()

OPTION(USE_ASAN "Use Address Sanitizer (current Clang only)" OFF)
IF (USE_ASAN)
  IF("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang")
    MESSAGE(STATUS "enable Address Sanitizer with Clang (is: ${CMAKE_CXX_COMPILER_ID})")
    SET(CMAKE_C_FLAGS   "${CMAKE_C_FLAGS}   -fsanitize=address -fno-optimize-sibling-calls -fsanitize-address-use-after-scope -fno-omit-frame-pointer -g -O1")
    SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=address -fno-optimize-sibling-calls -fsanitize-address-use-after-scope -fno-omit-frame-pointer -g -O1")
  ELSE()
    MESSAGE(STATUS "Address Sanitizer only supported with Clang (is: ${CMAKE_CXX_COMPILER_ID})")
  ENDIF()
ENDIF(USE_ASAN)

OPTION(USE_UBSAN "Use UndefinedBehavior Sanitizer (current Clang only)" OFF)
IF (USE_UBSAN)
  IF("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang")
    SET(CMAKE_C_FLAGS   "${CMAKE_C_FLAGS}   -fsanitize=undefined")
    SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=undefined")
  ELSE()
    MESSAGE(STATUS "UndefinedBehavior only supported with Clang (is: ${CMAKE_CXX_COMPILER_ID})")
  ENDIF()
ENDIF(USE_UBSAN)

OPTION(BUILD_RPM "Build a RPM - install script in scripts subdir" OFF)

# Build component options for NGL_ADD_LIBRARY
OPTION(BUILD_ALL "Build all components" ON)
OPTION(BUILD_SV "Build SV component" ON)
OPTION(BUILD_WS "Build WS component" ON)
OPTION(BUILD_AAR "Build AAR component" ON)
OPTION(BUILD_TOOLSWS "Build TOOLSWS component" ON)
OPTION(BUILD_TOOLSSV "Build TOOLSSV component" ON)
OPTION(BUILD_HLA "Build HLA component" ON)

# If BUILD_ALL is ON, enable all individual component flags
IF(BUILD_ALL)
  SET(BUILD_SV ON CACHE BOOL "Build SV component" FORCE)
  SET(BUILD_WS ON CACHE BOOL "Build WS component" FORCE)
  SET(BUILD_AAR ON CACHE BOOL "Build AAR component" FORCE)
  SET(BUILD_TOOLSWS ON CACHE BOOL "Build TOOLSWS component" FORCE)
  SET(BUILD_TOOLSSV ON CACHE BOOL "Build TOOLSSV component" FORCE)
  SET(BUILD_HLA ON CACHE BOOL "Build HLA component" FORCE)
ENDIF()

IF(BUILD_RPM)
  ADD_SUBDIRECTORY(scripts)
ELSE()
  ADD_DEFINITIONS(-DLTS_DEBUG)
ENDIF()

IF (NOT DEFINED _pname)
 IF(GUEZ_MODE)
   SET (_pname "guez")
   ADD_DEFINITIONS(-DPROJECTBUILD="guez")
    MESSAGE(STATUS "NO ProjectName givin! BUT GUEZ_MODE set PROJECTBUILD to guez")
  ELSE()
    MESSAGE(WARNING "NO ProjectName givin! Can't install coresponding lts-cc.conf! and PROJECTBUILD is empty")
    ADD_DEFINITIONS(-DPROJECTBUILD="")
  ENDIF()
ELSE()
    MESSAGE(STATUS "ProjectName givin! PROJECTBUILD is ${_pname} ")
    ADD_DEFINITIONS(-DPROJECTBUILD=\"${_pname}\")
ENDIF()


#
# DDS benoetigt zwingend RTI
#
FIND_PACKAGE(RTI QUIET)
if(NOT RTI_FOUND)
  message(WARNING "RTI not found; creating placeholder RTI::* imported targets to allow configure without RTI installation")
  set(_rti_libs nddscore nddsc nddscpp2 rtiroutingservice)
  foreach(_lib ${_rti_libs})
    if(NOT TARGET RTI::${_lib})
      add_library(RTI::${_lib} UNKNOWN IMPORTED)
      set_property(TARGET RTI::${_lib} PROPERTY INTERFACE_INCLUDE_DIRECTORIES "")
    endif()
  endforeach()
endif()

# Respect MIGRATE_MODULE: when set to a relative path (e.g. "Lts/Common"), only add
# the top-level subdirectories required to configure/build that module. This allows
# per-module migration builds via -DMIGRATE_MODULE=<path>.
if(NOT DEFINED MIGRATE_MODULE)
  set(MIGRATE_MODULE "" CACHE STRING "If set, only add subdirectories covering this module (path relative to repo root)")
endif()

# RELEASE_BUILD: when ON, only build the first release modules (TetraIF, Z, Lts/Common)
# This excludes Lts/Services, Lts/DDS, Lts/Tools, Lts/Application, Lts/Proxies, Lts/Plugins, Lts/Viewer, Lts/Projects
if(NOT DEFINED RELEASE_BUILD)
  set(RELEASE_BUILD OFF CACHE BOOL "Build only the first release modules (TetraIF, Z, Lts/Common)")
endif()

# For release builds, disable ArcGIS (not in release scope, requires Qt6Location which is not available)
if(RELEASE_BUILD)
  set(BUILD_ARCGIS OFF CACHE BOOL "Build ArcGIS SDK dependent modules" FORCE)
endif()

# Add only guarded subdirectories
if(RELEASE_BUILD)
  message(STATUS "RELEASE_BUILD=ON: Building only TetraIF, Z/src, and Lts/Common")
  NGL_ADD_SUBDIR_GUARDED(TetraIF)
  NGL_ADD_SUBDIR_GUARDED(Z/src)
  NGL_ADD_SUBDIR_GUARDED(Lts)
else()
  NGL_ADD_SUBDIR_GUARDED(TetraIF)
  NGL_ADD_SUBDIR_GUARDED(Z/src)
  # Services are included before plugins via Lts/CMakeLists.txt (LTS_SUBDIRS order)
  NGL_ADD_SUBDIR_GUARDED(Lts)
endif()

  # Add migration tests - skip when MIGRATE_MODULE targets specific Lts modules (tests need full codebase)
  # MUST be after Lts configuration so tests can access Lts targets (LtsTimelineClassic, codegen_base, etc.)
  if(NOT DEFINED MIGRATE_MODULE OR MIGRATE_MODULE STREQUAL "" OR MIGRATE_MODULE STREQUAL "tests")
      ADD_SUBDIRECTORY(tests)
  else()
      message(STATUS "MIGRATE_MODULE=${MIGRATE_MODULE} - skipping tests (need full codebase)")
  endif()

# TrainingAreaBase is included via Lts/Proxies when Lts is processed
# Special-case: when migrating TetraIF, also include ProjectDataManagement so generated headers
# and internal logger target are available in the same build tree for TetraIF dependents.
if(DEFINED MIGRATE_MODULE AND MIGRATE_MODULE STREQUAL "TetraIF")
  message(STATUS "Including helper modules for TetraIF migration: Lts/Plugins/ProjectDataManagement")
  # Services already included above when BUILD_RTI=ON
  add_subdirectory(Lts/Plugins/ProjectDataManagement)
endif()
# at last, to make sure we get all targets in NGL_TS_TARGETS property
NGL_ADD_SUBDIR_GUARDED(translations)
#-----------------------------------------------------------------------------------------------------


OPTION(BUILD_QAV "Build script for local QAV analysis" OFF)
IF (BUILD_QAV)
  ADD_SUBDIRECTORY(qav)
ENDIF()
