{-
	Copyright (C) 2018 Dr. Alistair Ward

	This file is part of BishBosh.

	BishBosh is free software: you can redistribute it and/or modify
	it under the terms of the GNU General Public License as published by
	the Free Software Foundation, either version 3 of the License, or
	(at your option) any later version.

	BishBosh is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
	GNU General Public License for more details.

	You should have received a copy of the GNU General Public License
	along with BishBosh.  If not, see <http://www.gnu.org/licenses/>.
-}
{- |
 [@AUTHOR@]	Dr. Alistair Ward

 [@DESCRIPTION@]	Exports functions to facilitate unification of the style of output text.
-}

module BishBosh.Text.ShowList(
-- * Constants
	showsInfoPrefix,
	showsWarningPrefix,
	showsErrorPrefix,
	showsAssociation,
-- * Functions
	capitaliseInitial,
	showsSeparator,
	showsDelimitedList,
	showsUnterminatedList,
	showsFormattedList,
	showsFormattedList',
	showsAssociationList,
	showsAssociationList',
	splitOn
) where

import qualified	Data.Char
import qualified	Data.List

-- | Used to qualify output.
showsInfoPrefix :: ShowS
showsInfoPrefix		= showString "INFO:\t"

-- | Used to qualify output.
showsWarningPrefix :: ShowS
showsWarningPrefix	= showString "WARNING:\t"

-- | Used to qualify output.
showsErrorPrefix :: ShowS
showsErrorPrefix	= showString "ERROR:\t"

-- | Used to separate an identifier & the it's value.
showsAssociation :: ShowS
showsAssociation	= showString " = "

-- | Capitalise the initial letter of the specified string.
capitaliseInitial :: ShowS
capitaliseInitial (c : cs)	= Data.Char.toUpper c : cs
capitaliseInitial _		= []

-- | Used to separate the items of a list.
showsSeparator :: ShowS
showsSeparator	= showString ", "

-- | Shows a list with the specified delimiters.
showsDelimitedList
	:: ShowS	-- ^ The list-separator.
	-> ShowS	-- ^ Left delimiter.
	-> ShowS	-- ^ Right delimiter.
	-> [ShowS]
	-> ShowS
showsDelimitedList separator lDelimiter rDelimiter	= foldr (.) rDelimiter . (lDelimiter :) . Data.List.intersperse separator

-- | Shows a list without terminal delimiters.
showsUnterminatedList :: [ShowS] -> ShowS
showsUnterminatedList	= showsDelimitedList showsSeparator id id

-- | Formats & shows a list with standard terminal delimiters.
showsFormattedList
	:: ShowS	-- ^ The list-separator.
	-> (a -> ShowS)	-- ^ Format the list-elements.
	-> [a]		-- ^ An arbitrary list of items.
	-> ShowS
showsFormattedList separator f	= showsDelimitedList separator (showChar '[') (showChar ']') . map f

-- | Formats & shows a list with standard delimiters.
showsFormattedList'
	:: (a -> ShowS)	-- ^ Format the list-elements.
	-> [a]		-- ^ An arbitrary list of items.
	-> ShowS
showsFormattedList'	= showsFormattedList showsSeparator

-- | Shows an association-list with standard terminal delimiters.
showsAssociationList
	:: ShowS	-- ^ The list-separator.
	-> [(String, ShowS)]
	-> ShowS
showsAssociationList separator	= showsDelimitedList separator (showChar '{') (showChar '}') . map (
	\(k, v) -> showString k . showsAssociation . v
 )

-- | Shows an association-list with standard delimiters.
showsAssociationList' :: [(String, ShowS)] -> ShowS
showsAssociationList'	= showsAssociationList showsSeparator

{- |
	Split the specified list, using the predicate to identify the separator.

	CAVEAT: the separator isn't included in the results.
-}
splitOn :: (a -> Bool) -> [a] -> [[a]]
splitOn _ []		= []
splitOn predicate l	= case break predicate l of
	(chunk, _ : l')	-> chunk : splitOn predicate l'	-- Recurse.
	(chunk, [])	-> [chunk]