#!/bin/sh

# Update SF-LUG's displayed meeting schedule (of upcoming
# meeting(s)) on its main web page, if should be updated.

# update_meeting_schedule -f -F -n
# -f force: ignore file age/recentness (mmin) of file
# -F force: ignore that file already has current schedule, replace it anyway
# -n no: make no changes to actual target file

# vi(1) se tabstop=2

set -e

umask 022

DocumentRoot=/var/www/www.sf-lug.org
file=index.html
File="$DocumentRoot/$file"

# Minimum minutes old for file to be to consider updating it,
# so we're less likely to clobber changes others may be actively working
# on.
mmin=25

# we put the schedule between these tag lines:
StartTag='<!-- START managed by update_meeting_schedule -->'
EndTag='<!-- END managed by update_meeting_schedule -->'

TZ=US/Pacific export TZ

# Current schedule is first Sunday of the month 11a-1p US/Pacific

progname="$(basename "$0")"

force=
Force=
no=
for arg in "$@"
do
	case "$arg" in
		-f)
			force=-f
		;;
		-F)
			Force=-F
		;;
		-n)
			no=-n
		;;
		*)
			2>&1 printf '%s\n%s\n%s\n' "$usage:" \
				"$progname [-f] [-F] [-n]" \
				aborting
			exit 1
		;;
	esac
done

# Are we < end of this month's meeting?
# If so we want to show this month's meeting.
# Otherwise we want to show next month's meeting.

# We'll follow convention from date(1):
# %Y year
# %m month (01..12)
# %w day of week (0..6); 0 is Sunday
# %d day of month (e.g., 01)
# %H hour (00..23)

# set variables accordingly:
eval $(date +"Y='%Y' m='%m' w='%w' d='%d' H='%H'")

# correspondingly, but strip leading 0 if present
m_=${m##0}
d_=${d##0}
H_=${H##0}

# In our logic, we aim for more probable matches first, assume this may
# be run at any random time of equal probability.

if \
	[ $d_ -ge 8 ] ||
	{
		[ $((d_ - w)) -ge 1 ] &&
		{
			[ $w -gt 0 ] ||
			[ $H_ -ge 13 ]
		}
	}
then
	# This month's meeting ending <= now:
	# now is >= 8th of month or
	# (
	# 	day of month - w >= 1 and
	# 	( w>0 or >=1pm )
	# )
	# Determine date for first Sunday of next month
	m_=$((m_ + 1))
	[ $m_ -le 12 ] || {
		# next year
		m_=1
		Y=$(($Y + 1))
	}
	m="$(printf '%02d' $m_)"
# else # This month's meeting isn't yet concluded, fall through to handle
fi
d_=1
d=01
w=$(date +%w -d "$Y-$m-$d")
inc=$(( ( 7 - w ) % 7 ))
[ $inc -eq 0 ] ||
{
	d_=$((d_ + inc))
	d="$(printf '%02d' $d_)"
	w=0
}

# full month name ASCII locale:
B=$(LC_ALL=C date +'%B' -d "$Y-$m-$d 12:00:00")
# day of month in ordial format
# 1st, 2nd, 3rd, 4th, ... 7th, 1st Su so we don't need higher
case "$d_" in
	[4-7])
		do="$d_"th
	;;
	1)
		do="$d_"st
	;;
	2)
		do="$d_"nd
	;;
	3)
		do="$d_"rd
	;;
