\begin{code}

module CollectionBVar where
import SetB
import ListB
import BVar
import FM
import IOExts
import FranCore
import CollectionB
import Identify
import List
import MapG

data CollectionBVar b c a = CollectionBVar {
	listenerOp :: Listener (CBVarOp a (b a)),
	collection :: CollectionB b c a 
	}

behaviorCV :: CollectionBVar b c a -> Behavior (c a)
behaviorCV = behaviorC . collection 

type CBVarOp a b =  (a -> IO (Maybe Ident))  
	         -> (a -> IO Ident) 
	         -> (a -> IO (Maybe Ident)) 
		 -> ([a] -> IO [(Ident,a)])
	         -> IO (Maybe b)

newCollectionBVar :: (CollectionOp b c,Eq a) =>
		    [a] -> ([(Ident,a)] -> c a)
		 -> IO (CollectionBVar b c a)
newCollectionBVar = newCollectionBVar' (==)

newCollectionBVar' :: (CollectionOp b c) =>
		    (a -> a -> Bool) -> 
		    [a] -> ([(Ident,a)] -> c a)
		 -> IO (CollectionBVar b c a)
newCollectionBVar' eq as newfm = do
 (Wire l e) <- newWire
 ref <- newIORef (0,[])
 let reset vs = do
        let ls = zipWith (\x a -> (a,identify x)) [(1 :: Int) ..] vs
        writeIORef ref (length ls + 1,ls)
        return $ map (\(a,b) -> (b,a)) ls
 let add v = do (x,fm) <- readIORef ref
		let id = identify x
	        writeIORef ref (x + 1,  (v,id):fm)
	        return id
 let delete v = do (x,fm) <- readIORef ref
		   case partition ((eq v) . fst) fm of
		     ((_,k):xs,ks) -> do writeIORef ref (x,ks ++ xs) 
				         return $ Just k
		     _ -> return Nothing
 let findItem v = do xs <- readIORef ref
		     return $ fmap snd $ find (eq v . fst) $ snd xs
 let e' = isJustE $ e `withIOE` (\f -> f findItem add delete reset) 
 as' <- reset as
 c <- newCollectionB e' $ newfm as'
 return $ CollectionBVar l c

newCollectionBVarI :: (CollectionOp b c) =>
		     (a -> Ident) ->
		     c a -> IO (CollectionBVar b c a)
newCollectionBVarI identify as = do
 (Wire l e) <- newWire
 let e' = isJustE $ e `withIOE` 
		(\f -> f (return . Just . identify) 
			 (return . identify) 
			 (return . Just . identify)
			 (return . map (\a -> (identify a,a))))
 c <- newCollectionB e' as
 return $ CollectionBVar l c

type SetBVar a = CollectionBVar SetOp Set a

newSetBVar' :: (a -> Ident) -> [a] -> IO (SetBVar a)
newSetBVar' identify as = newCollectionBVarI identify $ listToSet $ map (\a -> (identify a,a)) as

newSetBVar :: (Eq a) => [a] -> IO (SetBVar a)
newSetBVar as = newCollectionBVar as listToSet

insertSetB :: Eq a => SetBVar a -> Listener a
insertSetB (s :: SetBVar a) = comapL op $ listenerOp s
 where
   op :: a -> CBVarOp a (SetOp a)
   op v = \lookup add delete reset -> 
		do x <- add v;return $! Just $! InsertSet x v

deleteSetB :: Eq a => SetBVar a -> Listener a
deleteSetB s = comapL op $ listenerOp s
 where
   op v = \_ _ delete _ -> do
	     fmap (fmap DeleteSet) $ delete v  

resetSetB :: Eq a => SetBVar a -> Listener [a]
resetSetB s = comapL op $ listenerOp s
 where
   op v = \lookup add delete reset -> do
		reset v >>= return . Just . ResetSet . listToSet


setVBehavior :: SetBVar a -> Behavior [a]
setVBehavior s = setBehavior $ collection s

listVBehavior :: ListBVar a -> Behavior [a]
listVBehavior s = listBehavior $ collection s

type ListBVar a = CollectionBVar ListOp List a

newListBVar' :: (a -> Ident) -> [a] -> IO (ListBVar a)
newListBVar' identify as = newCollectionBVarI identify $ toList $ map (\a -> (identify a,a)) as

newListBVar :: (Eq a) => [a] -> IO (ListBVar a)
newListBVar as = newCollectionBVar as toList

insertListB :: ListBVar a -> Listener (a,PlacePos a)
insertListB l = comapL op $ listenerOp l
 where
  op (v,p) = \lookup insert _ _ -> do
		pos <- maybePlace lookup p
		k <- insert v
	        return $ Just $ InsertList k v pos

  maybePlace look PlaceTop = return PlaceTop
  maybePlace look PlaceBottom = return PlaceBottom
  maybePlace look (PlaceBefore x) =
        fmap (maybe PlaceBottom PlaceBefore) $ look x
  maybePlace look (PlaceAfter x) = 
        fmap (maybe PlaceBottom PlaceAfter) $ look x

deleteListB :: ListBVar a -> Listener a
deleteListB l = comapL op $ listenerOp l
 where
  op v = \ _ _ delete _ -> fmap (fmap DeleteList) $ delete v

resetListB :: ListBVar a -> Listener [a]
resetListB l = comapL op $ listenerOp l
 where
  op v = \_ _ _ reset -> reset v >>= return . Just . ResetList . toList

moveListB :: ListBVar a -> Listener (a,PlacePos a)
moveListB l = comapL op $ listenerOp l
 where
  op (v,pos) = \ find _ _ _ -> do
		 x <- find v
		 case x of
		  Nothing -> return Nothing
		  Just v -> do 
		   p <- case pos of
		         PlaceBefore p -> fmap (maybe PlaceTop PlaceBefore) 
					  $ find p
 		         PlaceAfter p -> fmap (maybe PlaceBottom PlaceAfter) 
					  $ find p
			 PlaceTop -> return PlaceTop
			 PlaceBottom -> return PlaceBottom
		   return $ Just $ MoveList v p	


appendListB :: ListBVar a -> Listener a
appendListB l = comapL (\v -> (v,PlaceBottom)) $ insertListB l

consListB :: ListBVar a -> Listener a
consListB l = comapL (\v -> (v,PlaceTop)) $ insertListB l
\end{code}
