root / trunk / Pithos.Client.WPF / Utils / EnumerableExtensions.cs @ 2341c603
History | View | Annotate | Download (8.3 kB)
1 |
using System; |
---|---|
2 |
using System.Collections; |
3 |
using System.Collections.Generic; |
4 |
using System.Linq; |
5 |
using System.Linq.Expressions; |
6 |
using System.Text; |
7 |
using System.Text.RegularExpressions; |
8 |
using Pithos.Client.WPF.SelectiveSynch; |
9 |
using Pithos.Core; |
10 |
using Pithos.Interfaces; |
11 |
|
12 |
namespace Pithos.Client.WPF.Utils |
13 |
{ |
14 |
public static class EnumerableExtensions |
15 |
{ |
16 |
public static IEnumerable<T> Slice<T>(this IEnumerable<T> collection, int start, int end) |
17 |
{ |
18 |
int index = 0; |
19 |
int count = 0; |
20 |
|
21 |
if (collection == null) |
22 |
throw new ArgumentNullException("collection"); |
23 |
|
24 |
// Optimise item count for ICollection interfaces. |
25 |
if (collection is ICollection<T>) |
26 |
count = ((ICollection<T>)collection).Count; |
27 |
else if (collection is ICollection) |
28 |
count = ((ICollection)collection).Count; |
29 |
else |
30 |
{ |
31 |
count = collection.Count(); |
32 |
} |
33 |
|
34 |
// Get start/end indexes, negative numbers start at the end of the collection. |
35 |
if (start < 0) |
36 |
start += count; |
37 |
|
38 |
if (end < 0) |
39 |
end += count; |
40 |
|
41 |
foreach (var item in collection) |
42 |
{ |
43 |
if (index >= end) |
44 |
yield break; |
45 |
|
46 |
if (index >= start) |
47 |
yield return item; |
48 |
|
49 |
++index; |
50 |
} |
51 |
} |
52 |
|
53 |
public static IEnumerable<Node<T>> ToTree<TSource,T>(this IEnumerable<TSource> enumerable,Func<TSource,string> pathFunc,Func<TSource,T> valueFunc,string delimiter="/") |
54 |
{ |
55 |
var orderedItems=enumerable.OrderBy(pathFunc); |
56 |
var lookups = new Dictionary<string,Node<T>>(); |
57 |
var nodes = new List<Node<T>>(); |
58 |
foreach (var item in orderedItems) |
59 |
{ |
60 |
var path = pathFunc(item); |
61 |
var value = valueFunc(item); |
62 |
var newNode = new Node<T> { Path = path,Data=value }; |
63 |
lookups[path] = newNode; |
64 |
|
65 |
var lastIndex = path.LastIndexOf(delimiter, StringComparison.Ordinal); |
66 |
var upTo = lastIndex < 0 ? path.Length - 1 : lastIndex; |
67 |
var parentPath = path.Substring(0, upTo); |
68 |
|
69 |
Node<T> parent; |
70 |
if (lookups.TryGetValue(parentPath, out parent)) |
71 |
{ |
72 |
parent.Children.Add(newNode); |
73 |
parent.Children.Sort((x,y)=>String.CompareOrdinal(x.Path, y.Path)); |
74 |
} |
75 |
else |
76 |
nodes.Add(newNode); |
77 |
|
78 |
} |
79 |
return nodes; |
80 |
} |
81 |
|
82 |
public static List<DirectoryRecord> ToTree(this IEnumerable<ObjectInfo> enumerable) |
83 |
{ |
84 |
//Order the items to ensure that children always come after their parents |
85 |
var orderedItems=enumerable.OrderBy(o=>o.Uri.ToString()); |
86 |
//Each item is stored in lookups |
87 |
var lookups = new Dictionary<string,DirectoryRecord>(); |
88 |
|
89 |
//RootNodes contains only the root nodes |
90 |
var rootNodes = new List<DirectoryRecord>(); |
91 |
|
92 |
foreach (var item in orderedItems) |
93 |
{ |
94 |
var path = item.Uri.ToString(); |
95 |
//Calculate the parent path |
96 |
var parentPath = GetParentPath(path); |
97 |
var parentName = GetParentPath(item.Name); |
98 |
DirectoryRecord parent; |
99 |
|
100 |
|
101 |
//First ensure that the parent items exist |
102 |
|
103 |
var parts = item.Name.Split('/'); |
104 |
|
105 |
if (item.IsDirectory) |
106 |
{ |
107 |
AddParentNodes(lookups, rootNodes, parts, item); |
108 |
|
109 |
//Store each item using its current path |
110 |
var newNode = new DirectoryRecord {DisplayName = parts.Last(), ObjectInfo = item}; |
111 |
AddNode(rootNodes, lookups, newNode); |
112 |
} |
113 |
else |
114 |
{ |
115 |
//Dont't add files |
116 |
//But check to ensure that we DO have it's parent on record |
117 |
//If it exist |
118 |
if (lookups.TryGetValue(parentPath, out parent)) |
119 |
{ |
120 |
//Just continue |
121 |
continue; |
122 |
} |
123 |
//If the item is directly below its parent container, there is no path to add |
124 |
if (String.IsNullOrWhiteSpace(parentName)) |
125 |
continue; |
126 |
//Otherwise we need to add it, because it is missing from the list |
127 |
//Store each item using its current path |
128 |
//Since this is not a directory, we won't add the item itself |
129 |
AddParentNodes(lookups, rootNodes, parts, item); |
130 |
} |
131 |
} |
132 |
return rootNodes; |
133 |
} |
134 |
|
135 |
private static void AddParentNodes(Dictionary<string, DirectoryRecord> lookups, List<DirectoryRecord> rootNodes, string[] parts, ObjectInfo item) |
136 |
{ |
137 |
for (int i = 0; i < parts.Length - 1; i++) |
138 |
{ |
139 |
var nodeName = String.Join("/", parts, 0, i + 1); |
140 |
var storageUri = GetStorageUri(item); |
141 |
var nodeKey = String.Format("{0}/{1}/{2}/{3}", storageUri, item.Account,item.Container, nodeName); |
142 |
//If the node was already addeds, skip |
143 |
if (lookups.ContainsKey(nodeKey)) |
144 |
continue; |
145 |
var newNode = new DirectoryRecord |
146 |
{ |
147 |
DisplayName = parts[i], |
148 |
ObjectInfo = new ObjectInfo |
149 |
{ |
150 |
Account = item.Account, |
151 |
Container = item.Container, |
152 |
Name = nodeName, |
153 |
StorageUri=item.StorageUri, |
154 |
Content_Type = "application/directory" |
155 |
} |
156 |
}; |
157 |
AddNode(rootNodes, lookups, newNode); |
158 |
} |
159 |
} |
160 |
|
161 |
private static string GetStorageUri(ObjectInfo item) |
162 |
{ |
163 |
var storageParts = item.StorageUri.ToString().Split('/'); |
164 |
var accountUri = String.Join("/", storageParts, 0, storageParts.Length - 1); |
165 |
return accountUri; |
166 |
} |
167 |
|
168 |
private static void AddNode(List<DirectoryRecord> rootNodes, Dictionary<string, DirectoryRecord> lookups, DirectoryRecord newNode) |
169 |
{ |
170 |
DirectoryRecord parent; |
171 |
var path = newNode.ObjectInfo.Uri.ToString(); |
172 |
var parentPath = GetParentPath(path); |
173 |
lookups[path] = newNode; |
174 |
|
175 |
//If the record is a directory, we need to add it no matter what |
176 |
|
177 |
//If it is a file, we need to check that its parent node exists |
178 |
//If the parent node doesn't exist, we need to add a node for it. |
179 |
//We need to add nodes for all parents recursively,in case they don't exist |
180 |
|
181 |
//Does a parent item exist? |
182 |
if (lookups.TryGetValue(parentPath, out parent)) |
183 |
{ |
184 |
//If so, add the current item under its parent |
185 |
parent.Directories.Add(newNode); |
186 |
parent.Directories.Sort((x, y) => String.CompareOrdinal(x.Uri.ToString(), y.Uri.ToString())); |
187 |
} |
188 |
else |
189 |
//Otherwise add it to the list of root nodes |
190 |
rootNodes.Add(newNode); |
191 |
} |
192 |
|
193 |
private static string GetParentPath(string path) |
194 |
{ |
195 |
var lastIndex = path.LastIndexOf("/", StringComparison.Ordinal); |
196 |
if (lastIndex < 0) |
197 |
return null; |
198 |
var parentPath = path.Substring(0, lastIndex); |
199 |
return parentPath; |
200 |
} |
201 |
|
202 |
static readonly Regex PascalCaseRegex = new Regex("[a-z][A-Z]", RegexOptions.Compiled); |
203 |
public static string Name(this Enum value) |
204 |
{ |
205 |
var name = Enum.GetName(value.GetType(), value); |
206 |
return PascalCaseRegex.Replace(name, m => m.Value[0] + " " + char.ToLower(m.Value[1])); |
207 |
} |
208 |
} |
209 |
} |