Package updates, added test server
[pithos-ms-client] / trunk / Pithos.OFM / Extensions.cs
1 using System;\r
2 using System.Collections.Generic;\r
3 using System.Linq;\r
4 using System.Text;\r
5 using Pithos.Interfaces;\r
6 \r
7 namespace Pithos.OFM\r
8 {\r
9     static class Extensions\r
10     {\r
11         public static List<ObjectRecord> ToTree(this IEnumerable<ObjectInfo> enumerable)\r
12         {\r
13             //Order the items to ensure that children always come after their parents\r
14             var orderedItems = enumerable.OrderBy(o => o.Uri.ToString());\r
15             //Each item is stored in lookups\r
16             var lookups = new Dictionary<string, ObjectRecord>();\r
17 \r
18             //RootNodes contains only the root nodes\r
19             var rootNodes = new List<ObjectRecord>();\r
20 \r
21             foreach (var item in orderedItems)\r
22             {\r
23                 var path = item.Uri.ToString();\r
24                 //Calculate the parent path\r
25                 var parentPath = GetParentPath(path);\r
26                 var parentName = GetParentPath(item.Name.ToString());\r
27                 ObjectRecord parent;\r
28 \r
29 \r
30                 //First ensure that the parent items exist\r
31 \r
32                 //We don't want to unescape here\r
33                 var parts = item.Name.ToString().Split('/');\r
34 \r
35                 if (item.IsDirectory)\r
36                 {\r
37                     AddParentNodes(lookups, rootNodes, parts, item);\r
38 \r
39                     //Store each item using its current path\r
40                     var newNode = new ObjectRecord { DisplayName = parts.Last(), ObjectInfo = item };\r
41                     AddNode(rootNodes, lookups, newNode);\r
42                 }\r
43                 else\r
44                 {\r
45                     //Dont't add files\r
46                     //But check to ensure that we DO have it's parent on record\r
47                     //If it exist\r
48                     if (lookups.TryGetValue(parentPath, out parent))\r
49                     {\r
50                         //Just continue\r
51                         continue;\r
52                     }\r
53                     //If the item is directly below its parent container, there is no path to add\r
54                     if (String.IsNullOrWhiteSpace(parentName))\r
55                         continue;\r
56                     //Otherwise we need to add it, because it is missing from the list\r
57                     //Store each item using its current path\r
58                     //Since this is not a directory, we won't add the item itself\r
59                     AddParentNodes(lookups, rootNodes, parts, item);\r
60                 }\r
61             }\r
62             return rootNodes;\r
63         }\r
64         private static void AddNode(List<ObjectRecord> rootNodes, Dictionary<string, ObjectRecord> lookups, ObjectRecord newNode)\r
65         {\r
66             ObjectRecord parent;\r
67             var path = newNode.Uri.ToString();\r
68             var parentPath = GetParentPath(path);\r
69             lookups[path] = newNode;\r
70 \r
71             //If the record is a directory, we need to add it no matter what\r
72 \r
73             //If it is a file, we need to check that its parent node exists\r
74             //If the parent node doesn't exist, we need to add a node for it.\r
75             //We need to add nodes for all parents recursively,in case they don't exist\r
76 \r
77             //Does a parent item exist? \r
78             if (lookups.TryGetValue(parentPath, out parent))\r
79             {\r
80                 //If so, add the current item under its parent\r
81                 parent.Directories.Add(newNode);\r
82                 parent.Directories.Sort((x, y) => String.CompareOrdinal(x.Uri.ToString(), y.Uri.ToString()));\r
83             }\r
84             else\r
85                 //Otherwise add it to the list of root nodes\r
86                 rootNodes.Add(newNode);\r
87         }\r
88 \r
89         private static string GetParentPath(string path)\r
90         {\r
91             var lastIndex = path.LastIndexOf("/", StringComparison.Ordinal);\r
92             if (lastIndex < 0)\r
93                 return null;\r
94             var parentPath = path.Substring(0, lastIndex);\r
95             return parentPath;\r
96         }\r
97 \r
98         private static void AddParentNodes(Dictionary<string, ObjectRecord> lookups, List<ObjectRecord> rootNodes, string[] parts, ObjectInfo item)\r
99         {\r
100             for (int i = 0; i < parts.Length - 1; i++)\r
101             {\r
102                 //The parts come from the ObjectInfo URI, therefore they should already be escaped\r
103                 var nodeName = String.Join("/", parts, 0, i + 1);\r
104                 var storageUri = GetStorageUri(item);\r
105                 var nodeKey = String.Format("{0}/{1}/{2}/{3}", storageUri, item.Account, item.Container, nodeName);\r
106                 //If the node was already addeds, skip\r
107                 if (lookups.ContainsKey(nodeKey))\r
108                     continue;\r
109                 var newNode = new ObjectRecord\r
110                 {\r
111                     DisplayName = parts[i],\r
112                     ObjectInfo = new ObjectInfo\r
113                     {\r
114                         Account = item.Account,\r
115                         Container = item.Container,\r
116                         Name = new Uri(nodeName, UriKind.Relative),\r
117                         StorageUri = item.StorageUri,\r
118                         Content_Type = "application/directory"\r
119                     }\r
120                 };\r
121                 AddNode(rootNodes, lookups, newNode);\r
122             }\r
123         }\r
124 \r
125         private static string GetStorageUri(ObjectInfo item)\r
126         {\r
127             var storageParts = item.StorageUri.ToString().Split('/');\r
128             var accountUri = String.Join("/", storageParts, 0, storageParts.Length - 1);\r
129             return accountUri;\r
130         }\r
131 \r
132     }\r
133 }\r