{- |
Module      :  Web.RBB
Description :  This module re-exports all necessary and some useful modules
Copyright   :  (c) Sebastian Witte
License     :  BSD3

Maintainer  :  woozletoff@gmail.com
Stability   :  experimental

-}
module Web.RBB (
    -- * Configuration
    -- $configuration
    BlogConfig (..),
    createDefaultBlogConfig,

    -- * Usage
    -- ** General
    -- $usage
    Blog,
    getBlogConfig,
    withBlog,
    blogEntries,

    -- ** XMonad style usage
    -- $example
    rbb,

    -- * Entry querying
    -- ** Entry
    Entry,
    entryId,
    -- | Unique 'Entry' identifier. It you do not mess with the repositories
    -- history, this should be the same across restarts.
    title,
    -- | Title of the 'Entry'.
    author,
    -- | Author of the 'Entry'.
    authorEmail,
    tags,
    fileType,

    -- $ixsetquery
    Title(..),
    AuthorName(..),
    AuthorEmail(..),
    Tags(..),
    Index(..),

    -- ** FileType
    FileType(..),

    def,
    ) where

import Data.Default              (Default (..))
import Web.RBB.Blog              (Blog, blogEntries, getBlogConfig, withBlog)
import Web.RBB.Config            (BlogConfig (..))
import Web.RBB.Main              (rbb)
import Web.RBB.Templates.Default (createDefaultBlogConfig)
import Web.RBB.Types.Entry
import Web.RBB.Types.FileType    (FileType (..))

-- $configuration
-- The blog configuration is essentially done by setting the fields of the
-- 'BlogConfig' data type. A basic configuration can be created with the
-- function 'createDefaultBlogConfig' that only takes the absolutely necessary
-- parameters.

-- $usage
-- To use the blog in an web application, you have to create an abstact 'Blog'
-- value via the 'withBlog' function and pass it to functions that need access
-- to it because they call blog related functions.
--
-- > importWeb.RBB
-- >
-- > myBlogConfig = createDefaultBlogConfig
-- >     "/path/to/repository/with/blog/entries"
-- >     "/path/to/folder/with/static/resources"
-- >
-- > main = withBlog myBlogConfig $ \blog -> do
-- >     putStrLn "Replace this with your web application code."

