include(GNUInstallDirs)

function(ExtractZipArchive ZIP_FILE OUTPUT_DIR)
    if(CMAKE_VERSION VERSION_LESS 3.18)
        # Use the older method for versions prior to CMake 3.18
        execute_process(COMMAND unzip -o "${ZIP_FILE}" -d "${OUTPUT_DIR}")
    else()
        # Use the newer method introduced in CMake 3.18 and later
        file(ARCHIVE_EXTRACT INPUT ${ZIP_FILE} DESTINATION ${OUTPUT_DIR})
    endif()
endfunction()

# Automatically fetch Unicode database if not present.
if (NOT EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/ucd.cpp) # if c++ files not auto-generated
    if(NOT IS_DIRECTORY ${LIBUNICODE_UCD_DIR})
        if(NOT EXISTS ${LIBUNICODE_UCD_ZIP_FILE})
            file(DOWNLOAD ${LIBUNICODE_UCD_ZIP_DOWNLOAD_URL} ${LIBUNICODE_UCD_ZIP_FILE} SHOW_PROGRESS STATUS LIBUNICODE_UCD_ZIP_DOWNLOAD_STATUS EXPECTED_MD5 ${LIBUNICODE_UCD_MD5})
        endif()
        ExtractZipArchive("${LIBUNICODE_UCD_ZIP_FILE}" "${LIBUNICODE_UCD_DIR}")
    endif()
endif()

# =========================================================================================================
if(IS_DIRECTORY "${LIBUNICODE_UCD_DIR}")
    find_package(Python3 REQUIRED COMPONENTS Interpreter)
    add_custom_command(
        OUTPUT
            "${CMAKE_CURRENT_SOURCE_DIR}/ucd.cpp"
            "${CMAKE_CURRENT_SOURCE_DIR}/ucd.h"
            "${CMAKE_CURRENT_SOURCE_DIR}/ucd_enums.h"
            "${CMAKE_CURRENT_SOURCE_DIR}/ucd_fmt.h"
            "${CMAKE_CURRENT_SOURCE_DIR}/ucd_ostream.h"
        COMMAND ${Python3_EXECUTABLE} "${CMAKE_CURRENT_SOURCE_DIR}/mktables.py" "${LIBUNICODE_UCD_DIR}"
        DEPENDS mktables.py
        WORKING_DIRECTORY "${CMAKE_BINARY_DIR}"
        COMMENT "Generating UCD API and tables from ${LIBUNICODE_UCD_DIR}"
        VERBATIM
        USES_TERMINAL
    )
endif()

set(LIBUNICODE_LIB_MODE)
if(LIBUNICODE_BUILD_STATIC)
    set(LIBUNICODE_LIB_MODE "STATIC")
else()
    set(LIBUNICODE_LIB_MODE "SHARED")
endif()
message(STATUS "libunicode library build mode: ${LIBUNICODE_LIB_MODE}")

add_library(unicode_ucd ${LIBUNICODE_LIB_MODE}
    ucd.cpp
    ucd.h
    ucd_enums.h
    ucd_fmt.h
    ucd_ostream.h
)
add_library(unicode::ucd ALIAS unicode_ucd)
set_target_properties(unicode_ucd PROPERTIES
    VERSION "${PROJECT_VERSION}"
    SOVERSION "${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}"
)
target_include_directories(unicode_ucd PUBLIC $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/..>
                                              $<INSTALL_INTERFACE:include>)

# =========================================================================================================

add_custom_command(
    OUTPUT
        "${CMAKE_CURRENT_SOURCE_DIR}/codepoint_properties_data.cpp"
        "${CMAKE_CURRENT_SOURCE_DIR}/codepoint_properties_data.h"
        "${CMAKE_CURRENT_SOURCE_DIR}/codepoint_properties_names.cpp"
    COMMAND unicode_tablegen
        "${LIBUNICODE_UCD_DIR}"
        "${CMAKE_CURRENT_SOURCE_DIR}/codepoint_properties_data.h"
        "${CMAKE_CURRENT_SOURCE_DIR}/codepoint_properties_data.cpp"
        "${CMAKE_CURRENT_SOURCE_DIR}/codepoint_properties_names.cpp"
        "unicode::precompiled"
    DEPENDS unicode_tablegen unicode::ucd
    WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}"
    COMMENT "Generating UCD codepoint properties tables from ${LIBUNICODE_UCD_DIR}"
    VERBATIM
    USES_TERMINAL
)

add_library(unicode_loader ${LIBUNICODE_LIB_MODE} codepoint_properties_loader.h codepoint_properties_loader.cpp)
add_library(unicode::loader ALIAS unicode_loader)
if(LIBUNICODE_TABLEGEN_FASTBUILD)
    target_compile_definitions(unicode_loader PRIVATE LIBUNICODE_TABLEGEN_FASTBUILD)
endif()
set_target_properties(unicode_loader PROPERTIES
    VERSION "${PROJECT_VERSION}"
    SOVERSION "${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}"
)
target_include_directories(unicode_loader PUBLIC $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/..>
                                                 $<INSTALL_INTERFACE:include>)
target_link_libraries(unicode_loader PUBLIC  unicode::ucd)

# =========================================================================================================

add_library(unicode ${LIBUNICODE_LIB_MODE}
    capi.cpp
    codepoint_properties.cpp
    emoji_segmenter.cpp
    grapheme_segmenter.cpp
    scan.cpp
    script_segmenter.cpp
    utf8.cpp
    width.cpp

    # auto-generated by unicode_tablegen
    codepoint_properties_data.h
    codepoint_properties_data.cpp
    codepoint_properties_names.cpp
)

if(LIBUNICODE_SIMD_IMPLEMENTATION STREQUAL "std")
    target_compile_definitions(unicode PRIVATE LIBUNICODE_USE_STD_SIMD)
elseif(LIBUNICODE_SIMD_IMPLEMENTATION STREQUAL "intrinsics")
    target_compile_definitions(unicode PRIVATE USE_INTRINSICS)
endif()

set(public_headers
    capi.h
    codepoint_properties.h
    convert.h
    emoji_segmenter.h
    grapheme_segmenter.h
    intrinsics.h
    multistage_table_view.h
    run_segmenter.h
    scan.h
    script_segmenter.h
    support.h
    utf8.h
    utf8_grapheme_segmenter.h
    width.h
    word_segmenter.h
)

set(private_headers
    multistage_table_generator.h
    scoped_timer.h
)

set_target_properties(unicode PROPERTIES PUBLIC_HEADER "${public_headers}")
set_target_properties(unicode PROPERTIES PRIVATE_HEADER "${private_headers}")
set_target_properties(unicode PROPERTIES
    VERSION "${PROJECT_VERSION}"
    SOVERSION "${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}"
)

add_library(unicode::unicode ALIAS unicode)
add_library(unicode::core ALIAS unicode)
target_include_directories(unicode PUBLIC $<BUILD_INTERFACE:${${PROJECT_NAME}_SOURCE_DIR}/src>
                                          $<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>
)
target_link_libraries(unicode PUBLIC unicode::ucd)

add_executable(unicode_tablegen tablegen.cpp)
set_target_properties(unicode_tablegen PROPERTIES CMAKE_BUILD_TYPE Release)
target_link_libraries(unicode_tablegen PRIVATE unicode::loader)


# {{{ installation
set(LIBUNICODE_CMAKE_DIR "${CMAKE_INSTALL_LIBDIR}/cmake/libunicode" CACHE PATH "Installation directory for cmake files, a relative path that will be joined with ${CMAKE_INSTALL_PREFIX} or an absolute path.")
set(LIBUNICODE_INSTALL_CMAKE_FILES ${MASTER_PROJECT} CACHE BOOL "Decides whether or not to install CMake config and -version files.")

# Create and install package configuration and version files.
# Install library and headers.
install(TARGETS unicode_ucd unicode_loader unicode
        EXPORT libunicode-targets
        LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
        ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
        PUBLIC_HEADER DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}/libunicode"
        PRIVATE_HEADER DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}/libunicode"
        FRAMEWORK DESTINATION "."
        RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR})

install(
    FILES
        ucd.h
        ucd_enums.h
        ucd_fmt.h
        ucd_ostream.h
    DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}/libunicode"
)
# }}}

# {{{ Generate the version, config and target files
if(LIBUNICODE_INSTALL_CMAKE_FILES)
    # Install version, config and target files.
    include(CMakePackageConfigHelpers)

    write_basic_package_version_file(${CMAKE_CURRENT_BINARY_DIR}/libunicode-config-version.cmake
        VERSION ${PROJECT_VERSION}
        COMPATIBILITY SameMajorVersion
    )

    configure_package_config_file(libunicode-config.cmake.in
        ${CMAKE_CURRENT_BINARY_DIR}/libunicode-config.cmake
        INSTALL_DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/libunicode
    )

    install(FILES ${CMAKE_CURRENT_BINARY_DIR}/libunicode-config.cmake
                  ${CMAKE_CURRENT_BINARY_DIR}/libunicode-config-version.cmake
            DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/libunicode
    )

    install(EXPORT libunicode-targets
            DESTINATION ${LIBUNICODE_CMAKE_DIR}
            NAMESPACE unicode::
    )
endif()
# }}}

# {{{ unicode_test
if(LIBUNICODE_TESTING)
    add_executable(unicode_test
        capi_test.cpp
        convert_test.cpp
        emoji_segmenter_test.cpp
        grapheme_segmenter_test.cpp
        run_segmenter_test.cpp
        scan_test.cpp
        script_segmenter_test.cpp
        test_main.cpp
        unicode_test.cpp
        utf8_grapheme_segmenter_test.cpp
        utf8_test.cpp
        width_test.cpp
        word_segmenter_test.cpp
    )

    if(NOT Catch2_FOUND)
        # supress conversion warnings for Catch2
        # https://github.com/catchorg/Catch2/issues/2583
        # https://github.com/SFML/SFML/blob/e45628e2ebc5843baa3739781276fa85a54d4653/test/CMakeLists.txt#L18-L22
        set_target_properties(Catch2 PROPERTIES COMPILE_OPTIONS "" EXPORT_COMPILE_COMMANDS OFF)
        set_target_properties(Catch2WithMain PROPERTIES EXPORT_COMPILE_COMMANDS OFF)
        get_target_property(CATCH2_INCLUDE_DIRS Catch2 INTERFACE_INCLUDE_DIRECTORIES)
        target_include_directories(Catch2 SYSTEM INTERFACE ${CATCH2_INCLUDE_DIRS})
    endif()

    target_link_libraries(unicode_test unicode Catch2::Catch2WithMain)
    add_test(unicode_test unicode_test)
endif()
# }}}



# {{{ unicode_test
if(LIBUNICODE_BENCHMARK)
    if(NOT benchmark_FOUND)
        # supress warnings for benchmark
        get_target_property(BENCHMARK_INCLUDE_DIRS benchmark INTERFACE_INCLUDE_DIRECTORIES)
        set_target_properties(benchmark PROPERTIES COMPILE_OPTIONS "" EXPORT_COMPILE_COMMANDS OFF)
        target_include_directories(benchmark SYSTEM INTERFACE ${BENCHMARK_INCLUDE_DIRS})
    endif()

    add_executable(libunicode_benchmark
        benchmark.cpp
    )
    target_compile_features(libunicode_benchmark PRIVATE cxx_std_20)
    target_link_libraries(libunicode_benchmark PRIVATE benchmark::benchmark unicode)
endif()
# }}}
