#!/bin/bash
apply_debug_settings() {
    # 在子脚本中应用调试设置
    [[ "$BASH_XTRACE" == "1" ]] && set -x
    [[ "$BASH_VERBOSE" == "1" ]] && set -v
    [[ "$BASH_ERREXIT" == "1" ]] && set -e
}
apply_debug_settings
target_file="$(readlink -f "${BASH_SOURCE[0]}")"
target_file_path="$(dirname "${target_file}")"

listp=()
nvccdate="1021"
jsondate="0220"

OS=$(uname -s)
WINDOWS=0
if [[ "$OS" == "MINGW"* ]] || [[ "$OS" == "MSYS"* ]]; then
    WINDOWS=1
    export WINDOWS
fi

# Traverse $@, if it is '-options-file file', read the content of file and remove '-options-file file' from the list.
# replace flag with nvccsign_*
optionsfile=0
compiler_op_flag=0
werro_no_compiler_flag=0
function predeal_args(){
    i="${1}"
    from_file_flag="${2}"
    if [[ "${i}" == "--options-file" ]]; then
        optionsfile=1
        return 0
    fi

    if [[ ${optionsfile} -eq 1 ]]; then
        optionsfile=0
        if [[ -f "${i}" ]]; then
            while read line
            do
                for j in ${line}; do
                    flag="${j// /nvccsign_space}"
                    # Strings that have been processed with -o do not need to be quote replace
                    # flag="${flag//\"/nvccsign_quote}"
                    flag="${flag//$/nvccsign_dollar}"
                    flag="${flag//\(/nvccsign_lparenthesis}"
                    flag="${flag//\)/nvccsign_rparenthesis}"
                    listp+=(${flag})
                done
            done < <(cat "${i}"; echo "")
            return 0
        fi
    fi

    if [[ "${i}" == "--compiler-options" ]] || [[ "${i}" == "-Xcompiler" ]] ; then
        compiler_op_flag=1
        return 0
    fi

    if [[ ${compiler_op_flag} -eq 1 ]]; then
        compiler_op_flag=0
        if [[ "${i}" =~  "-Wno-nonnull-compare" ]]; then
            #if options in -Xcompiler contain -Wno-nonnull-compare, disacard all
            return 0
        else
            listp+=("-Xcompiler")
            flag="${i// /nvccsign_space}"
            flag="${flag//\"/nvccsign_quote}"
            flag="${flag//$/nvccsign_dollar}"
            flag="${flag//\(/nvccsign_lparenthesis}"
            flag="${flag//\)/nvccsign_rparenthesis}"
            from_1="xhost"
            to_1="Xhost"
            from_2="qopemp"
            to_2="fopenmp"
            from_3="-fno-canonical-system-headers"
            to_3=""
            flag="${flag//${from_1}/${to_1}}"
            flag="${flag//${from_2}/${to_2}}"
            flag="${flag//${from_3}/${to_3}}"
            listp+=(${flag})
            return 0
        fi
    elif [[ "${i}" == "--Werror" ]] || [[ "${i}" == "-Werror" ]] ; then
        werro_no_compiler_flag=1
        return 0
    fi

    if [[ ${werro_no_compiler_flag} -eq 1 ]]; then
        werro_no_compiler_flag=0
        #discard --Werror kind,... no in -Xcompiler
        if [[ "${i}" =~ "all-warnings" ]] ; then
            return 0
        fi
        if [[ "${i}" =~ "cross-execution-space-call" ]]; then
            return 0
        fi
        if [[ "${i}" =~ "reorder" ]] ; then
            return 0
        fi
        if [[ "${i}" =~ "default-stream-launch" ]]; then
            return 0
        fi
        if [[ "${i}" =~ "missing-launch-bounds" ]]; then
            return 0
        fi
        if [[ "${i}" =~ "ext-lambda-captures-this" ]]; then
            return 0
        fi
        if [[ "${i}" =~ "deprecated-declarations" ]]; then
            return 0
        fi
        listp+=("--Werror")
        listp+=(${i})
        return 0
    fi

    macro_reg_blank_str="^-D\S+=\"\S+([[:blank:]]+\S+)+[[:blank:]]*\""
    macro_reg_str="^-D\S+=\"\S+\""
    macro_reg="^-D\S+=\S+"
    if [[ "${i}" =~  $macro_reg_blank_str ]]; then
        flag="${i/=/=\"\\}"
        flag="${flag/%\"/\\\"\"}"
        # echo "${i} 3--> ${flag}"
    elif [[ "${i}" =~  $macro_reg_str ]]; then
        flag="${i/=/=\\}"
        flag="${flag/%\"/\\\"}"
        # echo "${i} 2-->${flag}"
    elif [[ "${i}" =~  $macro_reg ]]; then
        if [[ "${i}" == *\"* ]]; then
            # echo "find quote in i"
            flag="${i// /nvccsign_space}"
            flag="${flag//\"/nvccsign_quote}"
            flag="${flag//$/nvccsign_dollar}"
            flag="${flag//\(/nvccsign_lparenthesis}"
            flag="${flag//\)/nvccsign_rparenthesis}"
        else
            flag="${i/=/=\"}"
            flag="${flag}\""
            # echo "${i} 1-->${flag}"
        fi
    else
        flag="${i// /nvccsign_space}"
        if [[ ${from_file_flag}x == "0"x ]]; then
            flag="${flag//\"/nvccsign_quote}"
        fi
        flag="${flag/$/nvccsign_dollar}"
        flag="${flag//\(/nvccsign_lparenthesis}"
        flag="${flag//\)/nvccsign_rparenthesis}"
    fi
    listp+=(${flag})
}

for i in "$@"; do
    if [[ "${i}" == \@* ]]; then
        delete_char="\@"
        add_char="./"
        file="${i/$delete_char/${add_char}}"
        # cat ${file}
        if [[ -f "${file}" ]]; then
            while read line
            do
                for j in ${line}; do
                    predeal_args "${j}" "1"
                done
            done < <(cat "${file}"; echo "")
            continue
        fi
        continue
    fi
    predeal_args "${i}" "0"
done

function debug_echo(){
    if [ "${WCUDA_DEBUG}" == "1" ]; then
        echo "/* $1 */"
    fi
}

# listp contain option from rsp file
found_offload_arch=0
for item in "${listp[@]}"; do
    if [ "$found_offload_arch" = "0" ]; then
        if [[ "$item" == *"offload-arch"* ]]; then
            # debug_echo "found offload-arch from orignial args"
            found_offload_arch=1
        fi
    else
        break
    fi
done


# 获取当前脚本所在目录
SCRIPT_PATH=$(readlink -f "${BASH_SOURCE[0]}")
SCRIPT_DIR="$(cd "$(dirname "${SCRIPT_PATH}")" && pwd)"
# 导入脚本
source "${SCRIPT_DIR}/../tools/multi_target.sh"

#debug_echo "found_offload_arch=${found_offload_arch}"
if [ "$found_offload_arch" = "0" ]; then
    if check_target_set ; then
        :
    else
        multi_target_check_tips
        exit 1
    fi
else
    #debug_echo "get target from build system"
    :
fi

# if param contains -x cu or -x maca, then set xcompilerflag=1
# if param contains -x cxx or -x cc, then set xcompilerflag=2
xcompilerflag=0
for i in "${listp[@]}"; do
    if [[ "${i}" == "-x" ]]; then
        barxflagfound=1
        continue
    fi

    if [[ ${barxflagfound} -eq 1 ]]; then
        if [[ "${i}" == "cu" ]] || [[ "${i}" == "maca" ]]; then
            xcompilerflag=1
        fi

        if [[ "${i}" == "cxx" ]] || [[ "${i}" == "cc" ]]; then
            xcompilerflag=2
        fi
    fi
    barxflagfound=0
done

# if xcompilerflag=0; check if param contains *.cu or *.maca, if yes, set xcompilerflag=1
# if xcompilerflag=0; check if param contains *.cpp or *.c *.cc *.C, if yes, set xcompilerflag=2
if [[ ${xcompilerflag} -eq 0 ]]; then
    for i in "${listp[@]}"; do
        if [[ "${i}" == *.cu ]] || [[ "${i}" == *.maca ]]; then
            xcompilerflag=1
            break
        fi

        if [[ "${i}" == *.cpp ]] || [[ "${i}" == *.c ]] || [[ "${i}" == *.cc ]] || [[ "${i}" == *.C ]]; then
            xcompilerflag=2
            break
        fi
    done
fi

# replace -Werror=implicit-fallthrough=0 to -Werror=-Wno-implicit-fallthrough to avoid warning in listp
# replace -Werror=implicit-fallthrough=1-5 to -Werror=-Wimplicit-fallthrough to avoid warning in listp
newlistp=()
for i in "${listp[@]}"; do
    if [[ "${i}" == "-Werror=implicit-fallthrough=0" ]]; then
        newlistp+=("-Werror=-Wno-implicit-fallthrough")
        continue
    fi
    if [[ "${i}" == "-Werror=implicit-fallthrough=1" ]]; then
        newlistp+=("-Werror=-Wimplicit-fallthrough")
        continue
    fi
    if [[ "${i}" == "-Werror=implicit-fallthrough=2" ]]; then
        newlistp+=("-Werror=-Wimplicit-fallthrough")
        continue
    fi
    if [[ "${i}" == "-Werror=implicit-fallthrough=3" ]]; then
        newlistp+=("-Werror=-Wimplicit-fallthrough")
        continue
    fi
    if [[ "${i}" == "-Werror=implicit-fallthrough=4" ]]; then
        newlistp+=("-Werror=-Wimplicit-fallthrough")
        continue
    fi
    if [[ "${i}" == "-Werror=implicit-fallthrough=5" ]]; then
        newlistp+=("-Werror=-Wimplicit-fallthrough")
        continue
    fi
    newlistp+=("${i}")
done
listp=("${newlistp[@]}")


## When the compiler supports -options-file, the following code is restored
# for i in "$@"; do
#     flag="${i// /nvccsign_space}"
#     flag="${flag//\"/nvccsign_quote}"
#     flag="${flag//$/nvccsign_dollar}"
#     flag="${flag//\(/nvccsign_lparenthesis}"
#     flag="${flag//\)/nvccsign_rparenthesis}"
#     listp+=(${flag})
# done

all_filter=()
all_replacer=()
all_adder=()

compile_filter=()
compile_replacer=()
compile_adder=()

link_filter=()
link_replacer=()
link_adder=()

compile_and_link_filter=()
compile_and_link_replacer=()
compile_and_link_adder=()

# if paras contains *.o file, then set dotofilefound=1
dotofilefound=0
for i in "${listp[@]}"; do
    if [[ "${i}" == *.o ]]; then
        dotofilefound=1
        break
    fi
done

# if paras contains *.o file, then add compile_and_link_adder with -fgpu-rdc and  --maca-link
if [[ ${dotofilefound} -eq 1 ]]; then
    compile_and_link_adder+=("-fgpu-rdc")
    compile_and_link_adder+=("--maca-link")
fi


not_found_dev_match=()
not_found_dev_adder=()

key_match=0
wrapperskipstrings=()
wrapperskipflag=0

[ -z ${CUBRIDGE_HOME+x} ] && CUBRIDGE_HOME=$HOME
[ -n "${WCUDA_HOME}" ] && CUBRIDGE_HOME=${WCUDA_HOME}
[ -z ${CUCC_PATH+x} ] && CUCC_PATH=${MACA_PATH}/tools/cu-bridge/

function output_entry() {

    rflag=${2// /\&}
    if [[ "$1" == "data" ]]; then
        jsondate="$2"
    fi

    if [[ "$1" == skipstring.* ]]; then
        wrapperskipstrings+=("$2")
    fi

    if [[ "$1" == all.filter.* ]]; then
        all_filter+=("$2")
    elif [[ "$1" == all.replacer.* ]]; then
        all_replacer+=("$rflag")
    elif [[ "$1" == all.adder.* ]]; then
        all_adder+=("$2")
    fi

    if [[ "$1" == compile.filter.* ]]; then
        compile_filter+=("$2")
    elif [[ "$1" == compile.replacer.* ]]; then
        compile_replacer+=("$rflag")
    elif [[ "$1" == compile.adder.* ]]; then
        compile_adder+=("$2")
    fi

    if [[ "$1" == link.filter.* ]]; then
        link_filter+=("$2")
    elif [[ "$1" == link.replacer.* ]]; then
        link_replacer+=("$rflag")
    elif [[ "$1" == link.adder.* ]]; then
        link_adder+=("$2")
    fi

    if [[ "$1" == compile_and_link.filter.* ]]; then
        compile_and_link_filter+=("$2")
    elif [[ "$1" == compile_and_link.replacer.* ]]; then
        compile_and_link_replacer+=("$rflag")
    elif [[ "$1" == compile_and_link.adder.* ]]; then
        compile_and_link_adder+=("$2")
    fi


    if [[ "$1" == condition.*.match ]]; then
        key_match=0
        for ((i=0; i<${#listp[@]}; i++)); do
            if [[ "${listp[$i]}" =~ $2 ]]; then
                key_match=1
            fi
        done
    fi

    if [[ "$1" == condition.*.filter.* ]] && [[ "$key_match" == 1 ]]; then
       all_filter+=("$2")
    fi

    if [[ "$1" == condition.*.replacer.* ]] && [[ "$key_match" == 1 ]]; then
       all_replacer+=("$rflag")
    fi

    if [[ "$1" == condition.*.adder.* ]] && [[ "$key_match" == 1 ]]; then
       all_adder+=("$2")
    fi

    if [[ "$1" == not_found.dev_compile.*.match ]]; then
        not_found_dev_match+=("$2")
    fi

    if [[ "$1" == not_found.dev_compile.*.adder ]]; then
        not_found_dev_adder+=("$2")
    fi

}

function parse_array() {
    local current_path="${1:+$1.}$2"
    local current_scope="root"
    local current_index=0

    while [ "$chars_read" -lt "$INPUT_LENGTH" ]; do
        [ "$preserve_current_char" == "0" ] && chars_read=$((chars_read + 1)) && read -r -s -n 1 c
        preserve_current_char=0
        c=${c:-' '}

        case "$current_scope" in
        "root") # Waiting for new object or value
            case "$c" in
            '{')
                parse_object "$current_path" "$current_index"
                current_scope="entry_separator"
                ;;
            ']')
                return
                ;;
            [\"tfTF\-0-9])
                preserve_current_char=1 # Let the parse value function decide what kind of value this is
                parse_value "$current_path" "$current_index"
                preserve_current_char=1 # Parse value has terminated with a separator or an array end, but we can handle this only in the next while iteration
                current_scope="entry_separator"
                ;;

            esac
            ;;
        "entry_separator")
            [ "$c" == "," ] && current_index=$((current_index + 1)) && current_scope="root"
            [ "$c" == "]" ] && return
            ;;
        esac
    done
}

function parse_value() {
    local current_path="${1:+$1.}$2"
    local current_scope="root"

    while [ "$chars_read" -lt "$INPUT_LENGTH" ]; do
        [ "$preserve_current_char" == "0" ] && chars_read=$((chars_read + 1)) && read -r -s -n 1 c
        preserve_current_char=0
        c=${c:-' '}

        case "$current_scope" in
        "root") # Waiting for new string, number or boolean
            case "$c" in
            '"') # String begin
                current_scope="string"
                current_varvalue=""
                ;;
            [\-0-9]) # Number begin
                current_scope="number"
                current_varvalue="$c"
                ;;
            [tfTF]) # True or false begin
                current_scope="boolean"
                current_varvalue="$c"
                ;;
            "[") # Array begin
                parse_array "" "$current_path"
                return
                ;;
            "{") # Object begin
                parse_object "" "$current_path"
                return
                ;;
            esac
            ;;
        "string") # Waiting for string end
            case "$c" in
            '"') # String end if not in escape mode, normal character otherwise
                [ "$current_escaping" == "0" ] && output_entry "$current_path" "$current_varvalue" && return
                [ "$current_escaping" == "1" ] && current_varvalue="$current_varvalue$c" && current_escaping=0
                ;;
            '\') # Escape character, entering or leaving escape mode
                [ "$current_escaping" == "1" ] && current_varvalue="$current_varvalue$c"
                current_escaping=$((1 - current_escaping))
                ;;
            *) # Any other string character
                current_escaping=0
                current_varvalue="$current_varvalue$c"
                ;;
            esac
            ;;
        "number") # Waiting for number end
            case "$c" in
            [,\]}]) # Separator or array end or object end
                output_entry "$current_path" "$current_varvalue"
                preserve_current_char=1 # The caller needs to handle this char
                return
                ;;
            [\-0-9.]) # Number can only contain digits, dots and a sign
                current_varvalue="$current_varvalue$c"
                ;;
                # Ignore everything else
            esac
            ;;
        "boolean") # Waiting for boolean to end
            case "$c" in
            [,\]}]) # Separator or array end or object end
                output_entry "$current_path" "$current_varvalue"
                preserve_current_char=1 # The caller needs to handle this char
                return
                ;;
            [a-zA-Z]) # No need to do some strict checking, we do not want to validate the incoming json data
                current_varvalue="$current_varvalue$c"
                ;;
                # Ignore everything else
            esac
            ;;
        esac
    done
}

