]> code.delx.au - offlineimap/blobdiff - src/Data/Syncable.hs
TESTS PASS
[offlineimap] / src / Data / Syncable.hs
index 08cd82a10c5d19532a26ef22fd39f565ff803454..69841c44d58da1a6fb4340b0958140ee85d455bc 100644 (file)
@@ -118,27 +118,44 @@ syncBiDir masterstate childstate lastchildstate =
                           findAdded masterstate childstate $ lastchildstate)
                          ++ (map (pairToFunc ModifyContent) . Map.toList $ childPayloadChanges)
           masterPayloadChanges = 
-              Map.union (findModified masterstate childstate lastchildstate)
-                        (findModified masterstate childstate masterstate)
+              Map.union 
+                 (findModified masterstate childstate childstate lastchildstate)
+                 (findModified masterstate childstate reducedChildState masterstate)
+              where reducedChildState = 
+                        Map.difference childstate lastchildstate
                  
           -- The child's payload takes precedence, so we are going to
           -- calculate the changes made on the master to apply to the client,
           -- then subtract out any items in the master changes that have the
           -- same key.
           childPayloadChanges = 
-              foldl (\m (k, v) -> Map.adjust (\_ -> v) k m)
-                        (findModified childstate masterstate lastchildstate)
-                        (Map.toList $ findModified masterstate childstate lastchildstate)
+              Map.difference (findModified childstate masterstate masterstate lastchildstate)
+                 (findModified masterstate childstate childstate lastchildstate)
 
 {- | Compares two SyncCollections, and returns the commands that, when
 applied to the first collection, would yield the second. -}
-diffCollection :: (Ord k, Show k, Show v) => 
+diffCollection :: (Ord k, Show k, Eq v, Show v) => 
                   SyncCollection k v
                -> SyncCollection k v
                -> [SyncCommand k v]
 diffCollection coll1 coll2 = 
     (map DeleteItem . findDeleted coll2 coll1 $ coll1) ++
-    (map (pairToFunc CopyItem) . findAdded coll2 coll1 $ coll1)
+    (map (pairToFunc CopyItem) . findAdded coll2 coll1 $ coll1) ++
+    modifiedData
+    where modifiedData = 
+              map (pairToFunc ModifyContent) .
+              Map.toList . 
+              Map.mapMaybe id .
+              Map.intersectionWith compareFunc coll1 $ coll2
+          compareFunc v1 v2
+              | v1 /= v2 = Just v2
+              | otherwise = Nothing
+              
+                         
+    {-
+    (map (pairToFunc ModifyContent) . Map.toList .
+         findModified coll1 coll2 $ coll1)
+     -}
 
 {- | Returns a list of keys that exist in state2 and lastchildstate
 but not in state1 -}
@@ -156,23 +173,34 @@ findAdded :: (Ord k, Eq k) =>
 findAdded state1 state2 lastchildstate =
     Map.toList . Map.difference state1 . Map.union state2 $ lastchildstate
 
+
 {- Finds all items that exist in both state1 and lastchildstate in which the payload
 is different in state1 than it was in lastchildstate.  Returns the key and new
 payload for each such item found. -}
 findModified :: (Ord k, Eq v) =>
-                SyncCollection k v -> SyncCollection k v -> SyncCollection k v -> SyncCollection k v
-findModified basestate state1 lastchildstate =
-    Map.mapMaybe id .  
-    Map.intersectionWithKey comparefunc state1 $ lastchildstate
-    where comparefunc k v1 v2 =
-              if v1 /= v2
-                 then case Map.lookup k basestate of
-                        Nothing -> Nothing
-                        Just baseval ->
-                            if baseval == v1
-                               then Nothing
-                               else Just v1
-                 else Nothing
+                SyncCollection k v 
+             -> SyncCollection k v
+             -> SyncCollection k v
+             -> SyncCollection k v
+             -> SyncCollection k v
+findModified basestate authoritativestate comparisonstate laststate =
+    Map.mapMaybe id $
+       Map.intersectionWithKey compareFunc comparisonstate laststate
+    where compareFunc k compv lastv =
+              if lastv == compv
+                 then Nothing
+                 else case (Map.lookup k basestate, Map.lookup k authoritativestate) of
+                        (Nothing, _) -> Nothing
+                        (Just basev, Nothing) ->
+                            if compv /= basev
+                               then Just compv
+                               else Nothing
+                        (Just basev, Just authv) ->
+                            if (authv /= lastv) && (authv /= basev)
+                               then Just authv
+                               else if compv /= basev && (authv /= basev)
+                                    then Just compv
+                                    else Nothing
 
 {- | Apply the specified changes to the given SyncCollection.  Returns
 a new SyncCollection with the changes applied.  If changes are specified