{-# LANGUAGE PatternGuards #-}

-- | The IO in this module is only to evaluate an envrionment variable,
--   the 'Env' itself it passed around purely.
module Development.Make.Env(Env, newEnv, addEnv, askEnv) where

import Development.Make.Type
import Data.Maybe
import qualified Data.HashMap.Strict as Map


newtype Env = Env (Map.HashMap String (Assign,Expr))

newEnv :: [(String,String)] -> Env
newEnv xs = Env $ Map.fromList [(a,(Equals,Lit b)) | (a,b) <- xs]


addEnv :: String -> Assign -> Expr -> Env -> IO Env
addEnv name ass val env@(Env e) = case ass of
    QuestionEquals -> if isJust $ Map.lookup name e then return env else addEnv name Equals val env
    Equals -> return $ Env $ Map.insert name (Equals,val) e
    ColonEquals -> do l <- askEnv env val; return $ Env $ Map.insert name (ColonEquals,Lit l) e
    PlusEquals -> case Map.lookup name e of
        Just (Equals,x) -> return $ Env $ Map.insert name (Equals,Concat [x,Lit " ",val]) e
        Just (ColonEquals,x) -> do l <- askEnv env val; return $ Env $ Map.insert name (ColonEquals,Concat [x,Lit " ",Lit l]) e
        _ -> addEnv name Equals val env


askEnv :: Env -> Expr -> IO String
askEnv (Env e) x = do
    res <- f [] x
    case simplifyExpr res of
        Lit x -> return x
        x -> error $ "Internal error in askEnv, " ++ show x
    where
        f seen (Var x) | x `elem` seen = error $ "Recursion in variables, " ++ show seen
                       | Just (_,y) <- Map.lookup x e = f (x:seen) y
                       | otherwise = return $ Lit ""
        f seen x = descendExprM (f seen) x