function parse_object() {
    local current_path="${1:+$1.}$2"
    local current_scope="root"

    while [ "$chars_read" -lt "$INPUT_LENGTH" ]; do
        [ "$preserve_current_char" == "0" ] && chars_read=$((chars_read + 1)) && read -r -s -n 1 c
        preserve_current_char=0
        c=${c:-' '}

        case "$current_scope" in
        "root") # Waiting for new field or object end
            [ "$c" == "}" ] && return
            [ "$c" == "\"" ] && current_scope="varname" && current_varname="" && current_escaping=0
            ;;
        "varname") # Reading the field name
            case "$c" in
            '"') # String end if not in escape mode, normal character otherwise
                [ "$current_escaping" == "0" ] && current_scope="key_value_separator"
                [ "$current_escaping" == "1" ] && current_varname="$current_varname$c" && current_escaping=0
                ;;
            '\') # Escape character, entering or leaving escape mode
                current_escaping=$((1 - current_escaping))
                current_varname="$current_varname$c"
                ;;
            *) # Any other string character
                current_escaping=0
                current_varname="$current_varname$c"
                ;;
            esac
            ;;
        "key_value_separator") # Waiting for the key value separator (:)
            [ "$c" == ":" ] && parse_value "$current_path" "$current_varname" && current_scope="field_separator"
            ;;
        "field_separator") # Waiting for the field separator (,)
            [ "$c" == ',' ] && current_scope="root"
            [ "$c" == '}' ] && return
            ;;
        esac
    done
}

