{-# LANGUAGE TypeOperators #-}
-- |Environment used while capturing model
module Data.Model.Env(State,Env,withEnv,enterCtx,addDef,closeCtx) where

import           Control.Monad.Trans.State.Lazy
import           Data.Bifunctor
import qualified Data.Map                       as M
import           Data.Model.Types

-- |Environment used while capturing model
data Env = Env {ctx::[QualName]  -- ^The stack of entered types
               ,env::HTypeEnv    -- ^The environment
               } deriving Show

-- |Run the model capturing computation
withEnv :: State Env HType -> HTypeModel
withEnv m = (\(t,e) -> TypeModel (unVar <$> t) e) . second env $ runState m (Env [] M.empty)

-- |Enter a type
enterCtx :: QualName -> State Env Bool
enterCtx name = do
   f <- inCtx name
   modify (\e -> e {ctx = name : ctx e})
   return f

-- |Returns True if we have already seen this data type and do not need to analyse it further
inCtx :: QualName -> State Env Bool
inCtx name = (name `elem`) <$> gets (\e -> ctx e ++ M.keys (env e))

-- |Add a new data type model to the environment
addDef :: QualName -> HADT -> State Env ()
addDef ref adt  = modify (\e -> e {env = M.insert ref adt (env e)})

-- |Leave current type
closeCtx :: State Env ()
closeCtx = modify (\e -> e {ctx = drop 1 (ctx e)})

-- pretty print environment
-- showEnv e = unlines [""
--                   ,show $ map locName $ seen e
--                   ,show $ map (first locName) $ ctx e
--                   ,show $ map (\(d,deps) -> (locName $ declName d,map locName deps)) $ defs e
--                   ]