module Data.BinaryTree.Zipper where
import Data.BinaryTree
data Ctx a = Top | L (Ctx a) a (BinaryTree a) | R (BinaryTree a) a (Ctx a)
           deriving (Show,Read,Eq,Ord,Functor,Foldable,Traversable)
data BinaryTreeZipper a = Loc (BinaryTree a) (Ctx a)
           deriving (Show,Read,Eq,Ord,Functor,Foldable,Traversable)
top   :: BinaryTree a -> BinaryTreeZipper a
top t = Loc t Top
left                            :: BinaryTreeZipper a -> Maybe (BinaryTreeZipper a)
left (Loc (Internal l x r) ctx) = Just $ Loc l (L ctx x r)
left (Loc Nil _)                = Nothing
right                            :: BinaryTreeZipper a -> Maybe (BinaryTreeZipper a)
right (Loc (Internal l x r) ctx) = Just $ Loc r (R l x ctx)
right (Loc Nil _)                = Nothing
up                     :: BinaryTreeZipper a -> Maybe (BinaryTreeZipper a)
up (Loc _ Top)         = Nothing
up (Loc l (L ctx x r)) = Just $ Loc (Internal l x r) ctx
up (Loc r (R l x ctx)) = Just $ Loc (Internal l x r) ctx
toRoot   :: BinaryTreeZipper a -> BinaryTreeZipper a
toRoot z = toRoot' z (Just z)
  where
    toRoot' z' Nothing   = z'
    toRoot' _  (Just z') = toRoot' z' (up z')
visitAll   :: BinaryTree a -> [BinaryTreeZipper a]
visitAll t = visitAll' (top t)
  where
    f           = maybe [] visitAll'
    visitAll' z = z : f (left z) <> f (right z)
accessZ           :: BinaryTreeZipper a -> Maybe a
accessZ (Loc t _) = access t
subTrees :: BinaryTree a -> [BinaryTree a]
subTrees t = Nil : subTrees' t
  where
    subTrees' Nil                 = []
    subTrees' tt@(Internal l _ r) = tt : subTrees' l <> subTrees' r
splitTree             :: BinaryTreeZipper a -> (BinaryTree a, BinaryTree a)
splitTree (Loc t ctx) = let (Loc r _) = toRoot $ Loc Nil ctx
                        in (t, r)