{-# LANGUAGE ScopedTypeVariables, PatternGuards #-}
{-# OPTIONS -fno-warn-orphans #-}

-- | A simple ''cron'' loop. Used for running commands according to a given schedule.
module BuildBox.Control.Cron
	( module BuildBox.Data.Schedule
	, cronLoop )
where
import BuildBox.Build
import BuildBox.Data.Schedule
import BuildBox.Command.Sleep
import Data.Time

-- | Given a schedule of commands, run them when their time is due.
--   Only one command is run at a time. If several commands could be started at a specific
--   moment, then we take the one with the earliest potential start time. If any command throws
--   an error in the `Build` monad then the whole loop does.
--
cronLoop :: Schedule (Build ())-> Build ()
cronLoop schedule
 = do	startTime	<- io $ getCurrentTime

	case earliestEventToStartAt startTime $ eventsOfSchedule schedule of
	 Nothing 
	  -> do	sleep 1
		cronLoop schedule
		
	 Just event 
	  -> do	let Just build	= lookupCommandOfSchedule (eventName event) schedule
		build
		endTime		<- io $ getCurrentTime

		let event'	= event
				{ eventLastStarted	= Just startTime
				, eventLastEnded	= Just endTime }

		let schedule'	= adjustEventOfSchedule event' schedule
	
		cronLoop schedule'