-- | This module contains a runner for a an Lseed garden. It can be passed an
-- observer that will receive the results.
module Lseed.Mainloop where

import Lseed.Data
import Lseed.Geometry
import Lseed.Data.Functions
import Lseed.Constants
import Lseed.Logic
import Lseed.StipeInfo
import System.Time
import System.Random
import Control.Concurrent
import Control.Monad

-- | Lets a garden grow for the given number of days, while keeping the
-- observer informed about any changes.
lseedMainLoop :: Bool -- ^ Run in real time, e.g. call 'threadDelay'
	-> Observer -- ^ Who to notify about the state of the game
	-> Integer -- ^ Maximum days to run
	-> Garden () -- ^ Initial garden state
	-> IO ()
lseedMainLoop rt obs maxDays garden = do
	obInit obs
	let nextDay (tick, garden) = 
		let (day, tickOfDay) = tick `divMod` ticksPerDay in
		if day > maxDays then
			obFinished obs garden
		else do

		tickStart <- getClockTime
		rgen <- newStdGen
		let sampleAngle = lightAngle $ (fromIntegral tickOfDay + 0.5) /
                                                fromIntegral ticksPerDay
		let growingGarden = growGarden sampleAngle rgen garden

		obState obs tick garden
		when rt $ do
			obGrowingState obs $ \later -> 
				let tickDiff = timeSpanFraction tickLength tickStart later
				    dayDiff = (fromIntegral tickOfDay + tickDiff) /
					      fromIntegral ticksPerDay
				    timeInfo = formatTimeInfo day dayDiff
				    visualizeAngle = lightAngle dayDiff
				    gardenNow = annotateGarden visualizeAngle $ 
				                growingGarden tickDiff
				in ScreenContent gardenNow visualizeAngle timeInfo

			threadDelay (round (tickLength * 1000 * 1000))
		nextDay (succ tick, growingGarden 1)
	nextDay (0::Integer, mapGarden (fmap (const NoGrowth)) garden)