{-# LANGUAGE OverloadedStrings #-}

module Network.MPD.Applicative.Util where

import           Network.MPD.Commands.Parse
import           Network.MPD.Commands.Types
import           Network.MPD.Util

import           Control.Monad (liftM)

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

-- Separate the result of an lsinfo\/listallinfo call into directories,
-- playlists, and songs.
takeEntries :: [ByteString] -> Either String [LsResult]
takeEntries :: [ByteString] -> Either String [LsResult]
takeEntries = ([(ByteString, ByteString)] -> Either String LsResult)
-> [[(ByteString, ByteString)]] -> Either String [LsResult]
forall (t :: * -> *) (m :: * -> *) a b.
(Traversable t, Monad m) =>
(a -> m b) -> t a -> m (t b)
forall (m :: * -> *) a b. Monad m => (a -> m b) -> [a] -> m [b]
mapM [(ByteString, ByteString)] -> Either String LsResult
toEntry ([[(ByteString, ByteString)]] -> Either String [LsResult])
-> ([ByteString] -> [[(ByteString, ByteString)]])
-> [ByteString]
-> Either String [LsResult]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [ByteString]
-> [(ByteString, ByteString)] -> [[(ByteString, ByteString)]]
splitGroups [ByteString]
groupHeads ([(ByteString, ByteString)] -> [[(ByteString, ByteString)]])
-> ([ByteString] -> [(ByteString, ByteString)])
-> [ByteString]
-> [[(ByteString, ByteString)]]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [ByteString] -> [(ByteString, ByteString)]
toAssocList
    where
        toEntry :: [(ByteString, ByteString)] -> Either String LsResult
toEntry xs :: [(ByteString, ByteString)]
xs@((ByteString
"file",ByteString
_):[(ByteString, ByteString)]
_)   = Song -> LsResult
LsSong (Song -> LsResult) -> Either String Song -> Either String LsResult
forall (m :: * -> *) a1 r. Monad m => (a1 -> r) -> m a1 -> m r
`liftM` [(ByteString, ByteString)] -> Either String Song
parseSong [(ByteString, ByteString)]
xs
        toEntry ((ByteString
"directory",ByteString
d):[(ByteString, ByteString)]
_) = (LsResult -> Either String LsResult
forall a. a -> Either String a
forall (m :: * -> *) a. Monad m => a -> m a
return (LsResult -> Either String LsResult)
-> (ByteString -> LsResult) -> ByteString -> Either String LsResult
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Path -> LsResult
LsDirectory (Path -> LsResult)
-> (ByteString -> Path) -> ByteString -> LsResult
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ByteString -> Path
Path) ByteString
d
        toEntry ((ByteString
"playlist",ByteString
pl):[(ByteString, ByteString)]
_) = (LsResult -> Either String LsResult
forall a. a -> Either String a
forall (m :: * -> *) a. Monad m => a -> m a
return (LsResult -> Either String LsResult)
-> (ByteString -> LsResult) -> ByteString -> Either String LsResult
forall b c a. (b -> c) -> (a -> b) -> a -> c
. PlaylistName -> LsResult
LsPlaylist (PlaylistName -> LsResult)
-> (ByteString -> PlaylistName) -> ByteString -> LsResult
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ByteString -> PlaylistName
PlaylistName) ByteString
pl
        toEntry [(ByteString, ByteString)]
_ = String -> Either String LsResult
forall a. HasCallStack => String -> a
error String
"takeEntries: splitGroups is broken"
        groupHeads :: [ByteString]
groupHeads = [ByteString
"file", ByteString
"directory", ByteString
"playlist"]

takeSongs :: [ByteString] -> Either String [Song]
takeSongs :: [ByteString] -> Either String [Song]
takeSongs = ([(ByteString, ByteString)] -> Either String Song)
-> [[(ByteString, ByteString)]] -> Either String [Song]
forall (t :: * -> *) (m :: * -> *) a b.
(Traversable t, Monad m) =>
(a -> m b) -> t a -> m (t b)
forall (m :: * -> *) a b. Monad m => (a -> m b) -> [a] -> m [b]
mapM [(ByteString, ByteString)] -> Either String Song
parseSong ([[(ByteString, ByteString)]] -> Either String [Song])
-> ([ByteString] -> [[(ByteString, ByteString)]])
-> [ByteString]
-> Either String [Song]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [ByteString]
-> [(ByteString, ByteString)] -> [[(ByteString, ByteString)]]
splitGroups [ByteString
"file"] ([(ByteString, ByteString)] -> [[(ByteString, ByteString)]])
-> ([ByteString] -> [(ByteString, ByteString)])
-> [ByteString]
-> [[(ByteString, ByteString)]]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [ByteString] -> [(ByteString, ByteString)]
toAssocList

-- Run 'toAssocList' and return only the values.
takeValues :: [ByteString] -> [ByteString]
takeValues :: [ByteString] -> [ByteString]
takeValues = ([ByteString], [ByteString]) -> [ByteString]
forall a b. (a, b) -> b
snd (([ByteString], [ByteString]) -> [ByteString])
-> ([ByteString] -> ([ByteString], [ByteString]))
-> [ByteString]
-> [ByteString]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [(ByteString, ByteString)] -> ([ByteString], [ByteString])
forall a b. [(a, b)] -> ([a], [b])
unzip ([(ByteString, ByteString)] -> ([ByteString], [ByteString]))
-> ([ByteString] -> [(ByteString, ByteString)])
-> [ByteString]
-> ([ByteString], [ByteString])
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [ByteString] -> [(ByteString, ByteString)]
toAssocList

-- an internal helper function
decodePair :: (ByteString, ByteString) -> (String, String)
decodePair :: (ByteString, ByteString) -> (String, String)
decodePair (ByteString
x, ByteString
y) = (ByteString -> String
UTF8.toString ByteString
x, ByteString -> String
UTF8.toString ByteString
y)