# SPDX-License-Identifier: GPL-3.0-or-later

cmake_minimum_required(VERSION 3.20)

project(BastionGuardRecoveryData VERSION 0.3.0 LANGUAGES CXX)

set(CMAKE_CXX_STANDARD 20)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_CXX_EXTENSIONS OFF)

# BastionGuard packages are installed under /usr by default, so the
# application and privileged launcher live in /usr/bin. Users may still
# override CMAKE_INSTALL_PREFIX explicitly when packaging for another layout.
if(CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT)
    set(CMAKE_INSTALL_PREFIX "/usr" CACHE PATH "Install prefix" FORCE)
endif()

include(GNUInstallDirs)

find_package(PkgConfig REQUIRED)

# gtkmm è una dipendenza obbligatoria: senza REQUIRED la configurazione
# passerebbe ma il build fallirebbe con errori criptici di header mancanti
pkg_check_modules(GTKMM REQUIRED gtkmm-4.0)

find_package(ZLIB REQUIRED)

# zstd: il file .pc (libzstd.pc) è distribuito ovunque
# (Arch: zstd, Debian/Ubuntu: libzstd-dev, Fedora/openSUSE: libzstd-devel)
pkg_check_modules(ZSTD QUIET libzstd)

# lzo2: upstream non installa un file .pc, quindi pkg-config può fallire
# anche con gli header presenti. Fallback con find_path/find_library.
# (Arch: lzo, Debian/Ubuntu: liblzo2-dev, Fedora/openSUSE: lzo-devel)
pkg_check_modules(LZO2 QUIET lzo2)
if(NOT LZO2_FOUND)
    find_path(LZO2_INCLUDE_DIRS NAMES lzo/lzo1x.h)
    find_library(LZO2_LIBRARIES NAMES lzo2)
    if(LZO2_INCLUDE_DIRS AND LZO2_LIBRARIES)
        set(LZO2_FOUND TRUE)
        message(STATUS "Found LZO2 (no pkg-config): ${LZO2_LIBRARIES}")
    else()
        message(STATUS "LZO2 not found - building without LZO support")
        set(LZO2_INCLUDE_DIRS "")
        set(LZO2_LIBRARY_DIRS "")
        set(LZO2_LIBRARIES "")
    endif()
endif()

if(NOT ZSTD_FOUND)
    message(STATUS "ZSTD not found - building without ZSTD support")
endif()

option(BASTIONGUARD_ENABLE_NLS "Enable translations" ON)

set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin)
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib)
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib)

add_executable(bastionguard-recovery-data
    src/main.cpp
    src/main_window.cpp
    src/device_enumerator.cpp
    src/device_health_probe.cpp
    src/disk_reader.cpp
    src/bad_block_map.cpp
    src/fault_tolerant_reader.cpp
    src/partition_parser.cpp
    src/signature_scanner.cpp
    src/lost_partition_finder.cpp
    src/ntfs_probe.cpp
    src/ntfs_recovery.cpp
    src/ext4_recovery.cpp
    src/btrfs_recovery.cpp
    src/xfs_format.cpp
    src/xfs_btree.cpp
    src/xfs_inode.cpp
    src/xfs_dir.cpp
    src/xfs_recovery.cpp
    src/hfs_format.cpp
    src/hfs_btree.cpp
    src/hfs_unicode.cpp
    src/hfs_fork_io.cpp
    src/hfs_catalog.cpp
    src/hfs_decmpfs.cpp
    src/hfs_attributes.cpp
    src/hfs_recovery.cpp
    src/carving.cpp
    src/filesystem_probes.cpp
    src/filesystem_recovery.cpp
    src/report_exporter.cpp
    src/file_carver.cpp
    src/recovery_exporter.cpp
    src/rescue_imager.cpp
    src/scanner_engine.cpp
    src/scan_worker.cpp
    src/recovery_worker.cpp
    src/i18n.cpp
    src/StyleProvider.cpp
    src/privilege_utils.cpp
    src/encryption_support.cpp
    src/encrypted_volume_support.cpp
)

