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/PollAgent.cs b/trunk/Pithos.Core/Agents/PollAgent.cs
index 33a93be..1a5d764 100644
--- a/trunk/Pithos.Core/Agents/PollAgent.cs
+++ b/trunk/Pithos.Core/Agents/PollAgent.cs
@@ -270,7 +270,9 @@ namespace Pithos.Core.Agents
                         
 
                         //Create a list of actions from the remote files
-                        var allActions = ChangesToActions(accountInfo, differencer.Changed.FilterDirectlyBelow(SelectiveUris))
+                        var allActions = MovesToActions(accountInfo,differencer.Moved.FilterDirectlyBelow(SelectiveUris))
+                                        .Union(
+                                        ChangesToActions(accountInfo, differencer.Changed.FilterDirectlyBelow(SelectiveUris)))
                                         .Union(
                                         CreatesToActions(accountInfo, differencer.Created.FilterDirectlyBelow(SelectiveUris)));
 
@@ -379,7 +381,12 @@ namespace Pithos.Core.Agents
 
         }
 
-        //Creates an appropriate action for each server file
+        /// <summary>
+        /// Creates a Sync action for each changed server file
+        /// </summary>
+        /// <param name="accountInfo"></param>
+        /// <param name="changes"></param>
+        /// <returns></returns>
         private IEnumerable<CloudAction> ChangesToActions(AccountInfo accountInfo, IEnumerable<ObjectInfo> changes)
         {
             if (changes == null)
@@ -392,11 +399,11 @@ namespace Pithos.Core.Agents
             foreach (var objectInfo in changes)
             {
                 var relativePath = objectInfo.RelativeUrlToFilePath(accountInfo.UserName);
-                //and remove any matching objects from the list, adding them to the commonObjects list
+                //If a directory object already exists, we may need to sync it
                 if (fileAgent.Exists(relativePath))
                 {
-                    //If a directory object already exists, we don't need to perform any other action                    
                     var localFile = fileAgent.GetFileSystemInfo(relativePath);
+                    //We don't need to sync directories
                     if (objectInfo.Content_Type == @"application/directory" && localFile is DirectoryInfo)
                         continue;
                     using (new SessionScope(FlushAction.Never))
@@ -418,6 +425,58 @@ namespace Pithos.Core.Agents
             }
         }
 
+        /// <summary>
+        /// Creates a Local Move action for each moved server file
+        /// </summary>
+        /// <param name="accountInfo"></param>
+        /// <param name="moves"></param>
+        /// <returns></returns>
+        private IEnumerable<CloudAction> MovesToActions(AccountInfo accountInfo, IEnumerable<ObjectInfo> moves)
+        {
+            if (moves == null)
+                throw new ArgumentNullException();
+            Contract.EndContractBlock();
+            var fileAgent = FileAgent.GetFileAgent(accountInfo);
+
+            //In order to avoid multiple iterations over the files, we iterate only once
+            //over the remote files
+            foreach (var objectInfo in moves)
+            {
+                var previousRelativepath = objectInfo.Previous.RelativeUrlToFilePath(accountInfo.UserName);
+                //If the previous file already exists, we can execute a Move operation
+                if (fileAgent.Exists(previousRelativepath))
+                {
+                    var previousFile = fileAgent.GetFileSystemInfo(previousRelativepath);
+                    using (new SessionScope(FlushAction.Never))
+                    {
+                        var state = StatusKeeper.GetStateByFilePath(previousFile.FullName);
+                        _lastSeen[previousFile.FullName] = DateTime.Now;
+
+                        //For each moved object we need to move both the local file and update                                                
+                        yield return new CloudAction(accountInfo, CloudActionType.RenameLocal,
+                                                     previousFile, objectInfo, state, accountInfo.BlockSize,
+                                                     accountInfo.BlockHash);
+                        //For modified files, we need to download the changes as well
+                        if (objectInfo.Hash!=objectInfo.PreviousHash)
+                            yield return new CloudDownloadAction(accountInfo,objectInfo);
+                    }
+                }
+                //If the previous file does not exist, we need to download it in the new location
+                else
+                {
+                    //Remote files should be downloaded
+                    yield return new CloudDownloadAction(accountInfo, objectInfo);
+                }
+            }
+        }
+
+
+        /// <summary>
+        /// Creates a download action for each new server file
+        /// </summary>
+        /// <param name="accountInfo"></param>
+        /// <param name="creates"></param>
+        /// <returns></returns>
         private IEnumerable<CloudAction> CreatesToActions(AccountInfo accountInfo, IEnumerable<ObjectInfo> creates)
         {
             if (creates == null)
@@ -430,10 +489,9 @@ namespace Pithos.Core.Agents
             foreach (var objectInfo in creates)
             {
                 var relativePath = objectInfo.RelativeUrlToFilePath(accountInfo.UserName);
-                //and remove any matching objects from the list, adding them to the commonObjects list
+                //If the object already exists, we probably have a conflict
                 if (fileAgent.Exists(relativePath))
                 {
-                    //If the object already exists, we probably have a conflict
                     //If a directory object already exists, we don't need to perform any other action                    
                     var localFile = fileAgent.GetFileSystemInfo(relativePath);
                     StatusKeeper.SetFileState(localFile.FullName, FileStatus.Conflict, FileOverlayStatus.Conflict);
