module Bookhound.Format.SyntaxTrees.Xml (XmlExpression(..), literalExpression, flatten, findAll, find) where

import Bookhound.Utils.Foldable (stringify)

import Data.Maybe (listToMaybe)

import           Data.Map (Map, elems, keys)
import qualified Data.Map as Map


data XmlExpression
  = XmlExpression
      { XmlExpression -> String
tagName     :: String
      , XmlExpression -> Map String String
fields      :: Map String String
      , XmlExpression -> [XmlExpression]
expressions :: [XmlExpression]
      }
  deriving (XmlExpression -> XmlExpression -> Bool
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: XmlExpression -> XmlExpression -> Bool
$c/= :: XmlExpression -> XmlExpression -> Bool
== :: XmlExpression -> XmlExpression -> Bool
$c== :: XmlExpression -> XmlExpression -> Bool
Eq, Eq XmlExpression
XmlExpression -> XmlExpression -> Bool
XmlExpression -> XmlExpression -> Ordering
XmlExpression -> XmlExpression -> XmlExpression
forall a.
Eq a
-> (a -> a -> Ordering)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> a)
-> (a -> a -> a)
-> Ord a
min :: XmlExpression -> XmlExpression -> XmlExpression
$cmin :: XmlExpression -> XmlExpression -> XmlExpression
max :: XmlExpression -> XmlExpression -> XmlExpression
$cmax :: XmlExpression -> XmlExpression -> XmlExpression
>= :: XmlExpression -> XmlExpression -> Bool
$c>= :: XmlExpression -> XmlExpression -> Bool
> :: XmlExpression -> XmlExpression -> Bool
$c> :: XmlExpression -> XmlExpression -> Bool
<= :: XmlExpression -> XmlExpression -> Bool
$c<= :: XmlExpression -> XmlExpression -> Bool
< :: XmlExpression -> XmlExpression -> Bool
$c< :: XmlExpression -> XmlExpression -> Bool
compare :: XmlExpression -> XmlExpression -> Ordering
$ccompare :: XmlExpression -> XmlExpression -> Ordering
Ord)


instance Show XmlExpression where

  show :: XmlExpression -> String
show XmlExpression { $sel:tagName:XmlExpression :: XmlExpression -> String
tagName = String
tag, [XmlExpression]
Map String String
expressions :: [XmlExpression]
fields :: Map String String
$sel:expressions:XmlExpression :: XmlExpression -> [XmlExpression]
$sel:fields:XmlExpression :: XmlExpression -> Map String String
.. }
    | String
tag forall a. Eq a => a -> a -> Bool
== String
"literal" = forall a. [a] -> a
head forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall k a. Map k a -> [a]
elems forall a b. (a -> b) -> a -> b
$ Map String String
fields
    | Bool
otherwise        = String
"<" forall a. Semigroup a => a -> a -> a
<> String
tag forall a. Semigroup a => a -> a -> a
<> String
flds forall a. Semigroup a => a -> a -> a
<> String
innerExprs   where

        innerExprs :: String
innerExprs = if | forall (t :: * -> *) a. Foldable t => t a -> Bool
null [XmlExpression]
expressions -> String
"/>"
                        | Bool
otherwise        -> String
">"  forall a. Semigroup a => a -> a -> a
<> String
ending

        (String
sep, Int
n) = if | ((XmlExpression -> String
tagName) forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a. [a] -> a
head) [XmlExpression]
expressions forall a. Eq a => a -> a -> Bool
== String
"literal" -> (String
"", Int
0)
                      | Bool
otherwise                                   -> (String
"\n", Int
2)

        ending :: String
ending = forall (m :: * -> *).
Foldable m =>
String -> String -> String -> Int -> m String -> String
stringify String
sep String
sep String
sep Int
n (forall a. Show a => a -> String
show forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> [XmlExpression]
expressions) forall a. Semigroup a => a -> a -> a
<> String
"</" forall a. Semigroup a => a -> a -> a
<> String
tag forall a. Semigroup a => a -> a -> a
<> String
">"

        flds :: String
flds | forall (t :: * -> *) a. Foldable t => t a -> Bool
null Map String String
fields = String
""
             | Bool
otherwise = String
" " forall a. Semigroup a => a -> a -> a
<> String
fieldsString where

            fieldsString :: String
fieldsString = forall (m :: * -> *).
Foldable m =>
String -> String -> String -> Int -> m String -> String
stringify String
" " String
"" String
"" Int
0 forall a b. (a -> b) -> a -> b
$ forall {a}. Show a => (String, a) -> String
showFn forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> [(String, String)]
tuples
            showFn :: (String, a) -> String
showFn (String
x, a
y) = String
x forall a. Semigroup a => a -> a -> a
<> String
"=" forall a. Semigroup a => a -> a -> a
<> forall a. Show a => a -> String
show a
y
            tuples :: [(String, String)]
tuples = forall a b. [a] -> [b] -> [(a, b)]
zip (forall k a. Map k a -> [k]
keys Map String String
fields) (forall k a. Map k a -> [a]
elems Map String String
fields)



literalExpression :: String -> XmlExpression
literalExpression :: String -> XmlExpression
literalExpression String
val = XmlExpression { $sel:tagName:XmlExpression :: String
tagName = String
"literal",
                                        $sel:fields:XmlExpression :: Map String String
fields = forall k a. Ord k => [(k, a)] -> Map k a
Map.fromList [(String
"value", String
val)],
                                        $sel:expressions:XmlExpression :: [XmlExpression]
expressions = [] }


flatten :: XmlExpression -> [XmlExpression]
flatten :: XmlExpression -> [XmlExpression]
flatten XmlExpression
expr = XmlExpression
expr forall a. a -> [a] -> [a]
: XmlExpression -> [XmlExpression]
expressions XmlExpression
expr forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= XmlExpression -> [XmlExpression]
flatten


findAll :: (XmlExpression -> Bool) -> XmlExpression -> [XmlExpression]
findAll :: (XmlExpression -> Bool) -> XmlExpression -> [XmlExpression]
findAll XmlExpression -> Bool
f = forall a. (a -> Bool) -> [a] -> [a]
filter XmlExpression -> Bool
f forall b c a. (b -> c) -> (a -> b) -> a -> c
. XmlExpression -> [XmlExpression]
flatten


find :: (XmlExpression -> Bool) -> XmlExpression -> Maybe XmlExpression
find :: (XmlExpression -> Bool) -> XmlExpression -> Maybe XmlExpression
find XmlExpression -> Bool
f = forall a. [a] -> Maybe a
listToMaybe forall b c a. (b -> c) -> (a -> b) -> a -> c
. (XmlExpression -> Bool) -> XmlExpression -> [XmlExpression]
findAll XmlExpression -> Bool
f