#!/bin/bash

USAGE="
USAGE: avds <action> [<when>] [<repeat>]

        action  A comma or space separated list of actions to associate with the
                update signal.

        when    The integer number of milliseconds to wait before sending the
                update signal, or one of the following values:
                  - m to send the update signal at the top of the next minute
                  - h to send the update signal at the top of the next hour
                  - d to send the update signal at the top of the next day
                If not present, the update signal will be sent immediately.

        repeat  If present, the update signal will be sent repeatedly according
                to <when>.

EXAMPLES:

        If the daemon interprets the actions 'vol' and 'bl' to mean update the
        volume and backlight statuses, respectively, send a signal to
        immediately update both of those statuses.

                avds 'vol,bl'

        If the daemon interprets the actions 'cpu' and 'mem' to mean update the
        cpu and memory usage statuses, respectively, send a signal to update
        both of those statuses every 5 seconds.

                avds 'cpu,mem' 5000 1

        If the daemon interprets the actions 'bat' and 'dt' to mean update the
        battery and date/time statuses, respectively, send a signal to update
        both of those statuses at the top of every minute.

                avds 'bat,dt' m true
"
DAEMON=avdd
ACTION_DIR=/tmp/"${DAEMON}"

# Convert integer milliseconds to floating point seconds
ms_to_s () {
  printf '%.3f' "${1}e-3"
}

# Validate the arguments
if [[ "$#" -lt 1 || "$#" -gt 3 ]]; then
  printf '%s' "${USAGE}" 1>&2
  exit 128
fi

IFS=', ' read -r -a actions <<< "$1"
when="${2:-0}"
repeat="$3"

if [[ ! "${when}" =~ ^[0-9]+|[mhd]$ ]]; then
  printf 'Invalid argument <when>: %s\n' "${when}" 1>&2
  exit 128
fi

# Send the signal if this is the first run or if repeat is on
first_run=1
while [[ "${first_run}" -eq 1 || -n "${repeat}" ]]; do
  first_run=0

  # Sleep until it's time to send the signal
  if [[ "${when}" != '0' ]]; then
    if [[ "${when}" =~ ^[0-9]+$ ]]; then
      sleep "$(ms_to_s "${when}")"
    else
      case "${when}" in
        m)
          sleep $((60 - $(date +%S)))
          ;;
        h)
          readarray -t ms < <(date +'%M%n%S')
          sleep $((3600 - ms[0] * 60 - ms[1]))
          ;;
        d)
          readarray -t hms < <(date +'%H%n%M%n%S')
          sleep $(((24 - hms[0]) * 3600 - hms[1] * 60 - hms[2]))
          ;;
        *)
          ;;
      esac
    fi
  fi

  # Create the signal data and send the signal to the daemon
  daemon_pid="$(pgrep --newest --exact "${DAEMON}")"
  if [[ -z "${daemon_pid}" ]]; then
    printf 'The daemon %s is not running\n' "${DAEMON}" 1>&2
    exit 1
  fi
  for action in "${actions[@]}"; do touch "${ACTION_DIR}/${action}"; done
  kill -USR1 "${daemon_pid}"
done