module Rules.Blog.EachPostSeries (
    eachPostsSeries
) where

import           Control.Monad        (forM_, (>=>))
import           Control.Monad.Reader (asks)
import           Control.Monad.Trans  (MonadTrans (..))
import           Data.Maybe           (catMaybes)
import           Hakyll

import           Config.Blog          (BlogConfig (..))
import           Rules.Blog.Type

eachPostsSeries :: (Context String -> Rules ()) -> BlogConfReader m Rules ()
eachPostsSeries :: forall (m :: * -> *).
(Context String -> Rules ()) -> BlogConfReader m Rules ()
eachPostsSeries Context String -> Rules ()
rules = do
    [Identifier]
postIDs <- (BlogConfig m -> Pattern) -> ReaderT (BlogConfig m) Rules Pattern
forall r (m :: * -> *) a. MonadReader r m => (r -> a) -> m a
asks BlogConfig m -> Pattern
forall (m :: * -> *). BlogConfig m -> Pattern
blogEntryPattern ReaderT (BlogConfig m) Rules Pattern
-> (Pattern -> ReaderT (BlogConfig m) Rules [Identifier])
-> ReaderT (BlogConfig m) Rules [Identifier]
forall a b.
ReaderT (BlogConfig m) Rules a
-> (a -> ReaderT (BlogConfig m) Rules b)
-> ReaderT (BlogConfig m) Rules b
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= Rules [Identifier] -> ReaderT (BlogConfig m) Rules [Identifier]
forall (m :: * -> *) a.
Monad m =>
m a -> ReaderT (BlogConfig m) m a
forall (t :: (* -> *) -> * -> *) (m :: * -> *) a.
(MonadTrans t, Monad m) =>
m a -> t m a
lift (Rules [Identifier] -> ReaderT (BlogConfig m) Rules [Identifier])
-> (Pattern -> Rules [Identifier])
-> Pattern
-> ReaderT (BlogConfig m) Rules [Identifier]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Pattern -> Rules [Identifier]
forall (m :: * -> *). MonadMetadata m => Pattern -> m [Identifier]
getMatches (Pattern -> Rules [Identifier])
-> ([Identifier] -> Rules [Identifier])
-> Pattern
-> Rules [Identifier]
forall (m :: * -> *) a b c.
Monad m =>
(a -> m b) -> (b -> m c) -> a -> m c
>=> [Identifier] -> Rules [Identifier]
forall (m :: * -> *).
(MonadMetadata m, MonadFail m) =>
[Identifier] -> m [Identifier]
sortChronological)
    [(Identifier, Maybe Identifier, Maybe Identifier)]
-> ((Identifier, Maybe Identifier, Maybe Identifier)
    -> BlogConfReader m Rules ())
-> BlogConfReader m Rules ()
forall (t :: * -> *) (m :: * -> *) a b.
(Foldable t, Monad m) =>
t a -> (a -> m b) -> m ()
forM_ ([Identifier]
-> [Maybe Identifier]
-> [Maybe Identifier]
-> [(Identifier, Maybe Identifier, Maybe Identifier)]
forall a b c. [a] -> [b] -> [c] -> [(a, b, c)]
zip3 [Identifier]
postIDs ([Identifier] -> [Maybe Identifier]
forall {a}. [a] -> [Maybe a]
nextPosts [Identifier]
postIDs) ([Identifier] -> [Maybe Identifier]
forall {a}. [a] -> [Maybe a]
prevPosts [Identifier]
postIDs)) (((Identifier, Maybe Identifier, Maybe Identifier)
  -> BlogConfReader m Rules ())
 -> BlogConfReader m Rules ())
-> ((Identifier, Maybe Identifier, Maybe Identifier)
    -> BlogConfReader m Rules ())
-> BlogConfReader m Rules ()
forall a b. (a -> b) -> a -> b
$ \(Identifier
pID, Maybe Identifier
np, Maybe Identifier
pp) -> do
        Identifier -> Item String -> Compiler String
pageTitleOf' <- (BlogConfig m -> Identifier -> Item String -> Compiler String)
-> ReaderT
     (BlogConfig m) Rules (Identifier -> Item String -> Compiler String)
forall r (m :: * -> *) a. MonadReader r m => (r -> a) -> m a
asks ((BlogConfig m -> Identifier -> Item String -> Compiler String)
 -> ReaderT
      (BlogConfig m)
      Rules
      (Identifier -> Item String -> Compiler String))
-> (BlogConfig m -> Identifier -> Item String -> Compiler String)
-> ReaderT
     (BlogConfig m) Rules (Identifier -> Item String -> Compiler String)
