-- | Combinators to match tags. Some people prefer to use @(~==)@ from
--   "Text.HTML.TagSoup", others prefer these more structured combinators.
--   Which you use is personal preference.

module Text.HTML.TagSoup.Match where

import Text.HTML.TagSoup.Type (Tag(..), Attribute)
import Data.List


-- | match an opening tag
tagOpen :: (str -> Bool) -> ([Attribute str] -> Bool) -> Tag str -> Bool
tagOpen pName pAttrs (TagOpen name attrs) =
   pName name && pAttrs attrs
tagOpen _ _ _ = False

-- | match an closing tag
tagClose :: (str -> Bool) -> Tag str -> Bool
tagClose pName (TagClose name) = pName name
tagClose _ _ = False

-- | match a text
tagText :: (str -> Bool) -> Tag str -> Bool
tagText p (TagText text) = p text
tagText _ _ = False

tagComment :: (str -> Bool) -> Tag str -> Bool
tagComment p (TagComment text) = p text
tagComment _ _ = False


-- | match a opening tag's name literally
tagOpenLit :: Eq str => str -> ([Attribute str] -> Bool) -> Tag str -> Bool
tagOpenLit name = tagOpen (name==)

-- | match a closing tag's name literally
tagCloseLit :: Eq str => str -> Tag str -> Bool
tagCloseLit name = tagClose (name==)

tagOpenAttrLit :: Eq str => str -> Attribute str -> Tag str -> Bool
tagOpenAttrLit name attr =
   tagOpenLit name (anyAttrLit attr)

{- |
Match a tag with given name, that contains an attribute
with given name, that satisfies a predicate.
If an attribute occurs multiple times,
all occurrences are checked.
-}
tagOpenAttrNameLit :: Eq str => str -> str -> (str -> Bool) -> Tag str -> Bool
tagOpenAttrNameLit tagName attrName pAttrValue =
   tagOpenLit tagName
      (anyAttr (\(name,value) -> name==attrName && pAttrValue value))


-- | Check if the 'Tag str' is 'TagOpen' and matches the given name
tagOpenNameLit :: Eq str => str -> Tag str -> Bool
tagOpenNameLit name = tagOpenLit name (const True)

-- | Check if the 'Tag str' is 'TagClose' and matches the given name
tagCloseNameLit :: Eq str => str -> Tag str -> Bool
tagCloseNameLit name = tagCloseLit name




anyAttr :: ((str,str) -> Bool) -> [Attribute str] -> Bool
anyAttr = any

anyAttrName :: (str -> Bool) -> [Attribute str] -> Bool
anyAttrName p = any (p . fst)

anyAttrValue :: (str -> Bool) -> [Attribute str] -> Bool
anyAttrValue p = any (p . snd)


anyAttrLit :: Eq str => (str,str) -> [Attribute str] -> Bool
anyAttrLit attr = anyAttr (attr==)

anyAttrNameLit :: Eq str => str -> [Attribute str] -> Bool
anyAttrNameLit name = anyAttrName (name==)

anyAttrValueLit :: Eq str => str -> [Attribute str] -> Bool
anyAttrValueLit value = anyAttrValue (value==)



getTagContent :: Eq str => str -> ([Attribute str] -> Bool) -> [Tag str] -> [Tag str]
getTagContent name pAttrs =
   takeWhile (not . tagCloseLit name) . drop 1 .
   head . sections (tagOpenLit name pAttrs)
    where sections p = filter (p . head) . init . tails