module Penny.Copper.Memos.Transaction (
  memo, render, isCommentChar
  ) where

import Control.Applicative ((<*>), (<$>), (<*), (<$))
import qualified Data.Text as X
import Text.Parsec (
  char, satisfy, sourceLine, getPosition, (<?>),
  many)
import Text.Parsec.Text ( Parser )

import Penny.Copper.Util (rangeLettersToSymbols, eol)
import qualified Penny.Lincoln as L
import qualified Penny.Lincoln.TextNonEmpty as TNE

isCommentChar :: Char -> Bool
isCommentChar c = rangeLettersToSymbols c
                  || c == ' '

memoLine :: Parser L.MemoLine
memoLine = L.MemoLine <$> (
  TNE.TextNonEmpty
  <$ char ';'
  <*> satisfy isCommentChar
  <*> (X.pack <$> many (satisfy isCommentChar))
  <* eol )
  <?> "posting memo line"

-- | Parses a transaction memo and associated whitespace afterward.
memo :: Parser (L.Memo, L.TopMemoLine)
memo =
  flip (,)
  <$> ((L.TopMemoLine . sourceLine) <$> getPosition)
  <*> (L.Memo <$> many memoLine)
  <?> "transaction memo"
  
-- | Renders a transaction memo. Fails if the memo is not renderable.
render :: L.Memo -> Maybe X.Text
render (L.Memo m) = X.concat <$> mapM renderLine m

renderLine :: L.MemoLine -> Maybe X.Text
renderLine (L.MemoLine l) =
  if TNE.all isCommentChar l
  then Just $ X.singleton ';' `X.append` TNE.toText l `X.snoc` '\n'
  else Nothing