#!/bin/bash

# Dusk and Dawn X10 schedule preprocessor
# Author Daniel B. Suthers

# This utility takes an X10 schedule file and creates multiple lines
# where-ever it sees the special string DAWN or DUSK  It calls the dawndusk
# utility to determine the actual sunrise and sunset times.
#
# An offset can be specified by adding a positive or negative number of minutes
# to the end of the dawn or dusk tag.
# Example:
#timer smtwtfs 01/11-04/29 dusk dawn+20 livinroom_on livinroom_off
#timer smtwtfs 01/11-04/29 07:00 dusk-20 lampoff lampon

PATH=$PATH:.

FINE_GRAIN=OK	# NO= 1 entry per month, OK=twice per month

if [ $# = 0 ] ; then
    SCHED=$HOME/.x10sched.conf
else
    SCHED=$1
fi

for FL in $X10CONFIG $HOME/.x10config /etc/x10.conf ; do
    egrep 'LATITUDE' $FL > /dev/null 2>&1
    if [ $? = 0 ] ; then
	LATITUDE=`sed -n -e "s/^OPTION *LATITUDE//p" -e  "s/^LATITUDE[ 	*]//p" $FL | tr -d 'NSEW' `
	LONGITUDE=`sed -n -e "s/^OPTION *LONGITUDE//p" -e  "s/^LONGITUDE[ 	*]//p" $FL | tr -d 'NSEW' `
	export LATITUDE LONGITUDE
	break
    fi
done

# return number of days in the month
maxdays() {
mo=`echo $1 | sed "s/^0//"`
case "$mo" in
  1|3|5|7|8|10|12)
	DAYS=31;;
  2)
	DAYS=28;;
  *)
	DAYS=30;;
esac
echo $DAYS
}



#Return the number of seconds since Jan 1, 1970.
# This is not real acurate, but it puts us within 48 hours of the correct
# time.
seconds() {
mo=$1
day=$2
SEC_IN_YEAR=31536000
SECS=0
if [ -f $HOME/.PRIORYEARS ] ; then
     read SECS < $HOME/.PRIORYEARS
fi

YEAR=`date +%Y`
# add up seconds since Jan 1, 1970 for each year before this one
if [ "$SECS" -eq 0 ] ; then
    while [ "$YEAR" -gt 1970 ]  ; do
	SECS=`echo 31536000 + $SECS | bc`
	if [ `expr "$YEAR" % 4` = 0 ] ; then
	    if [ `expr $YEAR % 100` != 0 ] ; then
		SECS=`echo 86400 + $SECS | bc`
	    fi
	fi
	YEAR=`expr "$YEAR" - 1`
    done
    echo $SECS > $HOME/.PRIORYEARS
fi

#Add a month at a time for this year
mo=`expr $mo - 1`
while [ $mo -gt 0 ] ; do
    DAYS=`maxdays $mo`
    mo=`expr $mo - 1`
    SECS=`echo $DAYS \* 86400 + $SECS | bc`
done
SECS=`echo $day \* 86400 + $SECS | bc `
HR=`date +%H`			# add the hours today
SECS=`echo $HR \* 3600 + $SECS | bc`
echo $SECS
}

cat $SCHED | while read label days month_range on off cmds ; do
    if [ "$label" != timer ] ; then
	# Just duplicate the line as is if it is not a timer
	echo $label $days $month_range $on $off $cmds
    else
	echo "$on $off" | egrep -i 'dawn|dusk' > /dev/null
	if [ $? != 0 ] ; then
	    echo $label $days $month_range $on $off $cmds
	    # This is a timer line without dawn or dusk.
	    continue
	fi
	echo "#  Some of the entries were generated by `basename $0` from the following line:"
	echo \#$label $days $month_range $on $off $cmds
	# Separate the days and months
	set `echo "$month_range" | sed "s/[\/-]/ /g"`
	ENDMO=$3
	STARTMO=$1
	NO_DEC=1;
	MID=NO
	while [ $STARTMO -le $ENDMO ] ; do
	    # set the start day for second and later months
	    if [ $STARTMO = $1 ] ; then
	    	SDAY=$2		# original start day
	    else 
	    	SDAY=01		# Start of month
	    fi

	    # EOM = end of month
	    if [ $STARTMO -lt $ENDMO ] ; then
		# Month 1 through N end on the last day of the month
		EOM=`maxdays $STARTMO`
	    else
		# The last month uses the real end day
	        EOM=$4
	    fi

	    # This logic is somewhat convoluted.  It's meant to increment the
	    # sday by two weeks on every other iteration so that the granularity
	    # is a bit finer.
	    if [ $FINE_GRAIN = OK ] ; then
		if [ `expr $EOM - $SDAY` -gt 14 -a $MID = OK ] ; then
		    SDAY=`expr $SDAY + 14`
		    NO_DEC=0	# this flag says not to decrement month
		else
		    NO_DEC=1
		    if [ `expr $EOM - $SDAY` -gt 14 ] ; then
			EOM=`expr $SDAY + 13`
		    else
			NO_DEC=0
		    fi
		fi
	    fi
	    STARTMO=`expr 0$STARTMO : '.*\(..\)'`
	    # get the number of seconds since Jan 1, 1970 for input to the 
	    # dawndusk utility
	    SECONDS=`seconds $STARTMO $SDAY`

	    offset=`echo $on | sed -n "s/.*\([+-][0-9]*\).*/\1/p"`
	    eval `dawndusk $SECONDS $offset`
	    ONDUSK=$DUSK
	    ONDAWN=$DAWN

	    offset=`echo $off | sed -n "s/.*\([+-][0-9]*\).*/\1/p"`
	    eval `dawndusk $SECONDS $offset`
	    OFFDUSK=$DUSK
	    OFFDAWN=$DAWN

	    case "$on" in
		dusk*)  ONVALUE=$ONDUSK;;
		dawn*)  ONVALUE=$ONDAWN;;
		*)	ONVALUE=$on;;
	    esac
	    case "$off" in
		dusk*)  OFFVALUE=$OFFDUSK;;
		dawn*)  OFFVALUE=$OFFDAWN;;
		*)	OFFVALUE=$off;;
	    esac


	    echo "$label $days $STARTMO/$SDAY-$STARTMO/$EOM $ONVALUE $OFFVALUE $cmds"
	    if [ $FINE_GRAIN = OK ] ; then
		if [ $NO_DEC = 0 -o $FINE_GRAIN = NO ] ; then
		   STARTMO=`expr $STARTMO + 1`
		   MID=NO
		else
		   MID=OK
		fi
	    else
		STARTMO=`expr $STARTMO + 1`
	    fi
	done
        echo "# end of auto generated entries."
    fi
done

[ -f $HOME/.PRIORYEARS ] && rm $HOME/.PRIORYEARS
