{-# LANGUAGE OverloadedStrings #-}

-- |
-- Module      :  ELynx.Import.Nexus
-- Description :  Nexus types and classes
-- Copyright   :  (c) Dominik Schrempf 2020
-- License     :  GPL-3
--
-- Maintainer  :  dominik.schrempf@gmail.com
-- Stability   :  unstable
-- Portability :  portable
--
-- Creation date: Tue Apr 28 17:10:05 2020.
module ELynx.Import.Nexus
  ( Block (..),
    nexus,
  )
where

import Data.Attoparsec.ByteString.Char8
import qualified Data.ByteString.Char8 as BS

-- | A Nexus block has a name (e.g., TREES), and parser for the entry.
data Block a = Block
  { name :: BS.ByteString,
    parser :: Parser a
  }

-- This has to be refined. Like this, only one block can be parsed, and the
-- block type has to be known beforehand.

-- | Parse a Nexus file with a given 'Block'.
nexus :: Block a -> Parser a
nexus b = start *> block b <* endOfInput <?> "nexus"

start :: Parser ()
start = (<?> "start") $ do
  _ <- string "#NEXUS"
  _ <- skipWhile isSpace
  return ()

block :: Block a -> Parser a
block b = beginB (name b) *> parser b <* endB <?> "block"

beginB :: BS.ByteString -> Parser ()
beginB n = (<?> "begin") $ do
  _ <- string "BEGIN"
  _ <- skipWhile isSpace
  _ <- string n
  _ <- char ';'
  _ <- skipWhile isSpace
  return ()

endB :: Parser ()
endB = (<?> "end") $ do
  _ <- string "END;"
  _ <- skipWhile isSpace
  return ()