forall a b. (a -> b) -> a -> b
$ Int -> Identifier -> Item String -> Compiler String
forall {m :: * -> *} {b}.
(MonadMetadata m, MonadFail m) =>
Int -> Identifier -> b -> m String
pageTitleOf (Int -> Identifier -> Item String -> Compiler String)
-> (BlogConfig m -> Int)
-> BlogConfig m
-> Identifier
-> Item String
-> Compiler String
forall b c a. (b -> c) -> (a -> b) -> a -> c
. BlogConfig m -> Int
forall (m :: * -> *). BlogConfig m -> Int
blogPrevNextTitleMaxNum
        Rules () -> BlogConfReader m Rules ()
forall (m :: * -> *) a.
Monad m =>
m a -> ReaderT (BlogConfig m) m a
forall (t :: (* -> *) -> * -> *) (m :: * -> *) a.
(MonadTrans t, Monad m) =>
m a -> t m a
lift (Rules () -> BlogConfReader m Rules ())
-> Rules () -> BlogConfReader m Rules ()
forall a b. (a -> b) -> a -> b
$ [Identifier] -> Rules () -> Rules ()
create [Identifier
pID] (Rules () -> Rules ()) -> Rules () -> Rules ()
forall a b. (a -> b) -> a -> b
$
            Context String -> Rules ()
rules (Context String -> Rules ()) -> Context String -> Rules ()
forall a b. (a -> b) -> a -> b
$ [Context String] -> Context String
forall a. Monoid a => [a] -> a
mconcat ([Context String] -> Context String)
-> [Context String] -> Context String
forall a b. (a -> b) -> a -> b
$ [Maybe (Context String)] -> [Context String]
forall a. [Maybe a] -> [a]
catMaybes [
                String -> (Item String -> Compiler String) -> Context String
forall a. String -> (Item a -> Compiler String) -> Context a
field String
"previousPageUrl" ((Item String -> Compiler String) -> Context String)
-> (Identifier -> Item String -> Compiler String)
-> Identifier
-> Context String
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Identifier -> Item String -> Compiler String
forall {b}. Identifier -> b -> Compiler String
pageUrlOf (Identifier -> Context String)
-> Maybe Identifier -> Maybe (Context String)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Maybe Identifier
pp
              , String -> (Item String -> Compiler String) -> Context String
forall a. String -> (Item a -> Compiler String) -> Context a
field String
"previousPageTitle" ((Item String -> Compiler String) -> Context String)
-> (Identifier -> Item String -> Compiler String)
-> Identifier
-> Context String
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Identifier -> Item String -> Compiler String
pageTitleOf' (Identifier -> Context String)
-> Maybe Identifier -> Maybe (Context String)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Maybe Identifier
pp
              , String -> (Item String -> Compiler String) -> Context String
forall a. String -> (Item a -> Compiler String) -> Context a
field String
"previousPageDate" ((Item String -> Compiler String) -> Context String)
-> (Identifier -> Item String -> Compiler String)
-> Identifier
-> Context String
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Identifier -> Item String -> Compiler String
forall {m :: * -> *} {b}.
(MonadMetadata m, MonadFail m) =>
Identifier -> b -> m String
pageDateOf (Identifier -> Context String)
-> Maybe Identifier -> Maybe (Context String)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Maybe Identifier
pp
              , String -> (Item String -> Compiler String) -> Context String
forall a. String -> (Item a -> Compiler String) -> Context a
field String
"nextPageUrl" ((Item String -> Compiler String) -> Context String)
-> (Identifier -> Item String -> Compiler String)
-> Identifier
-> Context String
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Identifier -> Item String -> Compiler String
forall {b}. Identifier -> b -> Compiler String
pageUrlOf (Identifier -> Context String)
-> Maybe Identifier -> Maybe (Context String)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Maybe Identifier
np
              , String -> (Item String -> Compiler String) -> Context String
forall a. String -> (Item a -> Compiler String) -> Context a
field String
"nextPageTitle" ((Item String -> Compiler String) -> Context String)
-> (Identifier -> Item String -> Compiler String)
-> Identifier
-> Context String
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Identifier -> Item String -> Compiler String
pageTitleOf' (Identifier -> Context String)
-> Maybe Identifier -> Maybe (Context String)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Maybe Identifier
np
              , String -> (Item String -> Compiler String) -> Context String
forall a. String -> (Item a -> Compiler String) -> Context a
field String
"nextPageDate" ((Item String -> Compiler String) -> Context String)
-> (Identifier -> Item String -> Compiler String)
-> Identifier
-> Context String
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Identifier -> Item String -> Compiler String
forall {m :: * -> *} {b}.
(MonadMetadata m, MonadFail m) =>
Identifier -> b -> m String
pageDateOf (Identifier -> Context String)
-> Maybe Identifier -> Maybe (Context String)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Maybe Identifier
np
              ]
    where
        nextPosts :: [a] -> [Maybe a]
