# shellcheck    shell=sh        disable=SC3043

___x_cmd_list_make(){
    local O="${1:?Please provide list name}"
    eval "$O=()"
}

___x_cmd_list_free(){
    eval "unset $O"
}

: <<'DOCTEST'
> ___x_cmd_list_make b
> O=b ___x_cmd_list_push $(seq 1 3); O=b ___x_cmd_list_print
1
2
3
DOCTEST
___x_cmd_list_print(){
    local IFS="
"
    eval printf "%s" "\"\${${O:?Please provide list name}[*]}\""
}

: <<'DOCTEST'
> ___x_cmd_list_make b
> O=b ___x_cmd_list_push $(seq 1 3); O=b ___x_cmd_list_get 0
1
> O=b ___x_cmd_list_size
3
DOCTEST
___x_cmd_list_size(){
    eval printf "%s" "\"\${#${O:?Please provide list name}[@]}\""
}

: <<'DOCTEST'
> ___x_cmd_list_make b
> O=b ___x_cmd_list_push $(seq 10);
> O=b ___x_cmd_list_get 1
2
> O=b ___x_cmd_list_get 8
9
DOCTEST
___x_cmd_list_get(){
    eval printf "%s" "\"\${${O:?Please provide list name}[${1:?idx}]}\""
}


___x_cmd_list_push() {
    eval "$O"'+=("$@")'
}

: <<'DOCTEST'
> ___x_cmd_list_make b
> O=b ___x_cmd_list_unshift $(seq 10);
> O=b ___x_cmd_list_get 0
1
> O=b ___x_cmd_list_get 8
9
DOCTEST
___x_cmd_list_unshift() {
    eval "${O:?Please provide list name}"'=("$@" "${'"$O"'[@]}")'
}

: <<'DOCTEST'
> ___x_cmd_list_make b
> O=b ___x_cmd_list_unshift $(seq 10);
> O=b ___x_cmd_list_head
1
DOCTEST
___x_cmd_list_head(){
    ___x_cmd_list_get 0
}

: <<'DOCTEST'
> ___x_cmd_list_make b
> O=b ___x_cmd_list_unshift $(seq 10);
> O=b ___x_cmd_list_tail
10
DOCTEST
___x_cmd_list_tail(){
    local len
    len=$(___x_cmd_list_size)
    ___x_cmd_list_get "$((len-1))"
}

: <<'DOCTEST'
> ___x_cmd_list_make b
> O=b ___x_cmd_list_unshift $(seq 10);
> O=b ___x_cmd_list_top
10
DOCTEST
___x_cmd_list_top(){ ___x_cmd_list_tail; }

: <<'DOCTEST'
> ___x_cmd_list_make b
> O=b ___x_cmd_list_unshift $(seq 3);
> O=b ___x_cmd_list_map echo
0 1
1 2
2 3
DOCTEST
___x_cmd_list_map(){
    local O="${O:?Please provide list name}"

    local f="${1:?function name}"
    local len
    len=$(___x_cmd_list_size)
    local idx=0
    while [ "$idx" -lt "$len" ]; do
        eval "$f" "$idx" '"${'"${O}"'['"$idx"']}"'
        idx=$((idx+1))
    done
}

: <<'DOCTEST'
> ___x_cmd_list_make b
> O=b ___x_cmd_list_unshift $(seq 10);
> O=b ___x_cmd_list_pop
10
> O=b ___x_cmd_list_size
9
DOCTEST
___x_cmd_list_pop(){
    local O="${O:?Please provide list name}"
    local len
    len=$(___x_cmd_list_size)
    len=$((len-1))
    eval printf "%s" '"${'"$O"'['"$len"']}"'
    eval unset ''"$O"'['"$len"']'
}

