module Seq
where

import qualified Char
import List

rDropWhile f = reverse . dropWhile f . reverse

lstrip = dropWhile Char.isSpace
rstrip = rDropWhile Char.isSpace
strip = lstrip . rstrip

-- | Split 'xs' before places where 'f' matches.
-- So "splitWith (==1) [1,2,1]" is "[[1,2][1]]".
splitWith :: (a -> Bool) -> [a] -> [[a]]
splitWith f xs = map reverse (doSplit f xs [])
    where
    doSplit f [] collect = [collect]
    doSplit f (x:xs) collect
        | f x = collect : doSplit f xs [x]
        | otherwise = doSplit f xs (x:collect)

-- | Like 'splitWith' except 'f' is given the rest of the list to decide if
-- it should split here.
splitSeqWith :: ([a] -> Bool) -> [a] -> [[a]]
splitSeqWith f xs = map reverse (doSplit f xs [])
    where
    doSplit f [] collect = [collect]
    doSplit f (x:xs) collect
        | f (x:xs) = collect : doSplit f xs [x]
        | otherwise = doSplit f xs (x:collect)

-- | Split 'xs' on 'sep', dropping 'sep' from the result.
split :: Eq a => [a] -> [a] -> [[a]]
split sep xs = case splitSeqWith (sep `isPrefixOf`) xs of
    [] -> []
    (y:ys) -> y : map (drop (length sep)) ys

-- | Concat a list with 'sep' in between.
join sep = concat . intersperse sep

-- | Replace sublists in 'xs'.  'repl' is given the tails of 'xs' and can
-- return (replacement, rest_of_xs) or Nothing.
replaceWith :: ([a] -> Maybe ([a], [a])) -> [a] -> [a]
replaceWith repl [] = []
replaceWith repl xs = case repl xs of
    Just (insert, rest) -> insert ++ replaceWith repl rest
    Nothing -> head xs : replaceWith repl (tail xs)

-- | Replace sublist 'val' with 'repl' in the given list.
replace val repl = replaceWith (replaceVal val repl)

-- | Helper for replaceWith to replace a constant sublist 'val' with 'repl'.
replaceVal val repl xs
    | val `isPrefixOf` xs = Just (repl, drop (length val) xs)
    | otherwise = Nothing
