#!/bin/bash
# aur-search - search for AUR packages
[[ -v AUR_DEBUG ]] && set -o xtrace
argv0=search
AUR_LOCATION=${AUR_LOCATION:-'https://aur.archlinux.org'}
PS4='+(${BASH_SOURCE}:${LINENO}): ${FUNCNAME[0]:+${FUNCNAME[0]}(): }'

# default options
multiple=section search_by=name-desc sort_key=Name type=search mode=query color=auto

# default arguments
query_args=()

hyperlink() {
    local uri=$1 mesg=$2

    # Interpret escapes with %b for "dumb" terminals (#1001)
    printf "\e]8;;%s\e\\%b\e]8;;\e\\" "$uri" "$mesg"
}

tabulate() {
    # It is important to have a default value for every field, or
    # parsing of the @tsv result might break.
    # See: https://lists.gnu.org/archive/html/help-bash/2016-05/msg00041.html
    # For arrays, individual elements have to be checked as well.
    # See: https://gitlab.archlinux.org/archlinux/aurweb/-/issues/332
    jq -r --arg key "$1" '
        def sel_join:
            if length > 0 then
                map(if . == "" then "-" else . end) | join(" ")
            else
                "-"
            end;

        [.results[]] | sort_by(.[$key])[] | [
            .Name        // "-",
            .PackageBase // "-",
            .Version     // "-",
            .Description // "-",
            .URL         // "-",

            (.Keywords | sel_join),
            (.License  | sel_join),

            .Maintainer  // "-",
            .NumVotes    // "-",
            .Popularity  // "-",
            .OutOfDate   // "-",

            (.FirstSubmitted | todate),
            (.LastModified   | todate),
            (.Depends        | sel_join),
            (.MakeDepends    | sel_join),
            (.CheckDepends   | sel_join),
            (.OptDepends     | sel_join)
        ] | @tsv'
}

info_long() {
    local -a desc=(
        'Name'
        'Base'
        'Version'
        'Description'
        'URL'
        'Keywords'
        'License'
        'Maintainer'
        'Votes'
        'Popularity'
        'Out Of Date'
        'Submitted'
        'Last Modified'
        'Depends On'
        'Makedepends'
        'Checkdepends'
        'Optdepends'
    )
    local -a info

    while IFS=$'\t' read -r -a info; do
        printf "$BOLD%s:$ALL_OFF\\t%s\\n" "AUR URL" "$AUR_LOCATION/packages/${info[0]}"

        for i in "${!info[@]}"; do
            printf "$BOLD%s:$ALL_OFF\\t%s\\n" "${desc[i]}" "${info[i]}"
        done

        # column(1) ignores empty lines (package delimitation)
        printf '%s\n' '-'
    done
}

info_short() {
    local Name Version NumVotes Popularity Maintainer OutOfDate Description Url Link

    while IFS=$'\t' read -r Name _ Version Description _ _ _ Maintainer NumVotes Popularity OutOfDate _; do
        case $OutOfDate in
            -) unset OutOfDate ;;
            *) printf -v OutOfDate '(Out-of-date: %(%d %B %Y)T)' "$OutOfDate"
        esac

        case $Maintainer in
            -) Maintainer='(Orphaned) ' ;;
            *) unset Maintainer ;;
        esac

        # Unset LC_ALL to ensure it doesn't override LC_NUMERIC.
        LC_ALL='' LC_NUMERIC=C printf -v Popularity '%.2f' "$Popularity"

        Url="${AUR_LOCATION}/packages/${Name}"
        Link="$(hyperlink "$Url" "${BLUE}aur/${ALL_OFF}${BOLD}${Name}")"

        printf "%s ${GREEN}%s ${ALL_OFF}(+%s %s%%) ${RED}%s%s${ALL_OFF}\\n    %s\\n" \
               "$Link" "$Version" "$NumVotes" "$Popularity" "$Maintainer" "$OutOfDate" "$Description"
    done
}

usage() {
    plain >&2 'usage: %s [-adimnqrsv] [-k key] pkgname...' "$argv0"
    exit 1
}

source /usr/share/makepkg/util/message.sh
source /usr/share/makepkg/util/parseopts.sh

opt_short='k:adimnqrsv'
opt_long=('any' 'info' 'search' 'desc' 'maintainer' 'name' 'depends' 'verbose' 'color:'
          'makedepends' 'optdepends' 'checkdepends' 'key:' 'short' 'table' 'json')
opt_hidden=('dump-options' 'raw' 'json-stdin')

if ! parseopts "$opt_short" "${opt_long[@]}" "${opt_hidden[@]}" -- "$@"; then
    usage
fi
set -- "${OPTRET[@]}"

unset format
while true; do
    case "$1" in
        -a|--any)
            multiple=union ;;
        -i|--info)
            type=info ;;
        -s|--search)
            type=search ;;
        -d|--desc)
            search_by=name-desc ;;
        -m|--maintainer)
            search_by=maintainer ;;
        -n|--name)
            search_by=name ;;
        --depends)
            search_by=depends ;;
        --makedepends)
            search_by=makedepends ;;
        --optdepends)
            search_by=optdepends ;;
        --checkdepends)
            search_by=checkdepends ;;
        --color)
            shift; color=$1 ;;
        -q|--short)
            format=short ;;
        -v|--verbose)
            format=long ;;
        --table)
            format=table ;;
        -r|--raw|--json)
            mode=json ;;
        --json-stdin)
            mode=json_stdin ;;
        -k|--key)
            shift; sort_key=$1 ;;
        --dump-options)
            printf -- '--%s\n' "${opt_long[@]}" ${AUR_DEBUG+"${opt_hidden[@]}"}
            printf -- '%s' "${opt_short}" | sed 's/.:\?/-&\n/g'
            exit ;;
        --) shift; break ;;
    esac
    shift
done

# Colored messages on both stdout and stderr may be desired if stdout is not
# connected to a terminal, e.g. when piping to less -R. (#585) When printing to
# a file, they should be disabled instead. Default to `--color=auto` but allow
# specifying other modes.
if [[ ! -v NO_COLOR ]] && [[ ! -v AUR_DEBUG ]]; then
    if [[ $color == 'auto' ]]; then
        [[ -t 1 ]] && colorize

    elif [[ $color == 'always' ]]; then
        colorize

    elif [[ $color != 'none' ]]; then
        printf >&2 '%s: invalid --color mode\n' "$argv0"
        exit 1
    fi
fi

if ! (( $# )) && ! [[ $mode == "json_stdin" ]]; then
    usage
fi

# set format depending on query type (#319)
case $type in
      info) format=${format-long}  ;;
    search) format=${format-short} ;;
esac

# set filters (1)
case $format in
     long) info() { info_long | column -ts $'\t' | sed -E 's/^-//; $d'; } ;;
    short) info() { info_short; } ;;
    table) info() { tee; } ;;
esac

# set filters (2)
case $multiple in
    section) ;; # aur-query default
      union) query_args+=('--any') ;;
esac

case $mode in
    query)
        aur query -t "$type" -b "$search_by" -e "${query_args[@]}" "$@" | tabulate "$sort_key" | info
        exit "${PIPESTATUS[0]}" ;;
    json)
        aur query -t "$type" -b "$search_by" -e "${query_args[@]}" "$@"
        ;;
    json_stdin)
        tabulate "$sort_key" | info
        ;;
esac

# vim: set et sw=4 sts=4 ft=sh:
