{-# OPTIONS_HADDOCK hide #-}
module Network.Xmpp.Concurrent.Basic where

import           Control.Concurrent.STM
import qualified Control.Exception as Ex
import           Control.Monad.State.Strict
import qualified Data.ByteString as BS
import           Network.Xmpp.Concurrent.Types
import           Network.Xmpp.Marshal
import           Network.Xmpp.Stream
import           Network.Xmpp.Types
import           Network.Xmpp.Utilities

semWrite :: WriteSemaphore -> BS.ByteString -> IO Bool
semWrite sem bs = Ex.bracket (atomically $ takeTMVar sem)
                          (atomically . putTMVar sem)
                          ($ bs)

writeStanza :: WriteSemaphore -> Stanza -> IO Bool
writeStanza sem a = do
    let outData = renderElement $ nsHack (pickleElem xpStanza a)
    semWrite sem outData

-- | Send a stanza to the server.
sendStanza :: Stanza -> Session -> IO Bool
sendStanza a session = writeStanza (writeSemaphore session) a


-- | Get the channel of incoming stanzas.
getStanzaChan :: Session -> TChan Stanza
getStanzaChan session = stanzaCh session

-- | Get the next incoming stanza
getStanza :: Session -> IO Stanza
getStanza session = atomically . readTChan $ stanzaCh session

-- | Create a new session object with the inbound channel duplicated
dupSession :: Session -> IO Session
dupSession session = do
    stanzaCh' <- atomically $ dupTChan (stanzaCh session)
    return $ session {stanzaCh = stanzaCh'}

-- | Return the JID assigned to us by the server
getJid :: Session -> IO (Maybe Jid)
getJid Session{streamRef = st} = do
    s <- atomically $ readTMVar st
    withStream' (gets streamJid) s

-- | Return the JID assigned to us by the server
getFeatures :: Session -> IO StreamFeatures
getFeatures Session{streamRef = st} = do
    s <- atomically $ readTMVar st
    withStream' (gets streamFeatures) s

-- | Wait until the connection of the stream is re-established
waitForStream :: Session -> IO ()
waitForStream Session{streamRef = sr} = atomically $ do
    s <- readTMVar sr
    ss <- readTMVar $ unStream s
    case streamConnectionState ss of
        Plain -> return ()
        Secured -> return ()
        _ -> retry