cmake_minimum_required(VERSION 3.19)

list(APPEND CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/cmake)
list(APPEND CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/cmake/modules)

include(CheckBuildDir)
include(CheckLevel)

project(
    fooyin
    VERSION 0.10.4
    DESCRIPTION "A customisable music player"
    HOMEPAGE_URL "https://www.fooyin.org"
    LANGUAGES CXX
)

set(FOOYIN_VERSION_MAJOR ${PROJECT_VERSION_MAJOR})
set(FOOYIN_VERSION_MINOR ${PROJECT_VERSION_MINOR})
set(FOOYIN_VERSION_PATCH ${PROJECT_VERSION_PATCH})
set(FOOYIN_VERSION ${PROJECT_VERSION})
set(FOOYIN_SOVERSION "0.0.0")
set(FOOYIN_PLUGIN_VERSION "0.0")

include(GenerateExportHeader)
include(FeatureSummary)

set(CMAKE_AUTOMOC ON)
set(CMAKE_AUTORCC ON)
set(CMAKE_LINK_DEPENDS_NO_SHARED ON)

# Enable setting options with SET cmake command
# Needed for some 3rdparty libs
set(CMAKE_POLICY_DEFAULT_CMP0077 NEW)

if(NOT DEFINED CMAKE_SKIP_BUILD_RPATH)
    set(CMAKE_SKIP_BUILD_RPATH OFF)
endif()
if(NOT DEFINED CMAKE_BUILD_WITH_INSTALL_RPATH)
    set(CMAKE_BUILD_WITH_INSTALL_RPATH OFF)
endif()
if(NOT DEFINED CMAKE_INSTALL_RPATH_USE_LINK_PATH)
    set(CMAKE_INSTALL_RPATH_USE_LINK_PATH ON)
endif()

if(NOT CMAKE_BUILD_TYPE)
    set(CMAKE_BUILD_TYPE "Release" CACHE STRING "" FORCE)
endif()

set(FOOYIN_REQUIRED_CXX_FEATURES cxx_std_23)

include(FooyinMacrosInternal)

fooyin_option(BUILD_SHARED_LIBS "Build fooyin libraries as shared" ON)
fooyin_option(BUILD_TESTING "Build fooyin tests" OFF)
fooyin_option(BUILD_SENSITIVE_TESTING "Build time-sensitive tests" OFF)
fooyin_option(BUILD_PLUGINS "Build plugins included with fooyin" ON)
set(PLUGIN_SELECTION "" CACHE STRING
"Plugin selection filter. Empty builds the default set; use 'none' to build no plugins; use a semicolon
or comma-separated list to build only those plugins, or prefix names with '-' to exclude them from the default set
(for example: -discord or discord,lyrics)."
)
fooyin_option(BUILD_ALSA "Build ALSA plugin" ON)
fooyin_option(BUILD_TRANSLATIONS "Build translation files" ON)
fooyin_option(BUILD_CCACHE "Build using CCache if found" ON)
fooyin_option(BUILD_PCH "Build with precompiled header support" OFF)
fooyin_option(BUILD_WERROR "Build with -Werror" OFF)
fooyin_option(BUILD_ASAN "Enable AddressSanitizer" OFF)
fooyin_option(INSTALL_FHS "Install in Linux distros /usr hierarchy" ON)
fooyin_option(INSTALL_HEADERS "Install public development headers" OFF)

if(UNIX)
    list(
        APPEND
        FOOYIN_COMPILE_OPTIONS
        -Wall
        -Wextra
        -Wpedantic
        -Wunused
        -Wshadow
        -Wundef
        -Wuninitialized
        -Wredundant-decls
        -Wcast-align
        -Winit-self
        -Wmissing-include-dirs
        -Wstrict-overflow=2
        -Wunused-parameter
        -Wdisabled-optimization
        -Woverloaded-virtual
        -Wold-style-cast
        -Wno-array-bounds
    )
    if(BUILD_WERROR)
        list(APPEND FOOYIN_COMPILE_OPTIONS -Werror)
    endif()
    if(BUILD_ASAN)
        list(APPEND FOOYIN_COMPILE_OPTIONS -fsanitize=address,undefined)
        list(APPEND FOOYIN_LINK_OPTIONS -fsanitize=address,undefined)
    endif()
