##+
## dep-link.cmake: Create the dependency interface libraries
##-
             
add_library(simh_regexp INTERFACE)
add_library(simh_video INTERFACE)
add_library(simh_network INTERFACE)
        
## LIBPCAP is a special case
set(LIBPCAP_PROJECT "libpcap")
set(LIBPCAP_ARCHIVE_NAME "libpcap")
set(LIBPCAP_RELEASE "1.10.1")
set(LIBPCAP_ARCHIVE_TYPE "tar.gz")
set(LIBPCAP_TAR_ARCHIVE "${LIBPCAP_ARCHIVE_NAME}-${LIBPCAP_RELEASE}.${LIBPCAP_ARCHIVE_TYPE}")
set(LIBPCAP_SOURCE_URL  "https://github.com/the-tcpdump-group/libpcap/archive/refs/tags/${LIBPCAP_TAR_ARCHIVE}")
                                                             
function(fix_interface_libs _targ)
get_target_property(_aliased ${_targ} ALIASED_TARGET)
    if(NOT _aliased)
        set(fixed_libs)
        get_property(orig_libs TARGET ${_targ} PROPERTY INTERFACE_LINK_LIBRARIES)
        foreach(each_lib IN LISTS ${_lib})
            get_filename_component(stripped_lib "${each_lib}" DIRECTORY)
            if (stripped_lib)
                string(STRIP ${each_lib} stripped_lib)
                file(TO_CMAKE_PATH "${stripped_lib}" stripped_lib)
                if (CMAKE_VERSION VERSION_GREATER_EQUAL "3.19")
                  file(REAL_PATH "${stripped_lib}" stripped_lib)
                endif ()
            endif ()
            list(APPEND fixed_libs ${stripped_lib})
            message("** \"${each_lib}\" -> \"${stripped_lib}\"")
        endforeach ()
        set_property(TARGET ${_targ} PROPERTY INTERFACE_LINK_LIBRARIES ${fixed_libs})
    endif ()
endfunction ()

## Ubuntu 16.04 -- when we find the SDL2 library, there are trailing spaces. Strip
## spaces from SDL2_LIBRARIES (and potentially others as we find them).
function (fix_libraries _lib)
    set(fixed_libs)
    foreach(each_lib IN LISTS ${_lib})
        get_filename_component(stripped_lib "${each_lib}" DIRECTORY)
        if (stripped_lib)
            string(STRIP ${stripped_lib} stripped_lib)
            file(TO_CMAKE_PATH "${stripped_lib}" stripped_lib)
            if (CMAKE_VERSION VERSION_GREATER_EQUAL "3.19")
              file(REAL_PATH "${stripped_lib}" stripped_lib)
            endif ()
        endif ()
        list(APPEND fixed_libs ${stripped_lib})
    endforeach ()
    set(${_lib} ${fixed_libs} PARENT_SCOPE)
endfunction ()

set(BUILD_WITH_VIDEO FALSE)
IF (WITH_VIDEO)
    ## +10 chaotic neutral hack: The SDL2_ttf CMake configuration include "-lfreetype" and
    ## "-lharfbuzz", but, if you're on MacOS, you need to tell the linker where these libraries
    ## are located...
    set(ldirs)
    foreach (lname ${FREETYPE_LIBRARIES} ${FREETYPE_LIBRARY} ${HARFBUZZ_LIBRARIES} ${HARFBUZZ_LIBRARY})
        get_filename_component(dirname "${lname}" DIRECTORY)
        if (dirname)
            string(STRIP ${dirname} dirname)
            file(TO_CMAKE_PATH "${dirname}" dirname)
            if (CMAKE_VERSION VERSION_GREATER_EQUAL "3.19")
              file(REAL_PATH "${dirname}" dirname)
            endif ()
            list(APPEND ldirs ${dirname})
        endif()
    endforeach ()
    get_property(ilink_dirs TARGET simh_video PROPERTY INTERFACE_LINK_DIRECTORIES)
    list(APPEND ilink_dirs ${ldirs})
    set_property(TARGET simh_video PROPERTY INTERFACE_LINK_DIRECTORIES ${ilink_dirs})
    unset(ilink_dirs)
    unset(ldirs)

    IF (SDL2_ttf_FOUND)
        IF (WIN32 AND TARGET SDL2_ttf::SDL2_ttf-static)
            target_link_libraries(simh_video INTERFACE SDL2_ttf::SDL2_ttf-static)
            list(APPEND VIDEO_PKG_STATUS "SDL2_ttf static")
        ELSEIF (TARGET SDL2_ttf::SDL2_ttf)
            target_link_libraries(simh_video INTERFACE SDL2_ttf::SDL2_ttf)
            list(APPEND VIDEO_PKG_STATUS "SDL2_ttf dynamic")
        ELSEIF (TARGET PkgConfig::SDL2_ttf)
            target_link_libraries(simh_video INTERFACE PkgConfig::SDL2_ttf)
            list(APPEND VIDEO_PKG_STATUS "pkg-config SDL2_ttf")
        ELSEIF (DEFINED SDL_ttf_LIBRARIES AND DEFINED SDL_ttf_INCLUDE_DIRS)
            target_link_libraries(simh_video INTERFACE ${SDL_ttf_LIBRARIES})
            target_include_directories(simh_video INTERFACE ${SDL_ttf_INCLUDE_DIRS})
            list(APPEND VIDEO_PKG_STATUS "detected SDL2_ttf")
        ELSE ()
            message(FATAL_ERROR "SDL2_ttf_FOUND set but no SDL2_ttf::SDL2_ttf import library or SDL_ttf_LIBRARIES/SDL_ttf_INCLUDE_DIRS? ")
        ENDIF ()
    ENDIF (SDL2_ttf_FOUND)

    IF (SDL2_FOUND)
        target_compile_definitions(simh_video INTERFACE USE_SIM_VIDEO HAVE_LIBSDL)
        ##
        ## Hopefully this hack can go away. Had to move the target_compile_definitions
        ## over to add_simulator.cmake to accomodate the BESM6 SDL irregularity.
        ##
        ## (keep)  if (CMAKE_HOST_APPLE)
        ## (keep)      ## NOTE: This shouldn't be just an Apple platform quirk; SDL_main should
        ## (keep)      ## be used by all platforms. <sigh!>
        ## (keep)      target_compile_definitions(simh_video INTERFACE SDL_MAIN_AVAILABLE)
        ## (keep)  endif ()

        ## Link to SDL2main if defined for this platform.
        target_link_libraries(simh_video INTERFACE $<TARGET_NAME_IF_EXISTS:SDL2::SDL2main>)

        IF (WIN32 AND TARGET SDL2::SDL2-static AND TARGET SDL2_ttf::SDL2_ttf-static)
            ## Prefer the static version on Windows, but only if SDL2_ttf is also static.
            target_link_libraries(simh_video INTERFACE SDL2::SDL2-static)
            list(APPEND VIDEO_PKG_STATUS "SDL2 static")
        ELSEIF (TARGET SDL2::SDL2)
            fix_interface_libs(SDL2::SDL2)
            target_link_libraries(simh_video INTERFACE SDL2::SDL2)
            list(APPEND VIDEO_PKG_STATUS "SDL2 dynamic")
        ELSEIF (TARGET PkgConfig::SDL2)
            fix_interface_libs(PkgConfig::SDL2)
            target_link_libraries(simh_video INTERFACE PkgConfig::SDL2)
            list(APPEND VIDEO_PKG_STATUS "pkg-config SDL2")
        ELSEIF (DEFINED SDL2_LIBRARIES AND DEFINED SDL2_INCLUDE_DIRS)
            fix_libraries(SDL2_LIBRARIES)
            target_link_libraries(simh_video INTERFACE ${SDL2_LIBRARIES})
            target_include_directories(simh_video INTERFACE ${SDL2_INCLUDE_DIRS})
            list(APPEND VIDEO_PKG_STATUS "detected SDL2")
        ELSE ()
            message(FATAL_ERROR "SDL2_FOUND set but no SDL2::SDL2 import library or SDL2_LIBRARIES/SDL2_INCLUDE_DIRS?")
        ENDIF ()
    ENDIF (SDL2_FOUND)

    IF (NOT USING_VCPKG AND FREETYPE_FOUND)
        if (TARGET Freetype::Freetype)
            target_link_libraries(simh_video INTERFACE freetype)
            list(APPEND VIDEO_PKG_STATUS "Freetype::Freetype")
        ELSEIF (TARGET PkgConfig::Freetype)
            target_link_libraries(simh_video INTERFACE PkgConfig::Freetype)
            list(APPEND VIDEO_PKG_STATUS "pkg-config Freetype")
        ELSE ()
            target_link_libraries(simh_video INTERFACE ${FREETYPE_LIBRARIES})
            target_include_directories(simh_video INTERFACE ${FREETYPE_INCLUDE_DIRS})
            list(APPEND VIDEO_PKG_STATUS "detected Freetype")
        ENDIF ()
    ENDIF ()

    IF (PNG_FOUND)
        target_compile_definitions(simh_video INTERFACE HAVE_LIBPNG)

        if (TARGET PNG::PNG)
            target_link_libraries(simh_video INTERFACE PNG::PNG)
            list(APPEND VIDEO_PKG_STATUS "interface PNG")
        elseif (TARGET PkgConfig::PNG)
            target_link_libraries(simh_video INTERFACE PkgConfig::PNG)
            list(APPEND VIDEO_PKG_STATUS "pkg-config PNG")
        else ()
            target_include_directories(simh_video INTERFACE ${PNG_INCLUDE_DIRS})
            target_link_libraries(simh_video INTERFACE ${PNG_LIBRARIES})
            list(APPEND VIDEO_PKG_STATUS "detected PNG")
        endif ()
    ENDIF (PNG_FOUND)

    set(BUILD_WITH_VIDEO TRUE)
