Preliminary fix for #1999, incorrect deletions
[pithos-ms-client] / trunk / Pithos.Core / Agents / CloudTransferAction.cs
1 using System;
2 using System.Diagnostics.Contracts;
3 using System.IO;
4 using System.Threading;
5 using Pithos.Interfaces;
6 using Pithos.Network;
7
8 namespace Pithos.Core.Agents
9 {
10     public enum CloudActionType
11     {
12         MustSynch,
13         UploadUnconditional,
14         DownloadUnconditional,
15         DeleteLocal,
16         DeleteCloud,
17         RenameCloud
18     }
19
20     public class CloudAction
21     {
22         public AccountInfo AccountInfo { get; set; }
23         public CloudActionType Action { get; set; }
24         public FileSystemInfo LocalFile { get; set; }
25         public ObjectInfo CloudFile { get; set; }
26         public FileState FileState { get; set; }
27         public string Container { get; set; }
28
29         public readonly DateTime Created = DateTime.Now;
30
31
32         public Lazy<string> LocalHash { get; protected set; }
33         private Lazy<string> _topHash;
34         public Lazy<string> TopHash
35         {
36             get { return _topHash; }
37             set { _topHash = value; }
38         }
39
40
41         [ContractInvariantMethod]
42         private void Invariants()
43         {
44             Contract.Invariant(AccountInfo!=null);
45         }
46
47         public bool IsShared
48         {
49             get { return  CloudFile!=null && AccountInfo.UserName != CloudFile.Account; }
50         }
51
52         protected CloudAction(AccountInfo accountInfo,CloudActionType action)
53         {
54             if (accountInfo==null)
55                 throw new ArgumentNullException("accountInfo");
56             Contract.EndContractBlock();
57
58             Action = action;
59             AccountInfo = accountInfo;
60         }
61
62         public CloudAction(AccountInfo accountInfo, CloudActionType action, FileSystemInfo localFile, ObjectInfo cloudFile, FileState state, int blockSize, string algorithm)
63             : this(accountInfo,action)
64         {
65             LocalFile = localFile.WithProperCapitalization();
66             CloudFile = cloudFile;
67             FileState = state;
68             if (LocalFile != null)
69             {
70
71                 LocalHash = new Lazy<string>(() => LocalFile.CalculateHash(blockSize,algorithm),
72                                              LazyThreadSafetyMode.ExecutionAndPublication);
73             }
74         }
75
76         //Calculate the download path for the cloud file
77         public string GetDownloadPath()
78         {
79             if (CloudFile == null)
80                 return String.Empty;
81             var filePath = CloudFile.RelativeUrlToFilePath(AccountInfo.UserName);
82             return Path.Combine(AccountInfo.AccountPath, filePath);
83         }
84
85         public override string ToString()
86         {
87             return String.Format("{0}:{1}->{2}", this.Action, this.LocalFile.FullName, this.CloudFile.Name);
88         }
89
90         protected static ObjectInfo CreateObjectInfoFor(AccountInfo accountInfo, FileSystemInfo fileInfo)
91         {
92             Contract.Requires(accountInfo!=null);
93             Contract.Requires(fileInfo!=null);
94             Contract.Ensures(Contract.Result<ObjectInfo>()!=null);
95
96             var capitalizedFileInfo = fileInfo.WithProperCapitalization();
97             var fullLocalName = capitalizedFileInfo.FullName;
98             var othersPath = Path.Combine(accountInfo.AccountPath, FolderConstants.OthersFolder);
99             
100             var isShared = fullLocalName.StartsWith(othersPath, StringComparison.InvariantCultureIgnoreCase);
101             if (isShared)
102             {                
103                 var pathRelativeToOther = fullLocalName.Substring(othersPath.Length + 1);
104                 var otherParts = pathRelativeToOther.Split('\\');
105                 var otherName = otherParts[0];
106                 var otherContainer = otherParts[1];
107                 return new ObjectInfo
108                            {
109                                Account = otherName, 
110                                Container = otherContainer, 
111                                Name = String.Join("/", otherParts.Splice(2))
112                            };
113             }
114             return new ObjectInfo(accountInfo.AccountPath, accountInfo.UserName, fileInfo);
115         }
116     }    
117
118     public class CloudDownloadAction:CloudAction
119     {
120         public CloudDownloadAction(AccountInfo accountInfo, ObjectInfo cloudFile)
121             :base(accountInfo,CloudActionType.DownloadUnconditional)
122         {            
123             if (String.IsNullOrWhiteSpace(cloudFile.Container))
124                 throw new ArgumentException("CloudFile.Container","cloudFile");
125             Contract.EndContractBlock();
126
127             CloudFile = cloudFile;
128         }
129
130         [ContractInvariantMethod]
131         private void Invariants()
132         {
133             Contract.Invariant(!String.IsNullOrWhiteSpace(CloudFile.Container));
134         }
135
136         public override string ToString()
137         {
138             return String.Format("{0}: _ <- {1}", this.Action, this.CloudFile.Name);
139         }
140         
141     }
142     public class CloudDeleteAction:CloudAction
143     {
144         public CloudDeleteAction(AccountInfo accountInfo,FileSystemInfo fileInfo, FileState fileState)
145             : this(accountInfo,fileInfo,CreateObjectInfoFor(accountInfo, fileInfo),fileState)
146         {            
147         }
148
149         public CloudDeleteAction(AccountInfo accountInfo, FileSystemInfo fileInfo,ObjectInfo cloudFile, FileState fileState) 
150             : base(accountInfo,CloudActionType.DeleteCloud)
151         {
152             CloudFile = cloudFile;
153             LocalFile = fileInfo;
154             FileState = fileState;
155         }
156
157         public CloudDeleteAction(CloudAction action)
158             : this(action.AccountInfo,action.LocalFile,action.CloudFile,action.FileState)
159         {}
160
161         [ContractInvariantMethod]
162         private void Invariants()
163         {
164             Contract.Invariant(!String.IsNullOrWhiteSpace(CloudFile.Container));
165         }
166
167         public override string ToString()
168         {
169             return String.Format("{0}: _ ->{1}", this.Action, this.CloudFile.Name);
170         }
171
172     }
173
174     public class CloudUploadAction:CloudAction
175     {
176         public CloudUploadAction(AccountInfo accountInfo, FileSystemInfo fileInfo, FileState state, int blockSize, string algorithm)
177             : base(accountInfo, CloudActionType.UploadUnconditional,fileInfo,CreateObjectInfoFor(accountInfo,fileInfo),state,blockSize,algorithm)             
178         {
179         }
180
181         [ContractInvariantMethod]
182         private void Invariants()
183         {
184             Contract.Invariant(!String.IsNullOrWhiteSpace(CloudFile.Container));
185         }
186
187     }
188
189     public class CloudMoveAction:CloudAction
190     {
191         public ObjectInfo OldCloudFile { get; set; }
192
193         public FileSystemInfo OldLocalFile { get; set; }
194
195         public CloudMoveAction(AccountInfo accountInfo, CloudActionType action, FileSystemInfo oldFile, FileSystemInfo newFile)
196             :base(accountInfo,action)
197         {
198             LocalFile = newFile;
199             CloudFile = CreateObjectInfoFor(accountInfo, newFile);
200             
201             OldLocalFile = oldFile;
202             OldCloudFile = CreateObjectInfoFor(accountInfo, oldFile);
203
204             //This is a rename operation, a hash will not be used
205             LocalHash = new Lazy<string>(() => String.Empty, LazyThreadSafetyMode.ExecutionAndPublication);
206         }
207
208         public override string ToString()
209         {
210             return String.Format("{0}:{1}->{2}", this.Action, OldCloudFile.Name, CloudFile.Name);
211         }
212
213     }
214
215 }