-- | Functions for pretty-printing games to the console.
module Hs2048.Renderer
    ( center
    , color
    , renderBoard
    , renderGame
    , renderTile
    ) where

import           Data.Monoid  ((<>))
import qualified Hs2048.Board as B
import qualified Hs2048.Tile  as T

{- |
    Centers a string in the given number of characters, using spaces for
    padding.

    >>> center 3 "x"
    " x "
    >>> center 2 "x"
    " x"
-}
center :: Int -> String -> String
center w s = prefix <> s <> suffix
  where
    prefix = replicate (ceiling n) ' '
    suffix = replicate (floor n) ' '
    n = fromIntegral (w - length s) / (2 :: Float)

{- |
    Calculates the color code for a tile. See
    <http://en.wikipedia.org/wiki/ANSI_escape_code#Colors>.

    >>> color Nothing
    30
    >>> color (Just 2)
    31
    >>> color (Just 2048)
    45
-}
color :: T.Tile -> Int
color t = 30 + x
  where
    x = if r > 6 then r + 4 else r
    r = T.rank t

{- |
    Renders a board with colorized, centered tiles. See 'renderTile' and
    'center'.

    >>> renderBoard [[Nothing, Just 2]]
    "\ESC[30m-\ESC[0m \ESC[31m2\ESC[0m\n"
    >>> renderBoard [[Nothing, Just 16]]
    " \ESC[30m-\ESC[0m \ESC[34m16\ESC[0m\n"
-}
renderBoard :: B.Board -> String
renderBoard b = unlines (fmap unwords vs')
  where
    vs' = fmap (fmap (center l)) vs
    vs = fmap (fmap renderTile) b
    l = maximum ls
    ls = vs >>= fmap length

{- |
    Renders a board along with its score. See 'renderBoard'.

    >>> renderGame [[Nothing, Just 2]]
    "Score: 0\n\ESC[30m-\ESC[0m \ESC[31m2\ESC[0m\n"
-}
renderGame :: B.Board -> String
renderGame b = concat
    [ "Score: "
    , show (B.score b)
    , "\n"
    , renderBoard b
    ]

{- |
    Renders a colorized tile. See 'color'.

    >>> renderTile Nothing
    "\ESC[30m-\ESC[0m"
    >>> renderTile (Just 2)
    "\ESC[31m2\ESC[0m"
-}
renderTile :: T.Tile -> String
renderTile t = concat
    [ "\ESC["
    , show (color t)
    , "m"
    , T.render t
    , "\ESC[0m"
    ]