content: {-|
  
  This module defines a TemplateDirectory data structure for convenient
  interaction with templates within web apps.
  
  -}
  
  module Heist.TemplateDirectory
      ( TemplateDirectory
      , newTemplateDirectory
      , newTemplateDirectory'
  
      , getDirectoryHS
      , getDirectoryCTS
      , reloadTemplateDirectory
      ) where
  
  ------------------------------------------------------------------------------
  import           Control.Concurrent
  import           Control.Monad
  import           Control.Monad.Trans
  import           Heist
  import           Heist.Internal.Types
  import           Heist.Splices.Cache
  
  
  ------------------------------------------------------------------------------
  -- | Structure representing a template directory.
  data TemplateDirectory n
      = TemplateDirectory
          FilePath
          (HeistConfig n)
          (MVar (HeistState n))
          (MVar CacheTagState)
  
  
  ------------------------------------------------------------------------------
  -- | Creates and returns a new 'TemplateDirectory' wrapped in an Either for
  -- error handling.
  newTemplateDirectory
      :: MonadIO n
      => FilePath
      -> HeistConfig n
      -- namespaced tag.
      -> IO (Either [String] (TemplateDirectory n))
  newTemplateDirectory dir hc = do
      let sc = (_hcSpliceConfig hc) { _scTemplateLocations = [loadTemplates dir] }
      let hc' = hc { _hcSpliceConfig = sc }
      epair <- initHeistWithCacheTag hc'
      case epair of
        Left es -> return $ Left es
        Right (hs,cts) -> do
          tsMVar <- liftIO $ newMVar hs
          ctsMVar <- liftIO $ newMVar cts
          return $ Right $ TemplateDirectory dir hc' tsMVar ctsMVar
  
  
  ------------------------------------------------------------------------------
  -- | Creates and returns a new 'TemplateDirectory', using the monad's fail
  -- function on error.
  newTemplateDirectory'
      :: MonadIO n
      => FilePath
      -> HeistConfig n
      -> IO (TemplateDirectory n)
  newTemplateDirectory' dir hc = do
      res <- newTemplateDirectory dir hc
      either (error . concat) return res
  
  
  ------------------------------------------------------------------------------
  -- | Gets the 'HeistState' from a TemplateDirectory.
  getDirectoryHS :: (MonadIO n)
                 => TemplateDirectory n
                 -> IO (HeistState n)
  getDirectoryHS (TemplateDirectory _ _ tsMVar _) =
      liftIO $ readMVar $ tsMVar
  
  
  ------------------------------------------------------------------------------
  -- | Clears the TemplateDirectory's cache tag state.
  getDirectoryCTS :: TemplateDirectory n -> IO CacheTagState
  getDirectoryCTS (TemplateDirectory _ _ _ ctsMVar) = readMVar ctsMVar
  
  
  ------------------------------------------------------------------------------
  -- | Clears cached content and reloads templates from disk.
  reloadTemplateDirectory :: (MonadIO n)
                          => TemplateDirectory n
                          -> IO (Either String ())
  reloadTemplateDirectory (TemplateDirectory p hc tsMVar ctsMVar) = do
      let sc = (_hcSpliceConfig hc) { _scTemplateLocations = [loadTemplates p] }
      ehs <- initHeistWithCacheTag (hc { _hcSpliceConfig = sc })
      leftPass ehs $ \(hs,cts) -> do
          modifyMVar_ tsMVar (const $ return hs)
          modifyMVar_ ctsMVar (const $ return cts)
  
  
  ------------------------------------------------------------------------------
  -- | Prepends an error onto a Left.
  leftPass :: Monad m => Either [String] b -> (b -> m c) -> m (Either String c)
  leftPass e m = either (return . Left . loadError . concat)
                        (liftM Right . m) e
    where
      loadError = (++) ("Error loading templates: " :: String)
  