module Database.Ferry.Algebra.Render.XMLUtils where import Text.XML.HaXml.Types import Database.Ferry.Algebra.Data.Algebra import qualified Data.Map as M import Control.Monad.State import Control.Monad.Writer import Control.Monad.Reader -- Convenient alias for column names type ColName = String -- The Graph is represented as a tuple of an int, that represents the first node, and -- a list of algebraic nodes with their node numbers. type Graph = (AlgNode, [(Algebra, AlgNode)]) -- Alias for GraphNode ids type GraphNode = Int -- Alias for xmlNode ids type XMLNode = Int -- Mapping from graphnodes to xmlnode ids. This dictionary is used to prevent duplicate xml nodes type Dictionary = M.Map GraphNode XMLNode -- XML monad, all elements are printed in bottom up!!! order into the writer monad so -- that the xml can easily be printed an will be accepted by pfopt. -- The reader monad contains the map with all the nodes from the algebraic plan, the keys -- are the node ids from the graph. The state monad keeps track of the supply of fresh ids -- for xml nodes and the dictionary for looking up whether a certain graphnode already has -- an xml representation. type XML = WriterT [Element ()] (ReaderT (M.Map AlgNode Algebra, M.Map AlgNode [String], Bool) (State (Int, Dictionary))) getTags :: GraphNode -> XML (Maybe [String]) getTags i = do (_, ts, _) <- ask return $ M.lookup i ts -- Debug enabled? debugEnabled :: XML Bool debugEnabled = do (_,_,d) <- ask return d -- Has a graphnode already been translated into an xml node. If yes which node? isDefined :: GraphNode -> XML (Maybe XMLNode) isDefined g = do (_, d) <- get return $ M.lookup g d -- Get a fresh xml node id. freshId :: XML Int freshId = do (n, d) <- get put (n + 1, d) return n -- Add a mapping from a graphnode to an xml node id to the dictionary addNodeTrans :: GraphNode -> XMLNode -> XML () addNodeTrans gId xId = do (n, d) <- get put (n, M.insert gId xId d) -- Get a node from the algebraic plan with a certain graphNode id number getNode :: Int -> XML Algebra getNode i = do (nodes, _, _) <- ask return $ nodes M.! i -- Run the monad and return a list of xml elements from the monad. runXML :: Bool -> M.Map AlgNode Algebra -> M.Map AlgNode [String] -> XML a -> [Element ()] runXML debug m t = snd . fst . flip runState (0, M.empty) . flip runReaderT (m, t, debug) . runWriterT -- * Helper functions for constructing xml nodes infixr 0 `childsOf` infixr 0 `dataChildOf` infixr 0 `attrsOf` -- | Childs of takes a list of xml elements, and nests them in the xml element given as a second argument childsOf :: [Element ()] -> Element () -> Element () childsOf cs (Elem n attrs cs') = Elem n attrs $ cs' ++ [CElem c () | c <- cs] -- | Data child of takes some data that can be printed and adds that as child to the xml element given as second argument dataChildOf :: Show a => a -> Element () -> Element () dataChildOf v (Elem n attrs cs) = Elem n attrs $ (CString False (show v) ()) : cs stringChildOf :: String -> Element () -> Element () stringChildOf v (Elem n attrs cs) = Elem n attrs $ (CString False v ()) : cs -- | Construct a column with name n, and new status v column :: String -> Bool -> Element () column n v = let new = case v of True -> "true" False -> "false" in [attr "name" n, attr "new" new] `attrsOf` xmlElem "column" -- | XML element representing a type typeN :: ATy -> Element () typeN t = [attr "name" $ show t] `attrsOf` xmlElem "type" -- | Construct an xml tag with name n xmlElem :: String -> Element () xmlElem n = Elem (N n) [] [] -- | Construct an algebraic node with id xId and of kind t node :: XMLNode -> String -> Element () node xId t = [attr "id" $ show xId, attr "kind" t] `attrsOf` xmlElem "node" -- | Construct a content node contentNode :: Element () contentNode = xmlElem "content" -- | Construct an attribute for an xml node, attrname = n and its value is v attr :: String -> String -> Attribute attr n v = (N n, AttValue [Left v]) -- | Attach list of attributes to an xml element attrsOf :: [Attribute] -> Element () -> Element () attrsOf at (Elem n attrs cs) = Elem n (at ++ attrs) cs