Fix the build.
[castle.git] / MonoRail / Castle.MonoRail.Framework / UrlPartsBuilder.cs
blobe353c8db19befc746b6c27b8f58a4faf9c56b649
1 // Copyright 2004-2007 Castle Project - http://www.castleproject.org/
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
15 namespace Castle.MonoRail.Framework
17 using System;
18 using System.Collections.Generic;
19 using System.Collections.Specialized;
20 using System.Text;
21 using Internal;
23 /// <summary>
24 /// Pendent
25 /// </summary>
26 public class UrlPartsBuilder
28 private readonly StringBuilder url;
29 private PathInfoBuilder pathInfoBuilder;
30 private PathInfoDictBuilder pathInfoDictBuilder;
31 private bool nextPathBelongsToPathInfo;
32 private string queryString;
33 private NameValueCollection queryStringDict;
35 /// <summary>
36 /// Initializes a new instance of the <see cref="UrlPartsBuilder"/> class.
37 /// </summary>
38 /// <param name="pathPieces">The path pieces.</param>
39 public UrlPartsBuilder(params string[] pathPieces)
41 url = new StringBuilder();
43 AppendPaths(pathPieces);
46 /// <summary>
47 /// Pendent
48 /// </summary>
49 /// <param name="url">The URL.</param>
50 /// <returns></returns>
51 public static UrlPartsBuilder Parse(string url)
53 if (url == null)
55 throw new ArgumentNullException("url");
58 Uri uri = new Uri(url, UriKind.RelativeOrAbsolute);
60 if (uri.IsAbsoluteUri)
62 return CreateForAbsolutePath(uri);
64 else
66 return CreateForRelativePath(url);
70 /// <summary>
71 /// Gets the path info builder.
72 /// </summary>
73 /// <value>The path info.</value>
74 public PathInfoBuilder PathInfo
76 get
78 if (pathInfoBuilder == null)
80 pathInfoBuilder = new PathInfoBuilder(this);
82 return pathInfoBuilder;
86 /// <summary>
87 /// Gets the path info builder with dictionary api.
88 /// </summary>
89 /// <value>The path info.</value>
90 public PathInfoDictBuilder PathInfoDict
92 get
94 if (pathInfoDictBuilder == null)
96 pathInfoDictBuilder = new PathInfoDictBuilder(this);
98 return pathInfoDictBuilder;
102 /// <summary>
103 /// Pendent
104 /// </summary>
105 /// <param name="queryStringParam">The query string.</param>
106 public UrlPartsBuilder SetQueryString(string queryStringParam)
108 if (queryStringParam != null && queryStringParam.StartsWith("?"))
110 queryStringParam = queryStringParam.Substring(1);
113 queryString = queryStringParam;
115 return this;
118 /// <summary>
119 /// Pendent
120 /// </summary>
121 /// <value>The query string.</value>
122 public NameValueCollection QueryString
126 if (queryStringDict == null)
128 queryStringDict = CreateQueryStringNameValueCollection(queryString);
131 return queryStringDict;
135 /// <summary>
136 /// Pendent
137 /// </summary>
138 /// <returns></returns>
139 public string QueryStringAsString()
141 if (queryStringDict != null)
143 queryString = CommonUtils.BuildQueryString(queryStringDict);
146 return queryString;
149 /// <summary>
150 /// Pendent
151 /// </summary>
152 /// <returns></returns>
153 public UrlPartsBuilder ConvertPathInfoToDict()
155 if (pathInfoBuilder == null)
157 return this;
160 PathInfoDict.Parse(pathInfoBuilder.ToString());
162 pathInfoBuilder = null;
164 return this;
167 /// <summary>
168 /// Builds the path.
169 /// </summary>
170 /// <returns></returns>
171 public string BuildPath()
173 StringBuilder sb = new StringBuilder(url.ToString());
175 BuildPathInfo(sb);
177 if (queryStringDict != null && queryStringDict.Count != 0)
179 sb.Append('?');
180 sb.Append(QueryStringAsString());
182 else if (!string.IsNullOrEmpty(queryString))
184 sb.Append('?');
185 sb.Append(queryString);
188 return sb.ToString();
191 /// <summary>
192 /// Builds the path.
193 /// </summary>
194 /// <returns></returns>
195 public string BuildPathForLink(IServerUtility serverUtiliy)
197 StringBuilder sb = new StringBuilder(url.ToString());
199 BuildPathInfo(sb);
201 if (queryStringDict != null && queryStringDict.Count != 0)
203 sb.Append('?');
204 sb.Append(CommonUtils.BuildQueryString(serverUtiliy, QueryString, true));
207 return sb.ToString();
210 /// <summary>
211 /// Pendent
212 /// </summary>
213 /// <param name="piece">The piece.</param>
214 public UrlPartsBuilder AppendPath(string piece)
216 if (piece.EndsWith("/"))
218 piece = piece.Substring(0, piece.Length - 1);
221 if (nextPathBelongsToPathInfo)
223 PathInfo.Add(piece);
225 else
227 if (!piece.StartsWith("/") && HasLastChar && LastChar != '/')
229 url.Append('/');
232 url.Append(piece);
235 if (HasLastChar && piece.IndexOf('.') != -1) // this is fragile!
237 nextPathBelongsToPathInfo = true;
240 return this;
243 private void AppendPaths(string[] pieces)
245 foreach (string piece in pieces)
247 AppendPath(piece);
251 private bool HasLastChar
253 get { return url.Length != 0; }
256 private char LastChar
260 if (url.Length != 0)
262 return url[url.Length - 1];
265 return '\0';
269 private void BuildPathInfo(StringBuilder sb)
271 if (pathInfoBuilder != null)
273 pathInfoBuilder.Build(sb);
275 if (pathInfoDictBuilder != null)
277 pathInfoDictBuilder.Build(sb);
281 private static UrlPartsBuilder CreateForRelativePath(string url)
283 string path = url;
284 string qs = null;
285 string pathInfo = null;
287 int queryStringStartIndex = url.IndexOf('?');
288 int fileExtIndex = url.IndexOf('.');
290 if (queryStringStartIndex != -1)
292 qs = url.Substring(queryStringStartIndex);
293 path = url.Substring(0, queryStringStartIndex);
296 if (fileExtIndex != -1)
298 int pathInfoStartIndex = path.IndexOf('/', fileExtIndex);
300 if (pathInfoStartIndex != -1)
302 pathInfo = path.Substring(pathInfoStartIndex);
303 path = path.Substring(0, pathInfoStartIndex);
307 UrlPartsBuilder parts = new UrlPartsBuilder(path);
308 parts.SetQueryString(qs);
309 parts.PathInfoDict.Parse(pathInfo);
311 return parts;
314 private static UrlPartsBuilder CreateForAbsolutePath(Uri uri)
316 string host = uri.AbsoluteUri.Substring(0, uri.AbsoluteUri.Length - uri.PathAndQuery.Length);
318 UrlPartsBuilder parts = new UrlPartsBuilder(host);
320 foreach (string segment in uri.Segments)
322 parts.AppendPath(segment);
325 parts.ConvertPathInfoToDict();
326 parts.SetQueryString(uri.Query);
328 return parts;
331 private static NameValueCollection CreateQueryStringNameValueCollection(string queryString)
333 NameValueCollection coll = new NameValueCollection(StringComparer.InvariantCultureIgnoreCase);
335 if (queryString == null)
337 return coll;
340 foreach(string valuePair in queryString.Split('&'))
342 string[] pairs = valuePair.Split(new char[] { '=' }, 2);
344 if (pairs.Length == 2)
346 coll.Add(pairs[0], pairs[1]);
348 else if (pairs.Length == 1)
350 coll.Add(pairs[0], string.Empty);
354 return coll;
357 /// <summary>
358 /// Pendent
359 /// </summary>
360 public class PathInfoBuilder
362 private readonly UrlPartsBuilder parent;
363 private readonly List<string> pieces;
365 /// <summary>
366 /// Initializes a new instance of the <see cref="PathInfoBuilder"/> class.
367 /// </summary>
368 /// <param name="parent">The parent.</param>
369 public PathInfoBuilder(UrlPartsBuilder parent)
371 this.parent = parent;
372 pieces = new List<string>();
375 /// <summary>
376 /// Adds a path info piece.
377 /// </summary>
378 /// <param name="pathInfoPiece">The path info piece.</param>
379 /// <returns></returns>
380 public PathInfoBuilder Add(string pathInfoPiece)
382 pieces.Add(pathInfoPiece);
383 return this;
386 /// <summary>
387 /// Returns to the previous builder context.
388 /// </summary>
389 public UrlPartsBuilder Done
391 get { return parent; }
394 /// <summary>
395 /// Returns a <see cref="T:System.String"></see> that represents the current <see cref="T:System.Object"></see>.
396 /// </summary>
398 /// <returns>
399 /// A <see cref="T:System.String"></see> that represents the current <see cref="T:System.Object"></see>.
400 /// </returns>
401 public override string ToString()
403 StringBuilder sb = new StringBuilder();
405 pieces.ForEach(delegate(string piece) { sb.Append(piece).Append('/'); });
407 return sb.ToString();
410 /// <summary>
411 /// Builds the specified URL.
412 /// </summary>
413 /// <param name="url">The URL.</param>
414 protected internal void Build(StringBuilder url)
416 if (pieces.Count == 0)
418 return;
421 foreach(string piece in pieces)
423 if (url[url.Length - 1] != '/')
425 url.Append('/');
428 url.Append(piece);
433 /// <summary>
434 /// Pendent
435 /// </summary>
436 public class PathInfoDictBuilder
438 private readonly UrlPartsBuilder parent;
439 private readonly IDictionary<string, string> parameters;
441 /// <summary>
442 /// Initializes a new instance of the <see cref="PathInfoBuilder"/> class.
443 /// </summary>
444 /// <param name="parent">The parent.</param>
445 public PathInfoDictBuilder(UrlPartsBuilder parent)
447 this.parent = parent;
448 parameters = new Dictionary<string, string>(StringComparer.InvariantCultureIgnoreCase);
451 /// <summary>
452 /// Gets or sets the <see cref="System.String"/> with the specified key.
453 /// </summary>
454 /// <value></value>
455 public string this[string key]
457 get { return parameters[key]; }
458 set { parameters[key] = value; }
461 /// <summary>
462 /// Gets the count.
463 /// </summary>
464 /// <value>The count.</value>
465 public int Count
467 get { return parameters.Count; }
470 /// <summary>
471 /// Adds a path info piece.
472 /// </summary>
473 /// <param name="key">The key.</param>
474 /// <param name="value">The value.</param>
475 /// <returns></returns>
476 public PathInfoDictBuilder Add(string key, string value)
478 parameters[key] = value;
479 return this;
482 /// <summary>
483 /// Parses the specified path info.
484 /// </summary>
485 /// <param name="pathInfo">The path info.</param>
486 public void Parse(string pathInfo)
488 if (string.IsNullOrEmpty(pathInfo))
490 return;
493 string key = null;
495 foreach(string piece in pathInfo.Split(new char[] { '/' }, StringSplitOptions.RemoveEmptyEntries))
497 if (key == null)
499 key = piece;
501 else
503 this[key] = piece;
504 key = null;
508 if (key != null)
510 this[key] = string.Empty;
515 /// <summary>
516 /// Returns to the previous builder context.
517 /// </summary>
518 public UrlPartsBuilder Done
520 get { return parent; }
523 /// <summary>
524 /// Builds the specified URL.
525 /// </summary>
526 /// <param name="url">The URL.</param>
527 protected internal void Build(StringBuilder url)
529 if (parameters.Count == 0)
531 return;
534 foreach(KeyValuePair<string, string> pair in parameters)
536 if (url[url.Length - 1] != '/')
538 url.Append('/');
541 url.Append(pair.Key);
543 if (pair.Value != string.Empty)
545 url.Append('/');
546 url.Append(pair.Value);