{- | Entry point for loading a 'Song' from disk. Dispatches to a
format-specific parser ("Termtab.Parser.MIDI", "Termtab.Parser.GP5") by
file extension, so callers don't need to know which parser handles which
format.
-}
module Termtab.Parser.Common (parseFile) where

import Data.Text qualified as T
import System.FilePath (takeExtension)

import Termtab.Parser.GP5 qualified as GP5
import Termtab.Parser.MIDI qualified as MIDI
import Termtab.Types (
    ParseError (..),
    Song,
    UnsupportedFormat (..),
 )

{- | Parse @path@ into a 'Song' using the parser selected by its file
extension (@.mid@\/@.midi@ -> 'MIDI.parseMidi', @.gp5@ -> 'GP5.parseGP5').
Recognized-but-unimplemented Guitar Pro extensions (@.gp3@, @.gp4@,
@.gpx@, @.gp@) and unknown extensions both fail with
'ParseErrorUnsupported' rather than being attempted.
-}
parseFile :: FilePath -> IO (Either ParseError Song)
parseFile :: String -> IO (Either ParseError Song)
parseFile String
path = case String -> String
takeExtension String
path of
    String
".mid" -> String -> IO (Either ParseError Song)
MIDI.parseMidi String
path
    String
".midi" -> String -> IO (Either ParseError Song)
MIDI.parseMidi String
path
    String
".gp5" -> String -> IO (Either ParseError Song)
GP5.parseGP5 String
path
    String
".gp3" -> String -> IO (Either ParseError Song)
forall {m :: * -> *} {b}.
Monad m =>
String -> m (Either ParseError b)
unsupported String
"GP3 not yet supported"
    String
".gp4" -> String -> IO (Either ParseError Song)
forall {m :: * -> *} {b}.
Monad m =>
String -> m (Either ParseError b)
unsupported String
"GP4 not yet supported"
    String
".gpx" -> String -> IO (Either ParseError Song)
forall {m :: * -> *} {b}.
Monad m =>
String -> m (Either ParseError b)
unsupported String
"GP6/GPX not yet supported"
    String
".gp" -> String -> IO (Either ParseError Song)
forall {m :: * -> *} {b}.
Monad m =>
String -> m (Either ParseError b)
unsupported String
"GP7 not yet supported"
    String
ext -> String -> IO (Either ParseError Song)
forall {m :: * -> *} {b}.
Monad m =>
String -> m (Either ParseError b)
unsupported (String
"Unknown file extension: " String -> String -> String
forall a. Semigroup a => a -> a -> a
<> String
ext)
  where
    unsupported :: String -> m (Either ParseError b)
unsupported String
msg =
        Either ParseError b -> m (Either ParseError b)
forall a. a -> m a
forall (m :: * -> *) a. Monad m => a -> m a
return
            ( ParseError -> Either ParseError b
forall a b. a -> Either a b
Left
                ( UnsupportedFormat -> ParseError
ParseErrorUnsupported
                    UnsupportedFormat
                        { unsupportedPath :: String
unsupportedPath = String
path
                        , unsupportedReason :: Text
unsupportedReason = String -> Text
T.pack String
msg
                        }
                )
            )