target_include_directories(bastionguard-recovery-data PRIVATE
    ${CMAKE_CURRENT_SOURCE_DIR}/src
    ${GTKMM_INCLUDE_DIRS}
    ${ZSTD_INCLUDE_DIRS}
    ${LZO2_INCLUDE_DIRS}
)

target_compile_options(bastionguard-recovery-data PRIVATE
    ${GTKMM_CFLAGS_OTHER}
    ${ZSTD_CFLAGS_OTHER}
    ${LZO2_CFLAGS_OTHER}
    -Wall
    -Wextra
    -Wpedantic
)

target_link_directories(bastionguard-recovery-data PRIVATE
    ${GTKMM_LIBRARY_DIRS}
    ${ZSTD_LIBRARY_DIRS}
    ${LZO2_LIBRARY_DIRS}
)

target_link_libraries(bastionguard-recovery-data PRIVATE
    ZLIB::ZLIB
    ${GTKMM_LIBRARIES}
    ${ZSTD_LIBRARIES}
    ${LZO2_LIBRARIES}
)

target_compile_definitions(bastionguard-recovery-data PRIVATE
    GLIBMM_DISABLE_DEPRECATED
    GIOMM_DISABLE_DEPRECATED
    GTKMM_DISABLE_DEPRECATED
    APP_ID="com.bastionguard.RecoveryData"
    APP_NAME="BastionGuard Recovery Data"
    DATADIR="${CMAKE_INSTALL_FULL_DATADIR}/bastionguard-recovery-data/data"
    LOCALEDIR="${CMAKE_INSTALL_FULL_LOCALEDIR}"
)

if(ZLIB_FOUND)
    target_compile_definitions(bastionguard-recovery-data PRIVATE HAVE_ZLIB=1)
endif()

if(ZSTD_FOUND)
    target_compile_definitions(bastionguard-recovery-data PRIVATE HAVE_ZSTD=1)
endif()

if(LZO2_FOUND)
    target_compile_definitions(bastionguard-recovery-data PRIVATE HAVE_LZO=1)
endif()

install(
    TARGETS bastionguard-recovery-data
    RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
)

if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/data)
    install(
        DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/data/
        DESTINATION ${CMAKE_INSTALL_DATADIR}/bastionguard-recovery-data/data
    )
endif()

set(BASTIONGUARD_LICENSE_FILES
    ${CMAKE_CURRENT_SOURCE_DIR}/LICENSE
    ${CMAKE_CURRENT_SOURCE_DIR}/COPYING
    ${CMAKE_CURRENT_SOURCE_DIR}/COPYRIGHT
)

install(
    FILES ${BASTIONGUARD_LICENSE_FILES}
    DESTINATION ${CMAKE_INSTALL_DATADIR}/bastionguard-recovery-data
)

if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/packaging/bastionguard-recovery-data-pkexec.in)
    configure_file(
        ${CMAKE_CURRENT_SOURCE_DIR}/packaging/bastionguard-recovery-data-pkexec.in
        ${CMAKE_CURRENT_BINARY_DIR}/bastionguard-recovery-data-pkexec
        @ONLY
    )
    install(
        PROGRAMS ${CMAKE_CURRENT_BINARY_DIR}/bastionguard-recovery-data-pkexec
        DESTINATION ${CMAKE_INSTALL_BINDIR}
    )
elseif(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/packaging/bastionguard-recovery-data-pkexec)
    install(
        PROGRAMS ${CMAKE_CURRENT_SOURCE_DIR}/packaging/bastionguard-recovery-data-pkexec
        DESTINATION ${CMAKE_INSTALL_BINDIR}
    )
endif()

if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/packaging/com.bastionguard.RecoveryData.policy)
    install(
        FILES ${CMAKE_CURRENT_SOURCE_DIR}/packaging/com.bastionguard.RecoveryData.policy
        DESTINATION ${CMAKE_INSTALL_DATADIR}/polkit-1/actions
    )
endif()

