#!/bin/bash

NOTIFY="notify-send -t 500 -i"
NOTIFY_UNMUTED="$NOTIFY audio-volume-high-panel"
NOTIFY_MUTED="$NOTIFY audio-volume-muted-panel"
main() {
    if [[ -z "$1" ]]; then
        usage 1 "specify an application name"
    fi
    local action=toggle
    while getopts :muq option; do 
        case "$option" in 
            m) action=mute ;;
            u) action=unmute ;;
            q) action=query ;;
            ?) usage 1 "invalid option: -$OPTARG" ;;
        esac
    done
    shift $((OPTIND - 1))
    $action "$1"
}

usage() {
    [[ "$2" ]] && echo "error: $2"
    echo "Usage: $0 [-m | -u] appname"
    echo "Default: toggle mute"
    echo "Arguments:"
    echo "-m = mute application"
    echo "-u = unmute application"
    echo "-q = query application's muted/unmuted status"
    exit $1
}

toggle() {
    local status=$(get_status "$1")
    if [[ "$status" == "yes" ]]; then
        unmute "$1"
        echo "unmuted $1"
        $NOTIFY_UNMUTED "$1"
    elif [[ "$status" == "no" ]]; then
        mute "$1"
        echo "muted $1"
        $NOTIFY_MUTED "$1"
    else 
        adjust_brutally "$1"
    fi
}
query() {
    local status=$(get_status "$1")
    if [[ "$status" == "yes" ]]; then
        echo "muted"
    elif [[ "$status" == "no" ]]; then
        echo "unmuted"
    else 
        query_brutally "$1"
    fi
}

mute()   { adjust_muteness "$1" 1; }
unmute() { adjust_muteness "$1" 0; }

adjust_muteness() { 
    local index=$(get_index "$1")
    if [[ -z "$1" ]]; then
        adjust_brutally
        exit
    fi
    local status=$(get_status "$1")
    [[ "$index" ]] && pacmd set-sink-input-mute "$index" $2 >/dev/null 
}

query_brutally() {
    local id=$(pacmd info | grep -m1 application.process.machine_id | cut -d\" -f 2)
    if [[ ! -r "$HOME/.pulse/$id-stream-volumes.tdb" ]]; then
        echo "error: could not get host stream volumes" >&2
        exit 1
    fi
    local volumes="$HOME/.pulse/$id-stream-volumes.tdb"
    local status=$(get_raw_status "$volumes" "$1")
    if [[ -z "$status" ]]; then
        echo "error: could not get volume status of $1" >&2
        exit 1
    fi
    if [[ "$status" == "B\010m\00v\00110N0N" ]]; then
        echo "muted"
    elif [[ "$status" == "B\010m\00v\00100N0N" ]]; then
        echo "unmuted"
    else
        echo "error: unrecognized status of $1: $status" >&2
        exit 1
    fi
}
adjust_brutally() {
    local id=$(pacmd info | grep -m1 application.process.machine_id | cut -d\" -f 2)
    if [[ ! -r "$HOME/.pulse/$id-stream-volumes.tdb" ]]; then
        echo "error: could not get host stream volumes" >&2
        exit 1
    fi
    local volumes="$HOME/.pulse/$id-stream-volumes.tdb"
    local status=$(get_raw_status "$volumes" "$1")
    if [[ -z "$status" ]]; then
        echo "error: could not get volume status of $1" >&2
        exit 1
    fi
    local new_status=undefined
    if [[ "$status" == "B\010m\00v\00110N0N" ]]; then
        new_status="B\010m\00v\00100N0N"
        echo "(brutally) unmuted $1"
        $NOTIFY_UNMUTED "$1"
    elif [[ "$status" != "B\010m\00v\00100N0N" ]]; then
        echo "error: unrecognized status of $1: $status" >&2
        exit 1
    else
        new_status="B\010m\00v\00110N0N"
        echo "(brutally) muted $1"
        $NOTIFY_MUTED "$1"
    fi
    local key="sink-input-by-application-name:$1"
    tdbtool "$volumes" store "sink-input-by-application-name:$1" $new_status > /dev/null
}
get_raw_status() {
    echo $(tdbdump "$1" | grep -A 1 "sink-input-by-application-name:$2" | tail -1 | cut -d\" -f 2)
}
get_index() {
    local name="$1"
    pacmd list-sink-inputs | 
    awk -v name=$name '
    $1 == "index:" {idx = $2} 
    $1 == "application.name" && $3 == "\"" name "\"" {print idx; exit}
    '
}

get_status() {
   local name="$1"
   pacmd list-sink-inputs | 
   awk -v name=$name '
   $1 == "muted:" {idx = $2} 
   $1 == "application.name" && $3 == "\"" name "\"" {print idx; exit}
   '
}

main "$@"