function parse() {
    chars_read=0
    preserve_current_char=0

    while [ "$chars_read" -lt "$INPUT_LENGTH" ]; do
        read -r -s -n 1 c
        c=${c:-' '}
        chars_read=$((chars_read + 1))

        # A valid JSON string consists of exactly one object
        [ "$c" == "{" ] && parse_object "" "" && return
        # ... or one array
        [ "$c" == "[" ] && parse_array "" "" && return

    done
}

function compileflag() {
    cflag="link"
}

function echolist() {
    index=0
    for i in "$@"; do
        let index+=1
        echo "$index:$i"
    done
}


function filterparam() {
    local len_param=$1
    local len_filter=$2
    newparam=()

    for ((i = 3; $i < $(($len_param + 3)); i++)); do
        findfilter=0
        skipflag=0
        ii=$((i + 1))
        param_pair=(${!i%%=*})
        if [[ ${!i%%=*} != ${!i} ]]; then
            param_pair+=(${!i#*=})
        fi

        for ((j = $(($len_param + 3)); $j < $(($len_param + $len_filter + 3)); j++)); do
            #IFS='=' read -ra filter_pair <<<${!j}
            filter_pair=("${!j%%=*}")
            if [[ ${!j%%=*} != ${!j} ]]; then
                filter_pair+=("${!j#*=}")
            fi
            if [[ ${param_pair[0]} == ${filter_pair[0]} ]]; then
                case ${#filter_pair[@]} in
                1)
                    findfilter=1
                    break
                    ;;
                2)
                    case ${#param_pair[@]} in
                    1)
                        if [[ $ii -ge $(($len_param + 3)) ]]; then
                            break
                        fi
                        if [[ ${!ii} == ${filter_pair[1]} ]]; then
                            findfilter=1
                            skipflag=1
                            break
                        fi
                        ;;
                    2)
                        if [[ ${param_pair[1]} == ${filter_pair[1]} ]]; then
                            findfilter=1
                            break
                        fi
                        ;;
                    esac
                    ;;
                esac
            fi
        done
        if [ $findfilter -eq 0 ]; then
            newparam+=(${!i})
        fi

        if [ $skipflag -eq 1 ]; then
            ((i++))
        fi
    done
    echo " ${newparam[@]}"
}

