# SPDX-FileCopyrightText: 2025 Filip Leonarski, Paul Scherrer Institute <filip.leonarski@psi.ch>
# SPDX-License-Identifier: GPL-3.0-only

SET(CMAKE_AUTOMOC ON)
SET(CMAKE_AUTOUIC ON)

# D-Bus (single-instance / remote control) is Linux-only: Qt6::DBus does not
# exist on Windows or macOS. Default ON on Linux, OFF elsewhere.
IF(UNIX AND NOT APPLE)
    OPTION(JFJOCH_VIEWER_DBUS "Build viewer with D-Bus support (Linux only)" ON)
ELSE()
    OPTION(JFJOCH_VIEWER_DBUS "Build viewer with D-Bus support (Linux only)" OFF)
ENDIF()

SET(JFJOCH_VIEWER_QT_COMPONENTS Core Gui Widgets Charts Concurrent)
IF(JFJOCH_VIEWER_DBUS)
    LIST(APPEND JFJOCH_VIEWER_QT_COMPONENTS DBus)
ENDIF()
FIND_PACKAGE(Qt6 COMPONENTS ${JFJOCH_VIEWER_QT_COMPONENTS} REQUIRED)

QT_ADD_RESOURCES(APP_RESOURCES resources/resources.qrc)

ADD_EXECUTABLE(jfjoch_viewer jfjoch_viewer.cpp JFJochViewerWindow.cpp JFJochViewerWindow.h
        JFJochViewerMenu.cpp
        JFJochViewerMenu.h
        RemoteDisplayMode.cpp
        RemoteDisplayMode.h
        ViewerTheme.cpp
        ViewerTheme.h
        image_viewer/JFJochDiffractionImage.cpp
        image_viewer/JFJochDiffractionImage.h
        image_viewer/JFJochSimpleImage.cpp
        image_viewer/JFJochSimpleImage.h
        JFJochImageReadingWorker.cpp
        JFJochImageReadingWorker.h
        JFJochHttpReader.cpp
        JFJochHttpReader.h
        RunData.h
        JFJochProcessController.cpp
        JFJochProcessController.h
        JFJochViewerDatasetInfo.cpp
        JFJochViewerDatasetInfo.h
        JFJochViewerSidePanel.cpp
        JFJochViewerSidePanel.h
        widgets/TitleLabel.cpp
        widgets/TitleLabel.h
        charts/JFJochDatasetInfoChartView.cpp
        charts/JFJochDatasetInfoChartView.h
        widgets/JFJochViewerImageStatistics.cpp
        widgets/JFJochViewerImageStatistics.h
        charts/JFJochSimpleChartView.cpp
        charts/JFJochSimpleChartView.h
        JFJochViewerStatusBar.cpp
        JFJochViewerStatusBar.h
        windows/JFJochViewerImageListWindow.cpp
        windows/JFJochViewerImageListWindow.h
        widgets/NumericComboBox.cpp
        widgets/NumericComboBox.h
        widgets/LiveComboBox.cpp
        widgets/LiveComboBox.h
        windows/JFJochViewerMetadataWindow.cpp
        windows/JFJochViewerMetadataWindow.h
        windows/JFJochMergeStatsWindow.cpp
        windows/JFJochMergeStatsWindow.h
        windows/JFJochCalibrationResultWindow.cpp
        windows/JFJochCalibrationResultWindow.h
        widgets/JFJochViewerMagnifier.cpp
        widgets/JFJochViewerMagnifier.h
        widgets/NumberLineEdit.cpp
        widgets/NumberLineEdit.h
        widgets/SliderPlusBox.cpp
        widgets/SliderPlusBox.h
        widgets/JFJochViewerSidePanelChart.cpp
        widgets/JFJochViewerSidePanelChart.h
        widgets/JFJochViewerSettingsDock.cpp
        widgets/JFJochViewerSettingsDock.h
        widgets/CollapsibleSection.cpp
        widgets/CollapsibleSection.h
        widgets/ToolbarIcons.cpp
        widgets/ToolbarIcons.h
        widgets/JFJochViewerFileBrowser.cpp
        widgets/JFJochViewerFileBrowser.h
        windows/JFJochViewerSpotListWindow.cpp
        windows/JFJochViewerSpotListWindow.h
        image_viewer/JFJochAzIntImage.cpp
        image_viewer/JFJochAzIntImage.h
        windows/JFJochViewerReflectionListWindow.cpp
        windows/JFJochViewerReflectionListWindow.h
        toolbar/JFJochViewerToolbarImage.cpp
        toolbar/JFJochViewerToolbarImage.h
        toolbar/JFJochViewerToolbarDisplay.cpp
        toolbar/JFJochViewerToolbarDisplay.h
        SimpleImage.h
        windows/JFJochCalibrationWindow.cpp
        windows/JFJochCalibrationWindow.h
        windows/JFJochHelperWindow.cpp
        windows/JFJochHelperWindow.h
        windows/JFJochLicenseWindow.cpp
        windows/JFJochLicenseWindow.h
        windows/JFJochMouseShortcutsWindow.cpp
        windows/JFJochMouseShortcutsWindow.h
        windows/JFJochAcknowledgementWindow.cpp
        windows/JFJochAcknowledgementWindow.h
        image_viewer/JFJochImage.cpp
        image_viewer/JFJochImage.h
        image_viewer/JFJochFollowerImage.cpp
        image_viewer/JFJochFollowerImage.h
        windows/JFJoch2DAzintImageWindow.cpp
        windows/JFJoch2DAzintImageWindow.h
        widgets/JFJochViewerROIResult.cpp
        widgets/JFJochViewerROIResult.h
        widgets/JFJochViewerROIList.cpp
        widgets/JFJochViewerROIList.h
        widgets/ResolutionRingWidget.cpp
        widgets/ResolutionRingWidget.h
        image_viewer/JFJochGridScanImage.cpp
        image_viewer/JFJochGridScanImage.h
        widgets/PowderCalibrationWidget.cpp
        widgets/PowderCalibrationWidget.h
        ${APP_RESOURCES}
        windows/JFJochProcessingJobsWindow.cpp
        windows/JFJochProcessingJobsWindow.h
)

