-- Copyright 2014 Alvaro J. Genial [http://alva.ro]; see LICENSE file for more.

{-# LANGUAGE FlexibleInstances, OverlappingInstances, UndecidableInstances #-}

module Text.Neat.Output where

import Data.Char (isSpace)
import Data.Foldable (toList)
import Data.List (intercalate, stripPrefix)
-- import Text.Neat.Template

-- TODO? list, output, zero => toList, toString, toBool

list x = toList x


class Output a where
  output :: a -> String

instance (Show a) => Output a where
  output = show

instance Output a => Output [a] where
  output = concatMap output

instance Output a => Output (Maybe a) where
  output = maybe "" output

instance (Output a, Output b) => Output (Either a b) where
  output = either output output

instance Output Char where
  output = return

class Zero a where
  zero :: a -> Bool

instance Zero [a] where
  zero = null

instance Zero (Maybe a) where
  zero Nothing = True
  zero _       = False

instance (Num a, Eq a) => Zero a where
  zero = (== 0)

instance Zero Bool where
  zero = (== False)

instance Zero Char where
  zero = (== '\0')

join :: (Output a, Output b) => a -> [b] -> String
join d l = intercalate (output d) (fmap output l)

trim :: Output a => a -> String
trim = f . f . output where f = reverse . dropWhile isSpace

nest :: Output a => a -> String
nest = join "\n  " . lines . output

prune :: Output a => a -> String
prune = xxx . lines . output where
  xxx [l] = l
  xxx ls = join "\n" . filter fluff $ ls
  fluff l = any (not . isSpace) l || l == ""

unless :: (Zero a, Output a, Output b) => a -> b -> String
unless a b = if zero a then output b else output a

quote :: Output a => a -> String
quote = show . output

append :: (Output a, Output b) => a -> b -> String
append a b = output b ++ output a

prepend :: (Output a, Output b) => a -> b -> String
prepend a b = output a ++ output b