module Cardano.Logging.DocuGenerator.Tree (Tree (..), foldTree, printTree, printList, toForest) where

import           Data.Function (on)
import           Data.List (groupBy, intersperse)
import           Data.Text.Internal (Text)
import           Data.Text.Internal.Builder (Builder)
import           Data.Tree (Forest, Tree (..), foldTree, unfoldForest)

-- T ::= ∙ x
--     |
--       ∙ x
--          T
--          T
--         ...
--          T
--
-- Example:
--
--  ∙ BlockFetch
--    ∙ Client
--      ∙ AcknowledgedFetchRequest
--      ∙ AddedFetchRequest
--      ∙ ClientMetrics
--    ∙ Decision
--    ∙ Remote
printTree :: Tree Text -> Text
printTree :: Tree Text -> Text
printTree =
  (Text -> [Text] -> Text) -> Tree Text -> Text
forall a b. (a -> [b] -> b) -> Tree a -> b
foldTree (\Text
x -> [Text] -> Text
forall a. Monoid a => [a] -> a
mconcat ([Text] -> Text) -> ([Text] -> [Text]) -> [Text] -> Text
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Text -> [Text] -> [Text]
forall a. a -> [a] -> [a]
intersperse Text
"\n" ([Text] -> [Text]) -> ([Text] -> [Text]) -> [Text] -> [Text]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Text
"∙ " Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
x Text -> [Text] -> [Text]
forall a. a -> [a] -> [a]
:) ([Text] -> [Text]) -> ([Text] -> [Text]) -> [Text] -> [Text]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Text -> Text) -> [Text] -> [Text]
forall a b. (a -> b) -> [a] -> [b]
map (Text
"\t" Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<>))

printList :: (a -> Builder) -> [a] -> Builder
printList :: forall a. (a -> Builder) -> [a] -> Builder
printList a -> Builder
fmt = [Builder] -> Builder
forall a. Monoid a => [a] -> a
mconcat ([Builder] -> Builder) -> ([a] -> [Builder]) -> [a] -> Builder
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Builder -> [Builder] -> [Builder]
forall a. a -> [a] -> [a]
intersperse Builder
"\n" ([Builder] -> [Builder]) -> ([a] -> [Builder]) -> [a] -> [Builder]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (a -> Builder) -> [a] -> [Builder]
forall a b. (a -> b) -> [a] -> [b]
map a -> Builder
fmt

-- Convert a list of namespaces to a tree representation
toForest :: [[Text]] -> Forest Text
toForest :: [[Text]] -> Forest Text
toForest = ([[Text]] -> (Text, [[[Text]]])) -> [[[Text]]] -> Forest Text
forall b a. (b -> (a, [b])) -> [b] -> [Tree a]
unfoldForest [[Text]] -> (Text, [[[Text]]])
build ([[[Text]]] -> Forest Text)
-> ([[Text]] -> [[[Text]]]) -> [[Text]] -> Forest Text
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [[Text]] -> [[[Text]]]
groupByHead
 where
  groupByHead :: [[Text]] -> [[[Text]]]
groupByHead = ([Text] -> [Text] -> Bool) -> [[Text]] -> [[[Text]]]
forall a. (a -> a -> Bool) -> [a] -> [[a]]
groupBy ((Text -> Text -> Bool)
-> ([Text] -> Text) -> [Text] -> [Text] -> Bool
forall b c a. (b -> b -> c) -> (a -> b) -> a -> a -> c
on Text -> Text -> Bool
forall a. Eq a => a -> a -> Bool
(==) [Text] -> Text
forall a. HasCallStack => [a] -> a
head)

  build :: [[Text]] -> (Text, [[[Text]]])
  build :: [[Text]] -> (Text, [[[Text]]])
build group :: [[Text]]
group@([Text]
representative : [[Text]]
_) = ([Text] -> Text
forall a. HasCallStack => [a] -> a
head [Text]
representative, ([[Text]] -> [[[Text]]]
groupByHead ([[Text]] -> [[[Text]]])
-> ([[Text]] -> [[Text]]) -> [[Text]] -> [[[Text]]]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ([Text] -> Bool) -> [[Text]] -> [[Text]]
forall a. (a -> Bool) -> [a] -> [a]
filter (Bool -> Bool
not (Bool -> Bool) -> ([Text] -> Bool) -> [Text] -> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [Text] -> Bool
forall a. [a] -> Bool
forall (t :: * -> *) a. Foldable t => t a -> Bool
null) ([[Text]] -> [[Text]])
-> ([[Text]] -> [[Text]]) -> [[Text]] -> [[Text]]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ([Text] -> [Text]) -> [[Text]] -> [[Text]]
forall a b. (a -> b) -> [a] -> [b]
map [Text] -> [Text]
forall a. HasCallStack => [a] -> [a]
tail) [[Text]]
group)