    -- |
    -- interface to the HXT XML and DTD parsers
    --
    -- version: $Id: ParserInterface.hs,v 1.1 2006/05/01 18:56:24 hxml Exp $

    module Text.XML.HXT.Arrow.ParserInterface
        ( module Text.XML.HXT.Arrow.ParserInterface )
    where

    import Control.Arrow
    import Control.Arrow.ArrowList
    import Control.Arrow.ArrowIf
    import Control.Arrow.ArrowTree
    import Control.Arrow.ListArrow

    import Text.XML.HXT.Parser.XmlEntities  ( xmlEntities   )
    import Text.XML.HXT.Parser.XhtmlEntities( xhtmlEntities )

    import Text.XML.HXT.DOM.Interface
    import Text.XML.HXT.Arrow.XmlArrow

    import qualified Text.XML.HXT.Parser.TagSoup             as TS
    import qualified Text.XML.HXT.Parser.HtmlParsec          as HP
    import qualified Text.XML.HXT.Parser.XmlParsec           as XP
    import qualified Text.XML.HXT.Parser.XmlDTDParser        as DP
    import qualified Text.XML.HXT.DTDValidation.Validation   as VA

    -- ------------------------------------------------------------

    parseXmlDoc                     :: ArrowXml a => a (String, String) XmlTree
    parseXmlDoc                     =  arr2L XP.parseXmlDocument

    parseXmlDTDPart                 :: ArrowXml a => a (String, XmlTree) XmlTree
    parseXmlDTDPart                 =  arr2L XP.parseXmlDTDPart

    parseXmlContent                 :: ArrowXml a => a String XmlTree
    parseXmlContent                 =  arrL XP.xread

    parseXmlEntityEncodingSpec
      , parseXmlDocEncodingSpec
      , removeEncodingSpec          :: ArrowXml a => a XmlTree XmlTree

    parseXmlDocEncodingSpec         =  arrL XP.parseXmlDocEncodingSpec
    parseXmlEntityEncodingSpec      =  arrL XP.parseXmlEntityEncodingSpec

    removeEncodingSpec              =  arrL XP.removeEncodingSpec

    parseXmlDTDdeclPart             :: ArrowXml a => a XmlTree XmlTree
    parseXmlDTDdeclPart             =  arrL DP.parseXmlDTDdeclPart

    parseXmlDTDdecl                 :: ArrowXml a => a XmlTree XmlTree
    parseXmlDTDdecl                 =  arrL DP.parseXmlDTDdecl

    parseXmlDTDEntityValue          :: ArrowXml a => a XmlTree XmlTree
    parseXmlDTDEntityValue          =  arrL DP.parseXmlDTDEntityValue

    parseXmlAttrValue               :: ArrowXml a => String -> a XmlTree XmlTree
    parseXmlAttrValue context       =  arrL (XP.parseXmlAttrValue context)

    parseXmlGeneralEntityValue      :: ArrowXml a => String -> a XmlTree XmlTree
    parseXmlGeneralEntityValue context
                                    =  arrL (XP.parseXmlGeneralEntityValue context)

    -- ------------------------------------------------------------

    parseHtmlDoc                    :: ArrowList a => a (String, String) XmlTree
    parseHtmlDoc                    = arr2L HP.parseHtmlDocument

    parseHtmlContent                :: ArrowList a => a String XmlTree
    parseHtmlContent                = arrL  HP.parseHtmlContent

    parseHtmlTagSoup                :: ArrowList a => Bool -> Bool -> Bool -> Bool -> Bool -> a (String, String) XmlTree
    parseHtmlTagSoup withNamespaces withWarnings preserveCmt removeWS asHtml
                                    = arr2L (TS.parseHtmlTagSoup withNamespaces withWarnings preserveCmt removeWS asHtml)

    -- ------------------------------------------------------------

    validateDoc                     :: ArrowList a => a XmlTree XmlTree
    validateDoc                     = fromLA ( VA.validate
                                               `when`
                                               VA.getDTDSubset      -- validate only when DTD decl is present
                                             )

    transformDoc                    :: ArrowList a => a XmlTree XmlTree
    transformDoc                    = fromLA VA.transform

    -- old stuff
    -- validateDoc                  = arrL VA.validate
    -- transformDoc                 = arrL VA.transform

    -- ------------------------------------------------------------

    -- | substitution of all predefined XHTMT entities for none ASCII chars
    --
    -- This arrow recurses through a whole XML tree and substitutes all
    -- entity refs within text nodes and attribute values by a text node
    -- containing of a single char corresponding to this entity.
    --
    -- Unknown entity refs remain unchanged

    substHtmlEntityRefs             :: ArrowList a => a XmlTree XmlTree
    substHtmlEntityRefs             = substEntityRefs xhtmlEntities

    -- | substitution of the five predefined XMT entities, works like 'substHtmlEntityRefs'

    substXmlEntityRefs              :: ArrowList a => a XmlTree XmlTree
    substXmlEntityRefs              = substEntityRefs xmlEntities

    -- | the entity substitution arrow called from 'substXmlEntityRefs' and 'substHtmlEntityRefs'

    substEntityRefs         :: ArrowList a => [(String, Int)] -> a XmlTree XmlTree
    substEntityRefs entities
        = fromLA substEntities
        where
        substEntities               :: LA XmlTree XmlTree
        substEntities
            = choiceA
              [ isEntityRef :-> ( substEntity $< getEntityRef )
              , isElem      :-> ( processAttrl (processChildren substEntities)
                                  >>>
                                  processChildren substEntities
                                )
              , this        :-> this
              ]
            where
            substEntity en
                = case (lookup en entities) of
                  Just i
                      -> txt [toEnum i]     -- constA i >>> mkCharRef
                  Nothing
                      -> this

    -- ------------------------------------------------------------