: <<'DOCTEST'
> ___x_cmd_list_make b
> O=b ___x_cmd_list_unshift $(seq 10);
> O=b ___x_cmd_list_shift
1
> echo "${#b[@]}"
9
> O=b ___x_cmd_list_size
9
DOCTEST
___x_cmd_list_shift(){
    local O="${O:?Please provide list name}"
    local IFS=          # Notice! IFS should be empty, or the following line won't work: eval "$O=( \"\${""$O""[@]:1}\" )"
    local len
    len=$(___x_cmd_list_size)
    if [ "$len" -gt 0 ]; then
        eval printf "%s" "\"\${"$O"[0]}\""
        eval "$O=( \"\${""$O""[@]:1}\" )"
    fi

    # len=$((len-1))
    # eval printf "%s" '"${'"$O"'['"0"']}"'
    # eval unset ''"$O"'['"$len"']'
}

: <<'DOCTEST'
> ___x_cmd_list_make b
> O=b ___x_cmd_list_unshift $(seq 10);
> O=b ___x_cmd_list_index_of 2
1
2
DOCTEST
___x_cmd_list_index_of(){
    local O="${O:?Please provide list name}"

    local tgt="${1:?value}"
    local len
    len=$(___x_cmd_list_size)
    local idx=0
    local v
    while [ $idx -lt "$len" ]; do
        eval v='"${'"${O}"'['"$idx"']}"'
        if [ "$v" == "$tgt" ]; then
            printf "%s\n%s\n" "$idx" "$v"
        fi
        idx=$((idx+1))
    done

    return 1
}

: <<'DOCTEST'
> ___x_cmd_list_make b
> O=b ___x_cmd_list_unshift $(seq 5);  O=b ___x_cmd_list_remove_by_value 3
> O=b ___x_cmd_list_print
1
2
4
5
DOCTEST
___x_cmd_list_remove_by_value(){
    local O="${O:?Please provide list name}"

    local tgt="${1:?value}"
    local len
    len=$(___x_cmd_list_size)
    local idx=0
    local v
    local sw=0
    while [ $idx -lt "$len" ]; do
        if [ "$sw" -eq 0 ]; then
            eval v='"${'"${O}"'['"$idx"']}"'
            if [ "$v" == "$tgt" ]; then
                sw=1
            fi
        else
            eval "$O"'['"$((idx-1))"']="${'"$O"'['"$idx"']}"'
        fi
        idx=$((idx+1))
    done
    [ "$sw" -eq 1 ] && eval unset "$O[$((idx-1))]"

    return 1
}

: <<'DOCTEST'
> ___x_cmd_list_make b
> O=b ___x_cmd_list_unshift $(seq 5);  O=b ___x_cmd_list_remove 3
> O=b ___x_cmd_list_print
1
2
3
5
> O=b ___x_cmd_list_remove 0; O=b ___x_cmd_list_print
2
3
5
DOCTEST
___x_cmd_list_remove(){
    local O="${O:?Please provide list name}"
    local idx="${1:?Provide idx}"
    local IFS=

    if [ "$idx" -eq 0 ]; then
        eval "$O"'=("${'"$O"'[@]:1}")'
    else
        eval "$O"'=("${'"$O"'[@]:0:'"$idx"'}" "${'"$O"'[@]:'$((idx+1))'}" )'
    fi
}

: <<'DOCTEST'
> ___x_cmd_list_make b
> O=b ___x_cmd_list_unshift $(seq 10);
> O=b ___x_cmd_list_get_by_regex "^2$"
1
2
DOCTEST
___x_cmd_list_get_by_regex(){
    local O="${O:?Please provide list name}"

    local tgt="${1:?regex pattern}"
    local len
    len=$(___x_cmd_list_size)
    local idx=0
    local v
    while [ $idx -lt "$len" ]; do
        eval v='"${'"${O}"'['"$idx"']}"'
        # We know it is bash, thus [[ is available.
        if [[ "$v" =~ $tgt ]]; then
            printf "%s\n%s\n" "$idx" "$v"
        fi
        idx=$((idx+1))
    done

    return 1
}