function replaceparam() {
    local len_param=$1
    local len_replace=$2

    newparam=()

    for ((i = 3; $i < $(($len_param + 3)); i++)); do
        findreplace=0
        skipflag=0
        ii=$((i + 1))

        parameq=0
        param_pair=(${!i%%=*})
        if [[ ${!i%%=*} != ${!i} ]]; then
            param_pair+=(${!i#*=})
            parameq=1
        else
            if [[ $ii -ge $(($len_param + 3)) ]]; then
                param_pair+=("")
            else
                param_pair+=(${!ii})
            fi
        fi

        for ((j = $(($len_param + 3)); $j < $(($len_param + $len_replace + 3)); j += 2)); do
            jj=$((j + 1))
            IFS='=' read -ra replace_pair <<<${!j}
            if [[ ${param_pair[0]} == ${replace_pair[0]} ]]; then
                case ${#replace_pair[@]} in
                1)
                    case ${!jj} in
                    *=*)
                        IFS='=' read -ra strsjj <<<${!jj}
                        newparam+=(${strsjj[0]}\=${strsjj[1]})
                        findreplace=1
                        break
                        ;;
                    *)
                        tmp=${!jj}
                        # replace & to space
                        tmpjj=${tmp//\&/ }
                        if [[ $parameq -eq 1 ]]; then
                            newparam+=($tmpjj=${param_pair[1]})
                        else
                            # newparam+=($tmpjj)
                            IFS='&' read -ra strsjj <<<${!jj}
                            for str in ${strsjj[@]}; do
                                if [[ -n "$str" ]]; then
                                    newparam+=($str)
                                fi
                            done
                        fi

                        findreplace=1
                        break
                        ;;
                    esac
                ;;
                2)
                    # case ${replace_pair[1]} in
                    # \* | ${param_pair[1]})
                    [ -z "${param_pair[1]}" ] && continue
                    if [[ ${param_pair[1]} == ${replace_pair[1]} ]]; then
                        case ${!jj} in
                        *#\*\*)
                            IFS='#' read -ra strsjj <<<${!jj}
                            IFS=',' read -ra strsii <<<${param_pair[1]}
                            for str in ${strsii[@]}; do
                                if [[ -n "$str" ]]; then
                                    newparam+=(${strsjj[0]}${str})
                                fi
                            done
                            findreplace=1
                            skipflag=$((1-$parameq))
                            break
                            ;;
                        *#\*)
                            IFS='#' read -ra strsjj <<<${!jj}
                            newparam+=(${strsjj[0]}${param_pair[1]})
                            findreplace=1
                            skipflag=$((1-$parameq))
                            break
                            ;;
                        *#*)
                            IFS='#' read -ra strsjj <<<${!jj}
                            newparam+=(${strsjj[0]}${strsjj[1]})
                            findreplace=1
                            skipflag=$((1-$parameq))
                            break
                            ;;
                        *=\*\*)
                            IFS='=' read -ra strsjj <<<${!jj}
                            IFS=',' read -ra strsii <<<${param_pair[1]}
                            for str in ${strsii[@]}; do
                                if [[ -n "$str" ]]; then
                                    newparam+=(${strsjj[0]})
                                    newparam+=($str)
                                fi
                            done
                            findreplace=1
                            skipflag=$((1-$parameq))
                            break
                            ;;
                        *=\*)
                            IFS='=' read -ra strsjj <<<${!jj}
                            if [[ $parameq -eq 1 ]]; then
                                newparam+=(${strsjj[0]}=${param_pair[1]})
                            else
                                newparam+=(${strsjj[0]})
                                newparam+=(${param_pair[1]})
                            fi

                            findreplace=1
                            skipflag=$((1-$parameq))
                            break
                            ;;
                        *=*)
                            # IFS='=' read -ra strsjj <<<${!jj}
                            # newparam+=(${strsjj[0]}=${strsjj[1]})

                            IFS='&' read -ra strsjj <<<${!jj}
                            for str in ${strsjj[@]}; do
                                if [[ -n "$str" ]]; then
                                    newparam+=($str)
                                fi
                            done


                            findreplace=1
                            skipflag=$((1-$parameq))
                            break
                            ;;
                        *\&*)
                            IFS='&' read -ra strsjj <<<${!jj}
                            for str in ${strsjj[@]}; do
                                if [[ -n "$str" ]]; then
                                    newparam+=($str)
                                fi
                            done

                            findreplace=1
                            skipflag=$((1-$parameq))
                            break
                            ;;
                        *)
                            newparam+=(${!jj})
                            findreplace=1
                            skipflag=$((1-$parameq))
                            break
                            ;;
                        esac
                    fi
                ;;
                esac
            fi
        done
        if [ $findreplace -eq 0 ]; then
            newparam+=(${!i})
        fi

        if [ $skipflag -eq 1 ]; then
            i=$((i + 1))
        fi
    done
    echo " ${newparam[@]}"
}

