module S09 (
  -- * Exercise 2
  lexer,
  -- * Exercise 3
  showXml,
  -- * Exercise 4
  uibkMail,
  -- * Exercise 5
  parseIntList,
  -- * Exercise 6
  select
  ) where

import Xml hiding (lexer)
import Parse


optional :: Parser t a -> Parser t ()
optional p = (p >> return ()) <|> return ()

lexer :: Parser Char [Token]
lexer = do
  many space
  optional parseProlog
  many space
  ts <- many (parseTag <|> parseComment <|> parseText)
  eoi
  return ts
  where
    parseProlog = string "<?xml version=\"1.0\" encoding=\"UTF-8\"?>"


showXml :: Xml -> String
showXml = tos 0
  where
    tos i (Txt t) = unlines $ map (replicate i ' ' ++) $ lines t
    tos i (Xml t ns) =
        indent ++ "<" ++ t ++ ">\n" ++
          concat (map (tos (i + 1)) ns) ++
        indent ++ "</" ++ t ++ ">\n"
      where
        indent = replicate i ' '


uibkMail :: String -> Maybe (String, String)
uibkMail = parse p
  where
    p = do
      forename <- many1 (noneof ".")
      char '.'
      surname  <- many1 (noneof "@")
      char '@'
      optional (string "student.")
      string "uibk.ac.at"
      return (forename, surname)


sepBy, sepBy1 :: Parser t a -> Parser t b -> Parser t [a]
sepBy1 p s = do { x <- p; xs <- many (s >> p); return (x:xs) }
sepBy p s = sepBy1 p s <|> return []

parseIntList :: Parser Char [Int]
parseIntList = between (char '[') (char ']') $
    parseInt `sepBy` char ','
  where
    parseInt = many1 digit >>= return . read


select :: Tag -> Xml -> [Xml]
select s x@(Xml t xs)
  | s == t = [x]
  | otherwise = concat (map (select s) xs)
select _ _ = []