#!/usr/local/gnubin/bash
# leave, 12-Apr-92 Noah Friedman <friedman@prep.ai.mit.edu>
# Last modified 18-Oct-92
#
#    Usage: leave  hh:mm
#           leave +hh:mm
#
# Requires bash 1.12 or later to work properly.
#
# Public domain
#

function usage ()
{
    if [ $# -gt 0 ]; then
       echo -e "${progname}: $*\n" 1>&2
    fi

    cat 1>&2 <<EOF
Usage: ${progname} {-o|--obnoxious}  hh:mm
       ${progname} {-o|--obnoxious} +hh:mm
EOF

   exit 1
}

function main ()
{
    initialize_variables "$@"
    parse_command_args "$@"
    shift $?

    # If this invocation was done by the user, invoke the daemonized
    # process and exit.  This way the user doesn't have to background the
    # process and does't have job control over it. 
    if [ "${daemonp}" ]; then
       do_daemon_tasks "$@"
    else
       do_nondaemon_tasks "$@"
    fi

    exit 0
}

function initialize_variables ()
{
    long_progname="$0"
    progname="${long_progname##*/}"
    tty="$(tty)"
    g=$(echo -e \\7)   # BEL
}

function parse_command_args ()
{
 local orig_number_options=$#

    if [ $# = 0 ]; then
       usage
       exit 1
    fi

    # unset option variables to make sure they weren't accidentally
    # exported 
    unset daemonp obnoxious

    # If you add new commands be sure to change the wildcards below to make
    # sure they are unambiguous (i.e. only match one possible long option)
    # Be sure to show at least one instance of the full long option name to
    # document what the long option is canonically called. 
    while [ $# -gt 0 ]; do
       case z$1 in
          z-h | z--help | z--h* )
             usage
            ;;
          z-o | z--obnoxious | z--o* )
             obnoxious="-o"
             shift
            ;;
          # Not ever meant to be executed by user. 
          # Script re-executes itself with -d option to indicate that it is
          # the background process and does not need to do the work that
          # the foreground one has already done (e.g. execute the daemon
          # process!) 
          z-d )
             daemonp=t
             seconds="$2"
             shift 2
            ;;
          z-- )
             shift
             break
            ;;
          z-* )
             usage "${bq}${1}${eq} is not a valid option."
            ;;
          * )
             break
            ;;
       esac
    done

    # Return number of shifted arguments so calling function can shift
    # appropriate amount.
    return $[ orig_number_options - $# ]
}

# Run background copy of process
function do_nondaemon_tasks ()
{
    seconds="$(compute_sleep_seconds "$@")"
    exit_status="$?"
    if [ ${exit_status} != 0 ]; then
       # Obfuscation: $seconds actually contains error message
       usage "${seconds}" 
    fi

    # exec daemon process and give it the number of seconds to sleep (we
    # don't have to recompute sleep time again this way)
    ( exec ${long_progname} ${obnoxious} -d ${seconds} ) &

    exit 0
}

# Compute the number of seconds script should sleep before pestering user
# about leaving.  This is done by the foreground invocation of the script.
# When the "daemon" process gets executed, it's just given the number of
# seconds to sleep.  We don't bother recomputing it.
function compute_sleep_seconds () 
{
   awk '
      END {
         split(cmd_args, tm, ":");
         cmd_mm = tm[2];
 
         if ( substr(tm[1], 1, 1) == "+" ) {
            cmd_hh = substr(tm[1], 2, length(tm[1]));
            cmd_ss = ((cmd_hh * 60) + cmd_mm) * 60;
            print cmd_ss; exit 0;
           }
         else
            cmd_hh = tm[1];
            if (cmd_hh > 23) {
               printf("%s: %s: hour out of range.\n", progname, cmd_hh);
               exit 1;
            }
            if (cmd_mm > 59) {
               printf("%s: %s: minutes out of range.\n", progname, cmd_mm);
               exit 1;
            }
         cmd_ss = ((cmd_hh * 60) + cmd_mm) * 60;
 
         split(date, date_words, " ");
         split(date_words[4], tm, ":");
         tm_hh = tm[1];
         tm_mm = tm[2];
         tm_ss = ((tm_hh * 60) + tm_mm) * 60;

         day_secs = 24 * 3600;
         ss = (cmd_ss > tm_ss) ? (cmd_ss - tm_ss) : (day_secs + cmd_ss - tm_ss);
         while ( ss >= day_secs ) ss -= day_secs;

         print ss;
         exit 0 ;
      }' cmd_args="$*" date="$(date)" progname="${progname}" /dev/null
}

