-- | A module that exports a simple regex interface. This code is mostly copied
--   from the regex-compat package at hackage.
module Text.Hakyll.Regex
    ( split
    , substitute
    ) where

import Text.Regex.TDFA

-- | Match a regular expression against a string, returning more information
--   about the match.
matchRegexAll :: Regex -> String -> Maybe (String, String, String, [String])
matchRegexAll p str = matchM p str

-- | Replaces every occurance of the given regexp with the replacement string.
subRegex :: Regex                          -- ^ Search pattern
      -> String                         -- ^ Input string
      -> String                         -- ^ Replacement text
      -> String                         -- ^ Output string
subRegex _ "" _ = ""
subRegex regexp inp replacement =
  let -- bre matches a backslash then capture either a backslash or some digits
      bre = makeRegex "\\\\(\\\\|[0-9]+)"
      lookup' _ [] _ = []
      lookup' [] _ _ = []
      lookup' match' repl groups =
        case matchRegexAll bre repl of
          Nothing -> repl
          Just (lead, _, trail, bgroups) ->
            let newval =
                 if (head bgroups) == "\\"
                   then "\\"
                   else let index :: Int
                            index = (read (head bgroups)) - 1
                        in if index == -1
                             then match'
                             else groups !! index
            in lead ++ newval ++ lookup' match' trail groups
  in case matchRegexAll regexp inp of
       Nothing -> inp
       Just (lead, match', trail, groups) ->
         lead ++ lookup' match' replacement groups ++ (subRegex regexp trail replacement)

-- | Splits a string based on a regular expression.  The regular expression
--   should identify one delimiter.
splitRegex :: Regex -> String -> [String]
splitRegex _ [] = []
splitRegex delim strIn = loop strIn where
  loop str = case matchOnceText delim str of
                Nothing -> [str]
                Just (firstline, _, remainder) ->
                  if null remainder
                    then [firstline,""]
                    else firstline : loop remainder

-- | Split a list at a certain element.
split :: String -> String -> [String]
split pattern = filter (not . null)
              . splitRegex (makeRegex pattern)

-- | Substitute a regex. Simplified interface.
substitute :: String -- ^ Pattern to replace (regex).
           -> String -- ^ Replacement string.
           -> String -- ^ Input string.
           -> String -- ^ Result.
substitute pattern replacement str = subRegex (makeRegex pattern) str replacement