module Network.Mail.Parse.Utils where

import Network.Mail.Parse.Types

import Data.Attoparsec.ByteString
import qualified Data.Attoparsec.ByteString as AP
import qualified Data.ByteString.Char8 as BS
import Data.Word8
import Data.List

import Data.Text (Text)
import qualified Data.Text as T
import Data.Either.Utils (maybeToEither)

-- |If the previous character was a carriage return and the current
-- is a line feed, stop parsing
hadCRLF :: Word8 -> Word8 -> Maybe Word8
hadCRLF prev current =
  if prev == _cr && current == _lf
    then Nothing
    else Just current

-- |Consumes a line until CRLF is hit
consumeTillEndLine :: Parser BS.ByteString
consumeTillEndLine = scan 0 hadCRLF <* satisfy (== _lf)

-- |Can a given character be regarded as a whitespace?
isWhitespace :: Word8 -> Bool
isWhitespace x = x == 9 || x == 32

-- |If the next line is a part of a previous header, parse it.
-- Fail otherwise
isConsequentHeaderLine :: Parser BS.ByteString
isConsequentHeaderLine = satisfy isWhitespace *>
                         AP.takeWhile isWhitespace *>
                         consumeTillEndLine

-- |Remove a MIME header comment and return a header without the comment
commentRemover :: Text -> Text
commentRemover contents = T.strip withoutComment
  where splitAtComment = T.split (\c -> c == '(' || c == ')') contents
        withoutComment = if length splitAtComment > 1
                          then T.append (head splitAtComment) (last splitAtComment)
                          else head splitAtComment

-- |Given a header name, it will try to locate it in
-- a list of headers, fail if it's not there
findHeader :: Text -> [Header] -> Either ErrorMessage Header
findHeader hdr headers = maybeToEither notFound header
  where notFound    = T.concat ["Cound not find header '", T.pack . show $ hdr, "'"]
        eigenHeader = T.toLower hdr
        header      = find (\x -> T.toLower (headerName x) == eigenHeader) headers

eitherToMaybe :: Either a b -> Maybe b
eitherToMaybe (Right a) = Just a
eitherToMaybe (Left _) = Nothing