module Parse.Utils
  (
    ParseError(..)
  , attributeHasWord
  , blockquoteNode
  , getAttributesFromNode
  , getClassAttribute
  , listItemNode
  ) where

import Control.Monad.Except (MonadError, throwError)
import qualified Data.Map as M (Map, lookup)
import Data.Maybe (fromMaybe)
import qualified Data.Text as T (Text, words, unpack)
import Text.XML (Element(..), Name, Node(..))
import Text.XML.Cursor (Axis, Cursor, element, node)

data ParseError =
    ExpectedAttributeMissing String
  | ForumIdFromListNodeClassWrong String
  | GenericParseError String
  | MultipleForumIdsInList String
  | NonElementAttribute String

instance Show ParseError where
  show (ExpectedAttributeMissing message) = message
  show (ForumIdFromListNodeClassWrong message) = message
  show (GenericParseError message) = message
  show (MultipleForumIdsInList message) = message
  show (NonElementAttribute message) = message

blockquoteNode :: Axis
blockquoteNode = element "blockquote"

orderedListNode :: Axis
orderedListNode = element "ol"

listItemNode :: Axis
listItemNode = element "li"

attributeHasWord :: Name -> T.Text -> Axis
attributeHasWord name word cursor =
  case node cursor of
    NodeElement (Element _ attributes _) -> case M.lookup name attributes >>= (\x -> return $ textHasWord word x) of
      Nothing -> []
      Just False -> []
      Just True -> [cursor]
    _ -> []

textHasWord :: T.Text -> T.Text -> Bool
textHasWord word text = elem word $ T.words text

getAttributesFromNode :: (MonadError ParseError m) => Node -> m (M.Map Name T.Text)
getAttributesFromNode (NodeElement (Element _ elementAttributes _)) = return elementAttributes
getAttributesFromNode (NodeContent content) = throwError $ NonElementAttribute $
  "Attempted to get attribute from content node with content: " ++ (T.unpack content)
getAttributesFromNode (NodeComment comment) = throwError $ NonElementAttribute $
  "Attempted to get attribute from comment node with comment: " ++ (T.unpack comment)
getAttributesFromNode (NodeInstruction _) = throwError $ NonElementAttribute $
  "Attempted to get attribute from instruction node"

getClassAttribute :: (MonadError ParseError m) => M.Map Name T.Text -> m T.Text
getClassAttribute attributes = do
  case M.lookup "class" attributes of
    Nothing -> throwError $ ExpectedAttributeMissing "Expected attribute 'class' missing"
    Just x -> return x