function do_daemon_tasks ()
{
    interval=${seconds}

    # Sleep until only 5 minutes are left
    if [ ${interval} -gt $(minutes 5) ]; then
       sleep $[ interval - $(minutes 5) ]
       say "You have to leave in 5 minutes!"
       interval="$(minutes 5)"
    fi

    # Sleep for another 4 minutes
    if [ ${interval} -gt $(minutes 1) ]; then
       sleep $[ interval - $(minutes 1) ];
       say "You have to leave in 1 minute!"
       interval="$(minutes 1)"
    fi

    # Complain once every minute
    sleep ${interval}
    say "It's time for you to leave!"
    sleep 60
    say "You're going to be late!"
    sleep 60
    if [ "${obnoxious}" ]; then
       print_obnoxious_warnings
    else
       print_standard_warnings
    fi
}

# Convert minutes to seconds
function minutes ()
{
    echo $[ $1 * 60 ]
}

# Write message out to tty
function say ()
{
 # Exit if it we no longer own tty.  It probably means user logged out.
 if [ ! -O "${tty}" ]; then exit 0; fi

 # If we're not in an emacs buffer, beep when sending the message. 
 if [ "${TERM}" = "emacs" ]; then
    echo "$@" > "${tty}"
 else
    echo "${g}${g}${g}$@" > "${tty}"
 fi
}

function print_standard_warnings ()
{
 local index=15;

    while [ ${index} -gt 0 ]; do
       say "You're going to be late!"
       index=$[ index - 1]
       sleep 60
    done
    say "You're going to be late!  (this is your last warning)"
    exit 0
}

function print_obnoxious_warnings ()
{
 local index=1;

    while [ ${index} -le 16 ]; do
       say "$(get_obnoxious_message ${index})"
       index=$[ index + 1]
       sleep 60
    done
    exit 0
}

# Return an obnoxious message for use by print_obnoxious_warnings
# I wish there were an inline way to do this, but bash doesn't have arrays,
# and the quoting to fake it is impossible to get right in this case. 
function get_obnoxious_message ()
{
   awk '
      BEGIN {
         "date" | getline date
         close("date")
         split(date, date_parts);
         split(date_parts[4], time_aref, ":");
         time = time_aref[1] ":" time_aref[2];

         msg[1]  = "You'\''d better leave now."
         msg[2]  = "It'\''s " time ", do you know where your gods are?"
         msg[3]  = "I'\''m getting rather sick of you hanging around."
         msg[4]  = "It'\''s " time ", do you know where your children are?"
         msg[5]  = "Don'\''t you have somewhere else to go?"
         msg[6]  = "It'\''s " time ", do you know where your bugs are?"
         msg[7]  = "Listen, actually, you should just get lost..."
         msg[8]  = "It'\''s " time ", do you know where your files are?"
         msg[9]  = "Although you find these messages amusing, how can you explain to your friends that you were late because you were reading them?"
         msg[10] = "Only gnurds hack past the time to LEAVE!"
         msg[11] = "'${progname}': at " time " rm *.c"
         msg[12] = "I'\''m not sure, but you might have something better to do."
         msg[13] = "Are you a losing twit tourist, or what?"
         msg[14] = "Leave is a great program, especially when it spits random garbage out over your screen, making it frustrating for you to attempt to continue working."
         msg[15] = "GO HOME!!!" 
         msg[16] = "I give up.  You'\''re on your own if you wind up being late."
      }
      END {
         print msg[i]
      }' progname="foo" i="$1" /dev/null
}

main "$@"

#
# eof
#
