# shellcheck shell=dash

# add: link a package to sphere
# rm:

# x pkg sphere link add --sphere X <pkg> <version>
___x_cmd_pkg_sphere_link(){
    local op="$1"
    case "$op" in
        --help|-h)
                ___x_cmd help -m pkg link;              return ;;
        rm|add|exist|ls|get_version_)
                shift; ___x_cmd_pkg_sphere_link_"$op"   "$@" ;;
        list_all_path_dir|list_all_path_expand)
                shift; ___x_cmd_pkg_sphere_link___"$op" "$@" ;;
        *)      N=pkg M="sphere link no such option '$op'" log:ret:1
                ;;
    esac
}

# Section: link add
___x_cmd_pkg_sphere_link_add(){
    local sphere_name=; local osarch=; local sociality=
    while [ "$#" -gt 0 ]; do
        case "$1" in
            --sphere)
                    sphere_name="$2";
                    [ -n "$sphere_name" ] || M="Provide a sphere name" N=pkg log:ret:1
                    shift 2
                    ;;
            --sphereroot)
                    local ___X_CMD_PKG_ROOT_SPHERE="$2"
                    [ -n "$___X_CMD_PKG_ROOT_SPHERE" ] || M="Provide sphere root path" N=pkg log:ret:1
                    shift 2
                    ;;
            --osarch)
                    osarch="$2";    shift 2 ;;
            --sociality)
                    sociality="$2"; shift 2 ;;
            *)      break ;;
        esac
    done
    [ -n "$osarch" ] || { ___x_cmd_pkg_osarch_ || return 1; osarch="$___X_CMD_PKG_OSARCH"; } || N=pkg M="Not found osarch" log:ret:1
    sphere_name="${sphere_name:-"X"}"
    pkg:sphere:name-version
    [ -n "$sociality" ] || {
        local x_="" >/dev/null 2>&1; ___x_cmd_pkg_sphere_sociality___get_       \
            --sphere "$sphere_name" --sphereroot "$___X_CMD_PKG_ROOT_SPHERE"    \
            --osarch "$osarch" "$name" "$version" || return $?
        sociality="$x_"
    }

    ___x_cmd fslock run "pkg_sphere_link_${sphere_name}_${name}_${version}" ___x_cmd_pkg_sphere_link_add___run || return $?

    if [ "$sociality" = intrusive ] || [ "$sociality" = dev ]; then
        pkg:info "Loading boot script file of $name $version [sociality=$sociality]"
        ___x_cmd_pkg_sphere_boot    \
            --sphere "$sphere_name" --sphereroot "$___X_CMD_PKG_ROOT_SPHERE"    \
            --osarch "$osarch" "$name" "$version" || return $?
        pkg:info "Other sessions need to boot \`x pkg sphere boot ${name} ${version}\`"
    fi

    ___x_cmd_pkg_sphere_bootrc add  \
        --sphere "$sphere_name" --sphereroot "$___X_CMD_PKG_ROOT_SPHERE"    \
        --osarch "$osarch" --sociality "$sociality" "$name" "$version" || return $?

    ___x_cmd_pkg_sphere_fastboot add \
        --sphere "$sphere_name" --sphereroot "$___X_CMD_PKG_ROOT_SPHERE"    \
        --osarch "$osarch" --sociality "$sociality" "$name" "$version" || return $?
}

___x_cmd_pkg_sphere_link_add___run(){
    local x_treename=; ___x_cmd_pkg_treename_ "$name" "$version" "$osarch" || return $?
    local target_dir="$___X_CMD_PKG_ROOT_SPHERE/$sphere_name/l/j/h"
    local tgt="$___X_CMD_PKG_ROOT_SPHERE/$sphere_name/$x_treename/$name/$version"
    local link_dir="$___X_CMD_PKG_ROOT_SPHERE/$sphere_name/.x-cmd/link/${name}_${version}"

    pkg:info --target_dir "$target_dir" "Attempting to link $name $version of the bin/ lib/ man/ file"

    ___x_cmd_pkg_sphere_link_add___run_inner "$name" "$version" "$osarch" "$tgt" bin "$target_dir" "$link_dir" "$sociality" || return $?
    ___x_cmd_pkg_sphere_link_add___run_inner "$name" "$version" "$osarch" "$tgt" lib "$target_dir" "$link_dir" "$sociality" || return $?
    ___x_cmd_pkg_sphere_link_add___run_inner_man "$name" "$version" "$osarch" "$tgt" "$target_dir" "$link_dir" "$sociality" || return $?

    pkg:info "Successfully set link from path"
}

