-- | A module that exports a simple regex interface. This code is mostly copied
--   from the regex-compat package at hackage. I decided to write this module
--   because I want to abstract the regex package used.
module Text.Hakyll.Regex
    ( splitRegex
    , substituteRegex
    , matchesRegex
    ) 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 = matchM

-- | 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.
splitRegex :: String -> String -> [String]
splitRegex pattern = filter (not . null)
                   . splitRegex' (makeRegex pattern)

-- | Substitute a regex. Simplified interface. This function performs a global
--   substitution.
substituteRegex :: String -- ^ Pattern to replace (regex).
                -> String -- ^ Replacement string.
                -> String -- ^ Input string.
                -> String -- ^ Result.
substituteRegex pattern replacement string =
    subRegex (makeRegex pattern) string replacement

-- | Simple regex matching.
matchesRegex :: String -- ^ Input string.
             -> String -- ^ Pattern to match.
             -> Bool
matchesRegex = (=~)