    {-# LANGUAGE Safe #-}
    {-
    Copyright (c) 2005-2011 John Goerzen <jgoerzen@complete.org>

    All rights reserved.

    For license and copyright information, see the file LICENSE
    -}

    {- |
       Module     : Network.Email.Mailbox
       Copyright  : Copyright (C) 2005-2011 John Goerzen
       License    : BSD3

       Maintainer : John Goerzen <jgoerzen@complete.org>
       Stability  : provisional
       Portability: portable

    General support for e-mail mailboxes

    Written by John Goerzen, jgoerzen\@complete.org
    -}

    module Network.Email.Mailbox(Flag(..), Flags, Message,
                                  MailboxReader(..),
                                  MailboxWriter(..))
    where

    {- | The flags which may be assigned to a message. -}
    data Flag =
               SEEN
               | ANSWERED
               | FLAGGED
               | DELETED
               | DRAFT
               | FORWARDED
               | OTHERFLAG String
               deriving (Eq, Show)

    {- | Convenience shortcut -}
    type Flags = [Flag]

    {- | A Message is represented as a simple String. -}
    type Message = String

    {- | Main class for readable mailboxes.

    The mailbox object /a/ represents zero or more 'Message's.  Each message
    has a unique identifier /b/ in a format specific to each given mailbox.
    This identifier may or may not be persistent.

    Functions which return a list are encouraged -- but not guaranteed -- to
    do so lazily.

    Implementing classes must provide, at minimum, 'getAll'.
    -}
    class (Show a, Show b, Eq b) => MailboxReader a b where
        {- | Returns a list of all unique identifiers. -}
        listIDs :: a -> IO [b]
        {- | Returns a list of all unique identifiers as well as all flags. -}
        listMessageFlags :: a -> IO [(b, Flags)]
        {- | Returns a list of all messages, including their content,
           flags, and unique identifiers. -}
        getAll :: a -> IO [(b, Flags, Message)]
        {- | Returns information about specific messages. -}
        getMessages :: a -> [b] -> IO [(b, Flags, Message)]

        listIDs mb = listMessageFlags mb >>= return . map fst
        listMessageFlags mb = getAll mb >>= return .
                               map (\(i, f, _) -> (i, f))
        getMessages mb list =
            do messages <- getAll mb
               return $ filter (\(id, f, m) -> id `elem` list) messages

    class (MailboxReader a b) => MailboxWriter a b where
        appendMessages :: a -> [(Flags, Message)] -> IO [b]
        deleteMessages :: a -> [b] -> IO ()
        addFlags :: a -> [b] -> Flags -> IO ()
        removeFlags :: a -> [b] -> Flags -> IO ()
        setFlags :: a -> [b] -> Flags -> IO ()