#!/bin/ksh -p

PRG=`basename $0`

usage ()
  {
  typeset u="Usage: $PRG (-h hh -m mm -s ss | [+][hh:]mm[:ss] args"
  cat 1>&2 <<-EnD
	$u

	Uses mdisplay to show a window on the screen containing the text of
	args; if one of the args is - (after a - or --) it also picks up text
	from stdin.

	    [hh:]mm[:ss]: interpreted as mm, hh:mm or hh:mm:ss; if preceded
	    by a '+', this is relative to the current time.

	EnD
  }

dieERR ()
  {
  usage "Internal error"
  exit 1
  }

trap ERR dieERR

# make sure hh, mm, ss etc treated as decimal integers!
typeset -i10 hh=0 mm=0 ss=0
typeset -i10 now_hh=0 now_mm=0 now_ss=0

have_time=n
add_time=n
ns=0
display=$DISPLAY

while getopts :d:h:m:s:0123456789: opt
do
    case $opt in
    d)  display=$OPTARG
        ;;
    h)  hh=$OPTARG
        have_time=y
        add_time=y
        ;;
    m)  mm=$OPTARG
        have_time=y
        add_time=y
        ;;
    s)  ss=$OPTARG
        have_time=y
        add_time=y
        ;;
    +[0-9])
        shift $((OPTIND - 1))
        arg1="${opt}$OPTARG"
        OPTIND=1
        break
        ;;
    \?)
        usage "Invalid option -$opt $OPTARG"
        exit 1
        ;;
    *)
        usage "Invalid option -$opt $OPTARG"
        exit 1
        ;;
    esac
done
[[ $OPTIND -gt 1 ]] && shift $((OPTIND - 1))

no_shift=n

val='tailval=""'
tailval=''

if [[ $# -gt 0 && "$have_time" != y ]]; then
  case "$1" in
    +[0-9][0-9]:[0-9][0-9]:[0-9][0-9])
        add_time=y
        val=`echo "$1" | sed -e 's/+/hh=/' -e 's/:/ mm=/' -e 's/:/ ss=/'`
        ;;
    [0-9][0-9]:[0-9][0-9]:[0-9][0-9]*)
        # absolute time - anything at the end to be checked for am/pm
        val=`echo "$1" | sed -e 's/^/hh=/' -e 's/:/ mm=/' -e 's/:/ ss=/'`
        tailval=${val#hh=?? mm=?? ss=??}
        val="${val%$tailval}"
        ;;
    +[0-9][0-9]:[0-9][0-9])
        add_time=y
        [[ $have_time = y ]] && usage "Time specified twice" && exit 1
        val=`echo "$1" | sed -e 's/+/hh=/' -e 's/:/ mm=/'`
        ;;
    [0-9][0-9]:[0-9][0-9]*)
        # absolute time - anything at the end to be checked for am/pm
        val=`echo "$1" | sed -e 's/^/hh=/' -e 's/:/ mm=/'`
        tailval=${val#hh=?? mm=??}
        val="${val%$tailval}"
        ;;
    +[0-9][0-9])
        add_time=y
        [[ $have_time = y ]] && usage "Time specified twice" && exit 1
        val=`echo "$1" | sed -e 's/+/mm=/'`
        ;;
    [0-9][0-9])
        [[ $have_time = y ]] && usage "Time specified twice" && exit 1
        val=`echo "$1" | sed -e 's/^/mm=/'`
        hh=`date +%H`
        ;;
    *)
        no_shift=y
        ;;
  esac

  [[ "$no_shift" != y ]] && shift

elif [[ $have_time != y ]]; then
  usage No arguments given && exit 1
fi

eval "$val"

if [[ -n "$tailval" ]]; then
    case "$tailval" in
        [aA][mM])   : ;;
        [pP][mM])   [[ $hh -le 12 ]] && hh=$((hh + 12)) ;;
        *)          set -- "$tailval" "$@" ;;
    esac
fi

typeset -i10 rel_secs=$(( ss + 60 * ( mm + ( 60 * hh ) ) ))
typeset -i10 abs_secs=0

# get absolute time
eval $(date '+now_hh=%H now_mm=%M  now_ss=%S start="%a %T"')
abs_secs=$(( now_ss + 60 * ( now_mm + ( 60 * now_hh ) ) ))

if [[ "$add_time" != y ]]; then
    while (( abs_secs > rel_secs )); do
        rel_secs=$((rel_secs + 86400))
    done

    rel_secs=$((rel_secs - abs_secs))
fi

# echo relative_time=$add_time hh=$hh mm=$mm ss=$ss
# echo rel_secs=$rel_secs

if (( rel_secs < 0 )); then
    usage "specified time in the past"
    exit
fi

# assemble other arguments
message=""
sp=""
for arg in "$@"; do
    if [[ "x$arg" = "x-" ]]; then
        message="$message$sp`cat`"
    else
        message="$message$sp$arg"
    fi
    sp=' '
done

# do we have a display
if [[ -z "$display" || "$display" != *:* ]]; then
    usage "No known X display (you can add '-d display-name')"
    exit 1
fi

# to fire when?
abs_secs=$((abs_secs + rel_secs))
dd=$(( abs_secs / 86400 ))
hh=$(( ( abs_secs / 3600 ) % 24 ))
mm=$(( ( abs_secs / 60 ) % 60 ))
ss=$(( abs_secs % 60 ))
target=$(printf '%02d:%02d:%02d' $hh $mm $ss)
[[ $dd -gt 0 ]] && dd=" (+$dd days)" || dd=""

lines=$(echo "$message" | wc -l)
cols=$(echo "$message" | awk '{n=length($0);l=l<n?n:l} END {print l}')

title="from $start for $target$dd"
echo "Alarm $title" 1>&2

trap '' TERM HUP

# now issue our command - mdisplay only shows its window when it receives data

setsidbg ksh -c "
exec >/dev/null 2>&1
untrapTERM () { trap - TERM HUP; }
trap untrapTERM TERM HUP
(sleep $rel_secs; printf '%s' '${message:-Alarm $title}') | \
mdisplay -icontitle '$target $PRG' \
         -title '$PRG (from $start for $target)' \
         -pb2label '' \
         -columns $cols \
         -rows $lines \
         -bg red \
         -display '$display'
"