endif()

list(
    APPEND
    FOOYIN_COMPILE_DEFINITIONS
    QT_USE_QSTRINGBUILDER
    QT_DISABLE_DEPRECATED_BEFORE=0x060200
    QT_NO_CAST_FROM_ASCII
    QT_NO_CAST_TO_ASCII
    QT_NO_CAST_FROM_BYTEARRAY
    QT_NO_NARROWING_CONVERSIONS_IN_CONNECT
    QT_NO_KEYWORDS
    QT_STRICT_ITERATORS
)

# ---- Dependencies ----

find_package(
    Qt6 REQUIRED
    COMPONENTS Core
               Widgets
               Gui
               Sql
               Concurrent
               Network
               Svg
)
set_package_properties(Qt6Core PROPERTIES TYPE REQUIRED)
set_package_properties(Qt6Widgets PROPERTIES TYPE REQUIRED)
set_package_properties(Qt6Gui PROPERTIES TYPE REQUIRED)
set_package_properties(Qt6Sql PROPERTIES TYPE REQUIRED)
set_package_properties(Qt6Concurrent PROPERTIES TYPE REQUIRED)
set_package_properties(Qt6Network PROPERTIES TYPE REQUIRED)
set_package_properties(Qt6Svg PROPERTIES TYPE REQUIRED)

find_package(ICU COMPONENTS uc i18n REQUIRED)
if(APPLE)
    include(FooyinMacIcu)
    fooyin_prepare_macos_icu()
endif()
find_package(Taglib REQUIRED taglib>=1.12)
find_package(
    FFmpeg REQUIRED
    COMPONENTS AVCODEC
               AVFILTER
               AVFORMAT
               AVUTIL
               SWRESAMPLE
)

if(WIN32)
	find_path(GETOPT_INCLUDE_DIR getopt.h)
	if (NOT GETOPT_INCLUDE_DIR)
		message(FATAL_ERROR "Cannot find getopt.h")
	endif()
	find_library(GETOPT_LIBRARY getopt)
	if (NOT GETOPT_LIBRARY)
		message(FATAL_ERROR "Cannot find getopt library")
	endif()
endif()

include(3rdparty/3rdparty.cmake)

if(BUILD_CCACHE)
    find_program(CCACHE_EXECUTABLE ccache)
    if(CCACHE_EXECUTABLE)
        set_property(GLOBAL PROPERTY RULE_LAUNCH_COMPILE ${CCACHE_EXECUTABLE})
        set_property(GLOBAL PROPERTY RULE_LAUNCH_LINK ${CCACHE_EXECUTABLE})
    endif()
endif()

# ---- Fooyin paths ----

include(GNUInstallDirs)

set(DATAROOTDIR "${CMAKE_INSTALL_DATAROOTDIR}")
fooyin_convert_to_relative_path(DATAROOTDIR)

if(APPLE)
  set(FOOYIN_BUNDLE_NAME "${PROJECT_NAME}.app")
  set(BIN_INSTALL_DIR "${FOOYIN_BUNDLE_NAME}/Contents/MacOS")
  set(LIB_INSTALL_DIR "${FOOYIN_BUNDLE_NAME}/Contents/Frameworks")
  set(TRANSLATION_INSTALL_DIR "${FOOYIN_BUNDLE_NAME}/Contents/Resources/translations")
elseif(INSTALL_FHS)
  set(BIN_INSTALL_DIR "${CMAKE_INSTALL_BINDIR}")
  set(LIB_INSTALL_DIR "${CMAKE_INSTALL_LIBDIR}/fooyin")
  set(TRANSLATION_INSTALL_DIR "${DATAROOTDIR}/fooyin/translations")
else()
  set(BIN_INSTALL_DIR .)
  set(LIB_INSTALL_DIR .)
  set(TRANSLATION_INSTALL_DIR "${BIN_INSTALL_DIR}/translations")
endif()

fooyin_convert_to_relative_path(BIN_INSTALL_DIR)
fooyin_convert_to_relative_path(LIB_INSTALL_DIR)

set(INCLUDE_INSTALL_DIR "${CMAKE_INSTALL_INCLUDEDIR}/fooyin")
set(CMAKECONFIG_INSTALL_DIR "${CMAKE_INSTALL_LIBDIR}/cmake/fooyin")

