{-# LANGUAGE FlexibleInstances #-}
module Text.Layout.Table.StringBuilder where

import Data.Semigroup
import qualified Data.Text as T
import qualified Data.Text.Lazy.Builder as TB

-- | A type that is used to construct parts of a table.
class Monoid a => StringBuilder a where
    -- | Create a builder with a 'String'.
    stringB :: String -> a

    -- | Create a builder with a single 'Char'.
    charB :: Char -> a

    -- | Create a builder with a 'Text'.
    textB :: T.Text -> a
    textB = String -> a
forall a. StringBuilder a => String -> a
stringB (String -> a) -> (Text -> String) -> Text -> a
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Text -> String
T.unpack

    -- | Create a builder with several 'Char's.
    replicateCharB :: Int -> Char -> a
    replicateCharB Int
i Char
c = Int -> a -> a
forall b a. (Integral b, Monoid a) => b -> a -> a
stimesMonoid Int
i (Char -> a
forall a. StringBuilder a => Char -> a
charB Char
c)

    {-# MINIMAL stringB, charB #-}

-- | Create a builder that contains /k/ spaces. Negative numbers are treated as
-- zero.
spacesB :: StringBuilder a => Int -> a
spacesB :: forall a. StringBuilder a => Int -> a
spacesB Int
k = Int -> Char -> a
forall a. StringBuilder a => Int -> Char -> a
replicateCharB Int
k Char
' '

-- | Creates a 'StringBuilder' with the amount of missing spaces.
remSpacesB'
    :: StringBuilder b
    => Int -- ^ The expected length.
    -> Int -- ^ The actual length.
    -> b
remSpacesB' :: forall b. StringBuilder b => Int -> Int -> b
remSpacesB' Int
n Int
k = Int -> b
forall a. StringBuilder a => Int -> a
spacesB (Int -> b) -> Int -> b
forall a b. (a -> b) -> a -> b
$ Int
n Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
k

instance StringBuilder String where
    stringB :: String -> String
stringB = String -> String
forall a. a -> a
id
    charB :: Char -> String
charB = (Char -> String -> String
forall a. a -> [a] -> [a]
: [])
    replicateCharB :: Int -> Char -> String
replicateCharB = Int -> Char -> String
forall a. Int -> a -> [a]
replicate

instance StringBuilder (Endo String) where
    stringB :: String -> Endo String
stringB = String -> Endo String
forall m. Semigroup m => m -> Endo m
diff
    charB :: Char -> Endo String
charB = (String -> String) -> Endo String
forall a. (a -> a) -> Endo a
Endo ((String -> String) -> Endo String)
-> (Char -> String -> String) -> Char -> Endo String
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (:)
    replicateCharB :: Int -> Char -> Endo String
replicateCharB Int
i Char
c = Int -> Endo String -> Endo String
forall b a. (Integral b, Monoid a) => b -> a -> a
stimesMonoid Int
i ((String -> String) -> Endo String
forall a. (a -> a) -> Endo a
Endo (Char
c Char -> String -> String
forall a. a -> [a] -> [a]
:))

instance StringBuilder T.Text where
    stringB :: String -> Text
stringB = String -> Text
T.pack
    charB :: Char -> Text
charB = Char -> Text
T.singleton
    textB :: Text -> Text
textB = Text -> Text
forall a. a -> a
id
    replicateCharB :: Int -> Char -> Text
replicateCharB Int
n = Int -> Text -> Text
T.replicate Int
n (Text -> Text) -> (Char -> Text) -> Char -> Text
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Char -> Text
T.singleton

instance StringBuilder TB.Builder where
    stringB :: String -> Builder
stringB = String -> Builder
TB.fromString
    charB :: Char -> Builder
charB = Char -> Builder
TB.singleton
    textB :: Text -> Builder
textB = Text -> Builder
TB.fromText
    replicateCharB :: Int -> Char -> Builder
replicateCharB Int
n = Text -> Builder
TB.fromText (Text -> Builder) -> (Char -> Text) -> Char -> Builder
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Int -> Text -> Text
T.replicate Int
n (Text -> Text) -> (Char -> Text) -> Char -> Text
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Char -> Text
T.singleton