module ListHelp 
    ( module Data.List
    , initOrNull
    , insertOver
    , swapIndices
    , (!?)
    , safeHead
    , safeUncons
    , errorHead
    , foldPairs
    , loopPairs
    ) where
import Data.List

loopPairs :: [a] -> [(a,a)]
loopPairs (a:as) = snd $ foldr f (Just a,[]) (a:as)
  where
    f x (Nothing,ps) = (Just x,ps)
    f x (Just y,ps)  = (Just x,(x,y):ps)
loopPairs [] = error "tried to make loop with empty list of elements"

foldPairs :: [a] -> [(a,a)]
foldPairs = snd . foldr f (Nothing, [])
  where
    f x (Nothing,ps) = (Just x,ps)
    f x (Just y,ps)  = (Just x,(x,y):ps)

initOrNull :: [a] -> [a]
initOrNull [] = []
initOrNull xs = init xs

insertOver :: Int -> a -> [a] -> [a]
insertOver i x xs = take i xs ++ x : drop (i+1) xs

swapIndices :: Int -> Int -> [a] -> [a]
swapIndices i j xs = insertOver i (xs !! j) . insertOver j (xs !! i) $ xs

--copied from Data.List.Extra:
-- | A total variant of the list index function `(!!)`.
--
-- > [2,3,4] !? 1    == Just 3
-- > [2,3,4] !? (-1) == Nothing
-- > []      !? 0    == Nothing
(!?) :: [a] -> Int -> Maybe a
xs !? n
  | n < 0     = Nothing
             -- Definition adapted from GHC.List
  | otherwise = foldr (\x r k -> case k of
                                   0 -> Just x
                                   _ -> r (k-1)) (const Nothing) xs n
{-# INLINABLE (!?) #-}

safeHead :: [a] -> Maybe a
safeHead (x:_) = Just x
safeHead _ = Nothing

safeUncons :: [a] -> Maybe (a,[a])
safeUncons (x:xs) = Just (x,xs)
safeUncons _ = Nothing

errorHead :: String -> [a] -> a
errorHead _ (x:_) = x
errorHead s [] = error s