set(XDG_APPS_INSTALL_DIR "${DATAROOTDIR}/applications")
set(APPDATA_INSTALL_DIR "${DATAROOTDIR}/metainfo")
set(ICON_INSTALL_DIR "${DATAROOTDIR}/icons")

set(DOC_INSTALL_DIR "${DATAROOTDIR}/doc/fooyin/")
file(RELATIVE_PATH FOOYIN_RELATIVE_TRANSLATION_PATH "/${BIN_INSTALL_DIR}" "/${TRANSLATION_INSTALL_DIR}")

if(APPLE)
    set(FOOYIN_PLUGIN_INSTALL_DIR "${FOOYIN_BUNDLE_NAME}/Contents/PlugIns")
else()
    set(FOOYIN_PLUGIN_INSTALL_DIR "${LIB_INSTALL_DIR}/plugins")
endif()
file(RELATIVE_PATH FOOYIN_RELATIVE_PLUGIN_PATH "/${BIN_INSTALL_DIR}" "/${FOOYIN_PLUGIN_INSTALL_DIR}")

if(NOT FOOYIN_OUTPUT_PREFIX)
    set(FOOYIN_OUTPUT_PREFIX "${PROJECT_BINARY_DIR}/run")
endif()

set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${FOOYIN_OUTPUT_PREFIX}/${BIN_INSTALL_DIR}")
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY "${FOOYIN_OUTPUT_PREFIX}/${LIB_INSTALL_DIR}")
set(FOOYIN_PLUGIN_OUTPUT_DIRECTORY "${FOOYIN_OUTPUT_PREFIX}/${FOOYIN_PLUGIN_INSTALL_DIR}")

# ---- Fooyin library ----

if(BUILD_SHARED_LIBS)
    set(FOOYIN_LIBRARY_TYPE SHARED)
else()
    set(FOOYIN_LIBRARY_TYPE STATIC)
endif()

if(BUILD_PCH)
    file(GENERATE OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/empty_pch.cpp
         CONTENT "/*dummy pch file*/"
    )
    add_library(fooyin_pch STATIC ${CMAKE_CURRENT_BINARY_DIR}/empty_pch.cpp)
    target_precompile_headers(
        fooyin_pch PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/src/app/pch.h
    )
    set_target_properties(
        fooyin_pch
        PROPERTIES POSITION_INDEPENDENT_CODE ON
                   CXX_VISIBILITY_PRESET hidden
                   VISIBILITY_INLINES_HIDDEN YES
    )
    target_link_libraries(fooyin_pch PRIVATE Qt::Core Qt::Gui Qt::Widgets)
    target_compile_features(fooyin_pch PRIVATE ${FOOYIN_REQUIRED_CXX_FEATURES})
    target_compile_definitions(fooyin_pch PRIVATE ${FOOYIN_COMPILE_DEFINITIONS})
    target_compile_options(fooyin_pch PRIVATE ${FOOYIN_COMPILE_OPTIONS})
    target_link_options(fooyin_pch INTERFACE ${FOOYIN_LINK_OPTIONS})
    if(CMAKE_VERSION GREATER_EQUAL 3.19)
        set(CMAKE_PCH_INSTANTIATE_TEMPLATES ON)
    endif()
endif()

configure_file(src/app/version.h.in app/version.h)
add_library(fooyin_version OBJECT)
target_include_directories(
    fooyin_version PUBLIC $<BUILD_INTERFACE:${CMAKE_CURRENT_BINARY_DIR}/app>
)
configure_file(src/app/config.h.in app/config.h)
add_library(fooyin_config OBJECT)
target_include_directories(
    fooyin_config PUBLIC $<BUILD_INTERFACE:${CMAKE_CURRENT_BINARY_DIR}/app>
)

add_library(fooyin_lib OBJECT)

target_include_directories(
    fooyin_lib PUBLIC "$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/src>"
                      "$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/src/app>"
)

set_target_properties(
    fooyin_lib PROPERTIES VERSION "${FOOYIN_VERSION}" EXPORT_NAME Fooyin
)

# ---- Mime Types ----

set_property(GLOBAL PROPERTY MIMETYPES
    x-content/audio-player
    application/x-cue
    audio/x-mpegurl
    application/vnd.apple.mpegurl
    application/ogg
    application/x-ogg
    application/x-ogm-audio
    audio/flac
    audio/ogg
    audio/vorbis
    audio/aac
    audio/mp4
    audio/mpeg
    audio/mpegurl
    audio/vnd.rn-realaudio
    audio/x-flac
    audio/x-oggflac
    audio/x-vorbis
    audio/x-vorbis+ogg
    audio/x-speex
    audio/x-wav
    audio/x-wavpack
    audio/x-ape
    audio/x-mp3
    audio/x-mpeg
    audio/x-mpegurl
    audio/x-ms-wma
    audio/x-musepack
    video/x-ms-asf
    application/vnd.ms-asf
)

add_subdirectory(src)

get_property(FOOYIN_MIMETYPES GLOBAL PROPERTY MIMETYPES)
list(REMOVE_DUPLICATES FOOYIN_MIMETYPES)

configure_file(
    "${CMAKE_CURRENT_SOURCE_DIR}/dist/linux/org.fooyin.fooyin.desktop.in"
    "${CMAKE_BINARY_DIR}/dist/linux/org.fooyin.fooyin.desktop" @ONLY
)

target_link_libraries(
    fooyin_lib
    PUBLIC Fooyin::Core
           Fooyin::Gui
           Fooyin::Utils
)

target_compile_features(fooyin_lib PUBLIC ${FOOYIN_REQUIRED_CXX_FEATURES})
target_compile_definitions(fooyin_lib PRIVATE ${FOOYIN_COMPILE_DEFINITIONS})
target_compile_options(fooyin_lib PRIVATE ${FOOYIN_COMPILE_OPTIONS})
target_link_options(fooyin_lib INTERFACE ${FOOYIN_LINK_OPTIONS})
if(APPLE)
    target_include_directories(fooyin_lib BEFORE PRIVATE "${FOOYIN_ICU_INCLUDE_DIR}")
endif()

# ---- Fooyin translations ----