ELSE ()
    set(VIDEO_PKG_STATUS "video support disabled")
ENDIF()

if (WITH_REGEX)
    ## TEMP: Use PCRE until patches for PCRE2 are avaiable.
    ##
    ## 1. Prefer PCRE2 over PCRE (unless PREFER_PCRE is set)
    ## 2. Prefer interface libraries before using detected find_package
    ##    variables.
    IF (TARGET PkgConfig::PCRE)
        target_link_libraries(simh_regexp INTERFACE PkgConfig::PCRE)
        if (PREFER_PCRE)
            target_compile_definitions(simh_regexp INTERFACE HAVE_PCRE_H)
            set(PCRE_PKG_STATUS "pkg-config pcre")
        else ()
            target_compile_definitions(simh_regexp INTERFACE HAVE_PCRE2_H)
            if (WIN32)
                ## Use static linkage (vice DLL) on Windows:
                target_compile_definitions(simh_regexp INTERFACE PCRE2_STATIC)
            endif ()
            set(PCRE_PKG_STATUS "pkg-config pcre2")
        endif ()
    ELSEIF (TARGET unofficial::pcre::pcre)
        ## vcpkg:
        target_link_libraries(simh_regexp INTERFACE unofficial::pcre::pcre)
        target_compile_definitions(simh_regexp INTERFACE HAVE_PCRE_H)
        target_compile_definitions(simh_regexp INTERFACE PCRE_STATIC)
        set(PCRE_PKG_STATUS "vcpkg pcre")
    ELSEIF (NOT PREFER_PCRE AND PCRE2_FOUND)
        target_compile_definitions(simh_regexp INTERFACE HAVE_PCRE2_H)
        target_include_directories(simh_regexp INTERFACE ${PCRE2_INCLUDE_DIRS})
        if (NOT WIN32)
            target_link_libraries(simh_regexp INTERFACE ${PCRE2_LIBRARY})
        else ()
            ## Use static linkage (vice DLL) on Windows:
            target_compile_definitions(simh_regexp INTERFACE PCRE2_STATIC)
        endif ()

        set(PCRE_PKG_STATUS "detected pcre2")
    ELSEIF (PCRE_FOUND)
        target_compile_definitions(simh_regexp INTERFACE HAVE_PCRE_H)
        target_include_directories(simh_regexp INTERFACE ${PCRE_INCLUDE_DIRS})
        target_link_libraries(simh_regexp INTERFACE ${PCRE_LIBRARY})
        if (WIN32)
            target_compile_definitions(simh_regexp INTERFACE PCRE_STATIC)
        endif ()
        set(PCRE_PKG_STATUS "detected pcre")
    endif ()
endif ()

