#!/usr/bin/env bash

# Reading the optional-application catalog.
#
# Sourced by both front doors -- the interview's checklist during ./install, and
# `panama apps` afterwards -- so the two can never disagree about what exists.
# One catalog, parsed once, here.
#
# The format is one file per category under setup/packages/extras/, and a line
# is one of:
#
#   gimp                              a dnf package
#   flatpak:org.gimp.GIMP             a Flathub id
#   flatpak:com.slack.Slack | Slack   either, with a name for the menu
#       flatpak:com.obsproject.Studio.Plugin.SceneSwitcher
#
# An indented line belongs to the entry above it and is installed with it, which
# is how OBS carries its sixteen plugin extensions as a single thing to tick
# rather than seventeen. Comments and blank lines are ignored.
#
# Without an explicit name, the menu derives one from the last dotted component
# of a Flathub id, or uses the package name as it stands.

# Every category name, one per line.
catalog_categories() {
    local dir="$1" file
    for file in "$dir"/*; do
        [[ -f "$file" ]] && basename "$file"
    done
}

# The selectable entries in one category, as `target<TAB>label`. Indented
# continuation lines are folded into the entry above and never listed.
catalog_entries() {
    local file="$1" line target label
    while IFS= read -r line; do
        line="${line%%#*}"
        [[ "$line" =~ ^[[:space:]]*$ ]] && continue
        [[ "$line" =~ ^[[:space:]] ]] && continue

        if [[ "$line" == *"|"* ]]; then
            target="${line%%|*}"
            label="${line#*|}"
        else
            target="$line"
            label=""
        fi
        target="${target#"${target%%[![:space:]]*}"}"; target="${target%"${target##*[![:space:]]}"}"
        label="${label#"${label%%[![:space:]]*}"}"; label="${label%"${label##*[![:space:]]}"}"

        if [[ -z "$label" ]]; then
            label="${target#flatpak:}"
            [[ "$target" == flatpak:* ]] && label="${label##*.}"
        fi
        printf '%s\t%s\n' "$target" "$label"
    done <"$file"
}

# Every install target for one entry: the entry itself, then the indented lines
# beneath it. Called with the category file and the entry's target.
catalog_targets() {
    local file="$1" want="$2" line target seen=0
    while IFS= read -r line; do
        line="${line%%#*}"
        [[ "$line" =~ ^[[:space:]]*$ ]] && continue

        if [[ "$line" =~ ^[[:space:]] ]]; then
            (( seen == 1 )) || continue
            line="${line#"${line%%[![:space:]]*}"}"
            printf '%s\n' "${line%%|*}" | sed 's/[[:space:]]*$//'
            continue
        fi

        target="${line%%|*}"
        target="${target#"${target%%[![:space:]]*}"}"; target="${target%"${target##*[![:space:]]}"}"
        if [[ "$target" == "$want" ]]; then
            seen=1
            printf '%s\n' "$target"
        elif (( seen == 1 )); then
            break
        fi
    done <"$file"
}

# Every install target in a whole category, in file order.
catalog_all_targets() {
    local file="$1" line
    while IFS= read -r line; do
        line="${line%%#*}"
        [[ "$line" =~ ^[[:space:]]*$ ]] && continue
        line="${line#"${line%%[![:space:]]*}"}"
        line="${line%%|*}"
        printf '%s\n' "${line%"${line##*[![:space:]]}"}"
    done <"$file"
}

# Is this target already on the machine? Used to mark the menu, never to skip
# silently -- a re-run that reinstalls what is present is harmless, but a menu
# that hides it is confusing.
catalog_installed() {
    local target="$1"
    if [[ "$target" == flatpak:* ]]; then
        flatpak info "${target#flatpak:}" >/dev/null 2>&1
    else
        rpm -q "$target" >/dev/null 2>&1
    fi
}