esac
# curl -s https://www.sf-lug.org/
#The next meeting is on <b>Sunday January 4th, from 11:00 AM until 1:00 PM</b>, at:<BR>
# our schedule line(s):
schedule="$(
	printf '%s %s\n' "The next meeting is on <b>Sunday $B $do," \
		"from 11:00 AM until 1:00 PM</b>, at:<BR>"
)"
# Alternative schedule format (commented out for now):
# s=$(date +%s -d "$Y-$m-$d 11:00:00")
# Sl="$(date +'%Y-%m-%d %I:%M:%S %p' -d @$s)"
# Su="$(TZ=GMT0 date +'%Y-%m-%dT%H:%M:%SZ' -d @$s)"
# e=$(date +%s -d "$Y-$m-$d 13:00:00")
# El="$(date +'%Y-%m-%d %I:%M:%S %p' -d @$e)"
# Eu="$(TZ=GMT0 date +'%Y-%m-%dT%H:%M:%SZ' -d @$e)"
# schedule="$(
# 	printf '%s\n%s\n%s\n%s%s\n%s\n' "The next meeting is from" \
# 		"<b>Sunday $Sl $Su" \
# 		"through" \
# 		"Sunday $El $Eu" \
# 		"</b>" \
# 		"at:<BR>"
# )"
[ -z "$no" ] || 1>&2 printf '%s\n' "$schedule"

File_="$File"
{
	[ x"$force" = x-f ] ||
	File_="$(
		find "$File" ! -type l -type f -mmin +"$mmin" -print -o -type d \
			-prune 2>>/dev/null
	)"
} &&
[ -n "$File_" ] &&
[ "$File" = "$File_" ] ||
{
	printf '%s\n' \
		"$progname: $File not found of sufficient age (mmin>$mmin), exiting"
	exit 0
}

FileData="$(cat "$File")"

{
	FileDataTags="$(printf '%s\n' "$FileData" |
		grep -Fx -e "$StartTag" -e "$EndTag")" \
		&&
	[ x"$FileDataTags" = x"$StartTag
$EndTag" ]
} ||
{
	1>&2 printf '%s %s\n%s\n%s\n%s\n' \
	"$progname: didn't find exactly one start tag and" \
	"one end tag in sequence, expecting:" \
	"$StartTag" \
	"$EndTag${FileDataTags:+
found:
$FileDataTags}" \
	aborting
	exit 1
}

oldschedule="$(
	printf '%s\n' "$FileData" |
	sed -ne '
		/^'"$StartTag"'$/{
			:n
			n
			/^'"$EndTag"'$/q
			p
			bn
		}
	'
)"
[ x"$Force" = x-F ] ||
[ x"$schedule" != x"$oldschedule" ] ||
{
	printf '%s\n' \
		"$progname: $File already has current schedule, exiting"
	# nothing further to do
	exit 0 # trap handles cleanup of temporary file
}
# we have -F force option, or schedule needs updating
before="$(
	printf '%s\n' "$FileData" |
	{
		sed -ne '
			/^'"$StartTag"'$/q
			p
		' &&
		printf X
	}
)"
# For the before section, we add and strip trailing X to preserve
# trailing newline(s)
before="${before%X}"
after="$(
	printf '%s\n' "$FileData" |
	sed -ne '
		/^'"$EndTag"'$/{
			:n
			n
			p
			bn
		}
	'
)"

tmp="$(mktemp "$DocumentRoot/tmp-$file.XXXXXXXXXX")"
# traps to handle cleanup up our temporary file:
for sig in 1 2 3 15
do
	trap '
		rm -f '"$tmp"'
		trap - 0
		trap - '"$sig"'
		kill -'"$sig"' "$$"
	' "$sig"
done
trap '
	rc=$?
	trap - 0
	rm -f '"$tmp"'
	exit $rc
' 0

chmod a+r "$tmp"

> "$tmp" \
	printf '%s%s\n%s\n%s\n%s\n' \
		"$before" \
		"$StartTag" \
		"$schedule" \
		"$EndTag" \
		"$after"

if [ -z "$no" ]; then
	mv -f "$tmp" "$File"
else
	(
		exec 1>&2
		printf '%s\n%s %s\n' "Not replacing target file $File because -n," \
			"our temporary file and its contents we'd otherwise use to" \
			'replace:'
		ls -ld -- "$tmp"
	)
	cat "$tmp"
	rm "$tmp"
fi
# Above handled temporary file, so traps no longer needed:
trap - 0 1 2 3 15
