# shellcheck shell=dash     disable=SC2039,SC1090,SC3043,SC2263

___x_cmd_httpget___main(){
    local op="$1"; shift
    case "$op" in
        gitx)
            ___x_cmd_httpget_gitx "$@" ;;
        ""|-h|--help)  ___x_cmd help -m httpget "$@" ;;
        *)
            ___x_cmd_httpget_with_cache "$op" "$@" ;;
    esac
}

___x_cmd_httpget_handle_resp_header(){
    local url="${1:?Provide url}"
    local code="${2:?Provide exit code of function ___x_cmd_httpget_inner}"

    local http_code
    http_code="$(
        ___x_cmd_cmds_awk '
            $0~"^[Hh][Tt][Tt][Pp]/"{ trycode = int($2); if (trycode > 1) code = trycode; }
            END{ print code; }
        '
    )"
    case "$http_code" in
        20*)    return 0 ;;
        40*)    x:debug "HTTP_CODE: $http_code. Fail to retrieve file from: $url"
                return 4 ;;     # TODO: consider using exit code 70
        "")     x:debug "Return code: $code. HTTP_CODE Unavialable. Fail to retrieve file from: $url"
                return 1 ;;
        5*)     x:debug "Return code: $code. Server internal error. Fail to retrieve file from: $url"
                return 5 ;;     # TODO: consider using exit code 69
        *)      x:debug "Unknow error. HTTP_CODE: $http_code. Fail to retrieve file from: $url"
                return 2 ;;
    esac
}

___x_cmd_httpget_with_cache() {
    # ___X_CMD_HTTPGET_AGE=-1
    ___X_CMD_HTTPGET_AGE=

    local url="${1:?Provide url}"
    local cache="$2"
    local cache_expiration="$3"
    local error_msg_varname="$4"

    local redirect_path=            # "&1"
    if [ -n "$cache" ]; then
        if [ -f "$cache" ]; then
            # days
            case "$cache_expiration" in
                "") # infinite time
                    x:debug "Function ___x_cmd_httpget_with_cache() terminated. Because local cache existed with update flag unset: $cache"
                    return 0
                    ;;
                -|0) # force update
                    ;;
                *)
                    # days
                    # if [ -n "$(find "$cache" -mtime "-$cache_expiration" 2>/dev/null)" ]; then
                    local x_
                    if ! ___x_cmd fileage --get_ "$cache"; then
                        x:error "Fail to get file age: $cache"
                        return 1
                    fi

                    if [ "$x_" -lt "$cache_expiration" ]; then
                        ___X_CMD_HTTPGET_AGE="$x_"
                        x:debug "Function ___x_cmd_httpget_with_cache() terminated. Because local cache existed within days: $cache_expiration"
                        return 0
                    else
                        ___X_CMD_HTTPGET_AGE="-$x_"
                        x_="-$x_"
                    fi
            esac
        fi

        # First make sure it works before webservice. Fail fast.
        ___x_cmd ensurefp "$cache"
        redirect_path="${___X_CMD_ROOT_TMP}/httpget/x-bash-temp-download.$RANDOM"
        ___x_cmd ensurefp "${redirect_path}"
        # TODO: Consider using following code
        # redirect_path="$(dirname "$cache")/x-bash-temp-download.$RANDOM"
    fi

    x:debug "URL is $url"
    if ___x_cmd_httpget_inner "$url" "$redirect_path"; then
        if [ -n "$cache" ]; then
            x:debug "Copy the temp file to CACHE file: $cache"
            ___x_cmd mv "$redirect_path" "$cache"
            ___X_CMD_HTTPGET_AGE=0
        fi
    else
        code=$?
        if [ -n "$cache" ] ; then
            [ -n "$error_msg_varname" ] && eval "$error_msg_varname=\"$(___x_cmd_cmds_cat "$redirect_path")\""
            ___x_cmd_cmds_rm -f "$redirect_path" # In centos, file in "$redirect_path" is write protected.
        fi
        return $code
    fi
}

