{- |
    Module: Data.Text.Interp.Get

    Functions to extract values from Subst mappings
-}
{-# LANGUAGE OverloadedStrings #-}
module Data.Text.Interp.Get
  ( get
  ) where

import Control.Monad.Except
import qualified Data.Map.Strict as M
import Data.Random (MonadRandom, randomElement)
import Data.RVar (sampleRVar)
import Data.Text (Text, append)

import Data.Text.Interp.Types


-- | Randomly retrieve a value out of a `Data.Text.Interp.Types.Subst` mapping
get :: Subst -- ^ source mapping
    -> [Key] -- ^ a list of `Data.Text.Interp.Types.Key`s leading to the value
    -> BindingMap -- ^ the `Data.Text.Interp.Types.BindingMap` to check for bound values in
    -> I Subst -- ^ retrieved value
get v@(SubstV _) [] m = return v
get (SubstV _) xs _ = throwError "too many keys"
get m@(SubstM _) [] _ = return $ m
get (SubstM m) (k:ks) bm = case M.lookup k bm of
                             Nothing -> do
                               res <- g k m
                               get res ks bm
                             (Just s') -> get s' ks bm

-- | Helper function that digs one layer down in a `Data.Text.Interp.Types.Subst` mapping
g :: Key -> (M.Map Key Subst) -> I Subst
g k m = case M.lookup k m of
  Nothing -> throwError $ "bad key: " `append` (unKey k)
  (Just (SubstL xs)) -> lift $ sampleRVar (randomElement xs)
  (Just v) -> return v