module Reactive.Event (Event(..),eventsToQList,eventsToTile,qListToEvents,tileToEvents, filterEvent, emptyWeight) where
import Tile.Tile
import Tile.QList
import Tile.Atom
import Duration.Lattice
import qualified Data.Map as M
import Data.List as L
data Event v = Start | Off !v | On !v | Stop deriving (Eq, Show)
instance Functor Event where
fmap f (Off v) = Off (f v)
fmap f (On v) = On (f v)
fmap _ Stop = Stop
fmap _ Start = Start
qListToEvents :: (Eq d, Num d,Ord d, Lattice d, Eq v, POrd v) =>
QList d iv v -> [(d, Event v)]
qListToEvents qList
= (0,Start):(L.sortOn fst . makeEvents 0 0) qList where
makeEvents now lastOff qList
= let ldv = getAllFromAtomsQ qList
dn = delayToTailQ (dropAtomsQ qList)
newLastOff = maximum (lastOff:[now + d | (d,_) <- ldv])
in (ldv >>= (\(d,v) -> [(now,On v), (now + d,Off v)]))
++ if dn == 0
then [(newLastOff,Stop)]
else makeEvents (now + dn) newLastOff (tailQ qList)
tileToEvents :: (Eq d, Num d,Ord d, Lattice d, Eq v, POrd v) =>
Tile d iv v -> [(d, Event v)]
tileToEvents t = qListToEvents $ toQList $ t
popFirstElementThatSatisfyPredicate :: (a -> Bool) -> [a] -> (Maybe a, [a])
popFirstElementThatSatisfyPredicate p l =
let (a,b) = break p l
in case b of
(e:b') -> (Just e, a ++ b')
[] -> (Nothing, a)
eventsToQList :: (Eq d, Eq v, Num d, Lattice d) => [(d, Event v)] -> QList d iv v
eventsToQList ((0,Start):l) = eventsToQList l
eventsToQList ((_,Start):_) = error "eventsToQList: illegal start event date"
eventsToQList ((t,On v):l) =
let (maybeMachingOff,l') = popFirstElementThatSatisfyPredicate (\e -> case e of (_,Off v') -> v == v'
_ -> False) l
in case maybeMachingOff of
Nothing -> error "eventsToQList : No matching Off"
Just (t', Off _) -> case (partialCompare 0 t) of
Just LT -> mergeQ (QList [] (DQ t (QList [Atom (t' t) v] (DQ 0 QEnd)))
,eventsToQList l')
Just EQ -> mergeQ (QList [Atom (t' t) v] (DQ 0 QEnd), eventsToQList l')
_ -> error "eventsToQList: this should never happen"
_ -> error "eventsToQList: this should never happen"
eventsToQList ((_,Off _):_) = error "eventsToQList : eventsToQListStand alone Off"
eventsToQList [(_,Stop)] = QEnd
eventsToQList ((_,Stop):_) = error "eventsToQList: events after End events"
eventsToQList [] = error "eventsToQList: empty list ! missing Stop event"
eventsToTile :: (Eq d, Eq v, Num d, Lattice d) => [(d, Event v)] -> Tile d iv v
eventsToTile l = Tile 0 0 $ eventsToQList l
type Weight v = M.Map v Integer
emptyWeight :: Weight v
emptyWeight = M.empty
updateWeight :: (Ord v) => Weight v -> Event v -> Weight v
updateWeight weight (On v) = M.insertWith (+) v 1 weight
updateWeight weight (Off v) = M.update (\w -> if w == 1 then Nothing else Just (w1)) v weight
updateWeight weight _ = weight
filterEvent :: (Ord v) => Weight v -> [Event v] -> (Weight v, [Event v])
filterEvent w el = stepFilterEvent w [] el where
stepFilterEvent w oel [] = (w,oel)
stepFilterEvent w oel (e:iel)
= let w1 = updateWeight w e
oel1 = case (e) of
Off v -> case M.lookup v w1 of
Nothing -> e:oel
_ -> oel
On v -> case M.lookup v w1 of
Just 1 -> e:oel
_ -> oel
_ -> oel
in stepFilterEvent w1 oel1 iel