{-# LANGUAGE CPP #-}

-- | Provides 'PathTree' type.
--
-- @since 0.1
module PathSize.Data.PathTree
  ( PathTree (..),
    singleton,
    pathTreeToSeq,
    sumTrees,
  )
where

import Control.DeepSeq (NFData)
import Data.Sequence (Seq (Empty, (:<|)))
import Data.Sequence.NonEmpty (NESeq ((:<||)))
import GHC.Generics (Generic)
import PathSize.Data.PathData
  ( PathData
      ( MkPathData,
        numDirectories,
        numFiles,
        size
      ),
  )

-- | Given a path, represents the directory tree, with each subpath
-- associated to its size. This structure is essentially a rose tree.
--
-- @since 0.1
data PathTree = !PathData :^| !(Seq PathTree)
  deriving stock
    ( -- | @since 0.1
      PathTree -> PathTree -> Bool
(PathTree -> PathTree -> Bool)
-> (PathTree -> PathTree -> Bool) -> Eq PathTree
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: PathTree -> PathTree -> Bool
== :: PathTree -> PathTree -> Bool
$c/= :: PathTree -> PathTree -> Bool
/= :: PathTree -> PathTree -> Bool
Eq,
      -- | @since 0.1
      (forall x. PathTree -> Rep PathTree x)
-> (forall x. Rep PathTree x -> PathTree) -> Generic PathTree
forall x. Rep PathTree x -> PathTree
forall x. PathTree -> Rep PathTree x
forall a.
(forall x. a -> Rep a x) -> (forall x. Rep a x -> a) -> Generic a
$cfrom :: forall x. PathTree -> Rep PathTree x
from :: forall x. PathTree -> Rep PathTree x
$cto :: forall x. Rep PathTree x -> PathTree
to :: forall x. Rep PathTree x -> PathTree
Generic,
      -- | @since 0.1
      Int -> PathTree -> ShowS
[PathTree] -> ShowS
PathTree -> String
(Int -> PathTree -> ShowS)
-> (PathTree -> String) -> ([PathTree] -> ShowS) -> Show PathTree
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> PathTree -> ShowS
showsPrec :: Int -> PathTree -> ShowS
$cshow :: PathTree -> String
show :: PathTree -> String
$cshowList :: [PathTree] -> ShowS
showList :: [PathTree] -> ShowS
Show
    )
  deriving anyclass
    ( -- | @since 0.1
      PathTree -> ()
(PathTree -> ()) -> NFData PathTree
forall a. (a -> ()) -> NFData a
$crnf :: PathTree -> ()
rnf :: PathTree -> ()
NFData
    )

-- | Flattens a 'PathTree' into a 'Seq'.
--
-- @since 0.1
pathTreeToSeq :: PathTree -> NESeq PathData
pathTreeToSeq :: PathTree -> NESeq PathData
pathTreeToSeq (PathData
x :^| Seq PathTree
subTrees) = PathData
x PathData -> Seq PathData -> NESeq PathData
forall a. a -> Seq a -> NESeq a
:<|| (Seq PathTree
subTrees Seq PathTree -> (PathTree -> Seq PathData) -> Seq PathData
forall a b. Seq a -> (a -> Seq b) -> Seq b
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= PathTree -> Seq PathData
pathTreeToSeq')
  where
    pathTreeToSeq' :: PathTree -> Seq PathData
    pathTreeToSeq' :: PathTree -> Seq PathData
pathTreeToSeq' (PathData
x' :^| Seq PathTree
subTrees') = PathData
x' PathData -> Seq PathData -> Seq PathData
forall a. a -> Seq a -> Seq a
:<| (Seq PathTree
subTrees' Seq PathTree -> (PathTree -> Seq PathData) -> Seq PathData
forall a b. Seq a -> (a -> Seq b) -> Seq b
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= PathTree -> Seq PathData
pathTreeToSeq')

-- | @since 0.1
singleton :: PathData -> PathTree
singleton :: PathData -> PathTree
singleton PathData
pd = PathData
pd PathData -> Seq PathTree -> PathTree
:^| Seq PathTree
forall a. Seq a
Empty

-- | @since 0.1
sumTrees :: Seq PathTree -> (# Integer, Integer, Integer #)
sumTrees :: Seq PathTree -> (# Integer, Integer, Integer #)
sumTrees = (# Integer, Integer, Integer #)
-> Seq PathTree -> (# Integer, Integer, Integer #)
go (# Integer
0, Integer
0, Integer
0 #)
  where
    go :: (# Integer, Integer, Integer #)
-> Seq PathTree -> (# Integer, Integer, Integer #)
go (# Integer, Integer, Integer #)
acc Seq PathTree
Empty = (# Integer, Integer, Integer #)
acc
    go (# Integer, Integer, Integer #)
acc (PathTree
x :<| Seq PathTree
xs) = (# Integer, Integer, Integer #)
-> Seq PathTree -> (# Integer, Integer, Integer #)
go ((# Integer, Integer, Integer #)
acc (# Integer, Integer, Integer #)
-> (# Integer, Integer, Integer #)
-> (# Integer, Integer, Integer #)
`addTuple` PathTree -> (# Integer, Integer, Integer #)
getSum PathTree
x) Seq PathTree
xs

-- | @since 0.1
addTuple ::
  (# Integer, Integer, Integer #) ->
  (# Integer, Integer, Integer #) ->
  (# Integer, Integer, Integer #)
addTuple :: (# Integer, Integer, Integer #)
-> (# Integer, Integer, Integer #)
-> (# Integer, Integer, Integer #)
addTuple (# !Integer
a, !Integer
b, !Integer
c #) (# !Integer
a', !Integer
b', !Integer
c' #) = (# Integer
a Integer -> Integer -> Integer
forall a. Num a => a -> a -> a
+ Integer
a', Integer
b Integer -> Integer -> Integer
forall a. Num a => a -> a -> a
+ Integer
b', Integer
c Integer -> Integer -> Integer
forall a. Num a => a -> a -> a
+ Integer
c' #)

getSum :: PathTree -> (# Integer, Integer, Integer #)
getSum :: PathTree -> (# Integer, Integer, Integer #)
getSum (MkPathData {Integer
size :: PathData -> Integer
size :: Integer
size, Integer
numFiles :: PathData -> Integer
numFiles :: Integer
numFiles, Integer
numDirectories :: PathData -> Integer
numDirectories :: Integer
numDirectories} :^| Seq PathTree
_) =
  (# Integer
size, Integer
numFiles, Integer
numDirectories #)