content: {-# OPTIONS_HADDOCK hide #-}
  module Network.Xmpp.Concurrent.Message where
  
  import Control.Applicative((<$>))
  import Network.Xmpp.Concurrent.Types
  import Control.Concurrent.STM
  import Network.Xmpp.Types
  import Network.Xmpp.Concurrent.Basic
  
  -- | Draw and discard stanzas from the inbound channel until a message or
  -- message error is found. Returns the message or message error with annotations.
  pullMessageA :: Session -> IO (Either (Annotated MessageError) (Annotated Message))
  pullMessageA session = do
      (stanza, as) <- atomically . readTChan $ stanzaCh session
      case stanza of
          MessageS m      -> return $ Right (m, as)
          MessageErrorS e -> return $ Left  (e, as)
          _ -> pullMessageA session
  
  -- | Draw and discard stanzas from the inbound channel until a message or
  -- message error is found. Returns the message or message error.
  pullMessage :: Session -> IO (Either MessageError Message)
  pullMessage s = either (Left . fst) (Right . fst) <$> pullMessageA s
  
  -- | Draw and discard stanzas from the inbound channel until a message is
  -- found. Returns the message with annotations.
  getMessageA :: Session -> IO (Annotated Message)
  getMessageA = waitForMessageA (const True)
  
  -- | Draw and discard stanzas from the inbound channel until a message is
  -- found. Returns the message.
  getMessage :: Session -> IO Message
  getMessage s = fst <$> getMessageA s
  
  -- | Draw and discard stanzas from the inbound channel until a message matching
  -- the given predicate is found. Returns the matching message with annotations.
  waitForMessageA :: (Annotated Message -> Bool) -> Session -> IO (Annotated Message)
  waitForMessageA f session = do
      s <- pullMessageA session
      case s of
          Left _ -> waitForMessageA f session
          Right m | f m -> return m
                  | otherwise -> waitForMessageA f session
  
  -- | Draw and discard stanzas from the inbound channel until a message matching
  -- the given predicate is found. Returns the matching message.
  waitForMessage :: (Message -> Bool) -> Session -> IO Message
  waitForMessage f s  = fst <$> waitForMessageA (f . fst) s
  
  -- | Draw and discard stanzas from the inbound channel until a message error
  -- matching the given predicate is found. Returns the matching message error with
  -- annotations.
  waitForMessageErrorA :: (Annotated MessageError -> Bool)
                      -> Session
                      -> IO (Annotated MessageError)
  waitForMessageErrorA f session = do
      s <- pullMessageA session
      case s of
          Right _ -> waitForMessageErrorA f session
          Left  m | f m -> return m
                  | otherwise -> waitForMessageErrorA f session
  
  -- | Draw and discard stanzas from the inbound channel until a message error
  -- matching the given predicate is found. Returns the matching message error
  waitForMessageError :: (MessageError -> Bool) -> Session -> IO MessageError
  waitForMessageError f s  = fst <$> waitForMessageErrorA (f . fst) s
  
  -- | Draw and discard stanzas from the inbound channel until a message or
  -- message error matching the given respective predicate is found. Returns the
  -- matching message or message error with annotations
  filterMessagesA :: (Annotated MessageError -> Bool)
                 -> (Annotated Message -> Bool)
                 -> Session -> IO (Either (Annotated MessageError)
                                          (Annotated Message))
  filterMessagesA f g session = do
      s <- pullMessageA session
      case s of
          Left  e | f e -> return $ Left e
                  | otherwise -> filterMessagesA f g session
          Right m | g m -> return $ Right m
                  | otherwise -> filterMessagesA f g session
  
  -- | Draw and discard stanzas from the inbound channel until a message or
  -- message error matching the given respective predicate is found. Returns the
  -- matching message or message error.
  filterMessages :: (MessageError -> Bool)
                 -> (Message -> Bool)
                 -> Session
                 -> IO (Either MessageError Message)
  filterMessages f g s = either (Left . fst) (Right . fst) <$>
                            filterMessagesA (f . fst) (g . fst) s
  
  -- | Send a message stanza. Returns @Left@ when the 'Message' could not be
  -- sent.
  sendMessage :: Message -> Session -> IO (Either XmppFailure ())
  sendMessage m session = sendStanza (MessageS m) session
  