TARGET_LINK_LIBRARIES(jfjoch_viewer Qt6::Core Qt6::Gui Qt6::Widgets Qt6::Charts Qt6::Concurrent
        JFJochReader JFJochLogger JFJochCommon JFJochWriter JFJochImageAnalysis JFJochRugnux JFJochRugnuxOutput
        fftw3f httplib::httplib MbedTLS::mbedtls)

# HTTPS for the live-broker client. Defined here, on the viewer only, not on httplib::httplib: the
# broker shares that target and stays plain HTTP. JFJochHttpReader.cpp is the one viewer source
# that includes <httplib.h>, so no other translation unit sees a different httplib.
TARGET_COMPILE_DEFINITIONS(jfjoch_viewer PRIVATE CPPHTTPLIB_MBEDTLS_SUPPORT)
IF (APPLE)
    # cpp-httplib reads the trusted roots from the Keychain; its own target adds these frameworks
    # only for the OpenSSL backend.
    TARGET_LINK_LIBRARIES(jfjoch_viewer "-framework CFNetwork" "-framework CoreFoundation"
            "-framework Security")
ENDIF()

# Native GUI app per platform: a .app bundle on macOS, GUI subsystem (no console window) on
# Windows. Each property is ignored on the platforms it does not apply to, so set both always.
SET_TARGET_PROPERTIES(jfjoch_viewer PROPERTIES
        MACOSX_BUNDLE    ON
        WIN32_EXECUTABLE ON)

# Application icon: embedded into the .exe via a Windows resource script, and copied into
# the macOS .app bundle (referenced from Info.plist through MACOSX_BUNDLE_ICON_FILE).
IF(WIN32)
    TARGET_SOURCES(jfjoch_viewer PRIVATE resources/jfjoch.rc)