-- $example
--
-- You can also define an xmonad-like configuration for your blog. If the few
-- functions from this module do not give you a basic idea on how to use this
-- library, a trivial example will not suffice.
-- The following example will contain two modules and for the sake of this
-- example, I will assume that the configuration is in
-- @~\/.config\/repo-based-blog@.
--
-- The first file is @repo-based-blog.hs@. It will containt the markup and a
-- minimal happstack server example. The blog will be present at
-- <http://127.0.0.1:8000>.
--
-- > {-# LANGUAGE OverloadedStrings #-}
-- > import Web.RBB
-- >
-- > import Query
-- >
-- > import Text.Blaze.Html5 as H
-- > import Control.Applicative ((<$>), optional)
-- > import Control.Monad
-- > import Control.Monad.IO.Class
-- > import Data.Text                   (Text, unpack)
-- > import Happstack.Server
-- > import Data.Maybe
-- > import qualified Data.IxSet as IxSet
-- > import System.Directory
-- > import Text.Blaze.Html5.Attributes as A hiding (dir, start, id)
-- > import Happstack.Server (Conf (port), notFound, nullConf, toResponse, simpleHTTP)
-- >
-- > siteTemplate :: (Monad m, Functor m)
-- >              => [Html] -- ^ Additional Headers
-- >              -> [Html] -- ^ Body content
-- >              -> m Html
-- > siteTemplate hs bodyContent = return $ do
-- >         docType
-- >         html $ do
-- >             H.head $ do
-- >                 meta ! httpEquiv "Content-Type"
-- >                      ! content "text/html;charset=utf-8"
-- >                 meta ! content "width=device-width, initial-scale=1, maximum-scale=1"
-- >                      ! name "viewport"
-- >                 link ! rel "stylesheet" ! type_ "text/css"
-- >                      ! href "resources/default.css"
-- >                 sequence_ hs
-- >             H.body $ do
-- >                 topNavigationBar [ ("Blog", Just "?")
-- >                                  , ("Github", Just "https://github.com/saep")
-- >                                  ]
-- >                 sequence_ bodyContent
-- >
-- > topNavigationBar :: [(Html, Maybe String)] -> Html
-- > topNavigationBar [] = return ()
-- > topNavigationBar xs =
-- >     H.div ! class_ "horiz-nav" $
-- >         H.nav ! A.class_ "horiz-nav" $
-- >             ul ! class_ "horiz-nav" $
-- >                 forM_ xs $ \(t, ml) ->
-- >                     case ml of
-- >                         Just l -> li $ a ! href (toValue l) $ t
-- >                         _ -> li t
-- >
-- > serveBlog :: Blog (ServerPartT IO)
-- >           -> ServerPartT IO Response
-- > serveBlog blog = do
-- >     qd <- parseQueryRqData
-- >     mId <- join . fmap readMaybe <$> optional (look "id")
-- >     let qfun = fmap (IxSet.getEQ . Index) mId
-- >     entries <- join $ blogEntries blog qd qfun
-- >     blogMarkup <- siteTemplate hs [entries]
-- >     ok . toResponse $ blogMarkup -- happstack specific
-- >   where
-- >     hs = [ H.title "Saeptain's log" ]
-- >
-- > myBlogConfig :: BlogConfig (ServerPartT IO)
-- > myBlogConfig =
-- >     let cfg = createDefaultBlogConfig "/home/saep/git/myblog"
-- >     in cfg { baseURL = return "http://127.0.0.1:8000/blog" }
-- >
-- > main :: IO ()
-- > main = rbb $ withBlog myBlogConfig $ \b -> do
-- >     liftIO $ simpleHTTP (nullConf { port = 8000 }) $ msum
-- >         [ dir "resources" $ serveDirectory DisableBrowsing [] "/home/saep/git/blog/resources"
-- >         , serveBlog b
-- >         , notFound $ toResponse ()
-- >         ]
--
-- The Query module, which you will be missing apart from the obvious missing
-- libraries is located in @lib/Query.hs@
--
-- > module Query where
-- >
-- > import Happstack.Server (look, HasRqData, ServerPartT)
-- > import Web.RBB.Blog.Query
-- > import Control.Applicative
-- > import Data.Maybe
-- >
-- > readMaybe :: Read a => String -> Maybe a
-- > readMaybe x = case reads x of
-- >     [(v,_)] -> Just v
-- >     _ -> Nothing
-- >
-- > -- | 'look' at the request data of the given name and try to parse it via
-- > -- 'readMaybe'. If the parse failed or the request data did not exist, return
-- > -- the provided default.
-- > maybeLookAndRead :: (Monad m, Read a, Alternative m, HasRqData m)
-- >                  => a -> String -> m a
-- > maybeLookAndRead a qry = do
-- >     l <- optional $ look qry
-- >     return $ fromMaybe a (maybe (Just a) readMaybe l)
-- >
-- > -- | Parse the supported request data and present it in a data type.
-- > parseQueryRqData :: ServerPartT IO EntryQuery
-- > parseQueryRqData = EntryQuery
-- >     <$> (sortMethodToComparator
-- >         <$> maybeLookAndRead Update "sortBy"
-- >         <*> maybeLookAndRead Descending "sortOrder")



-- $ixsetquery
-- These newtype wrappers are used by the 'IxSet' of 'Entry' values and needed
-- for search queries.
--
-- > queryEntryForIdentifier :: Ixset Entry -> Maybe Entry
-- > queryEntryForIdentifier set = getOne $ set @= Index 42
--