module MasterPlan.Backend.Identity (render) where
import Control.Monad (when)
import Control.Monad.RWS (RWS, evalRWS, gets, modify, tell)
import Data.Generics
import Data.List (nub)
import qualified Data.List.NonEmpty as NE
import qualified Data.Map as M
import Data.Maybe (isJust)
import Data.Monoid ((<>))
import qualified Data.Text as T
import MasterPlan.Data
render ∷ ProjectSystem → [ProjAttribute] -> T.Text
render (ProjectSystem bs) whitelist =
snd $ evalRWS (renderName "root" >> renderRest) whitelist bs
where
renderRest = gets M.keys >>= mapM_ renderName
type RenderMonad = RWS [ProjAttribute] T.Text (M.Map ProjectKey Binding)
renderName ∷ ProjectKey → RenderMonad ()
renderName projName =
do mb <- gets $ M.lookup projName
case mb of
Nothing -> pure ()
Just b -> do tell $ T.pack $ getProjectKey projName
when (hasAttribute b) $ do
tell " {\n"
renderAttr b
tell "}"
case b of
BindingExpr _ e -> tell $ " " <> expressionToStr False e <> ";\n"
_ -> tell ";\n"
modify $ M.delete projName
mapM_ renderName $ dependencies b
where
hasAttribute (BindingExpr props _) = hasProperty props
hasAttribute (BindingAtomic props c t p) = hasProperty props
|| c /= defaultCost
|| t /= defaultTrust
|| p /= defaultProgress
hasProperty props = title props /= getProjectKey projName
|| isJust (description props)
|| isJust (owner props)
|| isJust (url props)
percentage n = T.pack $ show (n * 100) <> "%"
renderAttr (BindingExpr props _) = renderProps props
renderAttr (BindingAtomic props c t p) =
do renderProps props
when (c /= defaultCost) $ tell $ "cost " <> T.pack (show $ getCost c) <> "\n"
when (t /= defaultTrust) $ tell $ "trust " <> percentage (getTrust t) <> "\n"
when (p /= defaultProgress) $ tell $ "progress " <> percentage (getProgress p) <> "\n"
renderProps :: ProjectProperties -> RenderMonad ()
renderProps p = do let maybeRender :: T.Text -> Maybe String -> RenderMonad ()
maybeRender n = maybe (pure ()) (\x -> tell $ n <> " " <> T.pack (show x) <> "\n")
when (title p /= getProjectKey projName) $
tell $ "title " <> T.pack (show $ title p) <> "\n"
maybeRender "description" (description p)
maybeRender "url" (url p)
maybeRender "owner" (owner p)
combinedEToStr parens op ps = let sube = map (expressionToStr True) $ NE.toList ps
s = T.intercalate (" " <> op <> " ") sube
in if parens && length ps > 1 then "(" <> s <> ")" else s
expressionToStr :: Bool -> ProjectExpr -> T.Text
expressionToStr _ (Reference (ProjectKey n)) = T.pack n
expressionToStr parens (Product ps) = combinedEToStr parens "*" ps
expressionToStr parens (Sequence ps) = combinedEToStr parens "->" ps
expressionToStr parens (Sum ps) = combinedEToStr parens "+" ps
dependencies ∷ Binding → [ProjectKey]
dependencies = nub . everything (++) ([] `mkQ` collectDep)
where
collectDep (Reference n) = [n]
collectDep _ = []