module Text.XML.HXT.Arrow.XmlArrow
    ( module Text.XML.HXT.Arrow.XmlArrow )
where
import           Control.Arrow                  
import           Control.Arrow.ArrowList
import           Control.Arrow.ArrowIf
import           Control.Arrow.ArrowTree
import           Control.Arrow.ListArrow                
import           Control.Arrow.StateListArrow
import           Control.Arrow.IOListArrow
import           Control.Arrow.IOStateListArrow
import           Data.Char.Properties.XMLCharProps        ( isXmlSpaceChar )
import           Data.Maybe
import           Text.XML.HXT.DOM.Interface
import qualified Text.XML.HXT.DOM.XmlNode as XN
import qualified Text.XML.HXT.DOM.ShowXml as XS
infixl 7 +=
class (Arrow a, ArrowList a, ArrowTree a) => ArrowXml a where
    
    
    isText              :: a XmlTree XmlTree
    isText              = isA XN.isText
    {-# INLINE isText #-}
    isBlob              :: a XmlTree XmlTree
    isBlob              = isA XN.isBlob
    {-# INLINE isBlob #-}
    
    isCharRef           :: a XmlTree XmlTree
    isCharRef           = isA XN.isCharRef
    {-# INLINE isCharRef #-}
    
    isEntityRef         :: a XmlTree XmlTree
    isEntityRef         = isA XN.isEntityRef
    {-# INLINE isEntityRef #-}
    
    isCmt               :: a XmlTree XmlTree
    isCmt               = isA XN.isCmt
    {-# INLINE isCmt #-}
    
    isCdata             :: a XmlTree XmlTree
    isCdata             = isA XN.isCdata
    {-# INLINE isCdata #-}
    
    isPi                :: a XmlTree XmlTree
    isPi                = isA XN.isPi
    {-# INLINE isPi #-}
    
    isXmlPi             :: a XmlTree XmlTree
    isXmlPi             = isPi >>> hasName "xml"
    
    isElem              :: a XmlTree XmlTree
    isElem              = isA XN.isElem
    {-# INLINE isElem #-}
    
    isDTD               :: a XmlTree XmlTree
    isDTD               = isA XN.isDTD
    {-# INLINE isDTD #-}
    
    isAttr              :: a XmlTree XmlTree
    isAttr              = isA XN.isAttr
    {-# INLINE isAttr #-}
    
    isError             :: a XmlTree XmlTree
    isError             = isA XN.isError
    {-# INLINE isError #-}
    
    isRoot              :: a XmlTree XmlTree
    isRoot              = isA XN.isRoot
    {-# INLINE isRoot #-}
    
    
    
    hasText             :: (String -> Bool) -> a XmlTree XmlTree
    hasText p           = (isText >>> getText >>> isA p) `guards` this
    
    
    
    isWhiteSpace        :: a XmlTree XmlTree
    isWhiteSpace        = hasText (all isXmlSpaceChar)
    {-# INLINE isWhiteSpace #-}
    
    
    hasNameWith         :: (QName  -> Bool) -> a XmlTree XmlTree
    hasNameWith p       = (getQName        >>> isA p) `guards` this
    {-# INLINE hasNameWith #-}
    
    
    
    hasQName            :: QName  -> a XmlTree XmlTree
    hasQName n          = (getQName        >>> isA (== n)) `guards` this
    {-# INLINE hasQName #-}
    
    
    
    hasName             :: String -> a XmlTree XmlTree
    hasName n           = (getName         >>> isA (== n)) `guards` this
    {-# INLINE hasName #-}
    
    
    
    hasLocalPart        :: String -> a XmlTree XmlTree
    hasLocalPart n      = (getLocalPart    >>> isA (== n)) `guards` this
    {-# INLINE hasLocalPart #-}
    
    
    
    hasNamePrefix       :: String -> a XmlTree XmlTree
    hasNamePrefix n     = (getNamePrefix   >>> isA (== n)) `guards` this
    {-# INLINE hasNamePrefix #-}
    
    
    
    hasNamespaceUri     :: String -> a XmlTree XmlTree
    hasNamespaceUri n   = (getNamespaceUri >>> isA (== n)) `guards` this
    {-# INLINE hasNamespaceUri #-}
    
    
    hasAttr             :: String -> a XmlTree XmlTree
    hasAttr n           = (getAttrl        >>> hasName n)  `guards` this
    {-# INLINE hasAttr #-}
    
    
    hasQAttr            :: QName -> a XmlTree XmlTree
    hasQAttr n          = (getAttrl        >>> hasQName n)  `guards` this
    {-# INLINE hasQAttr #-}
    
    
    hasAttrValue        :: String -> (String -> Bool) -> a XmlTree XmlTree
    hasAttrValue n p    = (getAttrl >>> hasName n >>> xshow getChildren >>> isA p)  `guards` this
    
    
    hasQAttrValue       :: QName -> (String -> Bool) -> a XmlTree XmlTree
    hasQAttrValue n p   = (getAttrl >>> hasQName n >>> xshow getChildren >>> isA p)  `guards` this
    
    
    mkText              :: a String XmlTree
    mkText              = arr  XN.mkText
    {-# INLINE mkText #-}
    
    mkBlob              :: a Blob XmlTree
    mkBlob              = arr  XN.mkBlob
    {-# INLINE mkBlob #-}
    
    mkCharRef           :: a Int    XmlTree
    mkCharRef           = arr  XN.mkCharRef
    {-# INLINE mkCharRef #-}
    
    mkEntityRef         :: a String XmlTree
    mkEntityRef         = arr  XN.mkEntityRef
    {-# INLINE mkEntityRef #-}
    
    mkCmt               :: a String XmlTree
    mkCmt               = arr  XN.mkCmt
    {-# INLINE mkCmt #-}
    
    mkCdata             :: a String XmlTree
    mkCdata             = arr  XN.mkCdata
    {-# INLINE mkCdata #-}
    
    mkError             :: Int -> a String XmlTree
    mkError level       = arr (XN.mkError level)
    
    
    
    mkElement           :: QName -> a n XmlTree -> a n XmlTree -> a n XmlTree
    mkElement n af cf   = (listA af &&& listA cf)
                          >>>
                          arr2 (\ al cl -> XN.mkElement n al cl)
    
    
    mkAttr              :: QName -> a n XmlTree -> a n XmlTree
    mkAttr qn f         = listA f >>> arr (XN.mkAttr qn)
    
    
    mkPi                :: QName -> a n XmlTree -> a n XmlTree
    mkPi qn f           = listA f >>> arr (XN.mkPi   qn)
    
    
    
    
    
    
    
    
    
    
    mkqelem             :: QName -> [a n XmlTree] -> [a n XmlTree] -> a n XmlTree
    mkqelem  n afs cfs  = mkElement n (catA afs) (catA cfs)
    {-# INLINE mkqelem #-}
    
    mkelem              :: String -> [a n XmlTree] -> [a n XmlTree] -> a n XmlTree
    mkelem  n afs cfs   = mkElement (mkName n) (catA afs) (catA cfs)
    {-# INLINE mkelem #-}
    
    aelem               :: String -> [a n XmlTree]                  -> a n XmlTree
    aelem n afs         = catA afs >. \ al -> XN.mkElement (mkName n) al []
    {-# INLINE aelem #-}
    
    selem               :: String                  -> [a n XmlTree] -> a n XmlTree
    selem n cfs         = catA cfs >.         XN.mkElement (mkName n) []
    {-# INLINE selem #-}
    
    eelem               :: String                                   -> a n XmlTree
    eelem n             = constA      (XN.mkElement (mkName n) [] [])
    {-# INLINE eelem #-}
    
    root                ::           [a n XmlTree] -> [a n XmlTree] -> a n XmlTree
    root                = mkelem t_root
    {-# INLINE root #-}
    
    qattr               :: QName -> a n XmlTree -> a n XmlTree
    qattr               = mkAttr
    {-# INLINE qattr #-}
    
    attr                :: String -> a n XmlTree -> a n XmlTree
    attr                = mkAttr . mkName
    {-# INLINE attr #-}
    
    
    txt                 :: String -> a n XmlTree
    txt                 = constA .  XN.mkText
    {-# INLINE txt #-}
    
    blb                 :: Blob -> a n XmlTree
    blb                 = constA .  XN.mkBlob
    {-# INLINE blb #-}
    
    charRef             :: Int    -> a n XmlTree
    charRef             = constA .  XN.mkCharRef
    {-# INLINE charRef #-}
    
    entityRef           :: String -> a n XmlTree
    entityRef           = constA .  XN.mkEntityRef
    {-# INLINE entityRef #-}
    
    cmt                 :: String -> a n XmlTree
    cmt                 = constA .  XN.mkCmt
    {-# INLINE cmt #-}
    
    warn                :: String -> a n XmlTree
    warn                = constA . (XN.mkError c_warn)
    {-# INLINE warn #-}
    
    err                 :: String -> a n XmlTree
    err                 = constA . (XN.mkError c_err)
    {-# INLINE err #-}
    
    fatal               :: String -> a n XmlTree
    fatal               = constA . (XN.mkError c_fatal)
    {-# INLINE fatal #-}
    
    spi                 :: String -> String -> a n XmlTree
    spi piName piCont   = constA (XN.mkPi (mkName piName) [XN.mkAttr (mkName a_value) [XN.mkText piCont]])
    {-# INLINE spi #-}
    
    
    sqattr              :: QName -> String -> a n XmlTree
    sqattr an av        = constA (XN.mkAttr an                 [XN.mkText av])
    {-# INLINE sqattr #-}
    
    
    sattr               :: String -> String -> a n XmlTree
    sattr an av         = constA (XN.mkAttr (mkName an)     [XN.mkText av])
    {-# INLINE sattr #-}
    
    
    getText             :: a XmlTree String
    getText             = arrL (maybeToList  . XN.getText)
    {-# INLINE getText #-}
    
    getCharRef          :: a XmlTree Int
    getCharRef          = arrL (maybeToList  . XN.getCharRef)
    {-# INLINE getCharRef #-}
    
    getEntityRef        :: a XmlTree String
    getEntityRef        = arrL (maybeToList  . XN.getEntityRef)
    {-# INLINE getEntityRef #-}
    
    getCmt              :: a XmlTree String
    getCmt              = arrL (maybeToList  . XN.getCmt)
    {-# INLINE getCmt #-}
    
    getCdata            :: a XmlTree String
    getCdata            = arrL (maybeToList  . XN.getCdata)
    {-# INLINE getCdata #-}
    
    getPiName           :: a XmlTree QName
    getPiName           = arrL (maybeToList  . XN.getPiName)
    {-# INLINE getPiName #-}
    
    getPiContent        :: a XmlTree XmlTree
    getPiContent        = arrL (fromMaybe [] . XN.getPiContent)
    {-# INLINE getPiContent #-}
    
    getElemName         :: a XmlTree QName
    getElemName         = arrL (maybeToList  . XN.getElemName)
    {-# INLINE getElemName #-}
    
    getAttrl            :: a XmlTree XmlTree
    getAttrl            = arrL (fromMaybe [] . XN.getAttrl)
    {-# INLINE getAttrl #-}
    
    getDTDPart          :: a XmlTree DTDElem
    getDTDPart          = arrL (maybeToList  . XN.getDTDPart)
    {-# INLINE getDTDPart #-}
    
    getDTDAttrl         :: a XmlTree Attributes
    getDTDAttrl         = arrL (maybeToList  . XN.getDTDAttrl)
    {-# INLINE getDTDAttrl #-}
    
    getAttrName         :: a XmlTree QName
    getAttrName         = arrL (maybeToList  . XN.getAttrName)
    {-# INLINE getAttrName #-}
    
    getErrorLevel       :: a XmlTree Int
    getErrorLevel       = arrL (maybeToList  . XN.getErrorLevel)
    {-# INLINE getErrorLevel #-}
    
    getErrorMsg         :: a XmlTree String
    getErrorMsg         = arrL (maybeToList  . XN.getErrorMsg)
    {-# INLINE getErrorMsg #-}
    
    getQName            :: a XmlTree QName
    getQName            = arrL (maybeToList  . XN.getName)
    {-# INLINE getQName #-}
    
    getName             :: a XmlTree String
    getName             = arrL (maybeToList  . XN.getQualifiedName)
    {-# INLINE getName #-}
    
    getUniversalName    :: a XmlTree String
    getUniversalName    = arrL (maybeToList  . XN.getUniversalName)
    {-# INLINE getUniversalName #-}
    
    getUniversalUri     :: a XmlTree String
    getUniversalUri     = arrL (maybeToList  . XN.getUniversalUri)
    {-# INLINE getUniversalUri #-}
    
    getLocalPart        :: a XmlTree String
    getLocalPart        = arrL (maybeToList  . XN.getLocalPart)
    {-# INLINE getLocalPart #-}
    
    getNamePrefix       :: a XmlTree String
    getNamePrefix       = arrL (maybeToList  . XN.getNamePrefix)
    {-# INLINE getNamePrefix #-}
    
    getNamespaceUri     :: a XmlTree String
    getNamespaceUri     = arrL (maybeToList  . XN.getNamespaceUri)
    {-# INLINE getNamespaceUri #-}
    
    
    getAttrValue        :: String -> a XmlTree String
    getAttrValue n      = xshow (getAttrl >>> hasName n >>> getChildren)
    
    getAttrValue0       :: String -> a XmlTree String
    getAttrValue0 n     = getAttrl >>> hasName n >>> xshow getChildren
    
    
    getQAttrValue       :: QName -> a XmlTree String
    getQAttrValue n     = xshow (getAttrl >>> hasQName n >>> getChildren)
    
    getQAttrValue0      :: QName -> a XmlTree String
    getQAttrValue0 n    = getAttrl >>> hasQName n >>> xshow getChildren
    
    
    changeText          :: (String -> String) -> a XmlTree XmlTree
    changeText cf       = arr (XN.changeText     cf) `when` isText
    
    changeBlob          :: (Blob -> Blob) -> a XmlTree XmlTree
    changeBlob cf       = arr (XN.changeBlob     cf) `when` isBlob
    
    changeCmt           :: (String -> String) -> a XmlTree XmlTree
    changeCmt  cf       = arr (XN.changeCmt      cf) `when` isCmt
    
    changeQName         :: (QName  -> QName) -> a XmlTree XmlTree
    changeQName cf      = arr (XN.changeName  cf) `when` getQName
    
    changeElemName      :: (QName  -> QName) -> a XmlTree XmlTree
    changeElemName cf   = arr (XN.changeElemName  cf) `when` isElem
    
    changeAttrName      :: (QName  -> QName) -> a XmlTree XmlTree
    changeAttrName cf   = arr (XN.changeAttrName cf) `when` isAttr
    
    changePiName        :: (QName  -> QName) -> a XmlTree XmlTree
    changePiName cf     = arr (XN.changePiName  cf) `when` isPi
    
    changeAttrValue     :: (String -> String) -> a XmlTree XmlTree
    changeAttrValue cf  = replaceChildren ( xshow getChildren
                                            >>> arr cf
                                            >>> mkText
                                          )
                          `when` isAttr
    
    changeAttrl         :: (XmlTrees -> XmlTrees -> XmlTrees) -> a XmlTree XmlTree -> a XmlTree XmlTree
    changeAttrl cf f    = ( ( listA f &&& this )
                            >>>
                            arr2 changeAL
                          )
                          `when`
                          ( isElem <+> isPi )
                        where
                        changeAL as x = XN.changeAttrl (\ xs -> cf xs as) x
    
    setQName            :: QName -> a XmlTree XmlTree
    setQName  n         = changeQName  (const n)
    {-# INLINE setQName #-}
    
    setElemName         :: QName -> a XmlTree XmlTree
    setElemName  n      = changeElemName  (const n)
    {-# INLINE setElemName #-}
    
    setAttrName         :: QName -> a XmlTree XmlTree
    setAttrName n       = changeAttrName (const n)
    {-# INLINE setAttrName #-}
    
    setPiName           :: QName -> a XmlTree XmlTree
    setPiName  n        = changePiName  (const n)
    {-# INLINE setPiName #-}
    
    setAttrl            :: a XmlTree XmlTree -> a XmlTree XmlTree
    setAttrl            = changeAttrl (const id)                
    {-# INLINE setAttrl #-}
    
    addAttrl            :: a XmlTree XmlTree -> a XmlTree XmlTree
    addAttrl            = changeAttrl (XN.mergeAttrl)
    {-# INLINE addAttrl #-}
    
    addAttr             :: String -> String  -> a XmlTree XmlTree
    addAttr an av       = addAttrl (sattr an av)
    {-# INLINE addAttr #-}
    
    removeAttr          :: String  -> a XmlTree XmlTree
    removeAttr an       = processAttrl (none `when` hasName an)
    
    removeQAttr         :: QName  -> a XmlTree XmlTree
    removeQAttr an      = processAttrl (none `when` hasQName an)
    
    processAttrl        :: a XmlTree XmlTree -> a XmlTree XmlTree
    processAttrl f      = setAttrl (getAttrl >>> f)
    
    
    processTopDownWithAttrl     :: a XmlTree XmlTree -> a XmlTree XmlTree
    processTopDownWithAttrl f   = processTopDown ( f >>> ( processAttrl (processTopDown f) `when` isElem))
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    (+=)                :: a b XmlTree -> a b XmlTree -> a b XmlTree
    tf += cf            = (tf &&& listA cf) >>> arr2 addChildren
                        where
                        addChildren     :: XmlTree -> XmlTrees -> XmlTree
                        addChildren t cs
                            = foldl addChild t cs
                        addChild        :: XmlTree -> XmlTree -> XmlTree
                        addChild t c
                            | not (XN.isElem t)
                                = t
                            | XN.isAttr c
                                = XN.changeAttrl (XN.addAttr c) t
                            | otherwise
                                = XN.changeChildren (++ [c]) t
    
    xshow               :: a n XmlTree -> a n String
    xshow f             = f >. XS.xshow
    {-# INLINE xshow #-}
    
    xshowBlob           :: a n XmlTree -> a n Blob
    xshowBlob f         = f >. XS.xshowBlob
    {-# INLINE xshowBlob #-}
class (ArrowXml a) => ArrowDTD a where
    isDTDDoctype        :: a XmlTree XmlTree
    isDTDDoctype        = isA (maybe False (== DOCTYPE ) . XN.getDTDPart)
    isDTDElement        :: a XmlTree XmlTree
    isDTDElement        = isA (maybe False (== ELEMENT ) . XN.getDTDPart)
    isDTDContent        :: a XmlTree XmlTree
    isDTDContent        = isA (maybe False (== CONTENT ) . XN.getDTDPart)
    isDTDAttlist        :: a XmlTree XmlTree
    isDTDAttlist        = isA (maybe False (== ATTLIST ) . XN.getDTDPart)
    isDTDEntity         :: a XmlTree XmlTree
    isDTDEntity         = isA (maybe False (== ENTITY  ) . XN.getDTDPart)
    isDTDPEntity        :: a XmlTree XmlTree
    isDTDPEntity        = isA (maybe False (== PENTITY ) . XN.getDTDPart)
    isDTDNotation       :: a XmlTree XmlTree
    isDTDNotation       = isA (maybe False (== NOTATION) . XN.getDTDPart)
    isDTDCondSect       :: a XmlTree XmlTree
    isDTDCondSect       = isA (maybe False (== CONDSECT) . XN.getDTDPart)
    isDTDName           :: a XmlTree XmlTree
    isDTDName           = isA (maybe False (== NAME    ) . XN.getDTDPart)
    isDTDPERef          :: a XmlTree XmlTree
    isDTDPERef          = isA (maybe False (== PEREF   ) . XN.getDTDPart)
    hasDTDAttr          :: String -> a XmlTree XmlTree
    hasDTDAttr n        = isA (isJust . lookup n . fromMaybe [] . XN.getDTDAttrl)
    getDTDAttrValue     :: String -> a XmlTree String
    getDTDAttrValue n   = arrL (maybeToList . lookup n . fromMaybe [] . XN.getDTDAttrl)
    setDTDAttrValue     :: String -> String -> a XmlTree XmlTree
    setDTDAttrValue n v = arr (XN.changeDTDAttrl (addEntry n v)) `when` isDTD
    mkDTDElem           :: DTDElem -> Attributes -> a n XmlTree -> a n XmlTree
    mkDTDElem e al cf   = listA cf >>> arr (XN.mkDTDElem e al)
    mkDTDDoctype        :: Attributes -> a n XmlTree -> a n XmlTree
    mkDTDDoctype        = mkDTDElem DOCTYPE
    mkDTDElement        :: Attributes -> a n XmlTree
    mkDTDElement al     = mkDTDElem ELEMENT al none
    mkDTDEntity         :: Attributes -> a n XmlTree
    mkDTDEntity al      = mkDTDElem ENTITY al none
    mkDTDPEntity        :: Attributes -> a n XmlTree
    mkDTDPEntity al     = mkDTDElem PENTITY al none
instance ArrowXml LA
instance ArrowXml (SLA s)
instance ArrowXml IOLA
instance ArrowXml (IOSLA s)
instance ArrowDTD LA
instance ArrowDTD (SLA s)
instance ArrowDTD IOLA
instance ArrowDTD (IOSLA s)