module Network.IPFS.SparseTree
  ( SparseTree (..)
  , Error.Linearization (..)
  , linearize
  , cIDs
  ) where

import           Network.IPFS.Prelude
import qualified Network.IPFS.Internal.UTF8 as UTF8
import qualified Network.IPFS.Error    as Error

import           Network.IPFS.CID.Types
import           Network.IPFS.Name.Types
import           Network.IPFS.Path.Types
import           Network.IPFS.SparseTree.Types

linearize :: SparseTree -> Either Error.Linearization Path
linearize :: SparseTree -> Either Linearization Path
linearize = forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap Text -> Path
Path forall b c a. (b -> c) -> (a -> b) -> a -> c
. SparseTree -> Either Linearization Text
go
  where
  go :: SparseTree -> Either Error.Linearization Text
  go :: SparseTree -> Either Linearization Text
go = \case
    Stub      (Name String
name)    -> forall a b. b -> Either a b
Right forall a b. (a -> b) -> a -> b
<| forall a. Show a => a -> Text
UTF8.textShow String
name
    Content   (CID Text
_)        -> forall a b. b -> Either a b
Right Text
""
    Directory [(Tag
tag, SparseTree
value)] -> Tag -> Text -> Text
fromPath Tag
tag forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> SparseTree -> Either Linearization Text
go SparseTree
value
    SparseTree
badDir                   -> forall a b. a -> Either a b
Left forall a b. (a -> b) -> a -> b
<| SparseTree -> Linearization
Error.NonLinear SparseTree
badDir
    where
      fromPath :: Tag -> Text -> Text
fromPath Tag
tag Text
""   = Tag -> Text
fromKey Tag
tag
      fromPath Tag
tag Text
text = Tag -> Text
fromKey Tag
tag forall a. Semigroup a => a -> a -> a
<> Text
"/" forall a. Semigroup a => a -> a -> a
<> Text
text

      fromKey :: Tag -> Text
      fromKey :: Tag -> Text
fromKey = Natural -> Text -> Text
UTF8.stripN Natural
1 forall b c a. (b -> c) -> (a -> b) -> a -> c
. \case
        Hash (CID Text
cid)   -> Text
cid
        Key  (Name String
name) -> forall a. Show a => a -> Text
UTF8.textShow String
name

-- | Get all CIDs from a 'SparseTree' (all levels)
cIDs :: (Monoid (f CID), Applicative f) => SparseTree -> f CID
cIDs :: forall (f :: * -> *).
(Monoid (f CID), Applicative f) =>
SparseTree -> f CID
cIDs (Stub Name
_)       = forall a. Monoid a => a
mempty
cIDs (Content CID
cid)  = forall (f :: * -> *) a. Applicative f => a -> f a
pure CID
cid
cIDs (Directory Map Tag SparseTree
kv) = forall (t :: * -> *) m a.
(Foldable t, Monoid m) =>
(a -> m) -> t a -> m
foldMap forall (f :: * -> *).
(Monoid (f CID), Applicative f) =>
SparseTree -> f CID
cIDs Map Tag SparseTree
kv