Statistics
| Branch: | Revision:

root / trunk / Pithos.Client.WPF / Utils / EnumerableExtensions.cs @ 85c6af07

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
                //Dont't add files
106
                if (!item.IsDirectory)
107
                {
108
                    //But check to ensure that we DO have it's parent on record
109
                    //It it exist
110
                    if (lookups.TryGetValue(parentPath, out parent))
111
                    {
112
                        //Just continue
113
                        continue;
114
                    }
115
                    //If the item is directly below its parent container, there is no path to add
116
                    if (String.IsNullOrWhiteSpace(parentName))
117
                        continue;
118
                    //Otherwise we need to add it, because it is missing from the list
119
                    //Store each item using its current path
120
                    //Since this is not a directory, we won't add the item itself
121
                    AddParentNodes(lookups, rootNodes, parts, item);
122
                }
123
                else
124
                {
125
                    AddParentNodes(lookups, rootNodes, parts, item);
126

    
127
                    //Store each item using its current path
128
                    var newNode = new DirectoryRecord {DisplayName = parts.Last(), ObjectInfo = item};
129
                    AddNode(rootNodes, lookups, newNode);
130
                }
131
                
132
            }
133
            return rootNodes;
134
        }
135

    
136
        private static void AddParentNodes(Dictionary<string, DirectoryRecord> lookups, List<DirectoryRecord> rootNodes, string[] parts, ObjectInfo item)
137
        {
138
            for (int i = 0; i < parts.Length - 1; i++)
139
            {
140
                var nodeName = String.Join("/", parts, 0, i + 1);
141
                var storageUri = GetStorageUri(item);
142
                var nodeKey = String.Format("{0}/{1}/{2}/{3}", storageUri, item.Account,item.Container, nodeName);
143
                //If the node was already addeds, skip
144
                if (lookups.ContainsKey(nodeKey))
145
                    continue;
146
                var newNode = new DirectoryRecord
147
                                  {
148
                                      DisplayName = parts[i],
149
                                      ObjectInfo = new ObjectInfo
150
                                                       {
151
                                                           Account = item.Account,
152
                                                           Container = item.Container,
153
                                                           Name = nodeName,
154
                                                           StorageUri=item.StorageUri,
155
                                                           Content_Type = "application/directory"
156
                                                       }
157
                                  };
158
                AddNode(rootNodes, lookups, newNode);
159
            }
160
        }
161

    
162
        private static string GetStorageUri(ObjectInfo item)
163
        {
164
            var storageParts = item.StorageUri.ToString().Split('/');
165
            var accountUri = String.Join("/", storageParts, 0, storageParts.Length - 1);
166
            return accountUri;
167
        }
168

    
169
        private static void AddNode(List<DirectoryRecord> rootNodes, Dictionary<string, DirectoryRecord> lookups, DirectoryRecord newNode)
170
        {
171
            DirectoryRecord parent;
172
            var path = newNode.ObjectInfo.Uri.ToString();
173
            var parentPath = GetParentPath(path);
174
            lookups[path] = newNode;
175

    
176
            //If the record is a directory, we need to add it no matter what
177

    
178
            //If it is a file, we need to check that its parent node exists
179
            //If the parent node doesn't exist, we need to add a node for it.
180
            //We need to add nodes for all parents recursively,in case they don't exist
181

    
182
            //Does a parent item exist? 
183
            if (lookups.TryGetValue(parentPath, out parent))
184
            {
185
                //If so, add the current item under its parent
186
                parent.Directories.Add(newNode);
187
                parent.Directories.Sort((x, y) => String.CompareOrdinal(x.Uri.ToString(), y.Uri.ToString()));
188
            }
189
            else
190
                //Otherwise add it to the list of root nodes
191
                rootNodes.Add(newNode);
192
        }
193

    
194
        private static string GetParentPath(string path)
195
        {            
196
            var lastIndex = path.LastIndexOf("/", StringComparison.Ordinal);
197
            if (lastIndex < 0)
198
                return null;
199
            var parentPath = path.Substring(0, lastIndex);
200
            return parentPath;
201
        }
202

    
203
        static readonly Regex PascalCaseRegex = new Regex("[a-z][A-Z]", RegexOptions.Compiled);        
204
        public static string Name(this  Enum value)
205
        {
206
            var name = Enum.GetName(value.GetType(), value);            
207
            return PascalCaseRegex.Replace(name, m => m.Value[0] + " " + char.ToLower(m.Value[1]));            
208
        }
209
    }
210
}