if [ x"${WCUDA_BAZEL_TF_BUILD}" == x"1"  ] ; then
    INPUT=$(cat $(dirname "${BASH_SOURCE[0]}")/conf_tf_bazel.json)
else
    INPUT=$(cat $(dirname "${BASH_SOURCE[0]}")/conf.json)
fi
INPUT_LENGTH="${#INPUT}"
parse "" "" <<<"${INPUT}"

params=()
CompilerFlag="link"
IsLinkFlag="yes"
IsCompileFlag="no"

# if params in wrapperskipstrings, set wrapperskipflag to 1
for i in $*; do
    for j in ${wrapperskipstrings[@]}; do
        if [[ $i == $j ]]; then
            wrapperskipflag=1
            break
        fi
    done
done

# "nvcc -c -o test.o test.cu "  is compile
# "nvcc -o test test.o "  is link
# "nvcc -o test test.cu "  is compile and link
FindOFlag="no"
for i in $*; do
    if [[ $FindOFlag == "yes" ]]; then
        FindOFlag="no"
        continue
    fi

    if [[ $i == *.mc ]] || [[ $i == *.cu ]] || [[ $i == *.cc ]] || [[ $i == *.c ]] || [[ $i == *.cpp ]] || [[ $i == *.C ]] ; then
        IsCompileFlag="yes"
    fi

    if [[ $i == -c ]] || [[ $i == -dc ]]; then
        IsCompileFlag="yes"
        IsLinkFlag="no"
        break
    fi

    if [[ $i == -o ]]; then
        FindOFlag="yes"
    fi
