--- /dev/null
+{-# LANGUAGE DeriveDataTypeable #-}
+{-# LANGUAGE NamedFieldPuns #-}
+{-# OPTIONS_GHC -fno-warn-tabs #-}
+
+module Hcompta.Lib.TreeMap.Zipper where
+
+import Control.Applicative ((<$>), (<*>), pure)
+import Control.DeepSeq (NFData(..))
+import Control.Monad (Monad(..), (>=>))
+import Data.Bool
+import Data.Eq (Eq)
+import Data.Data (Data)
+import Data.Foldable (Foldable, foldMap)
+import Data.Functor (Functor(..))
+import Data.Ord (Ord(..))
+import qualified Data.List as List
+import qualified Data.List.NonEmpty
+import Data.List.NonEmpty (NonEmpty(..))
+import Data.Map.Strict (Map)
+import qualified Data.Map.Strict as Map
+import Data.Maybe (Maybe(..), maybe, maybeToList)
+import Data.Monoid (Monoid(..))
+import qualified Data.Strict.Maybe as Strict
+import Data.Traversable (Traversable(..))
+import Data.Typeable (Typeable)
+import Prelude (($), (.), Int, Num(..), Show, const, flip, id, seq)
+
+import qualified Hcompta.Lib.Strict as Strict ()
+import Hcompta.Lib.TreeMap (TreeMap(..))
+import qualified Hcompta.Lib.TreeMap as TreeMap
+
+-- * Type 'Zipper'
+
+data Zipper k x
+ = Zipper
+ { zipper_path :: [Zipper_Step k x]
+ , zipper_curr :: TreeMap k x
+ } deriving (Data, Eq, Show, Typeable)
+
+zipper :: TreeMap k x -> Zipper k x
+zipper = Zipper []
+
+zipper_root :: Ord k => Zipper k x -> TreeMap k x
+zipper_root =
+ zipper_curr . List.last .
+ zipper_collect zipper_parent
+
+-- * Type 'Zipper_Step'
+
+data Zipper_Step k x
+ = Zipper_Step
+ { zipper_step_prec :: TreeMap k x
+ , zipper_step_self :: (k, TreeMap.Node k x)
+ , zipper_step_foll :: TreeMap k x
+ } deriving (Data, Eq, Show, Typeable)
+
+-- * Axis
+
+-- | Collect all 'Zipper's along a given axis,
+-- including the first 'Zipper'.
+zipper_collect :: (z -> Maybe z) -> z -> [z]
+zipper_collect f z = z : maybe [] (zipper_collect f) (f z)
+
+-- | Collect all 'Zipper's along a given axis,
+-- excluding the first 'Zipper'.
+zipper_collect_without_self :: (z -> Maybe z) -> z -> [z]
+zipper_collect_without_self f z = maybe [] (zipper_collect f) (f z)
+
+-- ** Axis self
+
+zipper_self :: Ord k => Zipper k x -> Maybe (k, TreeMap.Node k x)
+zipper_self z =
+ case z of
+ Zipper{ zipper_path=
+ Zipper_Step{zipper_step_self}
+ : _ } -> Just zipper_step_self
+ _ -> Nothing
+
+-- ** Axis child
+
+zipper_child :: Ord k => Zipper k x -> [Zipper k x]
+zipper_child z =
+ maybeToList (zipper_child_first z)
+ >>= zipper_collect zipper_foll
+
+zipper_child_at :: Ord k => k -> Zipper k x -> Maybe (Zipper k x)
+zipper_child_at k (Zipper path (TreeMap m)) =
+ case Map.splitLookup k m of
+ (_, Nothing, _) -> Nothing
+ (ps, Just s, fs) ->
+ Just $ Zipper
+ { zipper_path = Zipper_Step (TreeMap ps) (k, s) (TreeMap fs) : path
+ , zipper_curr = TreeMap.node_descendants s
+ }
+
+zipper_child_first :: Ord k => Zipper k x -> Maybe (Zipper k x)
+zipper_child_first (Zipper path (TreeMap m)) =
+ case Map.minViewWithKey m of
+ Nothing -> Nothing
+ Just ((k', s'), fs') ->
+ Just $ Zipper
+ { zipper_path = Zipper_Step TreeMap.empty (k', s') (TreeMap fs') : path
+ , zipper_curr = TreeMap.node_descendants s'
+ }
+
+zipper_child_last :: Ord k => Zipper k x -> Maybe (Zipper k x)
+zipper_child_last (Zipper path (TreeMap m)) =
+ case Map.maxViewWithKey m of
+ Nothing -> Nothing
+ Just ((k', s'), ps') ->
+ Just $ Zipper
+ { zipper_path = Zipper_Step (TreeMap ps') (k', s') TreeMap.empty : path
+ , zipper_curr = TreeMap.node_descendants s'
+ }
+
+-- ** Axis ancestor
+
+zipper_ancestor :: Ord k => Zipper k x -> [Zipper k x]
+zipper_ancestor = zipper_collect_without_self zipper_parent
+
+zipper_ancestor_or_self :: Ord k => Zipper k x -> [Zipper k x]
+zipper_ancestor_or_self = zipper_collect zipper_parent
+
+-- ** Axis descendant
+
+zipper_descendant_or_self :: Ord k => Zipper k x -> [Zipper k x]
+zipper_descendant_or_self =
+ collect_child []
+ where
+ collect_child acc z =
+ z : maybe acc
+ (collect_foll acc)
+ (zipper_child_first z)
+ collect_foll acc z =
+ collect_child
+ (maybe acc
+ (collect_foll acc)
+ (zipper_foll z)
+ ) z
+
+zipper_descendant_or_self_reverse :: Ord k => Zipper k x -> [Zipper k x]
+zipper_descendant_or_self_reverse z =
+ z : List.concatMap
+ zipper_descendant_or_self_reverse
+ (List.reverse $ zipper_child z)
+
+zipper_descendant :: Ord k => Zipper k x -> [Zipper k x]
+zipper_descendant = List.tail . zipper_descendant_or_self
+
+zipper_descendant_at :: Ord k => TreeMap.Path k -> Zipper k x -> Maybe (Zipper k x)
+zipper_descendant_at (k:|ks) =
+ case ks of
+ [] -> zipper_child_at k
+ k':ks' -> zipper_child_at k >=> zipper_descendant_at (k':|ks')
+
+-- ** Axis preceding
+
+zipper_prec :: Ord k => Zipper k x -> Maybe (Zipper k x)
+zipper_prec (Zipper path _curr) =
+ case path of
+ [] -> Nothing
+ Zipper_Step (TreeMap ps) (k, s) (TreeMap fs):steps ->
+ case Map.maxViewWithKey ps of
+ Nothing -> Nothing
+ Just ((k', s'), ps') ->
+ Just $ Zipper
+ { zipper_path = Zipper_Step (TreeMap ps')
+ (k', s')
+ (TreeMap $ Map.insert k s $ fs)
+ : steps
+ , zipper_curr = TreeMap.node_descendants s'
+ }
+
+zipper_preceding :: Ord k => Zipper k x -> [Zipper k x]
+zipper_preceding =
+ zipper_ancestor_or_self >=>
+ zipper_preceding_sibling >=>
+ zipper_descendant_or_self_reverse
+
+zipper_preceding_sibling :: Ord k => Zipper k x -> [Zipper k x]
+zipper_preceding_sibling = zipper_collect_without_self zipper_prec
+
+-- ** Axis following
+
+zipper_foll :: Ord k => Zipper k x -> Maybe (Zipper k x)
+zipper_foll (Zipper path _curr) =
+ case path of
+ [] -> Nothing
+ Zipper_Step (TreeMap ps) (k, s) (TreeMap fs):steps ->
+ case Map.minViewWithKey fs of
+ Nothing -> Nothing
+ Just ((k', s'), fs') ->
+ Just $ Zipper
+ { zipper_path = Zipper_Step (TreeMap $ Map.insert k s $ ps)
+ (k', s')
+ (TreeMap fs')
+ : steps
+ , zipper_curr = TreeMap.node_descendants s'
+ }
+
+zipper_following :: Ord k => Zipper k x -> [Zipper k x]
+zipper_following =
+ zipper_ancestor_or_self >=>
+ zipper_following_sibling >=>
+ zipper_descendant_or_self
+
+zipper_following_sibling :: Ord k => Zipper k x -> [Zipper k x]
+zipper_following_sibling = zipper_collect_without_self zipper_foll
+
+-- ** Axis parent
+
+zipper_parent :: Ord k => Zipper k x -> Maybe (Zipper k x)
+zipper_parent (Zipper path curr) =
+ case path of
+ [] -> Nothing
+ Zipper_Step (TreeMap ps) (k, s) (TreeMap fs):steps ->
+ let node = TreeMap.Node
+ { TreeMap.node_value = TreeMap.node_value s
+ , TreeMap.node_size = TreeMap.size curr
+ , TreeMap.node_descendants = curr
+ } in
+ Just $ Zipper
+ { zipper_path = steps
+ , zipper_curr = TreeMap $ Map.union ps $ Map.insert k node $ fs
+ }