{-# LANGUAGE DeriveFunctor         #-}
{-# LANGUAGE FlexibleContexts      #-}
{-# LANGUAGE FlexibleInstances     #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE NoImplicitPrelude     #-}
{-# LANGUAGE TypeOperators         #-}
-- | DSL/interpreter model for parsing XML into a 'Feed'
module Imm.XML where

-- {{{ Imports
import           Imm.Error
import           Imm.Feed
import           Imm.Prelude

import           Control.Monad.Trans.Free

import           URI.ByteString
-- }}}

-- * Types

-- | XML parsing DSL
data XmlParserF next
  = ParseXml URI LByteString (Either SomeException Feed -> next)
  deriving(Functor)

-- | XML parsing interpreter
newtype CoXmlParserF m a = CoXmlParserF
  { parseXmlH :: URI -> LByteString -> m (Either SomeException Feed, a)
  } deriving(Functor)

instance Monad m => PairingM (CoXmlParserF m) XmlParserF m where
  -- pairM :: (a -> b -> m r) -> f a -> g b -> m r
  pairM f (CoXmlParserF p) (ParseXml uri bytestring next) = do
    (result, a) <- p uri bytestring
    f a $ next result

-- * Primitives

-- | Parse XML into a 'Feed'
parseXml :: (MonadFree f m, XmlParserF :<: f, MonadThrow m)
         => URI -> LByteString -> m Feed
parseXml uri bytestring = do
  result <- liftF . inj $ ParseXml uri bytestring id
  liftE result