nextPosts [a]
postIDs = Int -> [Maybe a] -> [Maybe a]
forall a. Int -> [a] -> [a]
drop Int
1 ([Maybe a] -> [Maybe a]) -> [Maybe a] -> [Maybe a]
forall a b. (a -> b) -> a -> b
$ (a -> Maybe a) -> [a] -> [Maybe a]
forall a b. (a -> b) -> [a] -> [b]
map a -> Maybe a
forall a. a -> Maybe a
Just [a]
postIDs [Maybe a] -> [Maybe a] -> [Maybe a]
forall a. [a] -> [a] -> [a]
++ [Maybe a
forall a. Maybe a
Nothing]
        prevPosts :: [a] -> [Maybe a]
prevPosts [a]
postIDs = Maybe a
forall a. Maybe a
Nothing Maybe a -> [Maybe a] -> [Maybe a]
forall a. a -> [a] -> [a]
: (a -> Maybe a) -> [a] -> [Maybe a]
forall a b. (a -> b) -> [a] -> [b]
map a -> Maybe a
forall a. a -> Maybe a
Just [a]
postIDs
        pageTitleOf :: Int -> Identifier -> b -> m String
pageTitleOf Int
titleMax Identifier
i = m String -> b -> m String
forall a b. a -> b -> a
const (m String -> b -> m String) -> m String -> b -> m String
forall a b. (a -> b) -> a -> b
$ Identifier -> String -> m (Maybe String)
forall (m :: * -> *).
MonadMetadata m =>
Identifier -> String -> m (Maybe String)
getMetadataField Identifier
i String
"title"
            m (Maybe String) -> (Maybe String -> m String) -> m String
forall a b. m a -> (a -> m b) -> m b
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= m String -> (String -> m String) -> Maybe String -> m String
forall b a. b -> (a -> b) -> Maybe a -> b
maybe (String -> m String
forall a. String -> m a
forall (m :: * -> *) a. MonadFail m => String -> m a
fail String
"no 'title' field")
                (\String
t -> String -> m String
forall a. a -> m a
forall (m :: * -> *) a. Monad m => a -> m a
return (String -> m String) -> String -> m String
forall a b. (a -> b) -> a -> b
$ if String -> Int
forall a. [a] -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length String
t Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
> Int
titleMax then Int -> String -> String
forall a. Int -> [a] -> [a]
take Int
titleMax String
t String -> String -> String
forall a. Semigroup a => a -> a -> a
<> String
"..." else String
t)
        pageUrlOf :: Identifier -> b -> Compiler String
pageUrlOf Identifier
i = Compiler String -> b -> Compiler String
forall a b. a -> b -> a
const (Identifier -> Compiler (Maybe String)
getRoute Identifier
i Compiler (Maybe String)
-> (Maybe String -> Compiler String) -> Compiler String
forall a b. Compiler a -> (a -> Compiler b) -> Compiler b
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= Compiler String
-> (String -> Compiler String) -> Maybe String -> Compiler String
forall b a. b -> (a -> b) -> Maybe a -> b
maybe (String -> Compiler String
forall a. String -> Compiler a
forall (m :: * -> *) a. MonadFail m => String -> m a
fail String
"no route") (String -> Compiler String
forall a. a -> Compiler a
forall (m :: * -> *) a. Monad m => a -> m a
return (String -> Compiler String)
-> (String -> String) -> String -> Compiler String
forall b c a. (b -> c) -> (a -> b) -> a -> c
. String -> String
toUrl))
        pageDateOf :: Identifier -> b -> m String
pageDateOf Identifier
i = m String -> b -> m String
forall a b. a -> b -> a
const (m String -> b -> m String) -> m String -> b -> m String
forall a b. (a -> b) -> a -> b
$
            Identifier -> String -> m (Maybe String)
forall (m :: * -> *).
MonadMetadata m =>
Identifier -> String -> m (Maybe String)
getMetadataField Identifier
i String
"date"
                m (Maybe String) -> (Maybe String -> m String) -> m String
forall a b. m a -> (a -> m b) -> m b
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= m String -> (String -> m String) -> Maybe String -> m String
forall b a. b -> (a -> b) -> Maybe a -> b
maybe (String -> m String
forall a. String -> m a
forall (m :: * -> *) a. MonadFail m => String -> m a
fail String
"no 'date' field") (String -> m String
forall a. a -> m a
forall (m :: * -> *) a. Monad m => a -> m a
return (String -> m String) -> (String -> String) -> String -> m String
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Char -> Char) -> String -> String
forall a b. (a -> b) -> [a] -> [b]
map (\Char
x -> if Char
x Char -> Char -> Bool
forall a. Eq a => a -> a -> Bool
== Char
'-' then Char
'/' else Char
x))