{-# OPTIONS_GHC -XScopedTypeVariables #-}
-----------------------------------------------------------------------------
--
-- Module      :  MyMissing
-- Copyright   :  (c) Juergen Nicklisch-Franken, Hamish Mackenzie
-- License     :  GNU-GPL
--
-- Maintainer  :  Juergen Nicklisch-Franken <info@leksah.org>
-- Stability   :  provisional
-- Portability :  portable
--
-- | Module for missing base functions
--
------------------------------------------------------------------------------

module MyMissing (
    allOf
,   forceJust
,   forceHead
,   split
,   replace
,   nonEmptyLines
,   trim
) where

import Data.List (find,unfoldr)
import Data.Maybe (isJust)
import Data.Char (isSpace)


-- | remove leading and trailing spaces
trim :: String -> String
trim      = f . f
   where f = reverse . dropWhile isSpace

nonEmptyLines :: String -> [String]
nonEmptyLines = filter (\line -> isJust $ find (not . isSpace) line) . lines


allOf :: forall alpha. (Bounded alpha, Enum alpha) =>  [alpha]
allOf = map toEnum [fromEnum (minBound :: alpha) .. fromEnum (maxBound :: alpha)]

-- ---------------------------------------------------------------------
-- Convenience methods with error handling
--
forceJust :: Maybe alpha -> String -> alpha
forceJust mb str = case mb of
			Nothing -> error str
			Just it -> it

-- ---------------------------------------------------------------------
-- Convenience methods with error handling
--
forceHead :: [alpha] -> String -> alpha
forceHead (h:_) str = h
forceHead [] str = error str


-- ---------------------------------------------------------------------
-- Splitting a string into parts based on a token delimiter
--

split :: Eq a => a -> [a] -> [[a]]
split =  unfoldr . split'

split' :: Eq a => a -> [a] -> Maybe ([a], [a])
split' c l
  | null l = Nothing
  | otherwise = Just (h, drop 1 t)
  where (h, t) = span (/=c) l

-- ---------------------------------------------------------------------
-- Simple replacement
--

replace :: Eq a => [a] -> [a] -> [a] -> [a]
replace _ _ [] = []
replace from to xs@(a:as) =
    if isPrefixOf from xs
        then to ++ replace from to (drop (length from) xs)
        else a : replace from to as
    where isPrefixOf as bs = and $ zipWith (== ) as bs