done

if [[ $IsCompileFlag == "yes" ]] && [[ $IsLinkFlag == "yes" ]]; then
    CompilerFlag="compile_and_link"
elif [[ $IsCompileFlag == "yes" ]]; then
    CompilerFlag="compile"
elif [[ $IsLinkFlag == "yes" ]]; then
    CompilerFlag="link"
else
    :
fi

params+=("")
params+=("")

filters=(${all_filter[@]})
replacers=(${all_replacer[@]})
if [[ "$CompilerFlag" == "compile" ]]; then
    filters+=(${compile_filter[@]})
    replacers+=(${compile_replacer[@]})
fi
if [[ "$CompilerFlag" == "link" ]]; then
    filters+=(${link_filter[@]})
    replacers+=(${link_replacer[@]})
fi
if [[ "$CompilerFlag" == "compile_and_link" ]]; then
    filters+=(${compile_and_link_filter[@]})
    replacers+=(${compile_and_link_replacer[@]})
fi

check_python() {
    local cmd=$1
    local name=$2
    if command -v "$cmd" &> /dev/null; then
        local version=$($cmd --version 2>&1)
        #echo "$name is installed: $version"
        # is python 3.x
        if $cmd -c "import sys; exit(0 if sys.version_info[0] >= 3 else 1)" 2>/dev/null; then
            #echo "$name is version 3.x or higher ✓"
            return 0
        else
            #echo "$name is version 2.x ✗"
            return 1
        fi
    else
        #echo "$name is not installed ✗"
        return 1
    fi
}
if [[ ! -v CUCC_USE_PYTHON ]]; then
    check_python "python" "Python"
    if [ $? -eq 0 ]; then
        #the current shell cannot influence other shells
        export CUCC_USE_PYTHON=1
    fi
