--------------------------------------------------------------------------------
{-# LANGUAGE OverloadedStrings #-}
import qualified Data.ByteString.Lazy.Char8 as C
import           Hakyll
import           Hakyll.Web.Sass            (sassCompiler)
import           Text.Jasmine
import           Text.Pandoc.Options        (HTMLMathMethod (MathJax),
                                             WriterOptions,
                                             writerHTMLMathMethod, writerHtml5)


--------------------------------------------------------------------------------
main :: IO ()
main = hakyllWith config $ do
    match ("static/fonts/*" .||. "static/images/*") $ do
        route   idRoute
        compile copyFileCompiler

    -- compress js
    match "static/js/*" $ do
        route   idRoute
        compile compressJsCompiler

    match "static/css/index.scss" $ do
        route $ setExtension "css"
        let compressCssItem = fmap compressCss
        compile (fmap compressCssItem sassCompiler)

    -- render pages
    match "pages/*.md" $ do
        route $ composeRoutes (gsubRoute "pages/" (const ""))
                              (setExtension "html")
        compile $ pandocCompilerWith defaultHakyllReaderOptions writerOptions
            >>= finish defaultContext

    tags <- buildTags "posts/*" (fromCapture "tags/*.html")

    match "posts/*" $ do
        route $ setExtension "html"
        compile $ do
            let drop = fmap (unlines . takeWhile (/= "<!-- MORE -->") . lines)

            compiled <- pandocCompilerWith defaultHakyllReaderOptions writerOptions
            saveSnapshot "content" compiled
            saveSnapshot "teaser" $ drop compiled
            loadAndApplyTemplate "templates/post.html" (postCtxWithTags tags) compiled
            >>= finish (postCtxWithTags tags)

    create ["about.html"] $ do
        route idRoute
        compile $ do
            let ctx = mconcat
                      [ constField "title" "About"
                      , defaultContext
                      ]
            makeItem ""
                >>= loadAndApplyTemplate "templates/about.html"   ctx
                >>= finish ctx

    create ["archive.html"] $ do
        route idRoute
        compile $ do
            posts <- recentFirst =<< loadAll "posts/*"
            let archiveCtx = mconcat
                             [ listField "posts" postCtx (return posts)
                             , tagCloudField "tagcloud" 80 200 tags
                             , constField "title" "Archives"
                             , defaultContext
                             ]

            makeItem ""
                >>= loadAndApplyTemplate "templates/archive.html" archiveCtx
                >>= finish archiveCtx

    tagsRules tags $ \tag pattern -> do
        let title = "Posts tagged \"" ++ tag ++ "\""
        route idRoute
        compile $ do
            posts <- recentFirst =<< loadAll pattern
            let tagCtx = mconcat
                         [ constField "title" title
                         , listField "posts" postCtx (return posts)
                         , defaultContext
                         ]

            makeItem ""
                >>= loadAndApplyTemplate "templates/tag.html"     tagCtx
                >>= finish tagCtx

    create ["cv.html"] $ do
        route idRoute
        compile $ do
            let ctx = mconcat
                      [ constField "title" "Curriculum Vitae"
                      , defaultContext
                      ]

            makeItem ""
                >>= loadAndApplyTemplate "templates/cv.html" ctx
                >>= finish ctx

    create ["index.html"] $ do
        route idRoute
        compile $ do
            let indexCtx = mconcat
                           [ field "posts" $ fmap const (recentPostList tags) 3
                           , tagCloudField "tagcloud" 80 200 tags
                           , defaultContext
                           ]

                ctx = mconcat
                      [ constField "title" "Home"
                      , defaultContext
                      ]

            makeItem ""
                >>= loadAndApplyTemplate "templates/index.html" indexCtx
                >>= finish ctx

    create ["rss.xml"] $ do
        route idRoute
        compile $ do
            let rssCtx = mconcat
                         [ bodyField "description"
                         , defaultContext
                         ]

            posts <- fmap (take 5) . recentFirst
                     =<< loadAllSnapshots "posts/*" "content"

            renderRss (feedConfiguration "All Posts") rssCtx posts

    create ["atom.xml"] $ do
        route idRoute
        compile $ do
            let atomCtx = mconcat
                          [ bodyField "description"
                          , defaultContext
                          ]

            posts <- fmap (take 5) . recentFirst
                     =<< loadAllSnapshots "posts/*" "content"

            renderAtom (feedConfiguration "All Posts") atomCtx posts

    match "templates/*" $ compile templateBodyCompiler


--------------------------------------------------------------------------------
postCtx :: Context String
postCtx = mconcat
          [ dateField "date" "%B %e, %Y"
          , modificationTimeField "mtime" "%B %e, %Y"
          , bodyField "content"
          , defaultContext
          ]

finish :: Context String -> Item String -> Compiler (Item String)
finish ctx item = tpl ctx item >>= relativizeUrls
    where
        tpl = loadAndApplyTemplate "templates/default.html"

postCtxWithTags :: Tags -> Context String
postCtxWithTags tags = mconcat
                       [ tagsField "tags" tags
                       , postCtx
                       ]

recentPostList :: Tags -> Int -> Compiler String
recentPostList tags n = do
    posts <- loadAllSnapshots "posts/*" "teaser" >>= recentFirst
    itemTpl <- loadBody "templates/post-teaser.html"
    applyTemplateList itemTpl (postCtxWithTags tags) $ take n posts

compressJsCompiler :: Compiler (Item String)
compressJsCompiler = do
    let minifyJS = C.unpack . minify . C.pack . itemBody
    s <- getResourceString
    return $ itemSetBody (minifyJS s) s

feedConfiguration :: String -> FeedConfiguration
feedConfiguration title = FeedConfiguration
                          { feedTitle       = "Jared Rickert - " ++ title
                          , feedDescription = "Personal blog of Jared Rickert"
                          , feedAuthorName  = "Jared Rickert"
                          , feedAuthorEmail = "jaredrickert52@gmail.com"
                          , feedRoot        = "http://jlrickert.me/"
                          }


-- Add options to the pandoc compiler
writerOptions :: WriterOptions
writerOptions = defaultHakyllWriterOptions
                { writerHTMLMathMethod = MathJax "http://cdn.mathjax.org/mathjax/latest/MathJax.js"
                , writerHtml5          = True
                }

--------------------------------------------------------------------------------
config :: Configuration
config = defaultConfiguration
         { deployCommand = "./deploy.sh"
         }
