
# ==========================================
#   Copyright (c) 2016-2021 dynamic_static
#       Licensed under the MIT license
#     http://opensource.org/licenses/MIT
# ==========================================

include_guard()

include(CheckCxxCompilerFlag)
include(CmakeParseArguments)
include(ExternalProject)
include(FetchContent)

# TODO : Documentation
function(dst_create_file_group files)
    set_property(GLOBAL PROPERTY USE_FOLDERS ON)
    foreach(file ${files})
        get_filename_component(directory "${file}" DIRECTORY)
        string(REPLACE "${PROJECT_SOURCE_DIR}" "" groupName "${directory}")
        string(REPLACE "${CMAKE_SOURCE_DIR}" "" groupName "${groupName}")
        if(MSVC)
            string(REPLACE "/" "\\" groupName "${groupName}")
        endif()
        source_group("${groupName}" FILES "${file}")
    endforeach()
endfunction()

# TODO : Documentation
function(dst_setup_target)
    cmake_parse_arguments(args "" "target;folder" "includeDirectories;includeFiles;sourceFiles;linkLibraries;compileDefinitions" ${ARGN})
    target_include_directories(${args_target} PUBLIC "${args_includeDirectories}")
    target_compile_definitions(${args_target} PUBLIC "${args_compileDefinitions}")
    target_link_libraries(${args_target} PUBLIC "${args_linkLibraries}")
    set_target_properties(${args_target} PROPERTIES LINKER_LANGUAGE CXX)
    target_compile_options(${args_target} PRIVATE $<$<CXX_COMPILER_ID:MSVC>:/W4 /WX> $<$<NOT:$<CXX_COMPILER_ID:MSVC>>:-Wall -Wextra -Wpedantic -Werror>)
    dst_create_file_group("${args_includeFiles}")
    dst_create_file_group("${args_sourceFiles}")
    if(args_folder)
        set_target_properties(${args_target} PROPERTIES FOLDER ${args_folder})
    else()
        set_target_properties(${args_target} PROPERTIES FOLDER "dynamic_static/${args_target}/")
    endif()
endfunction()

# TODO : Documentation
function(dst_add_interface_library)
    cmake_parse_arguments(args "" "target;folder" "includeDirectories;includeFiles;linkLibraries;compileDefinitions" ${ARGN})
    add_library(${args_target} INTERFACE "${args_includeFiles}")
    # TODO : Figure out why are include directories not being setup correctly in
    #   Visual Studio for interface libraries.
    target_include_directories(${args_target} PUBLIC INTERFACE "${args_includeDirectories}")
    target_compile_definitions(${args_target} PUBLIC INTERFACE "${args_compileDefinitions}")
    target_link_libraries(${args_target} PUBLIC INTERFACE "${args_linkLibraries}")
    set_target_properties(${args_target} PROPERTIES LINKER_LANGUAGE CXX)
    dst_create_file_group("${args_includeFiles}")
    if(args_folder)
        set_target_properties(${args_target} PROPERTIES FOLDER ${args_folder})
    else()
        set_target_properties(${args_target} PROPERTIES FOLDER "dynamic_static/${args_target}/")
    endif()
endfunction()

# TODO : Documentation
function(dst_add_shared_library)
    cmake_parse_arguments(args "" "target" "includeFiles;sourceFiles;compileDefinitions" ${ARGN})
    add_library(${args_target} SHARED "${args_includeFiles}" "${args_sourceFiles}")
    dst_setup_target(${ARGN})
endfunction()

# TODO : Documentation
function(dst_add_static_library)
    cmake_parse_arguments(args "" "target" "includeFiles;sourceFiles;compileDefinitions" ${ARGN})
    add_library(${args_target} STATIC "${args_includeFiles}" "${args_sourceFiles}")
    dst_setup_target(${ARGN})
endfunction()

# TODO : Documentation
function(dst_add_executable)
    cmake_parse_arguments(args "" "target" "includeFiles;sourceFiles;compileDefinitions" ${ARGN})
    add_executable(${args_target} "${args_includeFiles}" "${args_sourceFiles}")
    dst_setup_target(${ARGN})
endfunction()

# TODO : Documentation
function(dst_add_code_generator)
    cmake_parse_arguments(args "" "target" "includeFiles;sourceFiles;inputFiles;outputFiles;compileDefinitions" ${ARGN})
    add_executable(${args_target} "${args_includeFiles}" "${args_sourceFiles}")
    dst_setup_target(${ARGN})
    add_custom_command(
        OUTPUT ${args_outputFiles}
        COMMAND "${args_target}" "${args_inputFiles}"
        DEPENDS ${args_target} ${args_inputFiles}
    )
endfunction()

# TODO : Documentation
function(dst_add_target_test)
    cmake_parse_arguments(args "" "target" "includeDirectories;includeFiles;sourceFiles;linkLibraries;compileDefinitions" ${ARGN})
    FetchContent_Declare(
        Catch2
        GIT_REPOSITORY "https://github.com/catchorg/Catch2.git"
        GIT_TAG c4e3767e265808590986d5db6ca1b5532a7f3d13 # 2.13.7
        GIT_PROGRESS TRUE
        FETCHCONTENT_UPDATES_DISCONNECTED
    )
    FetchContent_MakeAvailable(Catch2)
    FetchContent_GetProperties(Catch2 BINARY_DIR catchBinaryDirectory)
    set(catchCpp "${catchBinaryDirectory}/catch.cpp")
    if(NOT EXISTS ${catchCpp})
        file(WRITE "${catchCpp}" "\n#define CATCH_CONFIG_MAIN\n#include \"catch2/catch.hpp\"\n")
    endif()
    dst_add_executable(
        target ${args_target}.test
        folder "dynamic_static/${args_target}/"
        linkLibraries ${args_target} "${args_linkLibraries}" Catch2
        includeDirectories "${args_includeDirectories}"
        includeFiles "${args_includeFiles}"
        sourceFiles "${args_sourceFiles}" "${catchCpp}"
    )
    enable_testing()
    add_test(NAME ${args_target}.test COMMAND ${args_target}.test)
endfunction()
