{- | Plain-text summary of a 'Song', used for non-interactive (CLI) output
as opposed to the interactive Brick UI in "Termtab.UI".
-}
module Termtab.Display (printSong) where

import Data.Map.Strict qualified as Map
import Data.Text qualified as T
import Data.Text.IO qualified as TIO

import Termtab.Types

{- | Print title, artist, tempo, and one summary line per 'Track' (name and
total note count across all of its measures) to stdout.
-}
printSong :: Song -> IO ()
printSong :: Song -> IO ()
printSong Song
song = do
    Text -> IO ()
TIO.putStrLn (Text
"Title:  " Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Song -> Text
songTitle Song
song)
    Text -> IO ()
TIO.putStrLn (Text
"Artist: " Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Song -> Text
songArtist Song
song)
    let Tempo Int
bpm = Song -> Tempo
songTempo Song
song
    String -> IO ()
putStrLn (String
"Tempo:  " String -> String -> String
forall a. Semigroup a => a -> a -> a
<> Int -> String
forall a. Show a => a -> String
show Int
bpm String -> String -> String
forall a. Semigroup a => a -> a -> a
<> String
" BPM")
    String -> IO ()
putStrLn (String
"Tracks: " String -> String -> String
forall a. Semigroup a => a -> a -> a
<> Int -> String
forall a. Show a => a -> String
show ([Track] -> Int
forall a. [a] -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length (Song -> [Track]
songTracks Song
song)))
    ((Int, Track) -> IO ()) -> [(Int, Track)] -> IO ()
forall (t :: * -> *) (m :: * -> *) a b.
(Foldable t, Monad m) =>
(a -> m b) -> t a -> m ()
mapM_ (Int, Track) -> IO ()
printTrack ([Int] -> [Track] -> [(Int, Track)]
forall a b. [a] -> [b] -> [(a, b)]
zip [Int
1 :: Int ..] (Song -> [Track]
songTracks Song
song))

{- | Print one @[index] name: N notes@ line for 'printSong', where the
index is the caller-supplied 1-based position of the track.
-}
printTrack :: (Int, Track) -> IO ()
printTrack :: (Int, Track) -> IO ()
printTrack (Int
i, Track
track) =
    Text -> IO ()
TIO.putStrLn
        ( Text
"  ["
            Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> String -> Text
T.pack (Int -> String
forall a. Show a => a -> String
show Int
i)
            Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
"] "
            Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Track -> Text
trackName Track
track
            Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
": "
            Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> String -> Text
T.pack (Int -> String
forall a. Show a => a -> String
show Int
noteCount)
            Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
" notes"
        )
  where
    noteCount :: Int
noteCount = [Int] -> Int
forall a. Num a => [a] -> a
forall (t :: * -> *) a. (Foldable t, Num a) => t a -> a
sum ((Beat -> Int) -> [Beat] -> [Int]
forall a b. (a -> b) -> [a] -> [b]
map ([Note] -> Int
forall a. [a] -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length ([Note] -> Int) -> (Beat -> [Note]) -> Beat -> Int
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Beat -> [Note]
beatNotes) ([[Beat]] -> [Beat]
forall (t :: * -> *) a. Foldable t => t [a] -> [a]
concat (Map MeasureIndex [Beat] -> [[Beat]]
forall k a. Map k a -> [a]
Map.elems (Track -> Map MeasureIndex [Beat]
trackBeats Track
track))))