--------------------------------------------------------------------------------
-- | An identifier is a type used to uniquely identify an item. An identifier is
-- conceptually similar to a file path. Examples of identifiers are:
--
-- * @posts/foo.markdown@
--
-- * @index@
--
-- * @error/404@
{-# LANGUAGE DeriveDataTypeable         #-}
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
module Hakyll.Core.Identifier
    ( Identifier
    , fromFilePath
    , toFilePath
    , identifierVersion
    , setVersion
    ) where


--------------------------------------------------------------------------------
import           Control.DeepSeq     (NFData (..))
import           Data.List           (intercalate)
import           System.FilePath     (dropTrailingPathSeparator, splitPath,
                                      pathSeparator, normalise)


--------------------------------------------------------------------------------
import           Data.Binary         (Binary (..))
import           Data.Typeable       (Typeable)
import           GHC.Exts            (IsString, fromString)


--------------------------------------------------------------------------------
data Identifier = Identifier
    { Identifier -> Maybe String
identifierVersion :: Maybe String
    , Identifier -> String
identifierPath    :: String
    } deriving (Identifier -> Identifier -> Bool
(Identifier -> Identifier -> Bool)
-> (Identifier -> Identifier -> Bool) -> Eq Identifier
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: Identifier -> Identifier -> Bool
$c/= :: Identifier -> Identifier -> Bool
== :: Identifier -> Identifier -> Bool
$c== :: Identifier -> Identifier -> Bool
Eq, Eq Identifier
Eq Identifier
-> (Identifier -> Identifier -> Ordering)
-> (Identifier -> Identifier -> Bool)
-> (Identifier -> Identifier -> Bool)
-> (Identifier -> Identifier -> Bool)
-> (Identifier -> Identifier -> Bool)
-> (Identifier -> Identifier -> Identifier)
-> (Identifier -> Identifier -> Identifier)
-> Ord Identifier
Identifier -> Identifier -> Bool
Identifier -> Identifier -> Ordering
Identifier -> Identifier -> Identifier
forall a.
Eq a
-> (a -> a -> Ordering)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> a)
-> (a -> a -> a)
-> Ord a
min :: Identifier -> Identifier -> Identifier
$cmin :: Identifier -> Identifier -> Identifier
max :: Identifier -> Identifier -> Identifier
$cmax :: Identifier -> Identifier -> Identifier
>= :: Identifier -> Identifier -> Bool
$c>= :: Identifier -> Identifier -> Bool
> :: Identifier -> Identifier -> Bool
$c> :: Identifier -> Identifier -> Bool
<= :: Identifier -> Identifier -> Bool
$c<= :: Identifier -> Identifier -> Bool
< :: Identifier -> Identifier -> Bool
$c< :: Identifier -> Identifier -> Bool
compare :: Identifier -> Identifier -> Ordering
$ccompare :: Identifier -> Identifier -> Ordering
$cp1Ord :: Eq Identifier
Ord, Typeable)


--------------------------------------------------------------------------------
instance Binary Identifier where
    put :: Identifier -> Put
put (Identifier Maybe String
v String
p) = Maybe String -> Put
forall t. Binary t => t -> Put
put Maybe String
v Put -> Put -> Put
forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>> String -> Put
forall t. Binary t => t -> Put
put String
p
    get :: Get Identifier
get = Maybe String -> String -> Identifier
Identifier (Maybe String -> String -> Identifier)
-> Get (Maybe String) -> Get (String -> Identifier)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Get (Maybe String)
forall t. Binary t => Get t
get Get (String -> Identifier) -> Get String -> Get Identifier
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> Get String
forall t. Binary t => Get t
get


--------------------------------------------------------------------------------
instance IsString Identifier where
    fromString :: String -> Identifier
fromString = String -> Identifier
fromFilePath


--------------------------------------------------------------------------------
instance NFData Identifier where
    rnf :: Identifier -> ()
rnf (Identifier Maybe String
v String
p) = Maybe String -> ()
forall a. NFData a => a -> ()
rnf Maybe String
v () -> () -> ()
`seq` String -> ()
forall a. NFData a => a -> ()
rnf String
p () -> () -> ()
`seq` ()


--------------------------------------------------------------------------------
instance Show Identifier where
    show :: Identifier -> String
show Identifier
i = case Identifier -> Maybe String
identifierVersion Identifier
i of
        Maybe String
Nothing -> Identifier -> String
toFilePath Identifier
i
        Just String
v  -> Identifier -> String
toFilePath Identifier
i String -> ShowS
forall a. [a] -> [a] -> [a]
++ String
" (" String -> ShowS
forall a. [a] -> [a] -> [a]
++ String
v String -> ShowS
forall a. [a] -> [a] -> [a]
++ String
")"


--------------------------------------------------------------------------------
-- | Parse an identifier from a string
fromFilePath :: FilePath -> Identifier
fromFilePath :: String -> Identifier
fromFilePath = Maybe String -> String -> Identifier
Identifier Maybe String
forall a. Maybe a
Nothing (String -> Identifier) -> ShowS -> String -> Identifier
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ShowS
normalise


--------------------------------------------------------------------------------
-- | Convert an identifier to a relative 'FilePath'
toFilePath :: Identifier -> FilePath
toFilePath :: Identifier -> String
toFilePath = ShowS
normalise ShowS -> (Identifier -> String) -> Identifier -> String
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Identifier -> String
identifierPath


--------------------------------------------------------------------------------
setVersion :: Maybe String -> Identifier -> Identifier
setVersion :: Maybe String -> Identifier -> Identifier
setVersion Maybe String
v Identifier
i = Identifier
i {identifierVersion :: Maybe String
identifierVersion = Maybe String
v}