if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/packaging/com.bastionguard.RecoveryData.desktop.in)
    configure_file(
        ${CMAKE_CURRENT_SOURCE_DIR}/packaging/com.bastionguard.RecoveryData.desktop.in
        ${CMAKE_CURRENT_BINARY_DIR}/com.bastionguard.RecoveryData.desktop
        @ONLY
    )
    install(
        FILES ${CMAKE_CURRENT_BINARY_DIR}/com.bastionguard.RecoveryData.desktop
        DESTINATION ${CMAKE_INSTALL_DATADIR}/applications
    )
elseif(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/packaging/com.bastionguard.RecoveryData.desktop)
    install(
        FILES ${CMAKE_CURRENT_SOURCE_DIR}/packaging/com.bastionguard.RecoveryData.desktop
        DESTINATION ${CMAKE_INSTALL_DATADIR}/applications
    )
endif()

if(BASTIONGUARD_ENABLE_NLS)
    find_program(MSGFMT_EXECUTABLE msgfmt)

    if(MSGFMT_EXECUTABLE AND EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/po)
        foreach(lang en it de es fr ja nl pl pt ru ar)
            if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/po/${lang}.po)
                set(PO_FILE ${CMAKE_CURRENT_SOURCE_DIR}/po/${lang}.po)
                set(MO_DIR ${CMAKE_CURRENT_BINARY_DIR}/locale/${lang}/LC_MESSAGES)
                set(MO_FILE ${MO_DIR}/bastionguard-recovery-data.mo)

                add_custom_command(
                    OUTPUT ${MO_FILE}
                    COMMAND ${CMAKE_COMMAND} -E make_directory ${MO_DIR}
                    COMMAND ${MSGFMT_EXECUTABLE} -o ${MO_FILE} ${PO_FILE}
                    DEPENDS ${PO_FILE}
                    VERBATIM
                )

                add_custom_target(locale_${lang} ALL DEPENDS ${MO_FILE})
                add_dependencies(bastionguard-recovery-data locale_${lang})

                install(
                    FILES ${MO_FILE}
                    DESTINATION ${CMAKE_INSTALL_LOCALEDIR}/${lang}/LC_MESSAGES
                )
            endif()
        endforeach()
    endif()
endif()

# /usr/share/bastionguard-backup
set(BASTIONGUARD_BACKUP_DATADIR
    "${CMAKE_INSTALL_DATADIR}/bastionguard-backup"
)

set(BASTIONGUARD_BACKUP_SCRIPTS_DIR
    "${BASTIONGUARD_BACKUP_DATADIR}/scripts"
)

set(BASTIONGUARD_BACKUP_GRUB_DIR
    "${BASTIONGUARD_BACKUP_DATADIR}/grub"
)

# scripts
install(
    PROGRAMS
        ${CMAKE_CURRENT_SOURCE_DIR}/scripts/build-recovery-squashfs.sh
        ${CMAKE_CURRENT_SOURCE_DIR}/scripts/install-grub-entry.sh
    DESTINATION ${BASTIONGUARD_BACKUP_SCRIPTS_DIR}
)

# grub executable script
install(
    PROGRAMS
        ${CMAKE_CURRENT_SOURCE_DIR}/grub/42_bastionguard-recovery
    DESTINATION ${BASTIONGUARD_BACKUP_GRUB_DIR}
)

# grub zip data
install(
    FILES
        ${CMAKE_CURRENT_SOURCE_DIR}/grub/bastionguard-backup.zip
    DESTINATION ${BASTIONGUARD_BACKUP_GRUB_DIR}
)

# crea /usr/share/bastionguard-backup/data solo se non esiste
install(CODE "
    set(_bg_data_dir \"\$ENV{DESTDIR}${CMAKE_INSTALL_FULL_DATADIR}/bastionguard-backup/data\")
    if(NOT EXISTS \"\${_bg_data_dir}\")
        file(MAKE_DIRECTORY \"\${_bg_data_dir}\")
    endif()
")

# copia il contenuto di data dentro /usr/share/bastionguard-backup/data
if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/data)
    install(
        DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/data/
        DESTINATION ${BASTIONGUARD_BACKUP_DATADIR}/data
    )
endif()

# plymouth theme
if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/data/plymouth/bastionguard)
    install(
        DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/data/plymouth/bastionguard
        DESTINATION ${CMAKE_INSTALL_DATADIR}/plymouth/themes
    )
endif()
