{-|
Online Haskell Compiler.
Code, Compile, Run and Debug Haskell program online.
Write your code in this editor and press "Run" button to execute it.
-}
import System.Environment
data Side = Top | Centre | Bot deriving (Eq, Show)
art' :: Float -> Float -> IO ()
art' size depth = if depth > size then return () else putStrLn row >> art' size (depth+1)
where
side = if depth == (fromIntegral . ceiling $ size / 2) then Centre else if depth < (size / 2) then Top else Bot
startOrEnd = depth == 0 || depth == size
armWidth = floor $ size / 2
midOffset = if even (round size) then 2 else 1
stem = "X"
vArm = replicateBlank (armWidth-1) ++ "X"
hArm = replicateX armWidth
gap = replicateBlank armWidth
startRow = hArm ++ stem ++ vArm
gappedRow = gap ++ stem ++ vArm
midRow = replicateX (size + midOffset)
unsidedRow = if side == Centre then midRow else if startOrEnd then startRow else gappedRow
row = if side == Bot then reverse unsidedRow else unsidedRow
replicate s n = if n <= 0 then s else s ++ replicate s (n - 1)
replicateBlank n = replicate " " n
replicateX n = replicate "X" n
art n = art' (n + 4) 0
liftJust :: Maybe a -> a
liftJust (Just a) = a
interactive = putStrLn "Enter `size` [5 is the minimal offest hardcoded. smallest art size is 0]" >> loop
where
loop = getLine >>= \input -> let iSize = parseSize input in if iSize /= Nothing then art (liftJust iSize) >> loop else loop
parseSize :: String -> Maybe Float
parseSize n = case reads n of
[(n, "")] -> Just n
_ -> Nothing
main = interactive