{-# LANGUAGE NoImplicitPrelude #-}
{-# LANGUAGE OverloadedLists #-}

module Cmt.Parser.Config.PreDefined
    ( predefinedPartsP
    ) where

import ClassyPrelude hiding (fail)

import Control.Monad.Fail   (fail)
import Data.Attoparsec.Text

import Cmt.Parser.Attoparsec
import Cmt.Parser.Config.Format (formatP)
import Cmt.Types.Config

-- predefined
value :: Name -> [Part] -> Parser Config
value name parts = lexeme (char '"' *> takeTill (== '"') <* char '"') >>= getConfig
  where
    getConfig :: Text -> Parser Config
    getConfig template =
        case parseOnly (formatP $ partName <$> parts) template of
            Left _    -> fail $ "Invalid predefined template: " ++ show name
            Right fmt -> pure $ Config (filterParts fmt parts) fmt
    filterParts :: [FormatPart] -> [Part] -> [Part]
    filterParts fps = filter ((`elem` catMaybes (formatName <$> fps)) . partName)

partP :: [Part] -> Parser PreDefinedPart
partP ps =
    stripComments $ do
        name <- pack <$> many' letter <* lexeme (char '=')
        conf <- stripComments (value name ps)
        pure (name, conf)

predefinedPartsP :: [Part] -> Parser PreDefinedParts
predefinedPartsP ps =
    mapFromList <$>
    option [] (stripComments (char '{') *> many' (partP ps) <* stripComments (char '}'))