-- |
-- Convert an XPath result set into a node set
--


module Text.XML.HXT.XPath.XPathToNodeSet
    ( xPValue2XmlNodeSet
    , emptyXmlNodeSet
    )
where

import Text.XML.HXT.DOM.TypeDefs
import Text.XML.HXT.XPath.XPathDataTypes

-- -----------------------------------------------------------------------------
-- |
-- Convert a a XPath-value into a XmlNodeSet represented by a tree structure
--
-- The XmlNodeSet can be used to traverse a tree an process all
-- marked nodes.

xPValue2XmlNodeSet			:: XPathValue -> XmlNodeSet
xPValue2XmlNodeSet (XPVNode ns)		= toNodeSet' ns

xPValue2XmlNodeSet _			= emptyXmlNodeSet

emptyXmlNodeSet				:: XmlNodeSet
emptyXmlNodeSet				= XNS False [] []

leafNodeSet				:: XmlNodeSet
leafNodeSet				= XNS True [] []

toNodeSet'				:: NodeSet -> XmlNodeSet
toNodeSet'				= pathListToNodeSet . map toPath . fromNodeSet

toPath					:: NavXmlTree -> XmlNodeSet
toPath					= upTree leafNodeSet


upTree					:: XmlNodeSet -> NavXmlTree -> XmlNodeSet
upTree ps (NT _ _ [] _ _)		= ps	-- root node reached

upTree ps (NT (NTree n _)
              ix par _left _right)	= upTree ps' $ head par
    where
    ps'					= pix n

    pix (XAttr qn)			= XNS False [qn] []
    pix _				= XNS False []   [(ix, ps)]

pathListToNodeSet			::[XmlNodeSet] -> XmlNodeSet
pathListToNodeSet			= foldr mergePaths emptyXmlNodeSet
    where
    mergePaths (XNS p1 al1 cl1)
               (XNS p2 al2 cl2)		= XNS (p1 || p2) (al1 ++ al2) (mergeSubPaths cl1 cl2)

    mergeSubPaths []       sp2 		= sp2
    mergeSubPaths (s1:sp1) sp2 		= mergeSubPath s1 (mergeSubPaths sp1 sp2)

    mergeSubPath s1 []			= [s1]
    mergeSubPath s1@(ix1,p1)
                 sl@(s2@(ix2, p2) : sl')
	| ix1 < ix2			= s1 : sl
	| ix1 > ix2			= s2 : mergeSubPath s1 sl'		-- ordered insert of s1 
	| otherwise			= (ix1, mergePaths p1 p2) : sl'		-- same ix merge subpaths

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