#!/bin/bash

## timevox.sh is Copyright 2022 Matthew Chambers and is available
## freely available under the terms of the BSD 3-Clause license.
##
## This is a little script that is intended to run at about 5
## seconds before the top of every hour, it grabs the current time,
## optionally rounds up to the next minute or hour and announces it
## over the system's default audio output with a following tone.
## Much in the way you'd hear the time from NIST station WWV. 

re='^[0-9]+$'
version="v0.4.2"
append="";
tone=1000;
volume=50;
nxtHr=0;
nxtMin=0; 
noTone=0;
utc=0;
hours=minutes=timezone="";

invalid_option () {
    echo "ERROR: Invalid option: -${1}";
    display_usage;
}

display_usage () {
    echo "timevox ${version} Copyright 2022 Matthew A. Chambers";
    echo "Licensed under the BSD 3-Clause License";
    echo "Usage:";
    echo -e "-a\tAppend text to end of message (such as a ham repeater ID)."
    echo -e "-h\tDisplay usage message.";
    echo -e "-H\tAnnounce upcoming top of hour time (upcoming hour and 00 minutes).\n\tCan not be used with -M";
    echo -e "-M\tAnnounce upcoming minute (useful for running as a cron job just before the new minute).\n\tCan not be used with -H.";
    echo -e "-t\tSet the tone frequency in Hz between 30 and 8000 (Default 1000Hz).";
    echo -e "-T\tOmit the tone, just announce the time.";
    echo -e "-v\tDisplay the program version.";
    echo -e "-V\tSet the tone volume percentage (Default 50%).";
    echo -e "-z\tAnnounce UTC time.";
}

while getopts :a:hHMt:TvV:z flag
do
    case "${flag}" in
        a) append=${OPTARG};;
        h) display_usage; exit 0;;
        H) nxtHr=1;;
        M) nxtMin=1;;
        t) tone=${OPTARG};;
        T) noTone=1;;
        v) echo $version; exit 0;;
        V) volume=${OPTARG};;
        z) utc=1;;
        ?) invalid_option "${flag}"; exit 3;;
    esac
done
if ! [[ ${volume} =~ ${re} ]] || [ "${volume}" -lt 1 ] || [ "${volume}" -gt 100 ]
then
    echo -e "ERROR: Invalid usage!\n\tTone volume must be an integer percentage greater then 1% and less then 100%.\n";
    display_usage;
    exit 2;
fi
if ! [[ ${tone} =~ ${re} ]] || [ "${tone}" -lt 30 ] || [ "${tone}" -gt 8000 ]
then
    echo -e "ERROR: Invalid usage!\n\tTone frequency must be an integer frequency greater then 30Hz and less then 8000Hz.\n";
    display_usage;
    exit 2;
fi
if [ ${nxtHr} == 1 ] && [ ${nxtMin} == 1 ]
then
    echo -e "ERROR: Invalid usage!\n\tCannot annouce upcoming minute (-M) and hour (-H) at the same time.\n";
    display_usage;
    exit 2;
fi
if [ ${nxtHr} == 0 ] && [ ${nxtMin} == 0 ]
then
    if [ ${utc} == 1 ]
    then
        hours=$(TZ=UTC date +%H);
        minutes=$(TZ=UTC date +%M);
        timezone=$(TZ=UTC date +%Z);
    else
        hours=$(date +%H);
        minutes=$(date +%M);
        timezone=$(date +%Z);
    fi
fi
if [ ${nxtHr} == 1 ] && [ ${nxtMin} == 0 ]
then
    if [ ${utc} == 1 ]
    then
        hours=$(TZ=UTC date -d Next-hour +%H);
        minutes="00";
        timezone=$(TZ=UTC date +%Z);
    else
        hours=$(date -d Next-hour +%H);
        minutes="00";
        timezone=$(date +%Z);
    fi
fi
if [ ${nxtHr} == 0 ] && [ ${nxtMin} == 1 ]
then
    if [ ${utc} == 1 ]
    then
        hours=$(TZ=UTC date +%H);
        minutes=$(TZ=UTC date -d Next-minute +%M);
        timezone=$(TZ=UTC date +%Z);
    else
        hours=$(date +%H);
        minutes=$(date -d Next-minute +%M);
        timezone=$(date +%Z);
    fi
fi

echo "${hours} hours ${minutes} minutes ${timezone}";
if [ ${noTone} == 0 ]
then
    speak-ng "At the tone, the time will be ${hours} hours, ${minutes} minutes ${timezone}.";
    sleep 1s;
    speaker-test -t sine -f "${tone}" -b 800000 -p 800000 -l 1 -S "${volume}" > /dev/null;
    speak-ng "${append}";
else
    speak-ng "The time is ${hours} hours, ${minutes} minutes ${timezone}. ${append}";
fi

exit 0;