if ((WITH_REGEX OR WITH_VIDEO) AND ZLIB_FOUND)
    target_compile_definitions(simh_regexp INTERFACE HAVE_ZLIB)
    target_compile_definitions(simh_video INTERFACE HAVE_ZLIB)
    if (TARGET ZLIB::ZLIB)
        target_link_libraries(simh_regexp INTERFACE ZLIB::ZLIB)
        target_link_libraries(simh_video INTERFACE ZLIB::ZLIB)
        set(ZLIB_PKG_STATUS "interface ZLIB")
    elseif (TARGET PkgConfig::ZLIB)
        target_link_libraries(simh_regexp INTERFACE PkgConfig::ZLIB)
        target_link_libraries(simh_video INTERFACE PkgConfig::ZLIB)
        set(ZLIB_PKG_STATUS "pkg-config ZLIB")
    else ()
        target_include_directories(simh_regexp INTERFACE ${ZLIB_INCLUDE_DIRS})
        target_link_libraries(simh_regexp INTERFACE ${ZLIB_LIBRARIES})
        target_include_directories(simh_video INTERFACE ${ZLIB_INCLUDE_DIRS})
        target_link_libraries(simh_video INTERFACE ${ZLIB_LIBRARIES})
        set(ZLIB_PKG_STATUS "detected ZLIB")
    endif ()
endif ()


if (WITH_NETWORK)
    set(network_runtime USE_SHARED)
    ## pcap is special: Headers only and dynamically loaded.
    if (WITH_PCAP)
        find_package(PCAP)

        if (NOT PCAP_FOUND)
            list(APPEND NETWORK_PKG_STATUS "PCAP dynamic (unpacked)")

            message(STATUS "Downloading ${LIBPCAP_SOURCE_URL}")
            message(STATUS "Destination ${CMAKE_BINARY_DIR}/libpcap")
            execute_process(
                COMMAND ${CMAKE_COMMAND} -E make_directory "${CMAKE_BINARY_DIR}/libpcap"
                RESULT_VARIABLE LIBPCAP_MKDIR
            )
            if (NOT (${LIBPCAP_MKDIR} EQUAL 0))
                message(FATAL_ERROR "Could not create ${CMAKE_CMAKE_BINARY_DIR}/libpcap")
            endif (NOT (${LIBPCAP_MKDIR} EQUAL 0))

            file(DOWNLOAD "${LIBPCAP_SOURCE_URL}" "${CMAKE_BINARY_DIR}/libpcap/libpcap.${LIBPCAP_ARCHIVE_TYPE}"
                    STATUS LIBPCAP_DOWNLOAD
                )
            list(GET LIBPCAP_DOWNLOAD 0 LIBPCAP_DL_STATUS)
            if (NOT (${LIBPCAP_DL_STATUS} EQUAL 0))
                list(GET LIBPCAP_DOWNLOAD 1 LIBPCAP_DL_ERROR)
                message(FATAL_ERROR "Download failed: ${LIBPCAP_DL_ERROR}")
            endif (NOT (${LIBPCAP_DL_STATUS} EQUAL 0))

            message(STATUS "Extracting headers ${LIBPCAP_SOURCE_URL}")
            execute_process(
                COMMAND ${CMAKE_COMMAND} -E tar xvf "${CMAKE_BINARY_DIR}/libpcap/libpcap.${LIBPCAP_ARCHIVE_TYPE}"
                    "${LIBPCAP_PROJECT}-${LIBPCAP_ARCHIVE_NAME}-${LIBPCAP_RELEASE}/pcap.h"
                    "${LIBPCAP_PROJECT}-${LIBPCAP_ARCHIVE_NAME}-${LIBPCAP_RELEASE}/pcap/*.h"
                WORKING_DIRECTORY "${CMAKE_BINARY_DIR}/libpcap"
                RESULT_VARIABLE LIBPCAP_EXTRACT
            )
            if (NOT (${LIBPCAP_EXTRACT} EQUAL 0))
                message(FATAL_ERROR "Extract failed.")
            endif (NOT (${LIBPCAP_EXTRACT} EQUAL 0))

            message(STATUS "Copying headers from ${CMAKE_BINARY_DIR}/libpcap/${LIBPCAP_PROJECT}-${LIBPCAP_ARCHIVE_NAME}-${LIBPCAP_RELEASE}/pcap")
            message(STATUS "Destination ${CMAKE_BINARY_DIR}/include/pcap")
            execute_process(
                COMMAND "${CMAKE_COMMAND}" -E copy_directory
                    "${LIBPCAP_PROJECT}-${LIBPCAP_ARCHIVE_NAME}-${LIBPCAP_RELEASE}/"
                    "${CMAKE_BINARY_DIR}/include/"
                WORKING_DIRECTORY "${CMAKE_BINARY_DIR}/libpcap"
                RESULT_VARIABLE LIBPCAP_COPYDIR
            )
            if (NOT (${LIBPCAP_COPYDIR} EQUAL 0))
                message(FATAL_ERROR "Copy failed.")
            endif (NOT (${LIBPCAP_COPYDIR} EQUAL 0))

            ## And try finding it again...
            find_package(PCAP)
        else ()
            list (APPEND NETWORK_PKG_STATUS "PCAP dynamic")
        endif ()


        if (PCAP_FOUND)
            set(network_runtime USE_SHARED)
            foreach(hdr "${PCAP_INCLUDE_DIRS}")
              file(STRINGS ${hdr}/pcap/pcap.h hdrcontent REGEX "pcap_compile *\\(.*const")
              # message("hdrcontent: ${hdrcontent}")
              list(LENGTH hdrcontent have_bpf_const)
              if (${have_bpf_const} GREATER 0)
                message(STATUS "pcap_compile requires BPF_CONST_STRING")
                list(APPEND network_runtime BPF_CONST_STRING)
              endif()
            endforeach()

            target_include_directories(simh_network INTERFACE "${PCAP_INCLUDE_DIRS}")
            target_compile_definitions(simh_network INTERFACE HAVE_PCAP_NETWORK)
        endif ()
    endif ()

    ## TAP/TUN devices
    if (WITH_TAP)
        target_compile_definitions(simh_network INTERFACE ${NETWORK_TUN_DEFS})
    endif (WITH_TAP)

    if (WITH_VDE AND VDE_FOUND)
        if (TARGET PkgConfig::VDE)
            target_compile_definitions(simh_network INTERFACE $<TARGET_PROPERTY:PkgConfig::VDE,INTERFACE_COMPILE_DEFINITIONS>)
            target_include_directories(simh_network INTERFACE $<TARGET_PROPERTY:PkgConfig::VDE,INTERFACE_INCLUDE_DIRECTORIES>)
            target_link_libraries(simh_network INTERFACE PkgConfig::VDE)
            list(APPEND NETWORK_PKG_STATUS "pkg-config VDE")
        else ()
            target_include_directories(simh_network INTERFACE "${VDEPLUG_INCLUDE_DIRS}")
            target_link_libraries(simh_network INTERFACE "${VDEPLUG_LIBRARY}")
            list(APPEND NETWORK_PKG_STATUS "detected VDE")
        endif ()

        target_compile_definitions(simh_network INTERFACE HAVE_VDE_NETWORK)
    endif ()

    if (WITH_TAP)
        if (HAVE_TAP_NETWORK)
            target_compile_definitions(simh_network INTERFACE HAVE_TAP_NETWORK)

            if (HAVE_BSDTUNTAP)
                target_compile_definitions(simh_network INTERFACE HAVE_BSDTUNTAP)
                list(APPEND NETWORK_PKG_STATUS "BSD TUN/TAP")
            else (HAVE_BSDTUNTAP)
                list(APPEND NETWORK_PKG_STATUS "TAP")
            endif (HAVE_BSDTUNTAP)
   
        endif (HAVE_TAP_NETWORK)
    endif (WITH_TAP)

    if (WITH_SLIRP)
        target_link_libraries(simh_network INTERFACE slirp)
        list(APPEND NETWORK_PKG_STATUS "NAT(SLiRP)")
    endif (WITH_SLIRP)

    ## Finally, set the network runtime
    if (NOT network_runtime)
        ## Default to USE_SHARED... USE_NETWORK is deprecated.
        set(network_runtime USE_SHARED)
    endif (NOT network_runtime)

    target_compile_definitions(simh_network INTERFACE ${network_runtime})

    set(BUILD_WITH_NETWORK TRUE)
else (WITH_NETWORK)
    set(NETWORK_STATUS "networking disabled")
    set(NETWORK_PKG_STATUS "network disabled")
    set(BUILD_WITH_NETWORK FALSE)
endif (WITH_NETWORK)