___x_cmd_pkg_sphere_link_add___run_inner(){
    local name="$1";    local version="$2";    local osarch="$3";   local tgt="$4";
    local _path="${5:-bin}";    local target_dir="$6";   local link_dir="$7"; local sociality="$8"
    local link_file="$link_dir/association"
    [ ! -f "$link_file" ] || {
        pkg:debug "$name $version has already linked"
        return 0
    }
    ___x_cmd ensurefp "$link_file"
    local file; local target;
    ___x_cmd_pkg_sphere_link___list_all_path_expand "$name" "$version" "$osarch" "$tgt" "$_path" "$sociality" | while ___x_cmd_readr file; do
        [ -n "$file" ] || continue
        [ -e "$file" ] || {
            pkg:error "Not found $file to $name $version link $_path"
            ___x_cmd rmrf "$link_file"
            return 1
        }
        target="$target_dir/$_path/${file##*/}"
        ___x_cmd ensurefp "$target"
        pkg:debug "linking source=$file target=$target"
        command ln -s -f "$file" "$target" || N=pkg M="ln - Operation failure source=$file target=$target" log:ret:1
        printf "%s\n" "$target" >> "$link_file"
    done
}

___x_cmd_pkg_sphere_link_add___run_inner_man(){
    local name="$1";    local version="$2";    local osarch="$3";   local tgt="$4";
    local target_dir="$5";   local link_dir="$6";  local sociality="$7"
    local link_file="$link_dir/association"
    [ ! -f "$link_file" ] || {
        pkg:debug "$name $version has already linked"
        return 0
    }
    ___x_cmd ensurefp "$link_file"
    local mandir; local target; local file; local filename
    ___x_cmd_pkg_sphere_link___list_all_path_expand "$name" "$version" "$osarch" "$tgt" "man" "$sociality" | while ___x_cmd_readr mandir; do
        [ -n "$mandir" ] || continue
        [ -d "$mandir" ] || {
            pkg:warn "Invalid manpath[$mandir] for $name $version"
            continue
        }

        ___x_cmd fsiter "$mandir" | while ___x_cmd_readr filename; do
            case "$filename" in
                *.[1-9]|*.gz) target="$target_dir/man/${mandir##*/}/$filename" ;;
                *) continue ;;
            esac
            file="$mandir/$filename"
            ___x_cmd ensurefp "$target"
            pkg:debug "linking source=$file target=$target"
            command ln -s -f "$file" "$target" || N=pkg M="ln - Operation failure source=$file target=$target" log:ret:1
            printf "%s\n" "$target" >> "$link_file"
        done
    done
}

# EndSection

# Section: link rm
___x_cmd_pkg_sphere_link_rm(){
    local sphere_name=; local osarch=; local sociality=
    while [ "$#" -gt 0 ]; do
        case "$1" in
            --sphere)
                    sphere_name="$2";
                    [ -n "$sphere_name" ] || M="Provide a sphere name" N=pkg log:ret:1
                    shift 2
                    ;;
            --sphereroot)
                    local ___X_CMD_PKG_ROOT_SPHERE="$2"
                    [ -n "$___X_CMD_PKG_ROOT_SPHERE" ] || M="Provide sphere root path" N=pkg log:ret:1
                    shift 2
                    ;;
            --osarch)
                    osarch="$2";    shift 2 ;;
            --sociality)
                    sociality="$2"; shift 2 ;;
            *)      break ;;
        esac
    done
    [ -n "$osarch" ] || { ___x_cmd_pkg_osarch_ || return 1; osarch="$___X_CMD_PKG_OSARCH"; } || N=pkg M="Not found osarch" log:ret:1
    sphere_name="${sphere_name:-"X"}"
    pkg:sphere:name-version
    [ -n "$sociality" ] || {
        local x_="" >/dev/null 2>&1; ___x_cmd_pkg_sphere_sociality___get_       \
            --sphere "$sphere_name" --sphereroot "$___X_CMD_PKG_ROOT_SPHERE"    \
            --osarch "$osarch" "$name" "$version" || return $?
        sociality="$x_"
    }

    ___x_cmd fslock run "pkg_sphere_link_${sphere_name}_${name}_${version}" ___x_cmd_pkg_sphere_link_rm___run || return $?

    if [ "$sociality" = intrusive ] || [ "$sociality" = dev ]; then
        pkg:info "Loading unboot script file of $name $version"
        ___x_cmd_pkg_sphere_unboot  \
            --sphere "$sphere_name" --sphereroot "$___X_CMD_PKG_ROOT_SPHERE"    \
            --osarch "$osarch" "$name" "$version" || return $?
        pkg:info "Other sessions need to unboot \`x pkg sphere unboot ${name} ${version}\`"
    fi

    ___x_cmd_pkg_sphere_bootrc rm   \
        --sphere "$sphere_name" --sphereroot "$___X_CMD_PKG_ROOT_SPHERE"    \
        --osarch "$osarch" "$name" || return $?

    ___x_cmd_pkg_sphere_fastboot rm \
        --sphere "$sphere_name" --sphereroot "$___X_CMD_PKG_ROOT_SPHERE"    \
        --osarch "$osarch" "$name"
}
___x_cmd_pkg_sphere_link_rm___run(){
    local link_dir="$___X_CMD_PKG_ROOT_SPHERE/$sphere_name/.x-cmd/link/${name}_${version}"
    local link_file="$link_dir/association"

    if [ -f "$link_file" ]; then
        pkg:info "Attempting to unlink $name $version of the bin/ lib/ man/ file"
        local target
        while ___x_cmd_readr target;do
            [ -f "$target" ] || continue
            pkg:debug "unlink path => $target"
            ___x_cmd rmrf "$target"
        done < "$link_file"

        ___x_cmd rmrf "$link_file"
        ! ___x_cmd fsiter --dirempty "$link_dir" || ___x_cmd rmrf "$link_dir"
    fi
}

