module Data.Homeomorphic.ShellId(
    ShellIds, ShellId(..), empty, retrieve
    ) where

import qualified Data.Map as Map
import Data.List
import Data.Homeomorphic.Internal

data ShellId = ShellId {allId :: Int, headId :: Int, restId :: [ShellId]}

data ShellIds k = ShellIds
    (Map.Map (Shell k) ShellId)  -- for the entire result
    (Map.Map (k,Int) Int)              -- for the headId

empty :: ShellIds k
empty = ShellIds Map.empty Map.empty

retrieve :: Ord k => Shell k -> ShellIds k -> (ShellIds k, ShellId)
retrieve x@(Shell a b c) o@(ShellIds mAll mHead) =
    case Map.lookup x mAll of
        Just y -> (o, y)
        Nothing -> (ShellIds mAll3 mHead3, rAll)
                (ShellIds mAll2 mHead2, cs) = mapAccumL (flip retrieve) o c
                (mHead3, rHead) = retrieveHead (a,b) mHead2
                rAll = ShellId (Map.size mAll2) rHead cs
                mAll3 = Map.insert x rAll mAll2

retrieveHead :: Ord k => (k,Int) -> Map.Map (k,Int) Int -> (Map.Map (k,Int) Int, Int)
retrieveHead x m =
    case Map.lookup x m of
        Just y -> (m, y)
        Nothing -> (Map.insert x r m, r)
            where r = Map.size m