-- | This module provides means for reading and applying 'Template's.
--
-- Templates are tools to convert items into a string. They are perfectly suited
-- for laying out your site.
--
-- Let's look at an example template:
--
-- > <html>
-- >     <head>
-- >         <title>My crazy homepage - $title$</title>
-- >     </head>
-- >     <body>
-- >         <div id="header">
-- >             <h1>My crazy homepage - $title$</h1>
-- >         </div>
-- >         <div id="content">
-- >             $body$
-- >         </div>
-- >         <div id="footer">
-- >             By reading this you agree that I now own your soul
-- >         </div>
-- >     </body>
-- > </html>
--
-- As you can see, the format is very simple -- @$key$@ is used to render the
-- @$key$@ field from the page, everything else is literally copied. If you want
-- to literally insert @\"$key$\"@ into your page (for example, when you're
-- writing a Hakyll tutorial) you can use
--
-- > <p>
-- >     A literal $$key$$.
-- > </p>
--
-- Because of it's simplicity, these templates can be used for more than HTML:
-- you could make, for example, CSS or JS templates as well.
--
-- Apart from interpolating @$key$@s from the 'Context' you can also
-- use the following macros:
--
-- * @$if(key)$@
--
-- > $if(key)$
-- >  <b> Defined </b>
-- > $else$
-- >  <b> Non-defined </b>
-- > $endif$
--
-- This example will print @Defined@ if @key@ is defined in the
-- context and @Non-defined@ otherwise. The @$else$@ clause is
-- optional.
--
-- * @$for(key)$@
--
-- The @for@ macro is used for enumerating 'Context' elements that are
-- lists, i.e. constructed using the 'listField' function. Assume that
-- in a context we have an element @listField \"key\" c itms@. Then
-- the snippet
--
-- > $for(key)$
-- >   $x$
-- > $sep$,
-- > $endfor$
--
-- would, for each item @i@ in 'itms', lookup @$x$@ in the context @c@
-- with item @i@, interpolate it, and join the resulting list with
-- @,@.
--
-- Another concrete example one may consider is the following. Given the
-- context
--
-- > listField "things" (field "thing" (return . itemBody))
-- >    (sequence [makeItem "fruits", makeItem "vegetables"])
--
-- and a template
--
-- >  I like
-- >  $for(things)$
-- >    fresh $thing$$sep$, and
-- >  $endfor$
--
-- the resulting page would look like
--
-- > <p>
-- >  I like
-- >
-- >   fresh fruits, and
-- >
-- >   fresh vegetables
-- > </p>
--
-- The @$sep$@ part can be omitted. Usually, you can get by using the
-- 'applyListTemplate' and 'applyJoinListTemplate' functions.
--
-- * @$partial(path)$@
--
-- Loads a template located in a separate file and interpolates it
-- under the current context.
--
-- Assuming that the file @test.html@ contains
--
-- > <b>$key$</b>
--
-- The result of rendering
--
-- > <p>
-- >   $partial("test.html")$
-- > </p>
--
-- is the same as the result of rendering
--
-- > <p>
-- >   <b>$key$</b>
-- > </p>
--
-- That is, calling @$partial$@ is equivalent to just copying and pasting
-- template code.
--
-- In the examples above you can see that the outputs contain a lot of leftover
-- whitespace that you may wish to remove. Using @'$-'@ or @'-$'@ instead of
-- @'$'@ in a macro strips all whitespace to the left or right of that clause
-- respectively. Given the context
--
-- > listField "counts" (field "count" (return . itemBody))
-- >    (sequence [makeItem "3", makeItem "2", makeItem "1"])
--
-- and a template
--
-- > <p>
-- >     $for(counts)-$
-- >       $count$
-- >       $-sep$...
-- >     $-endfor$
-- > </p>
--
-- the resulting page would look like
--
-- > <p>
-- >     3...2...1
-- > </p>
--
{-# LANGUAGE TemplateHaskell #-}
module Hakyll.Web.Template
    ( Template
    , templateBodyCompiler
    , templateCompiler
    , applyTemplate
    , loadAndApplyTemplate
    , applyAsTemplate
    , readTemplate
    , compileTemplateItem
    , unsafeReadTemplateFile
    , embedTemplate
    ) where


--------------------------------------------------------------------------------
import           Hakyll.Web.Template.Internal


--------------------------------------------------------------------------------
import           Data.FileEmbed               (embedFile)
import qualified Data.Text                    as T
import qualified Data.Text.Encoding           as T
import           Language.Haskell.TH          (Exp, Q)


--------------------------------------------------------------------------------
-- | Embed template allows you embed a template within the Haskell binary.
-- Example:
--
-- > myTemplate :: Template
-- > myTemplate = $(embedTemplate "test.html")
embedTemplate :: FilePath -> Q Exp
embedTemplate :: FilePath -> Q Exp
embedTemplate FilePath
filePath = [|
    let source = T.unpack $ T.decodeUtf8 $(embedFile filePath) in
    case parseTemplateElemsFile filePath source of
        Left  err -> error err
        Right tpl -> template filePath tpl |]