module Codec.MIME.String.Internal.Utils where

import Data.Char

isAsciiDigit :: Char -> Bool
isAsciiDigit c = isAscii c && isDigit c

isAsciiHexDigit :: Char -> Bool
isAsciiHexDigit c = isAscii c && isHexDigit c

isAsciiPrint :: Char -> Bool
isAsciiPrint c = isAscii c && isPrint c

isAsciiAlpha :: Char -> Bool
isAsciiAlpha c = isAscii c && isAlpha c

isAsciiAlphaNum :: Char -> Bool
isAsciiAlphaNum c = isAscii c && isAlphaNum c

asciiToLower :: Char -> Char
asciiToLower c | isAscii c = toLower c
               | otherwise = c

asciiToUpper :: Char -> Char
asciiToUpper c | isAscii c = toUpper c
               | otherwise = c

splits :: Int -> [a] -> [[a]]
splits _ [] = []
splits n xs = case splitAt n xs of
                  (ys, zs) -> ys:splits n zs

box :: a -> [a]
box x = [x]

dropFromEndWhile :: (a -> Bool) -> [a] -> [a]
dropFromEndWhile p = foldr (\x xs -> if null xs && p x then [] else x:xs) []

-- We are generous about what we allow as line terminators. Any of
-- \r \n \r\n \n\r will satisfy us.
my_lines :: String -> [String]
my_lines xs = case get_line xs of
                  (ys, Nothing) -> [ys]
                  (ys, Just zs) -> ys:my_lines zs

get_line :: String -> (String, Maybe String)
get_line xs = case break is_cr_or_lf xs of
                  (ys, z1:z2:zs)
                   | is_cr_or_lf z2 && z1 /= z2 -> (ys, Just zs)
                  (ys, _:zs) -> (ys, Just zs)
                  (ys, "") -> (ys, Nothing)

is_cr_or_lf :: Char -> Bool
is_cr_or_lf '\r' = True
is_cr_or_lf '\n' = True
is_cr_or_lf _ = False