commit b666b39aaca5965ba58b484f1042c6a952f210f4
Author: Panagiotis Kanavos <pkanavos@gmail.com>
Date:   Tue Feb 28 13:41:41 2012 +0200

    Added modifications for move detection. Resolves #1999, #1891

diff --git a/trunk/Pithos.Core/Agents/SnapshotDifferencer.cs b/trunk/Pithos.Core/Agents/SnapshotDifferencer.cs
index fed03e9..4f46174 100644
--- a/trunk/Pithos.Core/Agents/SnapshotDifferencer.cs
+++ b/trunk/Pithos.Core/Agents/SnapshotDifferencer.cs
@@ -40,6 +40,7 @@
  */
 #endregion
 using System.Collections.Concurrent;
+using System.Diagnostics.Contracts;
 using Pithos.Interfaces;
 using Pithos.Network;
 using System;
@@ -71,6 +72,11 @@ namespace Pithos.Core.Agents
             /// </summary>
             public readonly ObjectInfo[] Current;
 
+            public readonly Dictionary<string, ObjectInfo> CurrentDict;
+
+            public readonly Dictionary<string, ObjectInfo> PreviousDict;
+
+
             /// <summary>
             /// Common objects, lazily evalueated. 
             /// The common objects are used to calculate both the Changed and Unchanged objects
@@ -79,20 +85,30 @@ namespace Pithos.Core.Agents
 
             private readonly static ObjectInfo[] Empty = new ObjectInfo[0];
 
+            [ContractInvariantMethod]
+            private void StatInvariant()
+            {
+// ReSharper disable InvocationIsSkipped
+                Contract.Invariant(Current!=null);
+                Contract.Invariant(Previous!=null);
+                Contract.Invariant(CurrentDict!=null);
+                Contract.Invariant(PreviousDict!=null);
+                Contract.Invariant(Common!=null);
+// ReSharper restore InvocationIsSkipped
+            }
+
             public State(ObjectInfo[] previous, ObjectInfo[] current)
             {
                 Previous = previous ?? Empty;
                 Current = current ?? Empty;
+                CurrentDict = Current.ToDictionary(info => info.UUID);
+                PreviousDict = Previous.ToDictionary(info => info.UUID);
 
                 Common=new Lazy<IEnumerable<ObjectInfo>>(() =>
                     Current.Join(Previous,
                                 outKey => new { outKey.Account, outKey.Container, outKey.Name },
                                 inKey => new { inKey.Account, inKey.Container, inKey.Name },
-                                (outer, inner) =>
-                                {
-                                    outer.PreviousHash = inner.Hash;
-                                    return outer;
-                                }));            
+                                (outer, inner) =>outer.SetPrevious(inner)));            
             }
         }
 
@@ -138,13 +154,26 @@ namespace Pithos.Core.Agents
             return this;
         }
         
+        /// <summary>
+        /// Deleted objects are those that existed in the Previous listing
+        /// but are not found in the Current listing, and their UUIDs do not
+        /// appear in the Current listing (ie they were not renamed/moved)
+        /// </summary>
         public IEnumerable<ObjectInfo> Deleted
         {
-            get { return _state.Previous.Except(_state.Current,_comparer); }
+            get { return _state.Previous.Except(_state.Current,_comparer)
+                .Where(info=>!_state.CurrentDict.ContainsKey(info.UUID)); }
         }
+
+        /// <summary>
+        /// Created objects are those that exist in the Current listing
+        /// but are not found in the Previous listing, and their UUIDs do not
+        /// appear in the Previous listing (ie they were not renamed/moved)
+        /// </summary>
         public IEnumerable<ObjectInfo> Created
         {
-            get { return _state.Current.Except(_state.Previous,_comparer); }
+            get { return _state.Current.Except(_state.Previous,_comparer)
+                .Where(info=>!_state.PreviousDict.ContainsKey(info.UUID)); }
         }
                 
         public IEnumerable<ObjectInfo> Common
@@ -160,6 +189,19 @@ namespace Pithos.Core.Agents
         {
             get{ return Common.Where(i => i.PreviousHash == i.Hash);}
         }
+
+        public IEnumerable<ObjectInfo>  Moved
+        {
+            get
+            {
+                                
+                return _state.Current.Join(_state.Previous,
+                                    outer => outer.UUID,
+                                    inner => inner.UUID,
+                                    (outer, inner) => (outer.Name == inner.Name ? null : outer.SetPrevious(inner)))
+                    .Where(t => t != null);                
+            }
+        }
     }
 
     public class AccountsDifferencer
