#!/bin/sh

#exec 2>> /tmp/bgrun.stderr
#set -x

SELF="${0##*/}"

TEMPDIR=
TEMPRUNDIR=.tempdir-run.d
cleanup() {
  if [ -d $TEMPRUNDIR ]; then
    local TEMPDIR; TEMPDIR="$PWD"
    notify_output
    cd /
    rm -rf "$TEMPDIR"
  fi
  trap - 1 2 3 4 5 6 7 8 10 11 12 13 14 15
}
trap cleanup 1 2 3 4 5 6 7 8 10 11 12 13 14 15

enter_tempdir() {
  if [ -d $TEMPRUNDIR ]; then
    return

  else
    if [ -z "${TMPDIR:-}" ]; then
      TMPDIR=/tmp
    fi
    for i in $LOGNAME volatile; do
      if [ -d "${TMPDIR}/$i" ]; then
        TMPDIR="${TMPDIR}/$i"
        break
      fi
    done
    cd $(mktemp -dp "$TMPDIR" mutt.XXXXXXXXXX)
    mkdir $TEMPRUNDIR
  fi
}

notify() {
  if [ -x "$(command -v awesome-client)" ]; then
    local stdout stderr escaped output
    stdout="${2:-}"
    stderr="${3:-}"
    for i in stdout stderr; do
      if eval test -s $TEMPRUNDIR/output.$i; then
        escaped=$(eval sed -e 's,\",\\\",g' $TEMPRUNDIR/output.$i)
        output="${output:+$output
}${i}:
$escaped"
      fi
    done
    [ -n "${escaped:-}" ] || return
    awesome-client <<-_eof
	local naughty = require("naughty")
	naughty.notify({ preset = naughty.config.presets.low,
		title  = "${1:-Output from mutt/$SELF}",
		text   = [[$output]]
		})
	_eof
  fi
}

notify_output() {
  [ -d $TEMPRUNDIR ] || return
  local stdout stderr anything

  for i in stdout stderr; do
    if [ -s "$TEMPRUNDIR/output.$i" ]; then
      eval $i="'$TEMPRUNDIR/output.$i'"
    else
      eval $i=/dev/null
    fi
  done

  notify "Output from mutt/$SELF" $stdout $stderr
}

guess_extension() {
  python3 -c "import mimetypes; print(mimetypes.guess_extension('$1'))"
}

get_file() {
  local t
  if [ -z "$1" ]; then
    t=$(mktemp -p "$PWD" tmp.XXXXXXXXXX$(guess_extension "$MIMETYPE"))
    cat > "$t"
    echo "$t"
  else
    t="$(echo -n ${1##*/} | sed -re 's![^[:alnum:],.@%^+=_-]!_!gi')"
    ln "$1" "$t" 2>/dev/null || cp "$1" "$t"
    echo "$PWD/$t"
  fi
}

MIMETYPE= FILENAME= VIEWER= DELAY=1
state=
for arg in "$@"; do
  case "$state/$arg" in

    (/-t) state=t;;
    (t/*) MIMETYPE="$arg"; state=;;

    (/-f) state=f;;
    (f/*) FILENAME="$arg"; state=;;

    (/-d) state=d;;
    (d/*) DELAY="$arg"; state=;;

    (/-v) state=v;;
    (v/*) VIEWER="$arg"; state=;;

    (*)
      echo >&2 "E: Invalid argument: $i"
      exit 1
      ;;

  esac
done

launch_viewer() {
  local filename; filename="$1"
  if [ -z "$VIEWER" ]; then
    [ -n "${2:-}" ] && filename="${2}:${1}"
    run-mailcap "$filename" > $TEMPRUNDIR/output.stdout 2> $TEMPRUNDIR/output.stderr
  else
    $VIEWER "$filename" > $TEMPRUNDIR/output.stdout 2> $TEMPRUNDIR/output.stderr
  fi
}

case "$SELF" in
  (bgview)
    # make a copy of the file, then launch a shell process in the background
    # to divert to run-mailcap, after which the temporary directory gets
    # cleaned up.
    enter_tempdir
    FILE="$(get_file "$FILENAME")"
    (
      ts=$(($(date +%s) + $DELAY))
      launch_viewer "$FILE" "$MIMETYPE"
      while [ $(date +%s) -lt $ts ]; do sleep 1; done
      cleanup
    ) &
    trap - 1 2 3 4 5 6 7 8 10 11 12 13 14 15
    ;;
  (bgview-fifo)
    # hack to stay around until the viewer has read the file: make a fifo and
    # wait for the cat process to finish writing to it, which means that it
    # must have been consumed on the other end.
    enter_tempdir
    FILE="$(get_file "$FILENAME")"
    FIFO="fifo-${FILE##*/}"
    mkfifo "$FIFO"
    cat "$FILE" > "$FIFO" &
    # For some reason, we do have to write a tempfile and cannot seem to
    # redirect stdin directly to the fifo, i.e. this does not work instead of
    # the previous three lines:
    ## cat > "$FIFO" &
    launch_viewer "$FIFO" "$MIMETYPE"
    wait
    cleanup
    ;;
  (bgview-delay)
    # hack to stay around until the file hasn't been accessed for a few
    # seconds, so that we can clean up. This is for cases when the FIFO method
    # doesn't work, because e.g. Firefox randomly chooses it needs to read
    # HTML files twice.
    enter_tempdir
    FILE="$(get_file "$FILENAME")"
    touch "$FILE"
    (launch_viewer "$FILE" "$MIMETYPE") &
    (
      while [ $(($(stat -c%X "$FILE") + $DELAY)) -gt $(date +%s) ]; do
        sleep 1
      done
      cleanup
    ) &
    trap - 1 2 3 4 5 6 7 8 10 11 12 13 14 15
    ;;
esac