#!/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="241018"
jsondate="241018"

function predeal_args(){
    i=${1}
    from_file_flag=${2}
    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}"
        else
            # start and end with "
            if [[ "${flag:0:1}" == '"' && "${flag: -1}" == '"' ]]; then
                flag=${flag:1:-1}
            fi
        fi
        flag="${flag//$/nvccsign_dollar}"
        flag="${flag//\(/nvccsign_lparenthesis}"
        flag="${flag//\)/nvccsign_rparenthesis}"
    fi
    listp+=(${flag})
}

version_check=0

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
    else
        if [[ "${i}" == "-v" ]]; then
            version_check=1
        fi
    fi
    predeal_args "${i}" "0"
done

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

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

# 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

#debug_echo "found_offload_arch=${found_offload_arch}"
if [ "$found_offload_arch" = "0" ]; then
    # if cannot get offload arch from command, complete necessary checks
    if check_target_set ; then
        :
    else
        multi_target_check_tips
        exit 1
    fi
else
    #debug_echo "get target from build system"
    :
fi
# echo "listp:${#listp[@]} ${listp[@]}"



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=()

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" == preprocess.filter.* ]]; then
        preprocess_filter+=("$2")
    elif [[ "$1" == preprocess.replacer.* ]]; then
        preprocess_replacer+=("$rflag")
    elif [[ "$1" == preprocess.adder.* ]]; then
        preprocess_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
                # echo "$1=$2" " matched"
                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
    # echo "len_param:$len_param len_filter:$len_filter"

    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
        # echo "param_pair:${#param_pair[@]}  ${param_pair[@]}    ${!i%%=*} not equal ${!i}"
        # echo "i:${!i} param_pair:${#param_pair[@]} ${param_pair[@]}  "

        for ((j = $(($len_param + 3)); $j < $(($len_param + $len_filter + 3)); j++)); do
            IFS='=' read -ra filter_pair <<<${!j}
            # echo "param_pair:${#param_pair[@]} ${param_pair[@]}  " "filter_pair:${#filter_pair[@]} ${filter_pair[@]}  "
            if [[ ${param_pair[0]} == ${filter_pair[0]} ]]; then
                case ${#filter_pair[@]} in
                1)
                    findfilter=1
                    break
                    ;;
                2)
                    # echo "param_pair len ${#param_pair[@]} "
                    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)
                        # printf "param_pair:${param_pair[1]} filter_pair:${filter_pair[1]} \n"
                        if [[ ${param_pair[1]} == ${filter_pair[1]} ]]; then
                            findfilter=1
                            break
                        fi
                        ;;
                    esac
                    ;;
                esac
            fi
        done
        # echo "findfilter:$findfilter skipflag:$skipflag"
        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
    # echo "len_param:$len_param len_replace:$len_replace"

    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

        # echo "param_pair:${#param_pair[@]}  ${param_pair[@]}    ${!i%%=*} not equal ${!i}" " parameq  $parameq"
        for ((j = $(($len_param + 3)); $j < $(($len_param + $len_replace + 3)); j += 2)); do
            # echo "j:$j"
            jj=$((j + 1))
            IFS='=' read -ra replace_pair <<<${!j}
            # echo "param_pair:${#param_pair[@]} ${param_pair[@]}  " "replace_pair:${#replace_pair[@]} ${replace_pair[@]}  "
            if [[ ${param_pair[0]} == ${replace_pair[0]} ]]; then
                # echo "320replace_pair:${#replace_pair[@]} ${replace_pair[@]}  "
                case ${#replace_pair[@]} in
                1)
                    # echo "323jj:$jj  ${!jj}"
                    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)
                        fi

                        findreplace=1
                        break
                        ;;
                    esac
                ;;
                2)
                    # echo "364replace_pair:${#replace_pair[@]} ${replace_pair[0]} ${replace_pair[1]} !jj ${!jj}" "param_pair[1]:${param_pair[1]}"
                    # case ${replace_pair[1]} in
                    # \* | ${param_pair[1]})
                    [ -z "${param_pair[1]}" ] && continue
                    if [[ ${param_pair[1]} == ${replace_pair[1]} ]]; then
                        # echo "399 enter  param_pair[1] ${param_pair[1]} replace_pair[1] ${replace_pair[1]} jj ${!jj}"
                        case ${!jj} in
                        *#\*\*)
                            # echo "369enter here jj:${!jj}, ii:${param_pair[1]}"
                            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}
                            # echo "strsjj:${#strsjj[@]} ${strsjj[@]}  ii:${param_pair[1]}"
                            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
                            ;;
                        *=\*)
                            # echo "405here  param_pair[1]: ${param_pair[1]}"
                            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}
                            # if [[ $parameq -eq 1 ]]; then
                            #     newparam+=(${strsjj[0]}=${strsjj[1]})
                            # else
                            #     newparam+=(${strsjj[0]})
                            #     newparam+=(${strsjj[1]})
                            # fi
                            newparam+=(${strsjj[0]}=${strsjj[1]})

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

                            findreplace=1
                            skipflag=$((1-$parameq))
                            break
                            ;;
                        *)
                            # echo "enter here486"
                            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 [ -z ${WCUDA_GUN_COMPILER+x} ] || [ $(basename $0) != "gnu" ]; then
    if [ x"${WCUDA_BAZEL_TF_BUILD}" == x"1"  ] ; then
        JSON_FILE=$(dirname $0)/conf_tf_bazel.json
    else 
        JSON_FILE=$(dirname $0)/conf.json
    fi
else
    JSON_FILE=$(dirname $0)/conf_gnu.json
fi

JSON_FILE=$(realpath ${JSON_FILE})
if [ -n "$CUCC_USE_JQ" ]; then\
    # 处理 普通选项
    # echo "use jq"
    # eval "all_filter=($(jq -r '.all.filter | @sh' ${JSON_FILE} ))"
    JQ_FILTER_GNERAY2=' [ 
        (.skipstring, .all.adder, .all.filter, .preprocess.adder,  .link.adder, .link.filter, .compile_and_link.adder, .compile_and_link.filter)  |  if type != "array" then
                    null
                else
                if length == 0 then 
                    ""
                else
                    .
                end
                end | @sh
        ] [] '
    # jq "$JQ_FILTER_GNERAY2" "$JSON_FILE"

    {
        read -r  skip_str_str
        read -r  all_adder_str
        read -r  all_filter_str
        read -r  preprocess_adder_str
        read -r  link_adder_str
        read -r  link_filter_str
        read -r  compile_and_link_adder_str
        read -r  compile_and_link_filter_str
    } < <(
        # jq 过滤器：按顺序输出三个字段，使用 @sh 确保安全和引号
        echo "$JSON_DATA" | jq  -r "$JQ_FILTER_GNERAY2" "$JSON_FILE"
    )

    eval "wrapperskipstrings=($skip_str_str)"
    eval "all_adder=($all_adder_str)"
    eval "all_filter=($all_filter_str)"
    eval "preprocess_adder=($preprocess_adder_str)"
    eval "link_adder=($link_adder_str)"
    eval "link_filter=($link_filter_str)"
    eval "compile_and_link_adder=($compile_and_link_adder_str)"
    eval "compile_and_link_filter=($compile_and_link_filter_str)"

    # echo "JQ all_adder-${#condition_i_replacer[@]}:${all_adder[@]}"
    # echo "JQ wrapperskipstrings:${wrapperskipstrings[@]}"

    # 处理 replacer
    JQ_FILTER_REPLACER='[ (.all.replacer , .link.replacer, .compile_and_link.replacer)| map(gsub(" +"; "\\&"))  | join(" ")  ] []'
    #jq -r "$JQ_FILTER_REPLACER" ${JSON_FILE}
    {
        # 注意：这里的 read 命令会依次读取三行数据并赋值给三个变量
        read -r  all_replacer_str
        read -r  link_replacer_str
        read -r  compile_and_link_replacer_str
    } < <(  echo "$JSON_DATA_REPLACER" | jq  -r "$JQ_FILTER_REPLACER" "$JSON_FILE" )

    eval "all_replacer=($all_replacer_str)"
    eval "link_replacer=($link_replacer_str)"
    eval "compile_and_link_replacer=($compile_and_link_replacer_str)"

    # echo "JQ compile_and_link_replacer-${#compile_and_link_replacer[@]}:${compile_and_link_replacer[@]}"
    
    # 处理 match
    JQ_FILTER_OTHER=' [.data , .not_found.dev_compile[].match, .not_found.dev_compile[].adder , ([ .condition[] | .match ] | join(" ")) ][]'
    # JQ_FILTER_MATCH=' [ ([.condition[] | .match] | join(" ")), .data, .not_found.dev_compile.match, .not_found.dev_compile.adder] '
    #jq  -r "$JQ_FILTER_OTHER" "$JSON_FILE"
    {
        # 注意：这里的 read 命令会依次读取三行数据并赋值给三个变量
        read -r  data_str
        read -r  dev_compiler_match_str
        read -r  dev_compiler_add_str
        read -r  match_key_str
    } < <(    echo "$JSON_DATA" | jq  -r "$JQ_FILTER_OTHER" "$JSON_FILE" )
    jsondate=${data_str}
    eval "not_found_dev_match=($dev_compiler_match_str)"
    eval "not_found_dev_adder=($dev_compiler_add_str)"
    eval "match_key=($match_key_str)"
    match_index=-1
    for ((i=0; i<${#listp[@]}; i++)); do
        for ((j=0; j<${#match_key[@]}; j++)); do 
        if [[ "${listp[$i]}" =~ ${match_key[$j]} ]]; then
                match_index=$j
                #echo "JQ matched yes @${match_index}=${match_key[$j]}"
                break
        fi
        done
    done

    if [ "$match_index" -eq -1 ]; then
        :
    else
        JQ_FILTER_CONDTION=' [.condition[$i].filter, .condition[$i].adder, (.condition[$i].replacer | map(gsub(" +"; "\\&"))  )  | join(" ") ] [] '
        # jq --argjson i ${match_index}  "${JQ_FILTER_CONDTION}" "$JSON_FILE"
        {
            read -r  condition_i_filter_str
            read -r  condition_i_adder_str
            read -r  condition_i_replacer_str
        } < <(  echo "$JSON_DATA_MATCH" | jq  -r --argjson i ${match_index}  "${JQ_FILTER_CONDTION}" "$JSON_FILE" )

        eval "condition_i_filter=($condition_i_filter_str)"
        eval "condition_i_adder=($condition_i_adder_str)"
        eval "condition_i_replacer=($condition_i_replacer_str)"
        # echo "++ condition_i_replacer -${#condition_i_replacer[@]}:${condition_i_replacer[@]}" 
        if [ "${#condition_i_replacer[@]}" -gt 0 ]; then
            all_replacer+=("${condition_i_replacer[@]}")
        fi
        if [ "${#condition_i_adder[@]}" -gt 0 ]; then
            all_adder+=("${condition_i_adder[@]}")
        fi
        if [ "${#condition_i_filter[@]}" -gt 0 ]; then
            all_adder+=("${condition_i_filter[@]}")
        fi
        # echo "++ all_adder:${all_adder[@]}" 
    fi

else
    INPUT=$(cat ${JSON_FILE})
    INPUT_LENGTH="${#INPUT}"
    parse "" "" <<<"${INPUT}"
fi


params=()
CompilerFlag="link"
IsLinkFlag="yes"
IsCompileFlag="no"
IsPreprocessFlag="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 = c++-header ]]; then
        IsPreprocessFlag="yes"
        break
    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 [[ $IsPreprocessFlag == "yes" ]]; then
    CompilerFlag="preprocess"
elif [[ $IsCompileFlag == "yes" ]] && [[ $IsLinkFlag == "yes" ]]; then
    CompilerFlag="compile_and_link"
elif [[ $IsCompileFlag == "yes" ]]; then
    CompilerFlag="compile"
elif [[ $IsLinkFlag == "yes" ]]; then
    CompilerFlag="link"
else
    :
fi

if [[ "$CompilerFlag" == "link" ]] || [[ "$CompilerFlag" == "compile_and_link" ]]  ; then
  # 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[@]}")
fi




# echo "listp:${#listp[@]} ${listp[@]}"

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

filters=(${all_filter[@]})
replacers=(${all_replacer[@]})
if [[ "$CompilerFlag" == "preprocess" ]]; then
    filters+=(${preprocess_filter[@]})
    replacers+=(${preprocess_replacer[@]})
fi
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
    # filterparam ${#listp[@]}  ${#filters[@]} ${listp[@]}  ${filters[@]}
    listp=(`filterparam ${#listp[@]}  ${#filters[@]} ${listp[@]}  ${filters[@]}`)
    # echo "listp:" ${listp[@]}

    # replaceparam ${#listp[@]} ${#replacers[@]} ${listp[@]} ${replacers[@]}
    listp=(`replaceparam ${#listp[@]}  ${#replacers[@]} ${listp[@]}  ${replacers[@]}`)
    # echo ${listp[@]}
fi

# if not_found_dev_match[j] in listp, then listp add not_found_dev_adder[j]
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

function choose_arch_gnu(){
    # 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`
    final_arch=""
    if [ $nv_arch_num -gt 1 ]; then
        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'
                [ "${final_arch}" != '-DNV_ARCH_A100' ] && [ $current_param == '-DNV_ARCH_T4' ] && final_arch='-DNV_ARCH_T4'
                [ -z "${final_arch}" ] && [ $current_param == '-DNV_ARCH_V100' ] && final_arch='-DNV_ARCH_V100'
                if [ "$current_next_param" == '-Xdevice' ]; then
                    i=$(($i+2))
                fi
            else
                listp+=(${current_param})
            fi
        done
    fi
    listp+=(${final_arch})
}
# if real nead, use this function
# choose_arch_gnu

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


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})
            if [[ "$CompilerFlag" == "link" ]]; then
                link_adder+=("--gcc-toolchain=${real_gcc_dir}/")
            fi
            if [[ "$CompilerFlag" == "compile_and_link" ]]; then
                compile_and_link_adder+=("--gcc-toolchain=${real_gcc_dir}/")
            fi
        fi
    fi
}
add_gcc_toolchain

mkdir -p $CUBRIDGE_HOME/_nvcc
name=$(basename $0)
wrapper_dir=$(dirname $0)
# if wrapperskipflag is 1, skip warpper
if [ $wrapperskipflag -eq 1 ]; then
    ${wrapper_dir}/${name}_wrapper  $*
    retv1=$?
    exit $retv1
fi

if [[ $version_check -eq 1 ]]; then
    if [ -e "${wrapper_dir}/${name}_wrapper" ]; then    # For gnu_wrapper exists
        debug_echo "${wrapper_dir}/${name}_wrapper ${listp[@]}"
        ${wrapper_dir}/${name}_wrapper ${listp[@]}
    else                                                # For using gnu -v directly, without make_maca
        naive_gnu_compiler=$(which g++)
        if [ -e $naive_gnu_compiler ]; then
            debug_echo "$naive_gnu_compiler ${listp[@]}"
            $naive_gnu_compiler ${listp[@]}
        else
            echo "ERROR: No naive gnu compiler found!"
            exit 1
        fi
    fi
    retv=$?
    exit $retv
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 =~ \# ]]; then
    #     if [[ $quoteflag -eq 0 ]]; then
    #         val="\"${i}\""
    #     fi
    # fi

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

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

# echo "params:" "${params[@]}"
params+=("${all_adder[@]}")
if [[ "$CompilerFlag" == "preprocess" ]]; then
    params+=("${preprocess_adder[@]}")
fi
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 [ -n "${CUCC_CUDA_VERSION}" ]; then
    params+=(" -DCUDA_VERSION=${CUCC_CUDA_VERSION}")
    echo "----add cuda version ${params}"
fi
strlistp="${params[@]}"
# strlistp="${strlistp//\#/ }"
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

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 ${strlistp[@]} | xargs -n1 | grep '\-DNV_ARCH_*' | wc -l`
    if [ $nv_arch_num -gt 1 ]; then
        final_arch=""
        tmp_listp=(${strlistp[@]})
        tmp_listp_len=${#tmp_listp[@]}
        strlistp=()
        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
                strlistp+=(${current_param})
            fi
        done
        strlistp+=(${final_arch})
    fi
}

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

# if cflag==link then use mxcc
if [[ "$CompilerFlag" == "link" ]] || [[ "$CompilerFlag" == "compile_and_link" ]] || [[ "$CompilerFlag" == "preprocess" ]] ; then
    choose_arch_nvcc

    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
                    strlistp+=(" --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
                strlistp+=(" --offload-arch=${off_load_arch_num}")
            done
        else
            :
            #debug_echo "nothing to do for target"
        fi
    else
        #debug_echo "get target from build system"
        :
    fi
    strlistp="${strlistp[@]}"
    if [[ "$name" == "mpicc" ]] || [[ "$name" == "mpicxx" ]] ; then
        cmdstr="${wrapper_dir}/ompi/${name} ${strlistp}"
    else
        cmdstr="${MXCC_PATH} ${strlistp}"
    fi
else
    if [ -z ${WCUDA_GUN_COMPILER+x} ]; then
        if [[ "$name" == "mpicc" ]] || [[ "$name" == "mpicxx" ]] ; then
            cmdstr="${wrapper_dir}/ompi/${name} ${strlistp}"
        else
            cmdstr="${wrapper_dir}/${name}_wrapper ${strlistp}"
        fi
    else
        wcuda_gnu_compiler=$(which ${wrapper_dir}/${WCUDA_GUN_COMPILER}_wrapper)
        if [ -z "$wcuda_gnu_compiler" ]; then
            wcuda_gnu_compiler=$(which ${WCUDA_GUN_COMPILER})
        fi
        [ -z "$wcuda_gnu_compiler" ] && debug_echo "WCUDA_GUN_COMPILER ${WCUDA_GUN_COMPILER} not found" && exit 1
        cmdstr="${wcuda_gnu_compiler}  ${strlistp}"
    fi
fi

TFILE="$CUBRIDGE_HOME/_nvcc/nvcc.$$.sh"
echo $cmdstr >$TFILE
(${CUCC_PATH}/bin/gomxccbin $TFILE ${TFILE}_go)
debug_echo "$(cat ${TFILE}_go)"
source ${TFILE}_go
retv=$?

rm $TFILE
exit $retv


