    {-# LANGUAGE OverloadedStrings #-}
    {-# LANGUAGE ViewPatterns #-}

    module Util (
        relativeDirFromPieces,
        defaultMkRedirect,
        replace,
        remove,
        dropLastIfNull,
    ) where

    import Data.ByteString (ByteString)
    import qualified Data.ByteString.Char8 as S8
    import qualified Data.Text as T
    import qualified Data.Text.Encoding as TE
    import WaiAppStatic.Types

    -- alist helper functions
    replace :: Eq a => a -> b -> [(a, b)] -> [(a, b)]
    replace :: forall a b. Eq a => a -> b -> [(a, b)] -> [(a, b)]
    replace a
    k b
    v [] = [(a
    k, b
    v)]
    replace a
    k b
    v ((a, b)
    x : [(a, b)]
    xs)
        | (a, b) -> a
    forall a b. (a, b) -> a
    fst (a, b)
    x a -> a -> Bool
    forall a. Eq a => a -> a -> Bool
    == a
    k = (a
    k, b
    v) (a, b) -> [(a, b)] -> [(a, b)]
    forall a. a -> [a] -> [a]
    : [(a, b)]
    xs
        | Bool
    otherwise = (a, b)
    x (a, b) -> [(a, b)] -> [(a, b)]
    forall a. a -> [a] -> [a]
    : a -> b -> [(a, b)] -> [(a, b)]
    forall a b. Eq a => a -> b -> [(a, b)] -> [(a, b)]
    replace a
    k b
    v [(a, b)]
    xs

    remove :: Eq a => a -> [(a, b)] -> [(a, b)]
    remove :: forall a b. Eq a => a -> [(a, b)] -> [(a, b)]
    remove a
    _ [] = []
    remove a
    k ((a, b)
    x : [(a, b)]
    xs)
        | (a, b) -> a
    forall a b. (a, b) -> a
    fst (a, b)
    x a -> a -> Bool
    forall a. Eq a => a -> a -> Bool
    == a
    k = [(a, b)]
    xs
        | Bool
    otherwise = (a, b)
    x (a, b) -> [(a, b)] -> [(a, b)]
    forall a. a -> [a] -> [a]
    : a -> [(a, b)] -> [(a, b)]
    forall a b. Eq a => a -> [(a, b)] -> [(a, b)]
    remove a
    k [(a, b)]
    xs

    -- | Turn a list of pieces into a relative path to the root folder.
    relativeDirFromPieces :: Pieces -> T.Text
    relativeDirFromPieces :: Pieces -> Text
    relativeDirFromPieces Pieces
    pieces = [Text] -> Text
    T.concat ([Text] -> Text) -> [Text] -> Text
    forall a b. (a -> b) -> a -> b
    $ (Piece -> Text) -> Pieces -> [Text]
    forall a b. (a -> b) -> [a] -> [b]
    map (Text -> Piece -> Text
    forall a b. a -> b -> a
    const Text
    "../") (Int -> Pieces -> Pieces
    forall a. Int -> [a] -> [a]
    drop Int
    1 Pieces
    pieces) -- last piece is not a dir

    -- | Construct redirects with relative paths.
    defaultMkRedirect :: Pieces -> ByteString -> S8.ByteString
    defaultMkRedirect :: Pieces -> ByteString -> ByteString
    defaultMkRedirect Pieces
    pieces ByteString
    newPath
        | ByteString -> Bool
    S8.null ByteString
    newPath
            Bool -> Bool -> Bool
    || ByteString -> Bool
    S8.null ByteString
    relDir
            Bool -> Bool -> Bool
    || ByteString -> Char
    S8.last ByteString
    relDir Char -> Char -> Bool
    forall a. Eq a => a -> a -> Bool
    /= Char
    '/'
            Bool -> Bool -> Bool
    || ByteString -> Char
    S8.head ByteString
    newPath Char -> Char -> Bool
    forall a. Eq a => a -> a -> Bool
    /= Char
    '/' =
            ByteString
    relDir ByteString -> ByteString -> ByteString
    `S8.append` ByteString
    newPath
        | Bool
    otherwise = ByteString
    relDir ByteString -> ByteString -> ByteString
    `S8.append` HasCallStack => ByteString -> ByteString
    ByteString -> ByteString
    S8.tail ByteString
    newPath
      where
        relDir :: ByteString
    relDir = Text -> ByteString
    TE.encodeUtf8 (Pieces -> Text
    relativeDirFromPieces Pieces
    pieces)

    dropLastIfNull :: [Piece] -> [Piece]
    dropLastIfNull :: Pieces -> Pieces
    dropLastIfNull Pieces
    pieces = case Pieces
    pieces of
        [Piece -> Text
    fromPiece -> Text
    ""] -> []
        (Piece
    a : Pieces
    r) -> Piece
    a Piece -> Pieces -> Pieces
    forall a. a -> [a] -> [a]
    : Pieces -> Pieces
    dropLastIfNull Pieces
    r
        [] -> []