ELSEIF(APPLE)
    SET(_viewer_icns ${CMAKE_CURRENT_SOURCE_DIR}/resources/jfjoch.icns)
    TARGET_SOURCES(jfjoch_viewer PRIVATE ${_viewer_icns})
    SET_SOURCE_FILES_PROPERTIES(${_viewer_icns} PROPERTIES MACOSX_PACKAGE_LOCATION Resources)
    SET_TARGET_PROPERTIES(jfjoch_viewer PROPERTIES MACOSX_BUNDLE_ICON_FILE jfjoch.icns)
    # Info.plist identity. Notarization needs the identifier; the short version must be numeric, so
    # the release-candidate suffix goes into the long version string (Finder's Get Info). The bundle
    # name is what the macOS menu bar shows, and matches the Qt application name.
    SET_TARGET_PROPERTIES(jfjoch_viewer PROPERTIES
            MACOSX_BUNDLE_GUI_IDENTIFIER       ch.psi.jfjoch.viewer
            MACOSX_BUNDLE_BUNDLE_NAME          "JFJoch Viewer"
            MACOSX_BUNDLE_SHORT_VERSION_STRING ${JFJOCH_VERSION_NUMERIC}
            MACOSX_BUNDLE_BUNDLE_VERSION       ${JFJOCH_VERSION_NUMERIC}
            MACOSX_BUNDLE_LONG_VERSION_STRING  ${JFJOCH_VERSION}
            MACOSX_BUNDLE_COPYRIGHT            "Copyright (C) 2019-2026 Paul Scherrer Institute")
    # Qt links as @rpath/Qt*.framework and the deploy step below copies the frameworks into the
    # bundle's Frameworks folder; without this rpath the installed app (and the .dmg) cannot find
    # them - install strips the build tree's rpath and leaves the executable with none.
    SET_TARGET_PROPERTIES(jfjoch_viewer PROPERTIES INSTALL_RPATH "@executable_path/../Frameworks")
ENDIF()

INSTALL(TARGETS jfjoch_viewer
        BUNDLE  DESTINATION .   COMPONENT viewer   # macOS .app bundle
        RUNTIME DESTINATION bin COMPONENT viewer)  # Windows .exe / Linux binary

# On macOS the notices go inside the bundle: a user drags only the .app out of the .dmg, so anything
# beside it is left behind. They must be installed before the Qt deploy script below, which signs
# the bundle - a file added after the signature invalidates it. (Other platforms install them into
# share/doc/jfjoch_viewer at the end of the top-level CMakeLists.txt.)
IF(APPLE)
    INSTALL(FILES ${JFJOCH_NOTICE_FILES}
            DESTINATION jfjoch_viewer.app/Contents/Resources COMPONENT viewer)
    INSTALL(DIRECTORY ${CMAKE_SOURCE_DIR}/licenses/
            DESTINATION jfjoch_viewer.app/Contents/Resources/licenses COMPONENT viewer
            PATTERN "COLLECT.sh" EXCLUDE)
ENDIF()

# libcufft_static.a carries a relocatable-device-code object (separate_callback.o), so an executable
# linking it needs a CUDA device-link step -- without it the host link fails on an undefined
# __cudaRegisterLinkedBinary_* symbol. CUDA 13 no longer ships libcufft_static_nocallback.a, which
# used to be the way around it. CUDA_RESOLVE_DEVICE_SYMBOLS makes CMake emit that step while leaving
# the host link driver alone, so the -march/-flto flags CI passes still apply.
IF (JFJOCH_PORTABLE_ONLY AND JFJOCH_CUDA_AVAILABLE AND TARGET CUDA::cufft_static)
    SET_TARGET_PROPERTIES(jfjoch_viewer PROPERTIES CUDA_RESOLVE_DEVICE_SYMBOLS ON)
ENDIF()


