{-# LANGUAGE DeriveGeneric #-} {-# LANGUAGE TypeFamilies #-} {-# LANGUAGE DeriveFunctor #-} module Cursor.Tree.Demote ( treeCursorDemoteElem , treeCursorDemoteSubTree , DemoteResult(..) , treeCursorDemoteElemUnder , treeCursorDemoteSubTreeUnder ) where import GHC.Generics (Generic) import Data.Validity import Control.DeepSeq import Cursor.Tree.Base import Cursor.Tree.Types -- | Demotes the current node to the level of its children. -- -- Example: -- -- Before: -- -- > p -- > |- a -- > | |- b -- > |- c <-- -- > | |- d -- > |- e -- -- After: -- -- > p -- > |- a -- > | |- b -- > | |- c <-- -- > | |- d -- > |- e treeCursorDemoteElem :: (a -> b) -> (b -> a) -> TreeCursor a b -> DemoteResult (TreeCursor a b) treeCursorDemoteElem f g tc = case treeAbove tc of Nothing -> CannotDemoteTopNode Just ta -> case treeAboveLefts ta of [] -> NoSiblingsToDemoteUnder (CNode t ls:ts) -> Demoted $ makeTreeCursorWithAbove g (CNode (f $ treeCurrent tc) emptyCForest) $ Just TreeAbove { treeAboveLefts = reverse $ unpackCForest ls , treeAboveAbove = Just ta {treeAboveLefts = ts} , treeAboveNode = t , treeAboveRights = unpackCForest $ treeBelow tc } -- | Demotes the current subtree to the level of its children. -- -- Example: -- -- Before: -- -- > p -- > |- a -- > | |- b -- > |- c <-- -- > | |- d -- > |- e -- -- After: -- -- > p -- > |- a -- > | |- b -- > | |- c <-- -- > | |- d -- > |- e treeCursorDemoteSubTree :: (a -> b) -> (b -> a) -> TreeCursor a b -> DemoteResult (TreeCursor a b) treeCursorDemoteSubTree f g tc = case treeAbove tc of Nothing -> CannotDemoteTopNode Just ta -> case treeAboveLefts ta of [] -> NoSiblingsToDemoteUnder (CNode t ls:ts) -> Demoted $ makeTreeCursorWithAbove g (currentTree f tc) $ Just TreeAbove { treeAboveLefts = reverse $ unpackCForest ls , treeAboveAbove = Just ta {treeAboveLefts = ts} , treeAboveNode = t , treeAboveRights = [] } data DemoteResult a = CannotDemoteTopNode | NoSiblingsToDemoteUnder | Demoted a deriving (Show, Eq, Generic, Functor) instance Validity a => Validity (DemoteResult a) instance NFData a => NFData (DemoteResult a) -- | Demotes the current node to the level of its children, by adding two roots. -- One for the current node and one for its children that are left behind. -- -- Example: -- -- Before: -- -- > p -- > |- a <-- -- > |- b -- -- After: -- -- > p -- > |- -- > | |- a <-- -- > |- -- > | |- b treeCursorDemoteElemUnder :: b -> b -> TreeCursor a b -> Maybe (TreeCursor a b) treeCursorDemoteElemUnder b1 b2 tc = do ta <- treeAbove tc let ta' = ta {treeAboveRights = CNode b2 (treeBelow tc) : treeAboveRights ta} pure tc { treeAbove = Just TreeAbove { treeAboveLefts = [] , treeAboveAbove = Just ta' , treeAboveNode = b1 , treeAboveRights = [] } , treeBelow = emptyCForest } -- | Demotes the current subtree to the level of its children, by adding a root. -- -- Example: -- -- Before: -- -- > a <-- -- > |- b -- -- After: -- -- > -- > |- a <-- -- > |- b treeCursorDemoteSubTreeUnder :: b -> TreeCursor a b -> TreeCursor a b treeCursorDemoteSubTreeUnder b tc = tc { treeAbove = Just TreeAbove { treeAboveLefts = [] , treeAboveAbove = treeAbove tc , treeAboveNode = b , treeAboveRights = [] } }