module GardGround.Utils.ListMaybe (
  ListMaybe(ListMaybe),
  push,
  fromList,
  toList
) where

import Numeric.Natural

data ListMaybe a = ListMaybe !Natural [(a, [a], Natural)]

push :: Maybe a -> ListMaybe a -> ListMaybe a
push Nothing (ListMaybe i xs) = ListMaybe (i + 1) xs
push (Just x) (ListMaybe 0 ((y, ys, i):xs)) = ListMaybe 0 $ (x, y:ys, i):xs
push (Just x) (ListMaybe i xs) = ListMaybe 0 $ (x, [], i):xs

fromList :: [Maybe a] -> ListMaybe a
fromList = foldl (flip push) (ListMaybe 0 [])

toList :: ListMaybe a -> [Maybe a]
toList (ListMaybe 0 []) = []
toList (ListMaybe 0 ((y, [], i):xs)) = (Just y):(toList $ ListMaybe i xs)
toList (ListMaybe 0 ((y, y2:ys, i):xs)) = (Just y):(toList $ ListMaybe 0 $ (y2, ys, i):xs)
toList (ListMaybe i xs) = Nothing:(toList $ ListMaybe (i - 1) xs)

instance Functor ListMaybe where
    fmap f (ListMaybe i xs) = ListMaybe i (fmap (\(y, ys, j) -> (f y, fmap f ys, j)) xs)
    {-# INLINE fmap #-}