{-# LANGUAGE DeriveAnyClass #-}

-- | Route types representing the resources in our `Model`.
--
-- See also: `Emanote.Route.SiteRoute`.
module Emanote.Route.ModelRoute
  ( -- Some route in a generated site
    ModelRoute (..),
    modelRouteCase,
    mkModelRouteFromFilePath,
    -- Only LML routes
    LMLRoute (..),
    defaultLmlRoute,
    possibleLmlRoutes,
    lmlRouteCase,
    withLmlRoute,
    mkLMLRouteFromFilePath,
    mkLMLRouteFromKnownFilePath,
    isMdRoute,
    -- Static file routes
    StaticFileRoute,
  )
where

import Data.Aeson.Types (ToJSON)
import Emanote.Route.Ext (FileType (AnyExt, LMLType), HasExt, LML (Md, Org))
import Emanote.Route.R (R)
import Emanote.Route.R qualified as R
import Relude

type StaticFileRoute = R 'AnyExt

-- | A R to anywhere in `Model`
data ModelRoute
  = ModelRoute_StaticFile StaticFileRoute
  | ModelRoute_LML LMLRoute
  deriving stock (ModelRoute -> ModelRoute -> Bool
(ModelRoute -> ModelRoute -> Bool)
-> (ModelRoute -> ModelRoute -> Bool) -> Eq ModelRoute
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: ModelRoute -> ModelRoute -> Bool
$c/= :: ModelRoute -> ModelRoute -> Bool
== :: ModelRoute -> ModelRoute -> Bool
$c== :: ModelRoute -> ModelRoute -> Bool
Eq, Int -> ModelRoute -> ShowS
[ModelRoute] -> ShowS
ModelRoute -> String
(Int -> ModelRoute -> ShowS)
-> (ModelRoute -> String)
-> ([ModelRoute] -> ShowS)
-> Show ModelRoute
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [ModelRoute] -> ShowS
$cshowList :: [ModelRoute] -> ShowS
show :: ModelRoute -> String
$cshow :: ModelRoute -> String
showsPrec :: Int -> ModelRoute -> ShowS
$cshowsPrec :: Int -> ModelRoute -> ShowS
Show, Eq ModelRoute
Eq ModelRoute
-> (ModelRoute -> ModelRoute -> Ordering)
-> (ModelRoute -> ModelRoute -> Bool)
-> (ModelRoute -> ModelRoute -> Bool)
-> (ModelRoute -> ModelRoute -> Bool)
-> (ModelRoute -> ModelRoute -> Bool)
-> (ModelRoute -> ModelRoute -> ModelRoute)
-> (ModelRoute -> ModelRoute -> ModelRoute)
-> Ord ModelRoute
ModelRoute -> ModelRoute -> Bool
ModelRoute -> ModelRoute -> Ordering
ModelRoute -> ModelRoute -> ModelRoute
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 :: ModelRoute -> ModelRoute -> ModelRoute
$cmin :: ModelRoute -> ModelRoute -> ModelRoute
max :: ModelRoute -> ModelRoute -> ModelRoute
$cmax :: ModelRoute -> ModelRoute -> ModelRoute
>= :: ModelRoute -> ModelRoute -> Bool
$c>= :: ModelRoute -> ModelRoute -> Bool
> :: ModelRoute -> ModelRoute -> Bool
$c> :: ModelRoute -> ModelRoute -> Bool
<= :: ModelRoute -> ModelRoute -> Bool
$c<= :: ModelRoute -> ModelRoute -> Bool
< :: ModelRoute -> ModelRoute -> Bool
$c< :: ModelRoute -> ModelRoute -> Bool
compare :: ModelRoute -> ModelRoute -> Ordering
$ccompare :: ModelRoute -> ModelRoute -> Ordering
Ord, (forall x. ModelRoute -> Rep ModelRoute x)
-> (forall x. Rep ModelRoute x -> ModelRoute) -> Generic ModelRoute
forall x. Rep ModelRoute x -> ModelRoute
forall x. ModelRoute -> Rep ModelRoute x
forall a.
(forall x. a -> Rep a x) -> (forall x. Rep a x -> a) -> Generic a
$cto :: forall x. Rep ModelRoute x -> ModelRoute
$cfrom :: forall x. ModelRoute -> Rep ModelRoute x
Generic)
  deriving anyclass ([ModelRoute] -> Encoding
[ModelRoute] -> Value
ModelRoute -> Encoding
ModelRoute -> Value
(ModelRoute -> Value)
-> (ModelRoute -> Encoding)
-> ([ModelRoute] -> Value)
-> ([ModelRoute] -> Encoding)
-> ToJSON ModelRoute
forall a.
(a -> Value)
-> (a -> Encoding)
-> ([a] -> Value)
-> ([a] -> Encoding)
-> ToJSON a
toEncodingList :: [ModelRoute] -> Encoding
$ctoEncodingList :: [ModelRoute] -> Encoding
toJSONList :: [ModelRoute] -> Value
$ctoJSONList :: [ModelRoute] -> Value
toEncoding :: ModelRoute -> Encoding
$ctoEncoding :: ModelRoute -> Encoding
toJSON :: ModelRoute -> Value
$ctoJSON :: ModelRoute -> Value
ToJSON)

-- | R to a note file in LML (lightweight markup language) format
data LMLRoute
  = LMLRoute_Md (R ('LMLType 'Md))
  | LMLRoute_Org (R ('LMLType 'Org))
  deriving stock (LMLRoute -> LMLRoute -> Bool
(LMLRoute -> LMLRoute -> Bool)
-> (LMLRoute -> LMLRoute -> Bool) -> Eq LMLRoute
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: LMLRoute -> LMLRoute -> Bool
$c/= :: LMLRoute -> LMLRoute -> Bool
== :: LMLRoute -> LMLRoute -> Bool
$c== :: LMLRoute -> LMLRoute -> Bool
Eq, Int -> LMLRoute -> ShowS
[LMLRoute] -> ShowS
LMLRoute -> String
(Int -> LMLRoute -> ShowS)
-> (LMLRoute -> String) -> ([LMLRoute] -> ShowS) -> Show LMLRoute
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [LMLRoute] -> ShowS
$cshowList :: [LMLRoute] -> ShowS
show :: LMLRoute -> String
$cshow :: LMLRoute -> String
showsPrec :: Int -> LMLRoute -> ShowS
$cshowsPrec :: Int -> LMLRoute -> ShowS
Show, Eq LMLRoute
Eq LMLRoute
-> (LMLRoute -> LMLRoute -> Ordering)
-> (LMLRoute -> LMLRoute -> Bool)
-> (LMLRoute -> LMLRoute -> Bool)
-> (LMLRoute -> LMLRoute -> Bool)
-> (LMLRoute -> LMLRoute -> Bool)
-> (LMLRoute -> LMLRoute -> LMLRoute)
-> (LMLRoute -> LMLRoute -> LMLRoute)
-> Ord LMLRoute
LMLRoute -> LMLRoute -> Bool
LMLRoute -> LMLRoute -> Ordering
LMLRoute -> LMLRoute -> LMLRoute
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 :: LMLRoute -> LMLRoute -> LMLRoute
$cmin :: LMLRoute -> LMLRoute -> LMLRoute
max :: LMLRoute -> LMLRoute -> LMLRoute
$cmax :: LMLRoute -> LMLRoute -> LMLRoute
>= :: LMLRoute -> LMLRoute -> Bool
$c>= :: LMLRoute -> LMLRoute -> Bool
> :: LMLRoute -> LMLRoute -> Bool
$c> :: LMLRoute -> LMLRoute -> Bool
<= :: LMLRoute -> LMLRoute -> Bool
$c<= :: LMLRoute -> LMLRoute -> Bool
< :: LMLRoute -> LMLRoute -> Bool
$c< :: LMLRoute -> LMLRoute -> Bool
compare :: LMLRoute -> LMLRoute -> Ordering
$ccompare :: LMLRoute -> LMLRoute -> Ordering
Ord, (forall x. LMLRoute -> Rep LMLRoute x)
-> (forall x. Rep LMLRoute x -> LMLRoute) -> Generic LMLRoute
forall x. Rep LMLRoute x -> LMLRoute
forall x. LMLRoute -> Rep LMLRoute x
forall a.
(forall x. a -> Rep a x) -> (forall x. Rep a x -> a) -> Generic a
$cto :: forall x. Rep LMLRoute x -> LMLRoute
$cfrom :: forall x. LMLRoute -> Rep LMLRoute x
Generic)
  deriving anyclass ([LMLRoute] -> Encoding
[LMLRoute] -> Value
LMLRoute -> Encoding
LMLRoute -> Value
(LMLRoute -> Value)
-> (LMLRoute -> Encoding)
-> ([LMLRoute] -> Value)
-> ([LMLRoute] -> Encoding)
-> ToJSON LMLRoute
forall a.
(a -> Value)
-> (a -> Encoding)
-> ([a] -> Value)
-> ([a] -> Encoding)
-> ToJSON a
toEncodingList :: [LMLRoute] -> Encoding
$ctoEncodingList :: [LMLRoute] -> Encoding
toJSONList :: [LMLRoute] -> Value
$ctoJSONList :: [LMLRoute] -> Value
toEncoding :: LMLRoute -> Encoding
$ctoEncoding :: LMLRoute -> Encoding
toJSON :: LMLRoute -> Value
$ctoJSON :: LMLRoute -> Value
ToJSON)

defaultLmlRoute :: R (ext :: FileType a) -> LMLRoute
defaultLmlRoute :: forall a (ext :: FileType a). R @a ext -> LMLRoute
defaultLmlRoute =
  R @SourceExt ('LMLType 'Md) -> LMLRoute
LMLRoute_Md (R @SourceExt ('LMLType 'Md) -> LMLRoute)
-> (R @a ext -> R @SourceExt ('LMLType 'Md))
-> R @a ext
-> LMLRoute
forall b c a. (b -> c) -> (a -> b) -> a -> c
. R @a ext -> R @SourceExt ('LMLType 'Md)
coerce

possibleLmlRoutes :: R (ext :: FileType a) -> [LMLRoute]
possibleLmlRoutes :: forall a (ext :: FileType a). R @a ext -> [LMLRoute]
possibleLmlRoutes R @a ext
r =
  [ R @SourceExt ('LMLType 'Md) -> LMLRoute
LMLRoute_Md (R @a ext -> R @SourceExt ('LMLType 'Md)
coerce R @a ext
r),
    R @SourceExt ('LMLType 'Org) -> LMLRoute
LMLRoute_Org (R @a ext -> R @SourceExt ('LMLType 'Org)
coerce R @a ext
r)
  ]

lmlRouteCase ::
  LMLRoute ->
  Either (R ('LMLType 'Md)) (R ('LMLType 'Org))
lmlRouteCase :: LMLRoute
-> Either
     (R @SourceExt ('LMLType 'Md)) (R @SourceExt ('LMLType 'Org))
lmlRouteCase = \case
  LMLRoute_Md R @SourceExt ('LMLType 'Md)
r -> R @SourceExt ('LMLType 'Md)
-> Either
     (R @SourceExt ('LMLType 'Md)) (R @SourceExt ('LMLType 'Org))
forall a b. a -> Either a b
Left R @SourceExt ('LMLType 'Md)
r
  LMLRoute_Org R @SourceExt ('LMLType 'Org)
r -> R @SourceExt ('LMLType 'Org)
-> Either
     (R @SourceExt ('LMLType 'Md)) (R @SourceExt ('LMLType 'Org))
forall a b. b -> Either a b
Right R @SourceExt ('LMLType 'Org)
r

isMdRoute :: LMLRoute -> Bool
isMdRoute :: LMLRoute -> Bool
isMdRoute = \case
  LMLRoute_Md R @SourceExt ('LMLType 'Md)
_ -> Bool
True
  LMLRoute
_ -> Bool
False

withLmlRoute :: (forall lmlType. HasExt ('LMLType lmlType) => R ('LMLType lmlType) -> r) -> LMLRoute -> r
withLmlRoute :: forall r.
(forall (lmlType :: LML).
 HasExt @SourceExt ('LMLType lmlType) =>
 R @SourceExt ('LMLType lmlType) -> r)
-> LMLRoute -> r
withLmlRoute forall (lmlType :: LML).
HasExt @SourceExt ('LMLType lmlType) =>
R @SourceExt ('LMLType lmlType) -> r
f = (R @SourceExt ('LMLType 'Md) -> r)
-> (R @SourceExt ('LMLType 'Org) -> r)
-> Either
     (R @SourceExt ('LMLType 'Md)) (R @SourceExt ('LMLType 'Org))
-> r
forall a c b. (a -> c) -> (b -> c) -> Either a b -> c
either R @SourceExt ('LMLType 'Md) -> r
forall (lmlType :: LML).
HasExt @SourceExt ('LMLType lmlType) =>
R @SourceExt ('LMLType lmlType) -> r
f R @SourceExt ('LMLType 'Org) -> r
forall (lmlType :: LML).
HasExt @SourceExt ('LMLType lmlType) =>
R @SourceExt ('LMLType lmlType) -> r
f (Either
   (R @SourceExt ('LMLType 'Md)) (R @SourceExt ('LMLType 'Org))
 -> r)
-> (LMLRoute
    -> Either
         (R @SourceExt ('LMLType 'Md)) (R @SourceExt ('LMLType 'Org)))
-> LMLRoute
-> r
forall b c a. (b -> c) -> (a -> b) -> a -> c
. LMLRoute
-> Either
     (R @SourceExt ('LMLType 'Md)) (R @SourceExt ('LMLType 'Org))
lmlRouteCase

modelRouteCase ::
  ModelRoute ->
  Either LMLRoute StaticFileRoute
modelRouteCase :: ModelRoute -> Either LMLRoute StaticFileRoute
modelRouteCase = \case
  ModelRoute_LML LMLRoute
r -> LMLRoute -> Either LMLRoute StaticFileRoute
forall a b. a -> Either a b
Left LMLRoute
r
  ModelRoute_StaticFile StaticFileRoute
r -> StaticFileRoute -> Either LMLRoute StaticFileRoute
forall a b. b -> Either a b
Right StaticFileRoute
r

mkModelRouteFromFilePath :: FilePath -> Maybe ModelRoute
mkModelRouteFromFilePath :: String -> Maybe ModelRoute
mkModelRouteFromFilePath String
fp =
  (LMLRoute -> ModelRoute) -> Maybe LMLRoute -> Maybe ModelRoute
forall (f :: Type -> Type) a b. Functor f => (a -> b) -> f a -> f b
fmap LMLRoute -> ModelRoute
ModelRoute_LML (String -> Maybe LMLRoute
mkLMLRouteFromFilePath String
fp)
    Maybe ModelRoute -> Maybe ModelRoute -> Maybe ModelRoute
forall (f :: Type -> Type) a. Alternative f => f a -> f a -> f a
<|> (StaticFileRoute -> ModelRoute)
-> Maybe StaticFileRoute -> Maybe ModelRoute
forall (f :: Type -> Type) a b. Functor f => (a -> b) -> f a -> f b
fmap StaticFileRoute -> ModelRoute
ModelRoute_StaticFile (String -> Maybe StaticFileRoute
forall a (ext :: FileType a).
HasExt @a ext =>
String -> Maybe (R @a ext)
R.mkRouteFromFilePath String
fp)

mkLMLRouteFromFilePath :: FilePath -> Maybe LMLRoute
mkLMLRouteFromFilePath :: String -> Maybe LMLRoute
mkLMLRouteFromFilePath String
fp =
  LML -> String -> Maybe LMLRoute
mkLMLRouteFromKnownFilePath LML
Md String
fp
    Maybe LMLRoute -> Maybe LMLRoute -> Maybe LMLRoute
forall (f :: Type -> Type) a. Alternative f => f a -> f a -> f a
<|> LML -> String -> Maybe LMLRoute
mkLMLRouteFromKnownFilePath LML
Org String
fp

-- | Like `mkLMLRouteFromFilePath`, but when the file extension is known ahead
-- to be of `lmlType`.
mkLMLRouteFromKnownFilePath :: LML -> FilePath -> Maybe LMLRoute
mkLMLRouteFromKnownFilePath :: LML -> String -> Maybe LMLRoute
mkLMLRouteFromKnownFilePath LML
lmlType String
fp =
  case LML
lmlType of
    LML
Md -> (R @SourceExt ('LMLType 'Md) -> LMLRoute)
-> Maybe (R @SourceExt ('LMLType 'Md)) -> Maybe LMLRoute
forall (f :: Type -> Type) a b. Functor f => (a -> b) -> f a -> f b
fmap R @SourceExt ('LMLType 'Md) -> LMLRoute
LMLRoute_Md (String -> Maybe (R @SourceExt ('LMLType 'Md))
forall a (ext :: FileType a).
HasExt @a ext =>
String -> Maybe (R @a ext)
R.mkRouteFromFilePath String
fp)
    LML
Org -> (R @SourceExt ('LMLType 'Org) -> LMLRoute)
-> Maybe (R @SourceExt ('LMLType 'Org)) -> Maybe LMLRoute
forall (f :: Type -> Type) a b. Functor f => (a -> b) -> f a -> f b
fmap R @SourceExt ('LMLType 'Org) -> LMLRoute
LMLRoute_Org (String -> Maybe (R @SourceExt ('LMLType 'Org))
forall a (ext :: FileType a).
HasExt @a ext =>
String -> Maybe (R @a ext)
R.mkRouteFromFilePath String
fp)