{-# LANGUAGE BangPatterns #-}
{-# LANGUAGE LambdaCase #-}
{-# LANGUAGE MultiWayIf #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE RecordWildCards #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
module Zenacy.HTML.Internal.Query
( HTMLQuery
, htmlQueryRun
, htmlQueryExec
, htmlQueryTry
, htmlQueryStop
, htmlQueryCont
, htmlQuerySucc
, htmlQueryZipper
, htmlQueryNode
, htmlQueryFirst
, htmlQueryLast
, htmlQueryNext
, htmlQueryPrev
, htmlQueryUp
, htmlQueryTest
, htmlQueryName
, htmlQueryIsFirst
, htmlQueryIsLast
, htmlQuerySave
, htmlQueryGet
, htmlQueryGetZipper
, htmlQuerySrc
, htmlQueryAttr
, htmlQueryAttrVal
, htmlQueryId
, htmlQueryHasClass
, htmlQueryOnly
) where
import Prelude
import Zenacy.HTML.Internal.HTML
import Zenacy.HTML.Internal.Oper
import Zenacy.HTML.Internal.Zip
import Control.Monad.State
( MonadState
, State
, evalState
, modify
, gets
)
import Control.Monad.Trans.Maybe
( MaybeT(..)
, runMaybeT
)
import Data.Bool
( bool
)
import Data.IntMap
( IntMap
)
import qualified Data.IntMap as IntMap
( fromList
, lookup
, insert
)
import Data.Maybe
( fromMaybe
, isNothing
)
import Data.Text
( Text
)
type QueryState = (HTMLZipper, IntMap HTMLZipper)
newtype HTMLQuery a = HTMLQuery { htmlQueryState :: MaybeT (State QueryState) a }
deriving (Functor, Applicative, Monad, MonadState QueryState)
htmlQueryRun :: HTMLNode -> HTMLQuery a -> Maybe a
htmlQueryRun x q = evalState (runMaybeT $ htmlQueryState q) s
where
z = htmlZip x
s = (z, IntMap.fromList [(0,z)])
htmlQueryExec :: HTMLQuery a -> HTMLNode -> Maybe a
htmlQueryExec = flip htmlQueryRun
htmlQueryTry :: HTMLQuery HTMLNode -> HTMLNode -> HTMLNode
htmlQueryTry q x = fromMaybe x $ htmlQueryRun x q
htmlQueryWrap :: Maybe a -> HTMLQuery a
htmlQueryWrap = HTMLQuery . MaybeT . pure
htmlQueryStop :: HTMLQuery a
htmlQueryStop = htmlQueryWrap $ Nothing
htmlQueryCont :: HTMLQuery ()
htmlQueryCont = htmlQuerySucc ()
htmlQuerySucc :: a -> HTMLQuery a
htmlQuerySucc = htmlQueryWrap . Just
htmlQueryZipper :: HTMLQuery HTMLZipper
htmlQueryZipper = gets fst
htmlQueryNode :: HTMLQuery HTMLNode
htmlQueryNode = htmlZipNode <$> htmlQueryZipper
withZip :: (HTMLZipper -> Maybe HTMLZipper) -> HTMLQuery ()
withZip f = do
z <- htmlQueryZipper
case f z of
Nothing ->
htmlQueryStop
Just z' -> do
modify $ \(_, m) -> (z', m)
htmlQueryCont
htmlQueryFirst :: HTMLQuery ()
htmlQueryFirst = withZip htmlZipFirst
htmlQueryLast :: HTMLQuery ()
htmlQueryLast = withZip htmlZipLast
htmlQueryNext :: HTMLQuery ()
htmlQueryNext = withZip htmlZipNext
htmlQueryPrev :: HTMLQuery ()
htmlQueryPrev = withZip htmlZipPrev
htmlQueryUp :: HTMLQuery ()
htmlQueryUp = withZip htmlZipUp
htmlQueryTest :: Bool -> HTMLQuery ()
htmlQueryTest = bool htmlQueryStop htmlQueryCont
htmlQueryName :: Text -> HTMLQuery ()
htmlQueryName x = do
n <- htmlQueryNode
htmlQueryTest $ htmlElemName n == x
htmlQueryIsFirst :: HTMLQuery ()
htmlQueryIsFirst = do
z <- htmlQueryZipper
htmlQueryTest $ isNothing $ htmlZipPrev z
htmlQueryIsLast :: HTMLQuery ()
htmlQueryIsLast = do
z <- htmlQueryZipper
htmlQueryTest $ isNothing $ htmlZipNext z
htmlQuerySave :: Int -> HTMLQuery ()
htmlQuerySave x = do
modify $ \(z, m) -> (z, IntMap.insert x z m)
htmlQueryCont
htmlQueryGet :: Int -> HTMLQuery HTMLNode
htmlQueryGet x = htmlZipNode <$> htmlQueryGetZipper x
htmlQueryGetZipper :: Int -> HTMLQuery HTMLZipper
htmlQueryGetZipper x = do
m <- gets snd
case IntMap.lookup x m of
Just z -> htmlQuerySucc z
Nothing -> htmlQueryStop
htmlQuerySrc :: HTMLQuery HTMLNode
htmlQuerySrc = htmlQueryGet 0
htmlQueryAttr :: Text -> HTMLQuery ()
htmlQueryAttr x = htmlQueryNode >>= htmlQueryTest . htmlElemHasAttrName x
htmlQueryAttrVal :: Text -> Text -> HTMLQuery ()
htmlQueryAttrVal n v = htmlQueryNode >>= htmlQueryTest . htmlElemHasAttrVal n v
htmlQueryId :: Text -> HTMLQuery ()
htmlQueryId x = htmlQueryNode >>= htmlQueryTest . htmlElemHasID x
htmlQueryHasClass :: Text -> HTMLQuery ()
htmlQueryHasClass x = htmlQueryNode >>= htmlQueryTest . htmlElemClassesContains x
htmlQueryOnly :: Text -> HTMLQuery ()
htmlQueryOnly x = htmlQueryFirst >> htmlQueryName x >> htmlQueryIsLast