#!/usr/bin/bash
#shellcheck disable=SC1090

. "$(sfpath)" || exit 3

shellfu import pretty
shellfu import saturnin

shellfu import bmo_be

usage() {
    mkusage "$@" \
        "--move AXIS:SPOT"                                      \
        "--lsspots [AXIS]"                                      \
        "--lsaxes"                                              \
        "--lssxprs"                                             \
        "--stat [AXIS]"                                         \
        "--leave AXIS"                                          \
        "[--] SXPR.."                                           \
      -c \
        "--move AXIS:SPOT   move on axis AXIS to spot SPOT"     \
        "--lsaxes           list available axes"                \
        "--lsspots [AXIS]   list spots on AXIS or all"          \
        "--lssxprs          list possible SXPRs"                \
        "--stat [AXIS]      show state of AXIS or all"          \
        "--leave AXIS       leave current spot on AXIS"         \
        "[--] SXPR          parse smart expression and move one"\
        "                   or more axes"                       \
      -o \
        "-n                 Enable dry mode -- don't actually"  \
        "                   change state, just show commands"   \
        "                   that would be used to do so."       \
      -- \
        "SXPR consists of single-character SIGIL which is just" \
        "a convenience symbol for an axis; and SPOT, which"     \
        "specifies desired state on that axis.  SXPR can be"    \
        "provided to move on more than one axes."               \
        ""                                                      \
        "There are three pre-defined axes: '%' is 'role', '@'"  \
        "is 'place' and '=' is 'feel'.  For example, command"   \
        "'bmo be @home %watching' would move axis 'place' to"   \
        "'home' and 'role' to 'watching'."
}


validate_axis() {
    #
    # Warn if AXIS $1 is not valid
    #
    bmo_be__isa_axis "$axis" && return 0
    warn "undefined axis: $axis"
    return 3
}

validate_spot() {
    #
    # Warn if AXIS:SPOT $1 not valid
    #
    bmo_be__isa_spot_on "$axis" "$spot" && return 0
    warn "no such spot on axis: $axis:$spot"
    return 3
}

do_leave() {
    #
    # Leave current spot on AXIS
    #
    local axis=$1
    test -n "$axis" || usage -w "no AXIS?"
    test $# -gt 1   && usage -w "too many args: $*"
    validate_axis "$axis"       || return 3
    bmo_be__leave "$axis" \
     || die "failed to leave axis: $axis"
}

do_lsaxes() {
    #
    # List axes
    #
    bmo_be__lsaxes
}

do_lsspots() {
    #
    # List spots on axis $1 or all
    #
    local axis=$1
    test -n "$axis" || { bmo_be__lsspots; return; }
    validate_axis "$axis" || return 3
    bmo_be__lsspots "$axis" \
      | cut -d: -f2
}

do_lssxprs() {
    #
    # List possible SXPRs
    #
    local axis
    local spot
    local sigil
    for axis in $(bmo_be__lsaxes); do
        sigil=$(bmo_be__a2s "$axis")
        test -n "$sigil" || continue
        bmo_be__lsspots "$axis" \
          | cut -d: -f2 \
          | while read -r spot; do
                echo "$sigil$spot"
            done
    done
}

do_move() {
    #
    # Try to move to the right $spot on $Axis
    #
    local point=$1
    local axis
    local spot
    grep -qxE '\w+:\w+' <<<"$point" \
     || usage -w "bad syntax: $point"
    axis=${point%:*}
    spot=${point#*:}
    validate_axis "$axis"       || return 3
    validate_spot "$axis:$spot" || return 3
    bmo_be__move "$axis" "$spot" \
     || die "failed to move: to '$axis:$spot'"
}

do_stat() {
    #
    # Show state of axis $1 or all
    #
    local axis=$1
    local axes=()
    if test -n "$axis"; then
        validate_axis "$axis" || return 3
        bmo_be__state "$axis"
    else
        mapfile -t axes <<<"$(bmo_be__lsaxes)"
        for axis in "${axes[@]}"; do
            bmo_be__state "$axis" \
              | sed "s/^/$axis:/"
        done
    fi
}

do_sxpr() {
    #
    # Try parsing smart sigil expression
    #
    local sxpr
    local axis
    local sigil
    local spot
    for sxpr in "$@"; do
        sigil=${sxpr:0:1}
        spot=${sxpr:1}
        debug -v sigil spot
        axis=$(bmo_be__s2a "$sigil") \
         || die "unknown sigil: $sigil"
        validate_spot "$axis:$spot" || return 3
        think "axis selected: '$sigil' => $axis"
        bmo_be__move "$axis" "$spot"
    done
}

like_sxpr() {
    #
    # True if $1 is a valid expression
    #
    local maybe_sxpr=$1
    grep -qE "^[^[:alnum:]][[:alnum:]_]+" <<<"$maybe_sxpr"
}

main() {
    local cmd
    local Dry=false
    while true; do case $1 in
        -n)         Dry=true;    shift ;;
        --move)     cmd=move;    shift; break ;;
        --leave)    cmd=leave;   shift; break ;;
        --lsspots)  cmd=lsspots; shift; break ;;
        --lsaxes)   cmd=lsaxes;  shift; break ;;
        --lssxprs)  cmd=lssxprs; shift; break ;;
        --stat)     cmd=stat;    shift; break ;;
        --)         cmd=sxpr;    shift; break ;;
        --*) usage -w "unknown argument: $1"  ;;
        -*)  usage -w "unknown argument: $1"  ;;
        *)   break ;;
    esac done
    if test -n "$cmd"; then
        __BMO_BE__DRY=$Dry \
            "do_$cmd" "$@"
    elif test -n "$1"; then
        like_sxpr "$1" \
         || usage -w "need a command or SXPR: $1"
        __BMO_BE__DRY=$Dry \
            "do_sxpr" "$@"
    else
         usage -w "need a command or SXPR: $1"
    fi
}

saturnin__wraphook main "$@"
