# Copyright (c) 2018 NoobsHPC Authors, Inc. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

# ----------------------------------------------------------------------------
# section: help to search src and include files
# ----------------------------------------------------------------------------
# fetch files(.cc .cpp .cu .c or .h .hpp etc.) in dir(search_dir) 
# and save to parent scope var outputs

function(noobshpc_fetch_files_with_suffix search_dir suffix outputs)
    exec_program(ls ${search_dir}
                 ARGS "*.${suffix}"
                 OUTPUT_VARIABLE OUTPUT
                 RETURN_VALUE VALUE)
    if(NOT VALUE)
        # message(STATUS "NOT VALUE")
        string(REPLACE "\n" ";" OUTPUT_LIST "${OUTPUT}")
        set(abs_dir "")
        foreach(var ${OUTPUT_LIST})
            set(abs_dir ${abs_dir} ${search_dir}/${var})
            message(STATUS "fetch_result: ${abs_dir}")
        endforeach()
        set(${outputs} ${${outputs}} ${abs_dir} PARENT_SCOPE)
    endif()
endfunction()

# recursively fetch files
function(noobshpc_fetch_files_with_suffix_recursively search_dir suffix outputs)
    file(GLOB_RECURSE ${outputs} ${search_dir} "*.${suffix}")    
    set(${outputs} ${${outputs}} PARENT_SCOPE)
endfunction()

