appEvent :: PlayerApp -> PlayerEvent -> EventM (Next PlayerApp)
appEvent app@(PlayerApp l status _ mPlayback) e =
  case e of
    -- press enter to play selected song, stop current song if playing
    VtyEvent (V.EvKey V.KEnter []) ->
      M.continue =<< stopAndPlaySelected app

    -- press spacebar to play/pause
    VtyEvent (V.EvKey (V.KChar ' ') []) ->
      case status of
        Play ->
          -- pause playing song
          case mPlayback of
            Nothing -> M.continue app
            Just (Playback playPos playProc _ _ _) -> do
              liftIO $ AP.pause playProc
              M.continue $ updateAppStatus app Pause playPos
        Pause ->
          -- resume playing song
          case mPlayback of
            Nothing -> M.continue app
            Just (Playback playPos playProc _ _ _) -> do
              liftIO $ AP.resume playProc
              M.continue $ updateAppStatus app Play playPos
        Stop ->
          -- play selected song
          M.continue =<< play (l ^. L.listSelectedL) app

    -- press left to play previous song
    VtyEvent (V.EvKey V.KLeft []) ->
      M.continue =<< stopAndPlayDelta (-1) app

    -- press right to play next song
    VtyEvent (V.EvKey V.KRight []) ->
      M.continue =<< stopAndPlayDelta 1 app

    -- press q to quit
    VtyEvent (V.EvKey (V.KChar 'q') []) ->
      M.halt =<< stop app

    -- any other event
    VtyEvent ev -> do
      l' <- handleEvent ev l
      M.continue app { songsList = l' }

    -- playhead advance event
    PlayheadAdvance ->
      M.continue =<< case status of
        Play ->
          case mPlayback of
            Nothing -> return app
            Just pb@(Playback _ _ ph _ _) ->
              if ph > 0 then
                -- advance playhead
                return app { playback = Just pb { playhead = ph - 1.0 } }
              else
                stopAndPlayDelta 1 app
        _ -> return app


-- | Forks a thread that will trigger a 'Types.PlayheadAdvance' event every
-- second.
appEvent :: PlayerApp -> PlayerEvent -> EventM (Next PlayerApp)
appEvent app@(PlayerApp l status _ mPlayback) e =
  case e of
    -- press enter to play selected song, stop current song if playing
    VtyEvent (V.EvKey V.KEnter []) ->
      M.continue =<< stopAndPlaySelected app

    -- press spacebar to play/pause
    VtyEvent (V.EvKey (V.KChar ' ') []) ->
      case status of
        Play ->
          -- pause playing song
          case mPlayback of
            Nothing -> M.continue app
            Just (Playback playPos playProc _ _ _) -> do
              liftIO $ AP.pause playProc
              M.continue $ updateAppStatus app Pause playPos
        Pause ->
          -- resume playing song
          case mPlayback of
            Nothing -> M.continue app
            Just (Playback playPos playProc _ _ _) -> do
              liftIO $ AP.resume playProc
              M.continue $ updateAppStatus app Play playPos
        Stop ->
          -- play selected song
          M.continue =<< play (l ^. L.listSelectedL) app

    -- press left to play previous song
    VtyEvent (V.EvKey V.KLeft []) ->
      M.continue =<< stopAndPlayDelta (-1) app

    -- press right to play next song
    VtyEvent (V.EvKey V.KRight []) ->
      M.continue =<< stopAndPlayDelta 1 app

    -- press q to quit
    VtyEvent (V.EvKey (V.KChar 'q') []) ->
      M.halt =<< stop app

    -- any other event
    VtyEvent ev -> do
      l' <- handleEvent ev l
      M.continue app { songsList = l' }

    -- playhead advance event
    PlayheadAdvance ->
      M.continue =<< case status of
        Play ->
          case mPlayback of
            Nothing -> return app
            Just pb@(Playback _ _ ph _ _) ->
              if ph > 0 then
                -- advance playhead
                return app { playback = Just pb { playhead = ph - 1.0 } }
              else
                stopAndPlayDelta 1 app
        _ -> return app


-- | Forks a thread that will trigger a 'Types.PlayheadAdvance' event every
-- second.
appEvent app@(PlayerApp l status _ mPlayback) e =
  case e of
    -- press enter to play selected song, stop current song if playing
    VtyEvent (V.EvKey V.KEnter []) ->
      M.continue =<< stopAndPlaySelected app

    -- press spacebar to play/pause
    VtyEvent (V.EvKey (V.KChar ' ') []) ->
      case status of
        Play ->
          -- pause playing song
          case mPlayback of
            Nothing -> M.continue app
            Just (Playback playPos playProc _ _ _) -> do
              liftIO $ AP.pause playProc
              M.continue $ updateAppStatus app Pause playPos
        Pause ->
          -- resume playing song
          case mPlayback of
            Nothing -> M.continue app
            Just (Playback playPos playProc _ _ _) -> do
              liftIO $ AP.resume playProc
              M.continue $ updateAppStatus app Play playPos
        Stop ->
          -- play selected song
          M.continue =<< play (l ^. L.listSelectedL) app

    -- press left to play previous song
    VtyEvent (V.EvKey V.KLeft []) ->
      M.continue =<< stopAndPlayDelta (-1) app

    -- press right to play next song
    VtyEvent (V.EvKey V.KRight []) ->
      M.continue =<< stopAndPlayDelta 1 app

    -- press q to quit
    VtyEvent (V.EvKey (V.KChar 'q') []) ->
      M.halt =<< stop app

    -- any other event
    VtyEvent ev -> do
      l' <- handleEvent ev l
      M.continue app { songsList = l' }

    -- playhead advance event
    PlayheadAdvance ->
      M.continue =<< case status of
        Play ->
          case mPlayback of
            Nothing -> return app
            Just pb@(Playback _ _ ph _ _) ->
              if ph > 0 then
                -- advance playhead
                return app { playback = Just pb { playhead = ph - 1.0 } }
              else
                stopAndPlayDelta 1 app
        _ -> return app


-- | Forks a thread that will trigger a 'Types.PlayheadAdvance' event every
-- second.