{-# LANGUAGE OverloadedStrings #-}

{- |
Module      : Network.MPD.Applicative.ClientToClient
Copyright   : (c) Joachim Fasting 2013
License     : MIT

Maintainer  : joachifm@fastmail.fm
Stability   : stable
Portability : unportable

Client to client communication.
-}

module Network.MPD.Applicative.ClientToClient
    ( -- * Types
      ChannelName
    , MessageText
      -- * Subscribing to channels
    , subscribe
    , unsubscribe
    , channels
      -- * Communicating with other clients
    , readMessages
    , sendMessage
    ) where

import           Network.MPD.Commands.Arg hiding (Command)
import           Network.MPD.Applicative.Internal
import           Network.MPD.Applicative.Util
import           Network.MPD.Util

import           Data.ByteString.Char8 (ByteString)
import qualified Data.ByteString.UTF8 as UTF8

------------------------------------------------------------------------

type ChannelName = String
type MessageText = String

------------------------------------------------------------------------

subscribe :: ChannelName -> Command ()
subscribe :: ChannelName -> Command ()
subscribe ChannelName
name = Parser () -> [ChannelName] -> Command ()
forall a. Parser a -> [ChannelName] -> Command a
Command Parser ()
emptyResponse [Command
"subscribe" Command -> ChannelName -> ChannelName
forall a. MPDArg a => Command -> a -> ChannelName
<@> ChannelName
name]

unsubscribe :: ChannelName -> Command ()
unsubscribe :: ChannelName -> Command ()
unsubscribe ChannelName
name = Parser () -> [ChannelName] -> Command ()
forall a. Parser a -> [ChannelName] -> Command a
Command Parser ()
emptyResponse [Command
"unsubscribe" Command -> ChannelName -> ChannelName
forall a. MPDArg a => Command -> a -> ChannelName
<@> ChannelName
name]

channels :: Command [ChannelName]
channels :: Command [ChannelName]
channels = Parser [ChannelName] -> [ChannelName] -> Command [ChannelName]
forall a. Parser a -> [ChannelName] -> Command a
Command Parser [ChannelName]
p [ChannelName
"channels"]
  where
    p :: Parser [ChannelName]
p = (ByteString -> ChannelName) -> [ByteString] -> [ChannelName]
forall a b. (a -> b) -> [a] -> [b]
map ByteString -> ChannelName
UTF8.toString ([ByteString] -> [ChannelName])
-> ([ByteString] -> [ByteString]) -> [ByteString] -> [ChannelName]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [ByteString] -> [ByteString]
takeValues ([ByteString] -> [ChannelName])
-> Parser [ByteString] -> Parser [ChannelName]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Parser [ByteString]
getResponse

------------------------------------------------------------------------

readMessages :: Command [(ChannelName, MessageText)]
readMessages :: Command [(ChannelName, ChannelName)]
readMessages = Parser [(ChannelName, ChannelName)]
-> [ChannelName] -> Command [(ChannelName, ChannelName)]
forall a. Parser a -> [ChannelName] -> Command a
Command (([ByteString] -> Either ChannelName [(ChannelName, ChannelName)])
-> Parser [(ChannelName, ChannelName)]
forall a. ([ByteString] -> Either ChannelName a) -> Parser a
liftParser [ByteString] -> Either ChannelName [(ChannelName, ChannelName)]
p) [ChannelName
"readmessages"]
  where
    p :: [ByteString] -> Either ChannelName [(ChannelName, ChannelName)]
p = ([(ByteString, ByteString)]
 -> Either ChannelName (ChannelName, ChannelName))
-> [[(ByteString, ByteString)]]
-> Either ChannelName [(ChannelName, ChannelName)]
forall (t :: * -> *) (m :: * -> *) a b.
(Traversable t, Monad m) =>
(a -> m b) -> t a -> m (t b)
mapM [(ByteString, ByteString)]
-> Either ChannelName (ChannelName, ChannelName)
parseMessage ([[(ByteString, ByteString)]]
 -> Either ChannelName [(ChannelName, ChannelName)])
-> ([ByteString] -> [[(ByteString, ByteString)]])
-> [ByteString]
-> Either ChannelName [(ChannelName, ChannelName)]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [ByteString]
-> [(ByteString, ByteString)] -> [[(ByteString, ByteString)]]
splitGroups [ByteString
"channel"] ([(ByteString, ByteString)] -> [[(ByteString, ByteString)]])
-> ([ByteString] -> [(ByteString, ByteString)])
-> [ByteString]
-> [[(ByteString, ByteString)]]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [ByteString] -> [(ByteString, ByteString)]
toAssocList

    parseMessage :: [(ByteString, ByteString)] -> Either String (ChannelName, MessageText)
    parseMessage :: [(ByteString, ByteString)]
-> Either ChannelName (ChannelName, ChannelName)
parseMessage [(ByteString
"channel", ByteString
ch),(ByteString
"message", ByteString
msg)] = (ChannelName, ChannelName)
-> Either ChannelName (ChannelName, ChannelName)
forall a b. b -> Either a b
Right (ByteString -> ChannelName
UTF8.toString ByteString
ch, ByteString -> ChannelName
UTF8.toString ByteString
msg)
    parseMessage [(ByteString, ByteString)]
_ = ChannelName -> Either ChannelName (ChannelName, ChannelName)
forall a b. a -> Either a b
Left ChannelName
"Unexpected result from readMessages"

sendMessage :: ChannelName -> MessageText -> Command ()
sendMessage :: ChannelName -> ChannelName -> Command ()
sendMessage ChannelName
name ChannelName
text = Parser () -> [ChannelName] -> Command ()
forall a. Parser a -> [ChannelName] -> Command a
Command Parser ()
emptyResponse [Command
"sendmessage" Command -> Args -> ChannelName
forall a. MPDArg a => Command -> a -> ChannelName
<@> ChannelName
name ChannelName -> ChannelName -> Args
forall a b. (MPDArg a, MPDArg b) => a -> b -> Args
<++> ChannelName
text]