#!/usr/bin/env bash

# Unofficial Bash Strict Mode
# http://redsymbol.net/articles/unofficial-bash-strict-mode/
set -euo pipefail
IFS=$'\n\t'
# End of Unofficial Bash Strict Mode

# defaults
mode="s"
list="0"
verbose=0
# defaults

# Helper functions
verbose() {
    (( verbose == 0 )) && return
    printf -- "$@"
    printf '\n'
}
die() {
    printf -- "$@" >&2
    printf '\n' >&2
    exit 1
}

show_help_and_die() {
    error_message="${1:-}"
    help_message="Syntax:
    $0 [-a] [-l] [-v] PANE_MATCHER LIST OF STRINGS

Options:
    -a : Enables matching across all sessions, not only current.
    -l : List all matching panes and exit, don't send any keys.
    -v : Print verbose information while working.

Arguments:
    PANE_MATCHER    : Regular expression (compatible with egrep), that will be
                      used to select panes that should be processed.  Without
                      -a, panes are listed only from current session, and have
                      format:
                      WINDOW_NAME.PANE_INDEX
                      With -a, panes are listed from all sessions, and have
                      format:
                      SESSION_NAME:WINDOW_NAME.PANE_INDEX
    LIST OF STRINGS : What should be sent to all selected panes."

    if [[ -n "${error_message}" ]]
    then
        printf "Error:\n    %s\n\n" "${error_message}" >&2
        echo "${help_message}" >&2
        exit 1
    fi

    echo "${help_message}"
    exit 0
}
# Helper functions

# MAIN PROGRAM

## Make sure we're under tmux
[[ -n "${TMUX_PANE:-}" ]] || die "You have to run $0 under Tmux!"
current_tmux_session="$( tmux display-message -p -t "${TMUX_PANE}" "#S" )"
## Make sure we're under tmux

## Parse and validate command line arguments
while getopts 'alvh?' opt "$@"
do
    case "${opt}" in
        a)
            mode="a"
            ;;
        v)
            verbose=1
            ;;
        l)
            list=1
            ;;
        h|?)
            show_help_and_die
            ;;
    esac
done

shift $((OPTIND - 1))
matcher="${1:-}"
[[ -n "${matcher}" ]] || show_help_and_die "You didn't provide PANE_MATCHER?!"
shift
(( list < 1 )) && (( $# < 1 )) && show_help_and_die "You didn't provide LIST OF STRINGS?!"
list_of_strings=( "$@" )
## Parse and validate command line arguments

verbose 'Current tmux session: %s' "${current_tmux_session}"

## Get list of panes
if [[ "${mode}" == "s" ]]
then
    full_pane_list="$( tmux list-panes -s -F $'#D\t#W.#P' | sort -t$'\t' -V -k 2,2 )"
else
    full_pane_list="$( tmux list-panes -a -F $'#D\t#S:#W.#P' | sort -t$'\t' -V -k 2,2 )"
fi
## Get list of panes

## Find matching panes
target_pane_ids=()
target_pane_names=()
while read -r pane_id pane_name
do
    [[ "${pane_name}" =~ $matcher ]] || continue

    target_pane_ids+=( "${pane_id}" )
    target_pane_names+=( "${pane_name}" )
done <<< "${full_pane_list}"
## Find matching panes

(( 0 == "${#target_pane_ids[@]}" )) && die "There are no matching panes."

if (( "${list}" == 1 ))
then
    echo "List of matching panes:"
    echo "======================="
    i=0
    while (( i < ${#target_pane_ids[@]} ))
    do
        printf -- "- %s\n" "${target_pane_names[$i]}"
        (( ++i ))
    done
    exit 1
fi

verbose "Sending to matching panes:"
verbose "- %s\n" "${list_of_strings[@]}"
verbose "Delivering to:"
i=0
while (( i < ${#target_pane_ids[@]} ))
do
    verbose '>> %s' "${target_pane_names[$i]}"
    tmux send-keys -t "${target_pane_ids[$i]}" "${list_of_strings[@]}"
    (( ++i ))
done

exit 0

# vim: set ft=sh:
