option(WITH_DOC_MAN "Build manpage documentation with Doxygen" OFF)
option(WITH_DOC_HTML "Build HTML documentation with Doxygen" OFF)

find_package(Doxygen 1.9.4 QUIET)
if(NOT DOXYGEN_FOUND)
    if(WITH_DOC_MAN OR WITH_DOC_HTML)
        message(FATAL_ERROR "Documentation generation requires Doxygen 1.9.4 or newer")
    endif()
    return()
endif()

set(DOC_NAMES ss-local ss-server ss-tunnel ss-redir ss-manager ss-nat shadowsocks-c)
set(DOC_INPUTS)
foreach(name IN LISTS DOC_NAMES)
    list(APPEND DOC_INPUTS "${CMAKE_CURRENT_SOURCE_DIR}/${name}.md")
endforeach()
set(DOC_SOURCES)
foreach(name local.cpp server.cpp tunnel.cpp redir.cpp manager.cpp utils.cpp crypto/aead.cpp)
    list(APPEND DOC_SOURCES "${PROJECT_SOURCE_DIR}/src/${name}")
endforeach()
list(APPEND DOC_SOURCES "${PROJECT_SOURCE_DIR}/src/ss-nat")

# Doxygen reads native documentation snippets directly from source. No target
# binary or Python/AsciiDoc conversion step is needed, including in cross builds.
foreach(format html man1 man8)
    set(DOXYGEN_HTML NO)
    set(DOXYGEN_MAN NO)
    set(DOXYGEN_MAN_EXTENSION .1)
    set(format_inputs ${DOC_INPUTS})
    set(outputs)
    if(format STREQUAL "html")
        set(DOXYGEN_HTML YES)
        list(APPEND format_inputs "${CMAKE_CURRENT_SOURCE_DIR}/index.md")
        list(APPEND outputs "${PROJECT_BINARY_DIR}/html/index.html")
        foreach(name IN LISTS DOC_NAMES)
            list(APPEND outputs "${PROJECT_BINARY_DIR}/html/${name}.html")
        endforeach()
    elseif(format STREQUAL "man1")
        set(DOXYGEN_MAN YES)
        list(REMOVE_ITEM format_inputs "${CMAKE_CURRENT_SOURCE_DIR}/shadowsocks-c.md")
        foreach(name ss-local ss-server ss-tunnel ss-redir ss-manager ss-nat)
            list(APPEND outputs "${PROJECT_BINARY_DIR}/man/${name}.1")
        endforeach()
    else()
        set(DOXYGEN_MAN YES)
        set(DOXYGEN_MAN_EXTENSION .8)
        set(format_inputs "${CMAKE_CURRENT_SOURCE_DIR}/shadowsocks-c.md")
        list(APPEND outputs "${PROJECT_BINARY_DIR}/man/shadowsocks-c.8")
    endif()
    set(DOXYGEN_INPUT)
    foreach(path IN LISTS format_inputs)
        string(APPEND DOXYGEN_INPUT " \"${path}\"")
    endforeach()
    set(config "${CMAKE_CURRENT_BINARY_DIR}/Doxyfile-${format}")
    configure_file(Doxyfile.in "${config}" @ONLY)
    set(stamp "${CMAKE_CURRENT_BINARY_DIR}/${format}.stamp")
    add_custom_command(OUTPUT "${stamp}" ${outputs}
        COMMAND "${DOXYGEN_EXECUTABLE}" "${config}"
        COMMAND ${CMAKE_COMMAND} -E touch "${stamp}"
        DEPENDS "${config}" ${format_inputs} ${DOC_SOURCES}
        WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}"
        COMMENT "Generating ${format} documentation with Doxygen"
        VERBATIM)
    set(DOC_${format}_OUTPUTS "${stamp}" ${outputs})
endforeach()

add_custom_target(doc-man ALL DEPENDS ${DOC_man1_OUTPUTS} ${DOC_man8_OUTPUTS})
add_custom_target(doc-html ALL DEPENDS ${DOC_html_OUTPUTS})
if(NOT WITH_DOC_MAN)
    set_target_properties(doc-man PROPERTIES EXCLUDE_FROM_ALL TRUE)
else()
    foreach(name ss-local ss-server ss-tunnel ss-redir ss-manager ss-nat)
        install(FILES "${PROJECT_BINARY_DIR}/man/${name}.1" DESTINATION share/man/man1)
    endforeach()
    install(FILES "${PROJECT_BINARY_DIR}/man/shadowsocks-c.8"
        "${PROJECT_BINARY_DIR}/man/shadowsocks-libev.8" DESTINATION share/man/man8)
endif()
if(NOT WITH_DOC_HTML)
    set_target_properties(doc-html PROPERTIES EXCLUDE_FROM_ALL TRUE)
else()
    install(DIRECTORY "${PROJECT_BINARY_DIR}/html/" DESTINATION share/doc/${PROJECT_NAME})
endif()

file(MAKE_DIRECTORY "${PROJECT_BINARY_DIR}/man")
file(WRITE "${PROJECT_BINARY_DIR}/man/shadowsocks-libev.8" ".so man8/shadowsocks-c.8\n")
