------------------------------------------------------------------------
-- |
-- Module      :  ALife.Creatur.Tools.Logger
-- Copyright   :  (c) Amy de Buitléir 2012-2013
-- License     :  BSD-style
-- Maintainer  :  amy@nualeargais.ie
-- Stability   :  experimental
-- Portability :  portable
--
-- A simple counter which persists between runs.
--
------------------------------------------------------------------------
{-# LANGUAGE UnicodeSyntax #-}
module ALife.Creatur.Counter
  (
    Counter(..),
    PersistentCounter,
    mkPersistentCounter
  ) where

import ALife.Creatur.Clock (Clock, currentTime, incTime)
import Control.Monad (unless)
import Control.Monad.IO.Class (liftIO)
import Control.Monad.State (StateT, get, gets, modify, put)
import System.Directory (doesFileExist)

class Counter c where
  current  StateT c IO Int
  increment  StateT c IO ()

data PersistentCounter = PersistentCounter {
    initialised  Bool,
    time  Int,
    filename  FilePath
  } deriving Show

-- | Creates a counter that will store its value in the specified file.
mkPersistentCounter  FilePath  PersistentCounter
mkPersistentCounter = PersistentCounter False (-1)

instance Counter PersistentCounter where
  current = do
    initIfNeeded
    gets time
  increment = do
    t  current
    let t' = t + 1
    f  gets filename
    modify (\c  c { time=t' })
    liftIO $ writeFile f $ show t'

initIfNeeded  StateT PersistentCounter IO ()
initIfNeeded = do
  isInitialised  gets initialised
  unless isInitialised $ do
    counter  get
    counter'  liftIO $ initialise counter
    put counter'

initialise  PersistentCounter  IO PersistentCounter
initialise counter = do
  let f = filename counter
  fExists  doesFileExist f
  if fExists
    then do
      s  readFile f
      return $ counter { initialised=True, time=read s }
    else return $ counter { initialised=True, time=0 }

instance Clock PersistentCounter where
  currentTime = current
  incTime = increment