Selective Sync now shows both server AND local folders
[pithos-ms-client] / trunk / Pithos.Client.WPF / Utils / SelectiveExtensions.cs
1 using System;
2 using System.Collections.Generic;
3 using System.IO;
4 using System.Linq;
5 using System.Text;
6 using Pithos.Client.WPF.SelectiveSynch;
7 using Pithos.Interfaces;
8 using Pithos.Network;
9
10 namespace Pithos.Client.WPF.Utils
11 {
12     public static class SelectiveExtensions
13     {
14         public static List<DirectoryRecord> LocalFolders(string accountName, string accountPath,string storageUrl)
15         {
16             var storageUri = storageUrl.EndsWith("/")
17                                  ? new Uri(storageUrl)
18                                  : new Uri(storageUrl + "/");
19
20             var cacheFolder = Path.Combine(accountPath, FolderConstants.CacheFolder);
21
22             var dir = new DirectoryInfo(accountPath);
23             var orderedItems = from directory in dir.EnumerateDirectories("*", SearchOption.AllDirectories)
24                                 where !directory.FullName.StartsWith(cacheFolder,StringComparison.InvariantCultureIgnoreCase)
25                                 orderby directory.FullName
26                                 let relativeUrl=directory.WithProperCapitalization().AsRelativeUrlTo(accountPath)
27                                 let dirUri = new Uri(storageUri, relativeUrl)    
28                                 select new DirectoryRecord { DisplayName = directory.Name,Uri=dirUri};
29
30
31             return orderedItems.ToList();
32
33 /*
34             //Order the items to ensure that children always come after their parents
35             var lookups = new Dictionary<string, DirectoryRecord>();
36
37             //RootNodes contains only the root nodes
38             var rootNodes = new List<DirectoryRecord>();
39
40             foreach (var newNode in orderedItems)
41             {
42                 AddNode(rootNodes, lookups, newNode);
43             }
44             return rootNodes;
45 */
46         }
47         public static List<DirectoryRecord> ToTree(this IEnumerable<ObjectInfo> enumerable)
48         {
49             //Order the items to ensure that children always come after their parents
50             var orderedItems = enumerable.OrderBy(o => o.Uri.ToString());
51             //Each item is stored in lookups
52             var lookups = new Dictionary<string, DirectoryRecord>();
53
54             //RootNodes contains only the root nodes
55             var rootNodes = new List<DirectoryRecord>();
56
57             foreach (var item in orderedItems)
58             {
59                 var path = item.Uri.ToString();
60                 //Calculate the parent path
61                 var parentPath = GetParentPath(path);
62                 var parentName = GetParentPath(item.Name);
63                 DirectoryRecord parent;
64
65
66                 //First ensure that the parent items exist
67
68                 var parts = item.Name.Split('/');
69
70                 if (item.IsDirectory)
71                 {
72                     AddParentNodes(lookups, rootNodes, parts, item);
73
74                     //Store each item using its current path
75                     var newNode = new DirectoryRecord { DisplayName = parts.Last(), ObjectInfo = item };
76                     AddNode(rootNodes, lookups, newNode);
77                 }
78                 else
79                 {
80                     //Dont't add files
81                     //But check to ensure that we DO have it's parent on record
82                     //If it exist
83                     if (lookups.TryGetValue(parentPath, out parent))
84                     {
85                         //Just continue
86                         continue;
87                     }
88                     //If the item is directly below its parent container, there is no path to add
89                     if (String.IsNullOrWhiteSpace(parentName))
90                         continue;
91                     //Otherwise we need to add it, because it is missing from the list
92                     //Store each item using its current path
93                     //Since this is not a directory, we won't add the item itself
94                     AddParentNodes(lookups, rootNodes, parts, item);
95                 }
96             }
97             return rootNodes;
98         }
99
100         private static void AddParentNodes(Dictionary<string, DirectoryRecord> lookups, List<DirectoryRecord> rootNodes, string[] parts, ObjectInfo item)
101         {
102             for (int i = 0; i < parts.Length - 1; i++)
103             {
104                 var nodeName = String.Join("/", parts, 0, i + 1);
105                 var storageUri = GetStorageUri(item);
106                 var nodeKey = String.Format("{0}/{1}/{2}/{3}", storageUri, item.Account, item.Container, nodeName);
107                 //If the node was already addeds, skip
108                 if (lookups.ContainsKey(nodeKey))
109                     continue;
110                 var newNode = new DirectoryRecord
111                 {
112                     DisplayName = parts[i],
113                     ObjectInfo = new ObjectInfo
114                     {
115                         Account = item.Account,
116                         Container = item.Container,
117                         Name = nodeName,
118                         StorageUri = item.StorageUri,
119                         Content_Type = "application/directory"
120                     }
121                 };
122                 AddNode(rootNodes, lookups, newNode);
123             }
124         }
125
126         private static string GetStorageUri(ObjectInfo item)
127         {
128             var storageParts = item.StorageUri.ToString().Split('/');
129             var accountUri = String.Join("/", storageParts, 0, storageParts.Length - 1);
130             return accountUri;
131         }
132
133         private static void AddNode(List<DirectoryRecord> rootNodes, Dictionary<string, DirectoryRecord> lookups, DirectoryRecord newNode)
134         {
135             DirectoryRecord parent;
136             var path = newNode.Uri.ToString();
137             var parentPath = GetParentPath(path);
138             lookups[path] = newNode;
139
140             //If the record is a directory, we need to add it no matter what
141
142             //If it is a file, we need to check that its parent node exists
143             //If the parent node doesn't exist, we need to add a node for it.
144             //We need to add nodes for all parents recursively,in case they don't exist
145
146             //Does a parent item exist? 
147             if (lookups.TryGetValue(parentPath, out parent))
148             {
149                 //If so, add the current item under its parent
150                 parent.Directories.Add(newNode);
151                 parent.Directories.Sort((x, y) => String.CompareOrdinal(x.Uri.ToString(), y.Uri.ToString()));
152             }
153             else
154                 //Otherwise add it to the list of root nodes
155                 rootNodes.Add(newNode);
156         }
157
158         private static string GetParentPath(string path)
159         {
160             var lastIndex = path.LastIndexOf("/", StringComparison.Ordinal);
161             if (lastIndex < 0)
162                 return null;
163             var parentPath = path.Substring(0, lastIndex);
164             return parentPath;
165         }
166
167     }
168 }