Logging changes, first changes to multi account support
[pithos-ms-client] / trunk / Pithos.Core / FileState.cs
1 // -----------------------------------------------------------------------
2 // <copyright file="FileState.cs" company="Microsoft">
3 // TODO: Update copyright text.
4 // </copyright>
5 // -----------------------------------------------------------------------
6
7 using System.Diagnostics.Contracts;
8 using System.IO;
9 using System.Threading.Tasks;
10 using Castle.ActiveRecord;
11 using Castle.ActiveRecord.Framework;
12 using Castle.ActiveRecord.Queries;
13 using NHibernate.Engine;
14 using Pithos.Core.Agents;
15 using Pithos.Interfaces;
16 using Pithos.Network;
17
18 namespace Pithos.Core
19 {
20     using System;
21     using System.Collections.Generic;
22     using System.Linq;
23     using System.Text;
24
25     /// <summary>
26     /// TODO: Update summary.
27     /// </summary>
28     [ActiveRecord]
29     public class FileState:ActiveRecordLinqBase<FileState>
30     {
31         private string _filePath;
32         private IList<FileTag> _tags=new List<FileTag>();
33
34         [PrimaryKey(PrimaryKeyType.Guid)]
35         public Guid Id { get; set; }
36
37         [Property(Unique=true,UniqueKey="IX_FileState_FilePath")]
38         public string FilePath
39         {
40             get { return _filePath; }
41             set { _filePath = value.ToLower(); }
42         }
43
44         [Property]
45         public FileOverlayStatus OverlayStatus { get; set; }
46
47         [Property]
48         public FileStatus FileStatus { get; set; }
49
50         [Property]
51         public string Checksum { get; set; }
52
53 /*
54         [Property]
55         public string TopHash { get; set; }
56 */
57
58         [Property]
59         public long? Version { get; set; }
60
61         [Property]
62         public DateTime? VersionTimeStamp { get; set; }
63
64
65         [Property]
66         public bool IsShared { get; set; }
67
68         [Property]
69         public string SharedBy { get; set; }
70
71         [Property]
72         public bool ShareWrite { get; set; }
73
74
75        [HasMany(Cascade = ManyRelationCascadeEnum.AllDeleteOrphan, Lazy = true,Inverse=true)]
76         public IList<FileTag> Tags
77         {
78             get { return _tags; }   
79             set { _tags=value;}
80         }
81
82 //        [HasMany(Cascade = ManyRelationCascadeEnum.AllDeleteOrphan, Lazy = true)]
83 //        public IList<FileHash> Hashes { get; set; }
84
85 //        [Property]
86 //        public byte[] HashmapHash { get; set; }
87        
88         public static FileState FindByFilePath(string absolutePath)
89         {
90             if (string.IsNullOrWhiteSpace(absolutePath))
91                 throw new ArgumentNullException("absolutePath");
92             Contract.EndContractBlock();
93             return Queryable.FirstOrDefault(s => s.FilePath == absolutePath.ToLower());
94         }
95
96         public static void DeleteByFilePath(string absolutePath)
97         {
98             if(string.IsNullOrWhiteSpace(absolutePath))
99                 throw new ArgumentNullException("absolutePath");
100             Contract.EndContractBlock();
101             
102             FileState.Execute((session, instance) =>
103                              {
104                                  const string hqlDelete = "delete FileState where FilePath = :path";                                 
105                                  var deletedEntities = session.CreateQuery(hqlDelete)
106                                          .SetString("path", absolutePath.ToLower())
107                                          .ExecuteUpdate();
108                                  return null;
109                              },null);
110             
111         }
112
113         public static void ChangeRootPath(string oldPath,string newPath)
114         {
115             if (String.IsNullOrWhiteSpace(oldPath))
116                 throw new ArgumentNullException("oldPath");
117             if (!Path.IsPathRooted(oldPath))
118                 throw new ArgumentException("oldPath must be an absolute path", "oldPath");
119             if (string.IsNullOrWhiteSpace(newPath))
120                 throw new ArgumentNullException("newPath");
121             if (!Path.IsPathRooted(newPath))
122                 throw new ArgumentException("newPath must be an absolute path", "newPath");
123             Contract.EndContractBlock();
124
125             //Ensure the paths end with the same character
126             if (!oldPath.EndsWith("\\"))
127                 oldPath = oldPath + "\\";
128             if (!newPath.EndsWith("\\"))
129                 newPath = newPath + "\\";
130
131             using (new TransactionScope())
132             {
133                 Execute((session, instance) =>
134                             {
135                                 const string hqlUpdate =
136                                     "update FileState set FilePath = replace(FilePath,:oldPath,:newPath) where FilePath like :oldPath || '%' ";
137                                 var result=session.CreateQuery(hqlUpdate)
138                                     .SetString("oldPath", oldPath.ToLower())
139                                     .SetString("newPath", newPath.ToLower())
140                                     .ExecuteUpdate();
141                                 return null;
142                             }, null);
143             }
144         }
145
146         public static Task<FileState> CreateForAsync(string filePath,int blockSize,string algorithm)
147         {
148             if (blockSize <= 0)
149                 throw new ArgumentOutOfRangeException("blockSize");
150             if (String.IsNullOrWhiteSpace(algorithm))
151                 throw new ArgumentNullException("algorithm");
152             Contract.EndContractBlock();
153
154
155             var fileState = new FileState
156                                 {
157                                     FilePath = filePath, 
158                                     OverlayStatus = FileOverlayStatus.Unversioned, 
159                                     FileStatus = FileStatus.Created,
160                                     Id=Guid.NewGuid()
161                                 };
162
163
164             return fileState.UpdateHashesAsync(blockSize,algorithm);            
165         }
166
167         public Task<FileState> UpdateHashesAsync(int blockSize,string algorithm)
168         {
169             if (blockSize<=0)
170                 throw new ArgumentOutOfRangeException("blockSize");
171             if (String.IsNullOrWhiteSpace(algorithm))
172                 throw new ArgumentNullException("algorithm");
173             Contract.EndContractBlock();
174             
175             //Skip updating the hash for folders
176             if (Directory.Exists(FilePath))
177                 return Task.Factory.FromResult(this);
178
179             var results = Task.Factory.StartNew(() =>
180             {
181                 var info = new FileInfo(FilePath);
182                 return info.CalculateHash(blockSize, algorithm);
183             });
184
185             var state=results.Then(hash =>
186             {
187                 Checksum = hash;
188                 return Task.Factory.FromResult(this);
189             });
190             
191             return state;
192         }
193     }
194
195     [ActiveRecord("Tags")]
196     public class FileTag : ActiveRecordLinqBase<FileTag>
197     {
198         [PrimaryKey]
199         public int Id { get; set; }
200
201         [Property]
202         public string Name { get; set; }
203
204         [Property]
205         public string Value { get; set; }
206
207         [BelongsTo("FileStateId")]
208         public FileState FileState { get; set; }
209
210     }
211     
212   /*  [ActiveRecord("hashes")]
213     public class FileHash : ActiveRecordLinqBase<FileHash>
214     {
215         [PrimaryKey]
216         public int Id { get; set; }
217
218         [Property]
219         public int Order { get; set; }
220
221         [Property]
222         public byte[] Value { get; set; }        
223
224         [BelongsTo("FileStateID")]
225         public FileState FileState { get; set; }
226
227     }*/
228
229
230 }