populate :: Path
         -> Templates
         -> Library
         -> Either Error (AnchoredDirTree Touch)
populate d Templates {..} l = (encodeString d :/) . dir lib <$> layout
  where
    layout :: Either Error [DirTree Touch]
    layout = traverse sequenceA
        [ dir "src"
              -- Supress cabal warnings about directories listed that don't exist.
            [ touch ".gitkeep"
            ]

        , file (lib <.> "cabal") cabalTemplate
        , file "README.md" readmeTemplate

        , dir "gen" $
            [ mod' (tocNS   l) tocImports  tocTemplate   (pure env)
            , mod' (typesNS l) typeImports typesTemplate (pure env)
            , mod' (prodNS  l) prodImports prodTemplate  (pure env)
            , mod' (sumNS   l) sumImports  sumTemplate   (pure env)
            ] ++ map resource (_apiResources (l ^. lAPI))
              ++ map method   (_apiMethods   (l ^. lAPI))
        ]
      where
        -- FIXME: now redundant
        resource a =
            mod' (_actNamespace a) actionImports actionTemplate (action a)

        method a =
            mod' (_actNamespace a) actionImports actionTemplate (action a)

        action a =
            let Object o = object ["action" .= a]
                Object e = env
             in pure $ Object (o <> e)

    Imports {..} = serviceImports l

    lib = fromText (l ^. sLibrary)

    mod' ns is t = write . module' ns is t

    file p t = write $ file' p t (pure env)

    env :: Value
    env = toJSON l
populate :: Path
         -> Templates
         -> Library
         -> Either Error (AnchoredDirTree Touch)
populate d Templates {..} l = (encodeString d :/) . dir lib <$> layout
  where
    layout :: Either Error [DirTree Touch]
    layout = traverse sequenceA
        [ dir "src"
              -- Supress cabal warnings about directories listed that don't exist.
            [ touch ".gitkeep"
            ]

        , file (lib <.> "cabal") cabalTemplate
        , file "README.md" readmeTemplate

        , dir "gen" $
            [ mod' (tocNS   l) tocImports  tocTemplate   (pure env)
            , mod' (typesNS l) typeImports typesTemplate (pure env)
            , mod' (prodNS  l) prodImports prodTemplate  (pure env)
            , mod' (sumNS   l) sumImports  sumTemplate   (pure env)
            ] ++ map resource (_apiResources (l ^. lAPI))
              ++ map method   (_apiMethods   (l ^. lAPI))
        ]
      where
        -- FIXME: now redundant
        resource a =
            mod' (_actNamespace a) actionImports actionTemplate (action a)

        method a =
            mod' (_actNamespace a) actionImports actionTemplate (action a)

        action a =
            let Object o = object ["action" .= a]
                Object e = env
             in pure $ Object (o <> e)

    Imports {..} = serviceImports l

    lib = fromText (l ^. sLibrary)

    mod' ns is t = write . module' ns is t

    file p t = write $ file' p t (pure env)

    env :: Value
    env = toJSON l
populate d Templates {..} l = (encodeString d :/) . dir lib <$> layout
  where
    layout :: Either Error [DirTree Touch]
    layout = traverse sequenceA
        [ dir "src"
              -- Supress cabal warnings about directories listed that don't exist.
            [ touch ".gitkeep"
            ]

        , file (lib <.> "cabal") cabalTemplate
        , file "README.md" readmeTemplate

        , dir "gen" $
            [ mod' (tocNS   l) tocImports  tocTemplate   (pure env)
            , mod' (typesNS l) typeImports typesTemplate (pure env)
            , mod' (prodNS  l) prodImports prodTemplate  (pure env)
            , mod' (sumNS   l) sumImports  sumTemplate   (pure env)
            ] ++ map resource (_apiResources (l ^. lAPI))
              ++ map method   (_apiMethods   (l ^. lAPI))
        ]
      where
        -- FIXME: now redundant
        resource a =
            mod' (_actNamespace a) actionImports actionTemplate (action a)

        method a =
            mod' (_actNamespace a) actionImports actionTemplate (action a)

        action a =
            let Object o = object ["action" .= a]
                Object e = env
             in pure $ Object (o <> e)

    Imports {..} = serviceImports l

    lib = fromText (l ^. sLibrary)

    mod' ns is t = write . module' ns is t

    file p t = write $ file' p t (pure env)

    env :: Value
    env = toJSON l