using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Collections.ObjectModel;
using System.Runtime.Serialization;
namespace dasBlog.Storage{
[DataContract]
public sealed class Moniker
{
public class Segment : ICloneable
{
public PathSegmentName Name { get; set; }
public string Id { get; set; }
public bool IsLast { get; set; }
public Segment()
{
}
public Segment(PathSegmentName name, string id, bool isLast)
{
Name = name;
Id = id;
IsLast = isLast;
}
public object Clone()
{
return new Segment(Name, Id, IsLast);
}
}
public const string Scheme = "dasblog";
private string _scope;
public string Scope { get { return _scope; } }
private List<Segment> _segments;
public IList<Segment> Segments { get { return new List<Segment>(_segments); } }
private Moniker()
{
_segments = new List<Segment>();
}
public Moniker(string contextIdentifier)
:this()
{
Parse( new Uri( contextIdentifier ));
}
public Moniker(string scopeid, Collection<string> pathSegments)
: this()
{
this._scope = scopeid;
for (int i = 0; i < pathSegments.Count; i += 2)
{
Segment segment = new Segment();
segment.Name = new PathSegmentName(pathSegments[i]);
if (i + 1 < pathSegments.Count && !string.IsNullOrEmpty(pathSegments[i + 1]))
{
segment.Id = pathSegments[i + 1];
}
if (i + 2 >= pathSegments.Count)
{
segment.IsLast = true;
}
_segments.Add(segment);
}
}
public Moniker(Uri moniker)
: this()
{
Parse(moniker);
}
public Moniker(Moniker uri, string id)
: this()
{
if (uri.ItemId != null)
throw new ArgumentException("Not a context-id", "uri");
_scope = uri.Scope;
_segments = new List<Segment>(from Segment s in uri._segments select (Segment)s.Clone());
_segments.Last().Id = id;
}
public Moniker(Moniker uri, PathSegmentName node)
: this()
{
if (uri._segments.Count > 0)
{
if (uri.ItemId == null)
throw new ArgumentException("Not an item-id", "uri");
_scope = uri.Scope;
_segments = new List<Segment>(from Segment s in uri._segments select (Segment)s.Clone());
_segments.Last().IsLast = false;
_segments.Add(new Segment { Name = node, IsLast = true });
}
else
{
_scope = uri._scope;
_segments = new List<Segment>();
_segments.Add(new Segment { Name = node, IsLast = true });
}
}
public Moniker(Moniker uri, string id, PathSegmentName subnode):this(uri,id)
{
_segments.Last().IsLast = false;
_segments.Add(new Segment { Name = subnode, IsLast = true });
}
public Moniker(Moniker uri, string id, PathSegmentName subnode, string subid):this(uri,id,subnode)
{
_segments.Last().Id = subid;
}
public Moniker(string scopeName, PathSegmentName node1)
:this()
{
_scope = scopeName;
_segments.Add(new Segment { Name = node1, IsLast = true });
}
public Moniker(string scopeName, PathSegmentName node1, string id1):this()
{
_scope = scopeName;
_segments.Add(new Segment { Name = node1, Id = id1, IsLast = true });
}
public Moniker(string scopeName, PathSegmentName node1, string id1, PathSegmentName node2):this(scopeName,node1,id1)
{
_segments.Last().IsLast = false;
_segments.Add(new Segment { Name = node2, IsLast = true });
}
public Moniker(string scopeName, PathSegmentName node1, string id1, PathSegmentName node2, string id2):this(scopeName,node1,id1)
{
_segments.Last().IsLast = false;
_segments.Add(new Segment { Name = node2, Id=id2, IsLast = true });
}
private void Parse(Uri moniker)
{
_scope = moniker.Host;
_segments = new List<Segment>();
if (moniker.AbsolutePath == "/")
return;
string[] pathSegments = moniker.AbsolutePath.Split('/');
int end = pathSegments[pathSegments.Length - 1] == "" ? pathSegments.Length - 1 : pathSegments.Length;
for (int i = 1; i < end; i += 2)
{
if (pathSegments[i] == "")
continue;
Segment segment = new Segment();
segment.Name = new PathSegmentName(Uri.UnescapeDataString(pathSegments[i]));
if (i + 1 < end && !string.IsNullOrEmpty(pathSegments[i+1]))
{
segment.Id = Uri.UnescapeDataString(pathSegments[i+1]);
}
if (i + 2 >= end)
{
segment.IsLast = true;
}
_segments.Add(segment);
}
}
public Uri ToUri()
{
return new Uri(ToString());
}
private Uri _uri = null;
public Uri ToUri(Uri baseUri)
{
if (_uri == null)
{
string path = "./" + Scope + "/";
for (int i = 0; i < _segments.Count; i++)
{
bool bLast = i + 1 >= _segments.Count;
var segment = _segments[i];
path += segment.Name.Value + "/";
if (segment.Id != null)
{
path += segment.Id + "/";
}
}
_uri = new Uri(baseUri, path.Substring(0, path.Length - 1));
}
return _uri;
}
public override string ToString()
{
return MakeString(true);
}
private string _stringWithId = null;
private string _string = null;
private string MakeString(bool withId)
{
if ((withId && _stringWithId == null) ||
(!withId && _string == null))
{
string path = Scheme + "://" + Scope + "/";
for (int i = 0; i < _segments.Count; i++)
{
bool bLast = i + 1 >= _segments.Count;
var segment = _segments[i];
path += segment.Name.Value + "/";
if (((!withId && !bLast) || withId) &&
segment.Id != null)
{
path += segment.Id + "/";
}
}
if (withId)
_stringWithId = path.Substring(0, path.Length - 1);
else
_string = path.Substring(0, path.Length - 1);
}
if (withId)
return _stringWithId;
else
return _string;
}
public string ItemId
{
get
{
if (_segments.Count == 0)
return null;
Segment lastSegment = _segments.Last();
return lastSegment.Id;
}
set
{
if (_segments.Count == 0)
throw new InvalidOperationException("Can't set Id on Uri without segments");
Segment lastSegment = _segments.Last();
lastSegment.Id = value;
}
}
public string ItemPath
{
get
{
return MakeString(false);
}
}
public override bool Equals(object obj)
{
return (obj).ToString() == ToString();
}
public override int GetHashCode()
{
return ToString().GetHashCode();
}
[DataMember]
private string Value
{
get
{
return ToString();
}
set
{
Parse(new Uri(value));
}
}
public static Moniker FromScopeName(string scopeName)
{
Moniker uri = new Moniker();
uri._scope = scopeName;
return uri;
}
}
}
|