# EndSection

___x_cmd_pkg_sphere_link_exist(){
    pkg:sphere:parse:args
    local link_dir="$___X_CMD_PKG_ROOT_SPHERE/$sphere_name/.x-cmd/link/${name}_${version}"
    local link_file="$link_dir/association"
    [ -f "$link_file" ]
}

___x_cmd_pkg_sphere_link_get_version_(){
    pkg:sphere:parse:option
    sphere_name="${sphere_name:-X}"
    local name="$1";    [ -n "$name" ] || N=pkg M="Provide a package name" log:ret:1
    local i; local version=""; x_=""
    for i in "$___X_CMD_PKG_ROOT_SPHERE/$sphere_name/.x-cmd/link/"*; do
        version="${i#"$___X_CMD_PKG_ROOT_SPHERE/$sphere_name/.x-cmd/link/${name}_"}"
        [ "$i" = "$version" ] || {
            x_="$version"
            return 0
        }
    done
    return 1
}

___x_cmd_pkg_sphere_link_ls(){
    pkg:sphere:parse:option
    sphere_name="${sphere_name:-"X"}"
    local link_dir="$___X_CMD_PKG_ROOT_SPHERE/$sphere_name/.x-cmd/link"
    [ -d "$link_dir" ] || return 0
    local i; for i in "$link_dir"/*; do
        [ ! -f "$i/association" ] || printf "%s\n" "$i"
    done 2>/dev/null
}

___x_cmd_pkg_sphere_link___list_all_path_dir(){
    local name="$1";    local version="$2";    local osarch="$3";   local tgt="$4";
    local _path="${5:-bin}";    local sociality="$6"
    [ -n "$sociality" ] || {
        local x_=; ___x_cmd_pkg_sphere_sociality get_ "$name" "$version" "$osarch" || return $?
        sociality="$x_"
    }

    local path_dir
    ___x_cmd_pkg___list "$name" "$version" "$osarch" "path.$_path" | while ___x_cmd_readr path_dir; do
        [ -n "$path_dir" ] || continue

        case "$path_dir" in
            shim_bin)
                path_dir="$tgt/shim_bin"
                [ ! -d "$tgt/adaptive_shim_bin" ] || { [ "$sociality" != adaptive ] && [ "$sociality" != dev ]; } || path_dir="$tgt/adaptive_shim_bin"
                ;;
            \.) path_dir="$tgt" ;;
            *)  path_dir="$tgt/$path_dir";;
        esac

        printf "%s\n" "$path_dir"
    done
}

___x_cmd_pkg_sphere_link___list_all_path_expand(){
    local path_dir=; local filename=
    ___x_cmd_pkg_sphere_link___list_all_path_dir "$@" | while ___x_cmd_readr path_dir; do
        [ -d "$path_dir" ] || {
            pkg:warn "Not found $path_dir directory"
            continue
        }

        ___x_cmd fsiter "$path_dir" | while ___x_cmd_readr filename; do
            [ -z "$filename" ] || printf "%s\n" "$path_dir/$filename"
        done
    done
}