if(BUILD_TRANSLATIONS)
    find_package(
        Qt6 REQUIRED
        COMPONENTS LinguistTools
    )

    if(Qt6LinguistTools_FOUND)
        set(translation_dir
            "${PROJECT_SOURCE_DIR}/data/translations"
            CACHE PATH "Path to the *.ts translation files"
        )

        # Detect new .ts files
        set_property(
                DIRECTORY
                APPEND
                PROPERTY CMAKE_CONFIGURE_DEPENDS ${translation_dir}
        )

        file(GLOB_RECURSE ts_files ${translation_dir}/*.ts)
        # Exclude the translation source
        list(REMOVE_ITEM ts_files ${translation_dir}/fooyin.ts)

        set_source_files_properties(
            ${ts_files} PROPERTIES OUTPUT_LOCATION "${CMAKE_CURRENT_BINARY_DIR}/data"
        )

        qt_add_lrelease(
            fooyin_lib
            TS_FILES
            ${ts_files}
            NO_GLOBAL_TARGET
            QM_FILES_OUTPUT_VARIABLE
            qm_files
        )

        if(NOT CMAKE_SKIP_INSTALL_RULES)
            install(
                FILES ${qm_files}
                DESTINATION ${TRANSLATION_INSTALL_DIR}
                COMPONENT fooyin
            )
        endif()
    endif()
endif()

# ---- Fooyin testing ----

if(BUILD_TESTING)
    find_package(Qt6 REQUIRED COMPONENTS Test)
    set_package_properties(Qt6Test PROPERTIES TYPE REQUIRED)
    find_package(GTest)
    add_subdirectory(tests)
endif()

# ---- Fooyin executable ----

set(SOURCES ${SOURCES} src/app/commandline.cpp src/app/main.cpp)

qt_add_resources(SOURCES data/data.qrc)
qt_add_resources(SOURCES data/icons.qrc)

set(FOOYIN_EXECUTABLE_ARGS WIN32)
if(APPLE)
    list(APPEND FOOYIN_EXECUTABLE_ARGS MACOSX_BUNDLE)
endif()

add_executable(fooyin ${FOOYIN_EXECUTABLE_ARGS} ${SOURCES} ${TRANSLATIONS})
if(APPLE)
    set_target_properties(fooyin PROPERTIES RUNTIME_OUTPUT_DIRECTORY "${FOOYIN_OUTPUT_PREFIX}")
    target_include_directories(fooyin BEFORE PRIVATE "${FOOYIN_ICU_INCLUDE_DIR}")
endif()
fooyin_set_rpath(fooyin ${BIN_INSTALL_DIR})
target_compile_features(fooyin PUBLIC ${FOOYIN_REQUIRED_CXX_FEATURES})
target_compile_definitions(fooyin PRIVATE ${FOOYIN_COMPILE_DEFINITIONS})
target_compile_options(fooyin PRIVATE ${FOOYIN_COMPILE_OPTIONS})
target_link_options(fooyin INTERFACE ${FOOYIN_LINK_OPTIONS})
target_link_libraries(
    fooyin
    PRIVATE KDAB::kdsingleapplication
            Qt6::Network
            fooyin_version
            fooyin_lib
            Fooyin::CorePrivate
)

if(WIN32)
	target_include_directories(fooyin PRIVATE ${GETOPT_INCLUDE_DIR})
	target_link_libraries(fooyin PRIVATE ${GETOPT_LIBRARY})
    configure_file(data/win_version.rc.in win_version.rc @ONLY)
    target_sources(fooyin PRIVATE win_version.rc)
endif()

if(APPLE)
    configure_file(dist/macos/org.fooyin.fooyin.plist.in Info.plist @ONLY)
    include(FooyinMacDmg)
    fooyin_prepare_macos_dmg_assets()
    include(FooyinMacIcon)
    fooyin_setup_macos_icon(fooyin)
    set_target_properties(
        fooyin
        PROPERTIES MACOSX_BUNDLE_INFO_PLIST "${CMAKE_CURRENT_BINARY_DIR}/Info.plist"
    )
    if(TARGET Qt6::macdeployqt)
        get_target_property(MACDEPLOYQT_EXECUTABLE Qt6::macdeployqt IMPORTED_LOCATION)
    endif()
    if(NOT MACDEPLOYQT_EXECUTABLE)
        find_program(
            MACDEPLOYQT_EXECUTABLE macdeployqt
            HINTS "${Qt6_DIR}/../../../bin"
        )
    endif()
    if(NOT MACDEPLOYQT_EXECUTABLE)
        message(FATAL_ERROR "macdeployqt not found")
    endif()
    configure_file(
        "${CMAKE_CURRENT_SOURCE_DIR}/cmake/FooyinMacBundleFixup.cmake.in"
        "${CMAKE_CURRENT_BINARY_DIR}/cmake/FooyinMacBundleFixup.cmake"
        @ONLY
    )
endif()

# ---- Fooyin install ----

if(NOT CMAKE_SKIP_INSTALL_RULES)
    include(FooyinInstall)
endif()

if(WIN32)
    include("${CMAKE_CURRENT_SOURCE_DIR}/cmake/DeployQt.cmake")
    windeployqt(fooyin)

    if(qm_files)
        add_custom_command(
            TARGET fooyin POST_BUILD
            COMMAND ${CMAKE_COMMAND} -E make_directory
                "$<TARGET_FILE_DIR:fooyin>/translations"
            COMMAND ${CMAKE_COMMAND} -E copy_if_different
                ${qm_files}
                "$<TARGET_FILE_DIR:fooyin>/translations"
            COMMENT "Copying fooyin translation files ..."
        )
    endif()
elseif(APPLE)
    install(SCRIPT "${CMAKE_CURRENT_BINARY_DIR}/cmake/FooyinMacBundleFixup.cmake" COMPONENT fooyin)
endif()

# ---- Fooyin uninstall ----

configure_file(
    "${CMAKE_CURRENT_SOURCE_DIR}/cmake/FooyinUninstall.cmake.in"
    "${CMAKE_BINARY_DIR}/cmake_uninstall.cmake" @ONLY
)
add_custom_target(
    uninstall "${CMAKE_COMMAND}" -P
              "${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake"
)

include(FooyinPackaging)

include(FooyinSummary)
fooyin_print_summary()