# recursively fetch include dir 
function(noobshpc_fetch_include_recursively root_dir)
    if (IS_DIRECTORY ${root_dir})
        include_directories(${root_dir})
        # message(STATUS "include dir: " ${Magenta}${root_dir}${ColourReset})
    endif()

    file(GLOB ALL_SUB RELATIVE ${root_dir} ${root_dir}/*)
    foreach(sub ${ALL_SUB})
        if (IS_DIRECTORY ${root_dir}/${sub})                    
            noobshpc_fetch_include_recursively(${root_dir}/${sub})
        endif()
    endforeach()
endfunction()

# judge fetch files
function(noobshpc_judge_avx outputs)
    exec_program(cat /proc/cpuinfo|greps flag|uniq
            OUTPUT_VARIABLE OUTPUT
            RETURN_VALUE VALUE)
    message("it is noobshpc_judge_avx " OUTPUT)
    set(${outputs} ${${outputs}} PARENT_SCOPE)
endfunction()

# ----------------------------------------------------------------------------
# section: help to detect the compiler options
# ----------------------------------------------------------------------------
# check and add  compiler options
macro(noobshpc_check_compiler_flag LANG FLAG RESULT)
    if(NOT DEFINED ${RESULT})
        if("_${LANG}_" MATCHES "_CXX_")
            set(_fname "${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeTmp/src.cxx")
        if("${CMAKE_CXX_FLAGS} ${FLAG} " MATCHES "-Werror " OR "${CMAKE_CXX_FLAGS} ${FLAG} " MATCHES "-Werror=unknown-pragmas ")
            FILE(WRITE "${_fname}" "int main() { return 0; }\n")
        else()
            FILE(WRITE "${_fname}" "#pragma\n int main() { return 0; }\n")
        endif()
    endif()

    if(_fname AND _fname MATCHES "src.cxx")
        MESSAGE(STATUS "Testing ${RESULT}")
        TRY_COMPILE(${RESULT}
                    "${CMAKE_BINARY_DIR}"
                    "${_fname}"
                    COMPILE_DEFINITIONS "${FLAG}" # check the compile option
                    OUTPUT_VARIABLE OUTPUT)

        # result true or false
        if(${RESULT})
            SET(${RESULT} 1 CACHE INTERNAL "Test ${RESULT}")
            MESSAGE(STATUS "Testing ${RESULT} - ${Green}Success${ColourReset}")
        else()
            MESSAGE(STATUS "Testing ${RESULT} - ${Red}Failed${ColourReset}")
            SET(${RESULT} "" CACHE INTERNAL "Test ${RESULT}")
            file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeError.log
                "Compilation failed:\n"
                "    source file: '${_fname}'\n"
                "    check option: '${FLAG}'\n"
                "===== BUILD LOG =====\n"
                "${OUTPUT}\n"
                "===== END =====\n\n")
        endif()
    else()
        set(${RESULT} 0)
        endif()
    endif()
endmacro()

macro(noobshpc_check_flag_support lang flag varname)
    if("_${lang}_" MATCHES "_CXX_")
        set(_lang CXX)
    endif()
    string(TOUPPER "${flag}" ${varname})
    string(REGEX REPLACE "^(/|-)" "HAVE_${_lang}_" ${varname} "${${varname}}")
    string(REGEX REPLACE " --|-|=| |\\." "_" ${varname} "${${varname}}")
    noobshpc_check_compiler_flag("${_lang}" "${ARGN} ${flag}" ${${varname}})
endmacro()

macro(noobshpc_add_compile_option option)
    if(CMAKE_BUILD_TYPE)
        set(CMAKE_TRY_COMPILE_CONFIGURATION ${CMAKE_BUILD_TYPE})
    endif()
    noobshpc_check_flag_support(CXX "${option}" _varname)
    if(${_varname})
        set(NBHPC_EXTRA_CXX_FLAGS "${NBHPC_EXTRA_CXX_FLAGS} ${option}")
    endif()
endmacro()

# ----------------------------------------------------------------------------
# section: Provides an noobshpc config option macro
# usage：  noobshpc_option(var "help string to describe the var" [if or IF (condition)])
# ----------------------------------------------------------------------------
macro(noobshpc_option variable description value)
    set(__value ${value})
    set(__condition "")
    set(__varname "__value")
    foreach(arg ${ARGN})
        if(arg STREQUAL "IF" OR arg STREQUAL "if")
            set(__varname "__condition")
        else()
            list(APPEND ${__varname} ${arg})
        endif()
    endforeach()
    unset(__varname)
    if(__condition STREQUAL "")
        set(__condition 2 GREATER 1)
    endif()

    if(${__condition})
        if(__value MATCHES ";")
            if(${__value})
                option(${variable} "${description}" ON)
            else()
                option(${variable} "${description}" OFF)
            endif()
         elseif(DEFINED ${__value})
            if(${__value})
                option(${variable} "${description}" ON)
            else()
                option(${variable} "${description}" OFF)
            endif()
         else()
            option(${variable} "${description}" ${__value})
        endif()
    else()
        unset(${variable} CACHE)
    endif()
    unset(__condition)
    unset(__value)
 endmacro()

# ----------------------------------------------------------------------------
# section: Provides macro for an noobshpc warning diasable
# ----------------------------------------------------------------------------
macro(noobshpc_disable_warnings)
    set(__flag_vars "")

    foreach(arg ${ARGN})
        if(arg MATCHES "^CMAKE_")
            list(APPEND __flag_vars ${arg})
        endif()
    endforeach()

    if(NOT __flag_vars)
        set(__flag_vars CMAKE_C_FLAGS CMAKE_CXX_FLAGS)
    endif()

    if(CMAKE_COMPILER_IS_GNUCXX OR CMAKE_COMPILER_IS_CLANGXX)
        foreach(var ${__flag_vars})
            string(REPLACE " " ";"  __list_flag  ${${var}})    
            foreach(warning ${__list_flag})
                if(NOT warning MATCHES "^-Wno-")
                    if((warning MATCHES "^-W") AND (NOT warning STREQUAL "-W"))
                        string(REGEX REPLACE "${warning}" "" ${var} "${${var}}")
                    endif()
                    # this may lead to error in project.
                    if(warning STREQUAL "-fpermissive")
                        #string(REGEX REPLACE "${warning}" "" ${var} "${${var}}")
                    endif()
                endif()
            endforeach()
        endforeach()
    endif()
    unset(_flag_vars)
    unset(_gxx_warnings)
endmacro()