    {-# LANGUAGE OverloadedStrings #-}

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

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

    Stored playlists.
    -}

    module Network.MPD.Applicative.StoredPlaylists
        ( listPlaylist
        , listPlaylistInfo
        , listPlaylists
        , load
        , playlistAdd
        , playlistClear
        , playlistDelete
        , playlistMove
        , rename
        , rm
        , save
        ) where

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

    -- | List song items in the playlist.
    listPlaylist :: PlaylistName -> Command [Path]
    listPlaylist :: PlaylistName -> Command [Path]
    listPlaylist PlaylistName
    plName = Parser [Path] -> [String] -> Command [Path]
    forall a. Parser a -> [String] -> Command a
    Command Parser [Path]
    p [Command
    "listplaylist" Command -> PlaylistName -> String
    forall a. MPDArg a => Command -> a -> String
    <@> PlaylistName
    plName]
        where
            p :: Parser [Path]
    p = (ByteString -> Path) -> [ByteString] -> [Path]
    forall a b. (a -> b) -> [a] -> [b]
    map ByteString -> Path
    Path ([ByteString] -> [Path])
    -> ([ByteString] -> [ByteString]) -> [ByteString] -> [Path]
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . [ByteString] -> [ByteString]
    takeValues ([ByteString] -> [Path]) -> Parser [ByteString] -> Parser [Path]
    forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
    <$> Parser [ByteString]
    getResponse

    -- | List song items in the playlist with metadata.
    listPlaylistInfo :: PlaylistName -> Command [Song]
    listPlaylistInfo :: PlaylistName -> Command [Song]
    listPlaylistInfo PlaylistName
    plName =
        Parser [Song] -> [String] -> Command [Song]
    forall a. Parser a -> [String] -> Command a
    Command (([ByteString] -> Either String [Song]) -> Parser [Song]
    forall a. ([ByteString] -> Either String a) -> Parser a
    liftParser [ByteString] -> Either String [Song]
    takeSongs) [Command
    "listplaylistinfo" Command -> PlaylistName -> String
    forall a. MPDArg a => Command -> a -> String
    <@> PlaylistName
    plName]

    -- | Get a list of stored playlists.
    listPlaylists :: Command [PlaylistName]
    listPlaylists :: Command [PlaylistName]
    listPlaylists = Parser [PlaylistName] -> [String] -> Command [PlaylistName]
    forall a. Parser a -> [String] -> Command a
    Command Parser [PlaylistName]
    p [String
    "listplaylists"]
        where
            p :: Parser [PlaylistName]
    p = (ByteString -> PlaylistName) -> [ByteString] -> [PlaylistName]
    forall a b. (a -> b) -> [a] -> [b]
    map ByteString -> PlaylistName
    PlaylistName ([ByteString] -> [PlaylistName])
    -> ([ByteString] -> [ByteString]) -> [ByteString] -> [PlaylistName]
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . [ByteString] -> [(ByteString, ByteString)] -> [ByteString]
    forall {a} {a}. [a] -> [(a, a)] -> [a]
    go [] ([(ByteString, ByteString)] -> [ByteString])
    -> ([ByteString] -> [(ByteString, ByteString)])
    -> [ByteString]
    -> [ByteString]
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . [ByteString] -> [(ByteString, ByteString)]
    toAssocList ([ByteString] -> [PlaylistName])
    -> Parser [ByteString] -> Parser [PlaylistName]
    forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
    <$> Parser [ByteString]
    getResponse

            -- XXX: need to fail gracefully here
            -- After each playlist name we get a timestamp
            go :: [a] -> [(a, a)] -> [a]
    go [a]
    acc [] = [a]
    acc
            go [a]
    acc ((a
    _, a
    b):(a, a)
    _:[(a, a)]
    xs) = [a] -> [(a, a)] -> [a]
    go (a
    b a -> [a] -> [a]
    forall a. a -> [a] -> [a]
    : [a]
    acc) [(a, a)]
    xs
            go [a]
    _ [(a, a)]
    _ = String -> [a]
    forall a. HasCallStack => String -> a
    error String
    "listPlaylists: bug"

    -- | Load playlist into the current queue.
    load :: PlaylistName -> Command ()
    load :: PlaylistName -> Command ()
    load PlaylistName
    plName = Parser () -> [String] -> Command ()
    forall a. Parser a -> [String] -> Command a
    Command Parser ()
    emptyResponse [Command
    "load" Command -> PlaylistName -> String
    forall a. MPDArg a => Command -> a -> String
    <@> PlaylistName
    plName]

    -- | Add a database path to the named playlist.
    playlistAdd :: PlaylistName -> Path -> Command ()
    playlistAdd :: PlaylistName -> Path -> Command ()
    playlistAdd PlaylistName
    plName Path
    path =
        Parser () -> [String] -> Command ()
    forall a. Parser a -> [String] -> Command a
    Command Parser ()
    emptyResponse [Command
    "playlistadd" Command -> Args -> String
    forall a. MPDArg a => Command -> a -> String
    <@> PlaylistName
    plName PlaylistName -> Path -> Args
    forall a b. (MPDArg a, MPDArg b) => a -> b -> Args
    <++> Path
    path]

    -- | Clear the playlist.
    playlistClear :: PlaylistName -> Command ()
    playlistClear :: PlaylistName -> Command ()
    playlistClear PlaylistName
    plName = Parser () -> [String] -> Command ()
    forall a. Parser a -> [String] -> Command a
    Command Parser ()
    emptyResponse [Command
    "playlistclear" Command -> PlaylistName -> String
    forall a. MPDArg a => Command -> a -> String
    <@> PlaylistName
    plName]

    -- | Delete the item at the given position from the playlist.
    playlistDelete :: PlaylistName -> Position -> Command ()
    playlistDelete :: PlaylistName -> Position -> Command ()
    playlistDelete PlaylistName
    name Position
    pos =
        Parser () -> [String] -> Command ()
    forall a. Parser a -> [String] -> Command a
    Command Parser ()
    emptyResponse [Command
    "playlistdelete" Command -> Args -> String
    forall a. MPDArg a => Command -> a -> String
    <@> PlaylistName
    name PlaylistName -> Position -> Args
    forall a b. (MPDArg a, MPDArg b) => a -> b -> Args
    <++> Position
    pos]

    -- | Move a song to a new position within the playlist.
    playlistMove :: PlaylistName -> Id -> Position -> Command ()
    playlistMove :: PlaylistName -> Id -> Position -> Command ()
    playlistMove PlaylistName
    name Id
    from Position
    to =
        Parser () -> [String] -> Command ()
    forall a. Parser a -> [String] -> Command a
    Command Parser ()
    emptyResponse [Command
    "playlistmove" Command -> Args -> String
    forall a. MPDArg a => Command -> a -> String
    <@> PlaylistName
    name PlaylistName -> Id -> Args
    forall a b. (MPDArg a, MPDArg b) => a -> b -> Args
    <++> Id
    from Args -> Position -> Args
    forall a b. (MPDArg a, MPDArg b) => a -> b -> Args
    <++> Position
    to]

    -- | Rename the playlist.
    rename :: PlaylistName -> PlaylistName -> Command ()
    rename :: PlaylistName -> PlaylistName -> Command ()
    rename PlaylistName
    plName PlaylistName
    new = Parser () -> [String] -> Command ()
    forall a. Parser a -> [String] -> Command a
    Command Parser ()
    emptyResponse [Command
    "rename" Command -> Args -> String
    forall a. MPDArg a => Command -> a -> String
    <@> PlaylistName
    plName PlaylistName -> PlaylistName -> Args
    forall a b. (MPDArg a, MPDArg b) => a -> b -> Args
    <++> PlaylistName
    new]

    -- | Remove the playlist.
    rm :: PlaylistName -> Command ()
    rm :: PlaylistName -> Command ()
    rm PlaylistName
    plName = Parser () -> [String] -> Command ()
    forall a. Parser a -> [String] -> Command a
    Command Parser ()
    emptyResponse [Command
    "rm" Command -> PlaylistName -> String
    forall a. MPDArg a => Command -> a -> String
    <@> PlaylistName
    plName]

    -- | Save current queue to the named playlist.
    save :: PlaylistName -> Command ()
    save :: PlaylistName -> Command ()
    save PlaylistName
    plName = Parser () -> [String] -> Command ()
    forall a. Parser a -> [String] -> Command a
    Command Parser ()
    emptyResponse [Command
    "save" Command -> PlaylistName -> String
    forall a. MPDArg a => Command -> a -> String
    <@> PlaylistName
    plName]