IF(JFJOCH_VIEWER_DBUS)
    TARGET_SOURCES(jfjoch_viewer PRIVATE dbus/JFJochViewerAdaptor.cpp dbus/JFJochViewerAdaptor.h)
    TARGET_LINK_LIBRARIES(jfjoch_viewer Qt6::DBus)
    TARGET_COMPILE_DEFINITIONS(jfjoch_viewer PRIVATE JFJOCH_VIEWER_DBUS)
    INSTALL(
            FILES ${CMAKE_CURRENT_SOURCE_DIR}/dbus/ch.psi.jfjoch_viewer.service
            DESTINATION share/dbus-1/services
            COMPONENT viewer
    )
ENDIF()

# Freedesktop menu entry and its icon: Linux only. On Windows the Start Menu shortcut comes from
# CPACK_PACKAGE_EXECUTABLES and on macOS from the .app bundle, so shipping these there would only
# put two dead files into the installer.
IF(UNIX AND NOT APPLE)
    INSTALL(
            FILES resources/jfjoch.png
            DESTINATION share/pixmaps
            COMPONENT viewer
    )

    INSTALL(
            FILES jfjoch_viewer.desktop
            DESTINATION share/applications
            COMPONENT viewer
    )
ENDIF()

# Platform integration plugin: XCB on Linux, native plugin on Windows/macOS.
IF(WIN32)
    qt_import_plugins(jfjoch_viewer INCLUDE Qt::QWindowsIntegrationPlugin)
ELSEIF(APPLE)
    qt_import_plugins(jfjoch_viewer INCLUDE Qt::QCocoaIntegrationPlugin)
ELSE()
    qt_import_plugins(jfjoch_viewer INCLUDE Qt::QXcbIntegrationPlugin)
ENDIF()

# No Qt JPEG or TIFF image plugins: the viewer encodes JPEG through our own encoder (stb_image_write,
# preview/) and reads/writes TIFF through our own libtiff, so the plugins would only add code. The
# TIFF plugin would also bind to whichever libtiff the link happens to offer. A shared Qt never loads
# either plugin, as nothing goes through QImage for these formats.
qt_import_plugins(jfjoch_viewer EXCLUDE Qt::QJpegPlugin Qt::QTiffPlugin)

# Bundle the Qt runtime into the install tree at install time: this drives windeployqt on Windows
# and macdeployqt on macOS, copying the Qt shared libraries + plugins next to the app. With a
# static Qt (e.g. our Linux build) there is nothing to copy, so it is a no-op. Requires Qt >= 6.5,
# which is when the OUTPUT_SCRIPT signature and the Linux deploy path landed (6.3/6.4 used the older
# FILENAME_VARIABLE and had no Linux support); skipped on older Qt. NO_UNSUPPORTED_PLATFORM_ERROR
# keeps it from hard-failing on configurations it does not handle.
# On macOS macdeployqt also signs the bundle (ad-hoc by default); with JFJOCH_MACOS_SIGNING_IDENTITY
# set it signs with that Developer ID instead, hardened runtime and secure timestamp included, which
# is what the .dmg needs to be notarized afterwards (DEPLOY_TOOL_OPTIONS needs Qt >= 6.7).
IF(Qt6_VERSION VERSION_GREATER_EQUAL "6.5")
    SET(_viewer_deploy_tool_options)
    IF(APPLE AND JFJOCH_MACOS_SIGNING_IDENTITY)
        SET(_viewer_deploy_tool_options
                DEPLOY_TOOL_OPTIONS "-sign-for-notarization=${JFJOCH_MACOS_SIGNING_IDENTITY}")
    ENDIF()
    qt_generate_deploy_app_script(
            TARGET jfjoch_viewer
            OUTPUT_SCRIPT jfjoch_viewer_deploy_script
            NO_UNSUPPORTED_PLATFORM_ERROR
            ${_viewer_deploy_tool_options})
    INSTALL(SCRIPT ${jfjoch_viewer_deploy_script} COMPONENT viewer)
ENDIF()

# cuFFT is linked statically (see image_analysis/indexing/CMakeLists.txt), so there is no CUDA
# runtime library to ship beside jfjoch_viewer on any platform.