# org reponame branch suburl
# rename to ___x_cmd_httpget_gitx_with_cache
___x_cmd_httpget_gitx(){   # Simple strategy
    local owner="${1:?Provide owner}"
    local reponame="${2:?Provide reponame}"
    local branch="${3:?Provide branch}"
    local suburl="${4:?Provide location like str}"
    local cache="${5}"
    local cache_expiration="${6}"

    ___x_cmd websrc load     # Reload ___X_CMD_MIRROR_LIST

    local mirror
    local urlpath
    while read -r mirror; do
        # shellcheck disable=SC2059
        urlpath="$(printf "$mirror" "$owner" "$reponame" "${branch}" "$suburl")"
        ___x_cmd_httpget_with_cache "$urlpath" "$cache" "$cache_expiration"

        case $? in
            0)  ___x_cmd websrc uproot "$mirror"
                return 0 ;;
            1)  x:debug "Network unavailable."
                return 1 ;;
            4)  x:debug "Resource Not Found."
                return 4 ;;
            *)  x:debug "Network unavailable Or Mirror is down: $urlpath"
                return 1 ;;
        esac
    done <<A
$___X_CMD_WEBSRC_LIST
A
    return 1
}

# rename to ___x_cmd_httpget_gitx_official
___x_cmd_httpget_gitx_official(){
    ___x_cmd_httpget_gitx x-cmd "$___X_CMD_CODESORUCE_REPO" "${___X_CMD_CODESORUCE_REPO_BRANCH}" "${1:?Provide resource path}" "$2" "$3"
}

___x_cmd_httpget_curl___main(){(
    local url="${1:?Provide url}"
    local cache="${2}"
    x:debug "___x_cmd_httpget_curl___main_fn -L --dump-header - --output $cache --speed-time 5 --speed-limit 10 $url"

    if [ -z "$cache" ]; then
        exec 3>&1
        ___X_CMD_HTTP_GET_INNER_HEADER="$(
            ___x_cmd_httpget_curl___main_fn -L --silent --dump-header - --speed-time 5 --speed-limit 10 "$url" | {
                ___x_cmd_cmds_awk '
                {
                    if (( $0 == "\r" ) || ( $0 == "" )) {
                        if ((has_te == 1) || ( (has_cl == 1)  && (has_ct == 1))) {
                            while (getline) {
                                print $0 > "/dev/stderr"
                            }
                        } else {
                            has_te = has_cl = has_ct = 0
                        }
                    }

                    print $0
                    line = tolower($0)
                    if (line ~ /^transfer-encoding/)    has_te = 1
                    else if (line ~ /^content-length/)  has_cl = 1
                    else if (line ~ /^content-type/)    has_ct = 1
                }
                ' 2>&3
            }
        )"
        exec 3>&-
    else
        ___X_CMD_HTTP_GET_INNER_HEADER="$(___x_cmd_httpget_curl___main_fn -L --silent --dump-header - --output "$cache" --speed-time 5 --speed-limit 10 "$url")"
    fi

    local code=$?
    printf "%s" "$___X_CMD_HTTP_GET_INNER_HEADER" | ___x_cmd_httpget_handle_resp_header "$url" "$code"
)}

# Section: httpget_inner
# TODO: &3 is a global var. Must be handled in the proper way.
if command -v curl >/dev/null; then
    ___x_cmd_httpget_curl___main_fn(){  ___x_cmd curl "$@";   }
    ___x_cmd_httpget_inner(){
        ___x_cmd_httpget_curl___main "$@"
    }
elif command -v wget >/dev/null && command -v ssl_client 1>/dev/null; then
    ___x_cmd_httpget_inner()(
        local url="${1:?Provide url}"
        local cache="${2}"

        if [ -z "$cache" ]; then
            exec 3>&1
            ___X_CMD_HTTP_GET_INNER_HEADER="$(wget -T 5 -qS "$url" 1>&3 2>/dev/stdout)"
            exec 3>&-
        else
            ___X_CMD_HTTP_GET_INNER_HEADER="$(wget -T 5 -O "$cache" -qS "$url" 2>/dev/stdout)"
        fi

        local code=$?
        printf "%s" "$___X_CMD_HTTP_GET_INNER_HEADER" | ___x_cmd_httpget_handle_resp_header "$url" "$code"
    )
else
    ___x_cmd_httpget_curl___main_fn(){  ___x_cmd curl "$@";   }
    ___x_cmd_httpget_inner(){
        ___x_cmd_httpget_curl___main "$@"
    }
fi
# EndSection
