#!/bin/bash
# sc-native launcher: finds the StarCraft install to read the game data from (asks the first time),
# then starts the natively built engine.
#   sc-native                 start the game
#   sc-native --choose        pick the StarCraft folder again, then start
#   sc-native --setup [DIR]   only find/ask for the folder and save it (used by the installers)
#   sc-native --find          print the folder that would be used (exit 1 if none)
#   sc-native --selfcheck     run the self-check against that folder
#   sc-native DIR             start with this folder (and remember it)
set -u

here=$(dirname "$(readlink -f "$0")")
libdir=$(readlink -f "$here/../lib/sc-native")
datadir="$HOME/.local/share/sc-native"   # same folder the engine uses for progress and saves
saved="$datadir/install-path.txt"

# A StarCraft (Remastered, version 1.x) install: .build.info and the CASC store in Data/data.
# StarCraft II has the same layout but versions 4.x/5.x.
is_install() {
    local d=$1 version
    [ -n "$d" ] && [ -f "$d/.build.info" ] && [ -d "$d/Data/data" ] || return 1
    version=$(awk -F'|' 'NR == 1 { for (i = 1; i <= NF; i++) if ($i ~ /^Version!/) c = i }
                         NR > 1 && c && $2 == "1" { print $c; exit }' "$d/.build.info" 2>/dev/null)
    [ -z "$version" ] || [ "${version%%.*}" = 1 ]
}

# Accept the install folder itself, its Data folder, or a folder that contains "StarCraft".
normalize() {
    local d=${1%/}
    for c in "$d" "$(dirname "$d")" "$d/StarCraft"; do
        if is_install "$c"; then (cd "$c" && pwd); return 0; fi
    done
    return 1
}

search() {
    local p
    if [ -f "$saved" ]; then
        p=$(head -n 1 "$saved")
        if is_install "$p"; then echo "$p"; return 0; fi
    fi
    for p in "$HOME/Games/battlenet" "$HOME/.wine" "$HOME/Games/battlenet-wine" "$HOME/Games/battle-net" \
             "$HOME/.local/share/lutris/prefixes/battlenet" \
             "$HOME/.var/app/com.usebottles.bottles/data/bottles/bottles/Battle.net"; do
        if is_install "$p/drive_c/Program Files (x86)/StarCraft"; then echo "$p/drive_c/Program Files (x86)/StarCraft"; return 0; fi
    done
    # Other Wine prefixes, game libraries and mounted drives (bounded depth, first match).
    local roots=() r f
    for r in "$HOME/Games" "$HOME/.local/share/lutris" "$HOME/.var/app" "$HOME/.local/share/bottles" \
             "$HOME/.steam/steam/steamapps/compatdata" /media /mnt /run/media; do
        [ -d "$r" ] && roots+=("$r")
    done
    [ ${#roots[@]} -gt 0 ] || return 1
    while IFS= read -r f; do
        if is_install "$(dirname "$f")"; then dirname "$f"; return 0; fi
    done < <(find "${roots[@]}" -maxdepth 7 -name .build.info -path '*StarCraft*' 2>/dev/null)
    return 1
}

message() {  # message <error|info> <text>
    if [ -n "${DISPLAY:-}${WAYLAND_DISPLAY:-}" ] && command -v zenity >/dev/null; then
        zenity "--$1" --title="StarCraft (sc-native)" --width=420 --text="$2" 2>/dev/null
    elif [ -n "${DISPLAY:-}${WAYLAND_DISPLAY:-}" ] && command -v kdialog >/dev/null; then
        kdialog --title "StarCraft (sc-native)" "--$([ "$1" = error ] && echo error || echo msgbox)" "$2"
    else
        echo "$2" >&2
    fi
}

ask() {
    local d
    while :; do
        if [ -n "${DISPLAY:-}${WAYLAND_DISPLAY:-}" ] && command -v zenity >/dev/null; then
            d=$(zenity --file-selection --directory --filename="$HOME/" 2>/dev/null \
                --title="Choose your StarCraft folder (the one with Data and .build.info)") || return 1
        elif [ -n "${DISPLAY:-}${WAYLAND_DISPLAY:-}" ] && command -v kdialog >/dev/null; then
            d=$(kdialog --title "Choose your StarCraft folder" --getexistingdirectory "$HOME") || return 1
        elif [ -t 0 ]; then
            read -r -p "Folder of your StarCraft install (empty to cancel): " d || return 1
            [ -n "$d" ] || return 1
            d=${d/#\~/$HOME}
        else
            return 1
        fi
        if d=$(normalize "$d"); then echo "$d"; return 0; fi
        message error "That folder is not a StarCraft (Remastered) install. Pick the folder that holds .build.info and Data."
    done
}

remember() {
    mkdir -p "$datadir" && printf '%s\n' "$1" > "$saved"
}

choose() {  # find (or ask with --choose) and save; prints the folder
    local d=""
    if [ "${1:-}" != ask ]; then d=$(search) || d=""; fi
    if [ -z "$d" ]; then
        [ "${1:-}" = ask ] || message info "StarCraft was not found automatically. Choose the folder of your StarCraft install; the game reads its data from there (nothing is copied)."
        d=$(ask) || return 1
    fi
    remember "$d"
    echo "$d"
}

case "${1:-}" in
    --find)
        search
        exit $?
        ;;
    --setup)
        if [ -n "${2:-}" ]; then
            d=$(normalize "$2") || { echo "not a StarCraft install: $2" >&2; exit 1; }
            remember "$d"; echo "$d"
        else
            choose
        fi
        exit $?
        ;;
    --selfcheck)
        d=$(search) || d=""
        exec "$libdir/sc_selfcheck" ${d:+"$d"}
        ;;
    --choose)
        game=$(choose ask) || exit 1
        ;;
    -h|--help)
        sed -n '2,9p' "$0" | sed 's/^# \{0,1\}//'
        exit 0
        ;;
    "")
        game=$(choose) || exit 1
        ;;
    *)
        game=$(normalize "$1") || { message error "Not a StarCraft install: $1"; exit 1; }
        remember "$game"
        ;;
esac

exec "$libdir/starcraft" "$game"