fi

if [[ "${CUCC_USE_PYTHON}" = "1" ]]; then
    listp=($(python ${target_file_path}/process_args.py "${#listp[@]}" "${#filters[@]}" "${#replacers[@]}" "${listp[@]}" "${filters[@]}" "${replacers[@]}"))
    # echo "listp:" ${listp[@]}
else
    # when debugmodel: filterparam ${#listp[@]}  ${#filters[@]} ${listp[@]}  ${filters[@]}
    listp=(`filterparam ${#listp[@]}  ${#filters[@]} ${listp[@]}  ${filters[@]}`)
    # echo "listp:" ${listp[@]}

    # when debugmodel: replaceparam ${#listp[@]} ${#replacers[@]} ${listp[@]} ${replacers[@]}
    listp=(`replaceparam ${#listp[@]}  ${#replacers[@]} ${listp[@]}  ${replacers[@]}`)
fi

# if xcompilerflag==1, then listp add not_found_dev_adders
# if not_found_dev_match[j] in listp, then listp add not_found_dev_adder[j]
if [[ $xcompilerflag == 1 ]]; then
    for ((j=0; j<${#not_found_dev_match[@]}; j++)); do
        foundflag=0
        for i in ${listp[@]}; do
            # echo "i:" $i "not_found_dev_match[j]:" ${not_found_dev_match[j]}
            if [[ $i == ${not_found_dev_match[j]} ]]; then
                foundflag=1
                break
            fi
        done
        if [[ $foundflag == 0 ]]; then
            listp+=(${not_found_dev_adder[j]})
        fi
    done
fi

function choose_arch_nvcc()
{
    # filter repeatedly defined NV_ARCH_*, the filtering are as follows:
    # 1. if defined NV_ARCH_V100, choose this;
    # 2. else choose highest ARCH.
    nv_arch_num=`echo ${listp[@]} | xargs -n1 | grep '\-DNV_ARCH_*' | wc -l`
    if [ $nv_arch_num -gt 1 ]; then
        final_arch=""
        tmp_listp=(${listp[@]})
        tmp_listp_len=${#tmp_listp[@]}
        listp=()
        for ((i = 0; $i < $tmp_listp_len; i++)); do
            current_param=${tmp_listp[$i]}
            if echo ${current_param} | grep '\-DNV_ARCH_*' > /dev/null 2>&1; then
                current_next_param=${tmp_listp[(($i + 1))]}
                [ $current_param == '-DNV_ARCH_A100' ] && final_arch='-DNV_ARCH_A100 -Xdevice -D__CUDA_ARCH__=800'
                [ "${final_arch}" != '-DNV_ARCH_A100 -Xdevice -D__CUDA_ARCH__=800' ] && [ $current_param == '-DNV_ARCH_T4' ] && final_arch='-DNV_ARCH_T4 -Xdevice -D__CUDA_ARCH__=750'
                [ -z "${final_arch}" ] && [ $current_param == '-DNV_ARCH_V100' ] && final_arch='-DNV_ARCH_V100 -Xdevice -D__CUDA_ARCH__=700'
                if [ "$current_next_param" == '-Xdevice' ]; then
                    i=$(($i+2))
                fi
            else
                listp+=(${current_param})
            fi
        done
        listp+=(${final_arch})
    fi
}
choose_arch_nvcc

if [ -z "${MXCC_PATH}" ]; then
    if [ -n "${MACA_CLANG_PATH}" ] && [ -f "${MACA_CLANG_PATH}/mxcc" ]; then
        MXCC_PATH=${MACA_CLANG_PATH}/mxcc
    else
        if [ -n "${MACA_PATH}" ] && [ -f "${MACA_PATH}/mxgpu_llvm/bin/mxcc" ]; then
            MXCC_PATH=${MACA_PATH}/mxgpu_llvm/bin/mxcc
        else
            MXCC_PATH=/opt/maca/mxgpu_llvm/bin/mxcc
        fi
    fi
fi

barxflag=0
for i in "${listp[@]}"; do
    sizei=${#i}
    spaceleft=${i%%#*}
    eqleft=${i%%=*}
    eqright=${i#*=}
    val=${i}

    quoteflag=0

    if [ $barxflag -eq 1 ]; then
        params[1]="${i}"
        barxflag=0
        continue
    fi


    if [[ $i == "-x"  ]]; then
        params[0]="-x"
        barxflag=1
        continue
    fi

    if [[ $i =~ \= ]]; then
        if [[ $eqright == *[\=\#]* ]]; then
            val="${eqleft}=\"${eqright}\""
            quoteflag=1
        fi
    fi

    if [[ $i =~ "nvccsign_space" ]]; then
        val="\"${i}\""
    fi
    params+=(${val})
done

function add_gcc_toolchain(){
    real_gcc=$(which gcc_wrapper 2>/dev/null)
    if [ -n "${real_gcc}" ]; then
        real_gcc_dir=$(readlink ${real_gcc})
        if [ "${real_gcc_dir}"x != "/usr/bin/gcc"x ]; then
            real_gcc_dir=$(dirname ${real_gcc_dir})
            real_gcc_dir=$(dirname ${real_gcc_dir})
            all_adder+=("--gcc-toolchain=${real_gcc_dir}/")
        fi
    fi
}
add_gcc_toolchain

if [ -n "$CUCC_CCCL_VERSION" ]; then
    if [ "$CUCC_CCCL_VERSION" -ge 3000000 ] && [ "$CUCC_CCCL_VERSION" -le 3002000 ]; then
        all_adder=("-I" "${CUDA_PATH}/include/cccl" "${all_adder[@]}")
    fi
fi

params+=("${all_adder[@]}")
if [[ "$CompilerFlag" == "link" ]]; then
    params+=("${link_adder[@]}")
fi
if [[ "$CompilerFlag" == "compile" ]]; then
    params+=("${compile_adder[@]}")
fi
if [[ "$CompilerFlag" == "compile_and_link" ]]; then
    params+=("${compile_and_link_adder[@]}")
fi

if [ "$found_offload_arch" = "0" ]; then
    if [ -n "${CUCC_TARGETS}" ]; then
        if [ "$CUCC_TARGETS" = "auto" ]; then
            #debug_echo "CUCC_TARGETS is auto"
            :
        else
            #debug_echo "set target from CUCC_TARGETS=${CUCC_TARGETS}"
            archs_str="${CUCC_TARGETS//,/ }"
            read -ra archs <<< "$archs_str"
            for off_load_arch_num in "${archs[@]}"
            do
                params+=(" --offload-arch=${off_load_arch_num}")
            done
        fi
    elif [ -n "${CUCC_TARGETS_FROM_DEVICE}" ]; then
        archs="${CUCC_TARGETS_FROM_DEVICE//,/ }"
        #debug_echo "set target from CUCC_TARGETS_FROM_DEVICE=${CUCC_TARGETS_FROM_DEVICE}"
        for off_load_arch_num in ${archs}
        do
            params+=(" --offload-arch=${off_load_arch_num}")
        done
    else
        #debug_echo "nothing to do for target"
        :
    fi
else
    :
fi

if [ -n "${CUCC_CUDA_VERSION}" ]; then
    params+=(" -DCUDA_VERSION=${CUCC_CUDA_VERSION}")
    echo "----add cuda version ${params}"
fi

strlistp="${params[@]}"
strlistp="${strlistp//nvccsign_space/ }"
strlistp="${strlistp//nvccsign_quote/\\\"}"
strlistp="${strlistp//nvccsign_dollar/\\\$}"
strlistp="${strlistp//nvccsign_lparenthesis/\\(}"
strlistp="${strlistp//nvccsign_rparenthesis/\\)}"


# read env: LDFLAGS for conda
if [ -z "${LDFLAGS}" ]; then
    :
else
    if [ -z "${CONDA_EXE}" ]; then
        :
    else
        if [[ "$CompilerFlag" == "link" ]] || [[ "$CompilerFlag" == "compile_and_link" ]]  ; then
        strlistp="${strlistp} ${LDFLAGS}"
        fi
    fi
fi

# if wrapperskipflag is 1, skip warpper
if [ $wrapperskipflag -eq 1 ]; then
    # debug_echo "${MXCC_PATH}/bin/mxcc $*"
    if [ $# -eq 1 ] && [ "$1" == "-V" ] ; then
        major_ver=11
        minor_ver=6
        fix_ver=124
        echo "cucc: cu-bridge compiler driver"
        echo "Copyright Apache License 2.0"
        echo "cu-bridge compilation tool, compatible with release ${major_ver}.${minor_ver}, V${major_ver}.${minor_ver}.${fix_ver}"
    else
        ${MXCC_PATH} $*
    fi
    exit 0
fi

debug_echo "nvcc: $nvccdate json: $jsondate $CompilerFlag"

mkdir -p $CUBRIDGE_HOME/_nvcc
cmdstr="${MXCC_PATH}  ${strlistp}"
TFILE="$CUBRIDGE_HOME/_nvcc/nvcc.$$.sh"
if [[ ${WINDOWS} -eq 1 ]]; then
    echo $cmdstr '-D__CUDACC_VER_MAJOR__=11' >$TFILE
else
    echo $cmdstr >$TFILE
fi


(${CUCC_PATH}/bin/gomxccbin $TFILE ${TFILE}_go)
debug_echo "$(cat ${TFILE}_go)"
source ${TFILE}_go
retv=$?
rm $TFILE
exit $retv
