-- |
-- Module      : $Header$
-- Description : Simple format strings with named identifiers.
-- Copyright   : (c) Justus Adam 2017. All Rights Reserved.
-- License     : BSD3
-- Maintainer  : dev@justus.science
-- Stability   : experimental
{-# LANGUAGE FlexibleInstances          #-}
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
{-# LANGUAGE OverloadedStrings          #-}
{-# LANGUAGE TypeFamilies               #-}
module Data.Text.Format.Simple
    ( format
    , format'
    , formatC
    , formatC'
    , SubMap
    , Compiled
    , Name
    ) where


import           Data.Either
import qualified Data.Foldable                    as F
import           Data.Text                        (Text)
import qualified Data.Text                        as T
import           Data.Text.Format.Simple.Internal as I


-- | Resolver for names.
type SubMap = Name -> Maybe Text


-- | Like 'format' but with the string already compiled
formatC :: Compiled -> SubMap -> (Text, [Name])
formatC (Compiled parts) lookup = (T.concat $ rights results, lefts results)
  where
    results = map f parts
    f (String t)   = return t
    f (NamedVar n) = maybe (Left n) return $ lookup n


-- | Like 'format'' but with the string already compiled
formatC' :: Compiled -> SubMap -> Text
formatC' p = fst . formatC p


-- | Compile a string to a format string and substitute the identifiers from the provided function into it.
--
-- Fails if the string canno be parsed.
-- Retuns the rendered string and a list of names which were used in the string but could not be resolved by the function.
format :: Text -> SubMap -> Either String (Text, [Name])
format a m = do
    a' <- I.parse a
    return $ formatC a' m

-- | Compile a string to a format string and substitute the identifiers from the provided function into it.
--
-- All errors are ignored. Parse failure is thrown as an error and the missing names are discarded.
format' :: Text -> SubMap -> Text
format' a = either error fst . format a