module Data.Woot ( WootClient , wootClientId , wootClientClock , wootClientString , wootClientOperationQueue -- Construction , makeWootClient , makeWootClientEmpty -- Operation handling , sendOperation , sendOperations , sendLocalDelete , sendLocalInsert -- Useful data types from other modules , WString , WChar(..) , WCharId(..) , Operation(..) , ClientId ) where import Data.Woot.Core import Data.Woot.Operation import Data.Woot.WChar import Data.Woot.WString data WootClient = WootClient { wootClientId :: Int , wootClientClock :: Int , wootClientString :: WString , wootClientOperationQueue :: [Operation] } deriving (Eq, Show) incClock :: WootClient -> WootClient incClock client = client {wootClientClock = succ $ wootClientClock client} -- TODO: should this check is the client id already exists in the provided string -- and then start the client clock at the correct value? makeWootClient :: WString -> ClientId -> WootClient makeWootClient ws cid = WootClient cid 0 ws [] makeWootClientEmpty :: ClientId -> WootClient makeWootClientEmpty = makeWootClient emptyWString -- sends an operation to a woot client, returning a new woot client -- the operation will either be integrated into the woot client's string -- or it will be added to the client's interal operation queue to be tried again sendOperation :: WootClient -> Operation -> WootClient sendOperation (WootClient cid clock ws ops) op = WootClient cid clock ws' ops' where (ops', ws') = integrateAll (op:ops) ws sendOperations :: WootClient -> [Operation] -> WootClient sendOperations = foldl sendOperation -- identical to sendOperation, but increments the clients internal clock -- not exposed - consumers should use sendLocalDelete or sendLocalInsert sendLocalOperation :: WootClient -> Operation -> WootClient sendLocalOperation client = incClock . sendOperation client -- note: failed local operations can result in no-ops if the underlying operation is invalid -- they will not be added to a client's operation queue -- the assumption is that anything done locally should already be verified -- if the local operation was successful, the operation should be broadcasted to other clients sendLocalDelete :: WootClient -> Int -> (Maybe Operation, WootClient) sendLocalDelete client pos = (op,) $ maybe client (sendLocalOperation client) op where op = makeDeleteOperation (wootClientId client) pos (wootClientString client) sendLocalInsert :: WootClient -> Int -> Char -> (Maybe Operation, WootClient) sendLocalInsert client@(WootClient cid clock ws _) pos a = (op,) $ maybe client (sendLocalOperation client) op where op = makeInsertOperation (WCharId cid clock) pos a ws