## ctulu_target_include_directories(target_name [PRIVATE [SYSTEM] pr_includes...]
##     [PUBLIC [SYSTEM] pu_includes...] [INTERFACE [SYSTEM] in_includes...] [EXT_INCLUDES ext_includes...])
# Set includes for the given target
#   {value}  [in] pr_includes:      Private includes. Use system to disable warning for these includes.
#   {value}  [in] pu_includes:      Public includes. Use system to disable warning for these includes.
#   {value}  [in] in_includes:      Interface includes. Use system to disable warning for these includes.
#   {value}  [in] ext_includes:     Externals includes. Shortcut for "PRIVATE_INCLUDES SYSTEM ${ext_includes}"
function(ctulu_target_include_directories target_name)
    set(options)
    set(oneValueArgs)
    set(multiValueArgs PRIVATE PUBLIC EXT_INCLUDES INTERFACE)
    cmake_parse_arguments(ctulu_target_include_directories "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})

    ctulu_target_include_wrapper(${target_name} ${ctulu_target_include_directories_EXT_INCLUDES} SYSTEM)
    ctulu_target_include_wrapper(${target_name} ${ctulu_target_include_directories_PRIVATE} ${ctulu_target_include_directories_UNPARSED_ARGUMENTS} PRIVATE)
    ctulu_target_include_wrapper(${target_name} ${ctulu_target_include_directories_PUBLIC} PUBLIC)
    ctulu_target_include_wrapper(${target_name} ${ctulu_target_include_directories_INTERFACE} INTERFACE)

    get_target_property(target_type ${target_name} TYPE)
    if(NOT "${target_type}" STREQUAL "INTERFACE_LIBRARY")
        ctulu_remove_system_impl(ctulu_target_include_directories_PRIVATE)
        ctulu_remove_system_impl(ctulu_target_include_directories_PUBLIC)
        ctulu_remove_system_impl(ctulu_target_include_directories_EXT_INCLUDES)
        ctulu_create_file_architecture(ignored
                ${ctulu_target_include_directories_EXT_INCLUDES}
                ${ctulu_target_include_directories_PRIVATE}
                ${ctulu_target_include_directories_PUBLIC})

        if (DEFINED ENV{CLION_IDE} OR MSVC OR XCODE)
            message(STATUS "Ctulu -- Adding includes files to sources for IDE")
            foreach (it ${multiValueArgs})
                if (NOT "${it}" STREQUAL "INTERFACE")
                    if (ctulu_target_include_directories_${it})
                        ctulu_list_files(tmp_files ${ctulu_target_include_directories_${it}})
                        target_sources(${target_name} PRIVATE ${tmp_files})
                    endif()
                endif()
            endforeach()
        endif()
	else()
		if(MSVC OR XCODE OR DEFINED ENV{CLION_IDE})
			ctulu_list_files(tmp_files ${ctulu_target_include_directories_INTERFACE})
            add_custom_target("${target_name}.headers" SOURCES ${tmp_files})
        endif()
    endif()
endfunction()

## ctulu_target_language(target_name [C c_version] [CXX cxx_version])
## Set language standard for the given target.
#   {value}  [in] target_name:      Name of the target
#   {value}  [in] c_version:        C Standard to use.
#   {value}  [in] cxx_version:      C++ Standard to use.
function(ctulu_target_language target_name)
    set(options)
    set(oneValueArgs C CXX)
    set(multiValueArgs)
    cmake_parse_arguments(ctulu_target_language "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})

    foreach(it ${oneValueArgs})
        if(ctulu_target_language_${it})
            message(STATUS "Ctulu -- \"${target_name}\" ${it} standard version: ${ctulu_target_language_${it}}")
            set_target_properties(${target_name} PROPERTIES ${it}_STANDARD ${ctulu_target_language_${it}} ${it}_STANDARD_REQUIRED ON
                    ${it}_EXTENSIONS OFF)
        endif()
    endforeach()
endfunction()

## ctulu_target_sources(target_name files... [FILES files...] [DIRS dirs...]
##      [<PRIVATE,PUBLIC,INTERFACE>] [NORECURSE])
# Set sources for the given target
#   {value}  [in] files:            Files of the target. Please note that if your want the folder in VS
#                                   you need to use ${dirs}.
#   {value}  [in] dirs              Add all files in the directory. Use "NORECURSE" if you don't want to include
#                                   sources from the subdirectories.
#   {option} [in] visibility        Set the visibility of the sources. Could be one of <PRIVATE,PUBLIC,INTERFACE>
function(ctulu_target_sources target_name)
    set(options PRIVATE PUBLIC INTERFACE NORECURSE)
    set(oneValueArgs)
    set(multiValueArgs FILES DIRS)
    cmake_parse_arguments(ctulu_target_sources "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})

    set(target_option PRIVATE)
    foreach(it ${options})
		if("${it}" STREQUAL "NORECURSE")
			continue()
		endif()
        if(ctulu_target_sources_${it})
            set(target_option ${it})
        endif ()
    endforeach()

    if(ctulu_target_sources_FILES OR ctulu_target_sources_UNPARSED_ARGUMENTS)
        message(STATUS "Ctulu -- Adding sources from files")
        target_sources(${target_name} ${target_option} ${ctulu_target_sources_FILES} ${ctulu_target_sources_UNPARSED_ARGUMENTS})
    endif()

    if(ctulu_target_sources_DIRS)
        message(STATUS "Ctulu -- Adding sources from directories")
		if(ctulu_target_sources_NORECURSE)
			ctulu_create_file_architecture(sources ${ctulu_target_sources_DIRS} NORECURSE)
		else()
			ctulu_create_file_architecture(sources ${ctulu_target_sources_DIRS})
		endif()
        target_sources(${target_name} ${target_option} ${sources})
    endif()
endfunction()

function(ctulu_directory_is_empty output_bool dir)
    set(tmp_output false)
    get_filename_component(dir_path ${dir} REALPATH)

    if(EXISTS "${dir_path}")
        if(IS_DIRECTORY "${dir_path}")
            file(GLOB files "${dir_path}/*")
            list(LENGTH files len)
            if(len EQUAL 0)
                set(tmp_output true)
            endif()
        else()
            set(tmp_output true)
        endif()
    else()
        set(tmp_output true)
    endif()
    set(${output_bool} ${tmp_output} PARENT_SCOPE)
endfunction()

function(ctulu_configure_folder input_folder output_folder)
    if(NOT EXISTS ${output_folder})
        file(MAKE_DIRECTORY ${output_folder})
    endif()
    file(GLOB_RECURSE files "${input_folder}/*")
    foreach(file ${files})
        file(RELATIVE_PATH relative_file ${input_folder} ${file})
        configure_file(${file} "${output_folder}/${relative_file}" ${ARGN})
    endforeach()
endfunction()

macro(ctulu_define_os_variables)
    set(OS_WINDOWS OFF)
    set(OS_UNIX OFF)
    set(OS_ANDROID OFF)
    set(OS_LINUX OFF)
    set(OS_FREEBSD OFF)
    set(OS_IOS OFF)
    set(OS_MACOSX OFF)
    set(OS_UNKNOW OFF)
    if(${CMAKE_SYSTEM_NAME} STREQUAL "Windows")
        set(OS_WINDOWS ON)
    elseif(${CMAKE_SYSTEM_NAME} STREQUAL "Linux")
        set(OS_UNIX ON)
        if(ANDROID)
            set(OS_ANDROID ON)
        else()
            set(OS_LINUX ON)
        endif()
    elseif(CMAKE_SYSTEM_NAME MATCHES "^k?FreeBSD$")
        set(OS_FREEBSD ON)
    elseif(${CMAKE_SYSTEM_NAME} STREQUAL "Darwin")
        if(IOS)
            set(OS_IOS ON)
        else()
            set(OS_MACOSX ON)
        endif()
    elseif(${CMAKE_SYSTEM_NAME} STREQUAL "Android")
        set(OS_ANDROID ON)
    else()
        set(OS_UNKNOW ON)
    endif()
endmacro()

macro(ctulu_define_arch_variables)
    set(ARCH_32BITS OFF)
    set(ARCH_64BITS OFF)
    set(ARCH_UNKNOW OFF)
    if(${CMAKE_SIZEOF_VOID_P} EQUAL 4)
        set(ARCH_32BITS ON)
    elseif(${CMAKE_SIZEOF_VOID_P} EQUAL 8)
        set(ARCH_64BITS ON)
    else()
        set(ARCH_UNKNOW ON)
    endif()
endmacro()

macro(ctulu_define_compiler_variables)
    set(COMPILER_UNKNOW OFF)
    set(COMPILER_GCC OFF)
    set(COMPILER_CLANG OFF)
    set(COMPILER_MSVC OFF)

    if(CMAKE_COMPILER_IS_GNUCC OR CMAKE_COMPILER_IS_GNUCXX)
        set(COMPILER_GCC ON)
    elseif(CMAKE_CXX_COMPILER MATCHES ".*clang[+][+]" OR CMAKE_CXX_COMPILER_ID STREQUAL "Clang")
        set(COMPILER_CLANG ON)
    elseif(MSVC)
        set(COMPILER_MSVC ON)
    else()
        set(COMPILER_UNKNOW ON)
    endif()
endmacro()