module MPD.Current.JSON.Builder
    ( mkStatus
    , mkPlaylist
    , mkFile
    ) where


import MPD.Current.JSON.Types qualified as Current
import Network.MPD qualified as MPD
import Text.Read ( readMaybe )
import Text.Printf ( printf )
import GHC.Num ( integerToInt )

mkStatus :: MPD.Status -> Current.Status
mkStatus :: Status -> Status
mkStatus Status
st = Current.Status
  { state :: MPDPlaybackState
Current.state          = PlaybackState -> MPDPlaybackState
Current.MPDPlaybackState Status
st.stState
  , repeat :: Bool
Current.repeat         = Status
st.stRepeat
  , random :: Bool
Current.random         = Status
st.stRandom
  , single :: Bool
Current.single         = Status
st.stSingle
  , consume :: Bool
Current.consume        = Status
st.stConsume
  , duration :: Maybe FractionalSeconds
Current.duration       = (FractionalSeconds, FractionalSeconds) -> FractionalSeconds
forall a b. (a, b) -> b
snd ((FractionalSeconds, FractionalSeconds) -> FractionalSeconds)
-> Maybe (FractionalSeconds, FractionalSeconds)
-> Maybe FractionalSeconds
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Status
st.stTime
  , elapsed :: Maybe FractionalSeconds
Current.elapsed        = (FractionalSeconds, FractionalSeconds) -> FractionalSeconds
forall a b. (a, b) -> a
fst ((FractionalSeconds, FractionalSeconds) -> FractionalSeconds)
-> Maybe (FractionalSeconds, FractionalSeconds)
-> Maybe FractionalSeconds
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Status
st.stTime
  , elapsedPercent :: Maybe FractionalSeconds
Current.elapsedPercent = Maybe (FractionalSeconds, FractionalSeconds)
-> Maybe FractionalSeconds
calcElapsedPercent Status
st.stTime
  , volume :: Maybe Position
Current.volume         = Volume -> Position
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Volume -> Position) -> Maybe Volume -> Maybe Position
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Status
st.stVolume
  , audioFormat :: Maybe (Position, Position, Position)
Current.audioFormat    = (Position, Position, Position)
-> Maybe (Position, Position, Position)
forall a. a -> Maybe a
Just Status
st.stAudio
  , bitrate :: Maybe Position
Current.bitrate        = Status
st.stBitrate
  , crossfade :: Maybe Position
Current.crossfade      = Position -> Maybe Position
forall a. a -> Maybe a
Just (Position -> Maybe Position)
-> (Integer -> Position) -> Integer -> Maybe Position
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Integer -> Position
integerToInt (Integer -> Maybe Position) -> Integer -> Maybe Position
forall a b. (a -> b) -> a -> b
$ Status
st.stXFadeWidth
  , mixRampDb :: Maybe FractionalSeconds
Current.mixRampDb      = FractionalSeconds -> Maybe FractionalSeconds
forall a. a -> Maybe a
Just Status
st.stMixRampdB
  , mixRampDelay :: Maybe FractionalSeconds
Current.mixRampDelay   = FractionalSeconds -> Maybe FractionalSeconds
forall a. a -> Maybe a
Just Status
st.stMixRampDelay
  , updatingDb :: Maybe Position
Current.updatingDb     = Integer -> Position
integerToInt (Integer -> Position) -> Maybe Integer -> Maybe Position
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Status
st.stUpdatingDb
  , error :: Maybe String
Current.error          = Status
st.stError
  }
  where
    calcElapsedPercent :: Maybe (MPD.FractionalSeconds, MPD.FractionalSeconds) -> Maybe Double
    calcElapsedPercent :: Maybe (FractionalSeconds, FractionalSeconds)
-> Maybe FractionalSeconds
calcElapsedPercent Maybe (FractionalSeconds, FractionalSeconds)
Nothing = Maybe FractionalSeconds
forall a. Maybe a
Nothing
    calcElapsedPercent (Just (FractionalSeconds
elapsed, FractionalSeconds
duration)) = do
      let elapsedPercent :: FractionalSeconds
elapsedPercent = (FractionalSeconds
elapsed FractionalSeconds -> FractionalSeconds -> FractionalSeconds
forall a. Fractional a => a -> a -> a
/ FractionalSeconds
duration) FractionalSeconds -> FractionalSeconds -> FractionalSeconds
forall a. Num a => a -> a -> a
* FractionalSeconds
100
      if FractionalSeconds
duration FractionalSeconds -> FractionalSeconds -> Bool
forall a. Ord a => a -> a -> Bool
> FractionalSeconds
0
        then String -> Maybe FractionalSeconds
forall a. Read a => String -> Maybe a
readMaybe (String -> Maybe FractionalSeconds)
-> String -> Maybe FractionalSeconds
forall a b. (a -> b) -> a -> b
$ String -> FractionalSeconds -> String
forall r. PrintfType r => String -> r
printf String
"%02.2f" FractionalSeconds
elapsedPercent :: Maybe Double
        else Maybe FractionalSeconds
forall a. Maybe a
Nothing

mkPlaylist :: MPD.Status -> Current.Playlist
mkPlaylist :: Status -> Playlist
mkPlaylist Status
st = Current.Playlist
  { position :: Maybe Position
Current.position     = Status
st.stSongPos
  , nextPosition :: Maybe Position
Current.nextPosition = Status
st.stNextSongPos
  , id :: Maybe MPDId
Current.id           = Id -> MPDId
Current.MPDId (Id -> MPDId) -> Maybe Id -> Maybe MPDId
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Status
st.stSongID
  , nextId :: Maybe MPDId
Current.nextId       = Id -> MPDId
Current.MPDId (Id -> MPDId) -> Maybe Id -> Maybe MPDId
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Status
st.stNextSongID
  , length :: Position
Current.length       = Integer -> Position
forall a b. (Integral a, Num b) => a -> b
fromIntegral Status
st.stPlaylistLength
  }

mkFile :: MPD.Song -> MPD.Song -> Current.File
mkFile :: Song -> Song -> File
mkFile Song
cs Song
ns = Current.File
  { currentFile :: Maybe MPDPath
Current.currentFile = if String -> Bool
forall a. [a] -> Bool
forall (t :: * -> *) a. Foldable t => t a -> Bool
null (String -> Bool) -> String -> Bool
forall a b. (a -> b) -> a -> b
$ Path -> String
forall a. ToString a => a -> String
MPD.toString Song
cs.sgFilePath
                          then Maybe MPDPath
forall a. Maybe a
Nothing
                          else MPDPath -> Maybe MPDPath
forall a. a -> Maybe a
Just (MPDPath -> Maybe MPDPath) -> MPDPath -> Maybe MPDPath
forall a b. (a -> b) -> a -> b
$ Path -> MPDPath
Current.MPDPath Song
cs.sgFilePath
  , nextFile :: Maybe MPDPath
Current.nextFile    = if String -> Bool
forall a. [a] -> Bool
forall (t :: * -> *) a. Foldable t => t a -> Bool
null (String -> Bool) -> String -> Bool
forall a b. (a -> b) -> a -> b
$ Path -> String
forall a. ToString a => a -> String
MPD.toString Song
ns.sgFilePath
                          then Maybe MPDPath
forall a. Maybe a
Nothing
                          else MPDPath -> Maybe MPDPath
forall a. a -> Maybe a
Just (MPDPath -> Maybe MPDPath) -> MPDPath -> Maybe MPDPath
forall a b. (a -> b) -> a -> b
$ Path -> MPDPath
Current.MPDPath Song
ns.sgFilePath
  }