using System; using System.Collections.Generic; using System.Linq; namespace Inspectron.Settings { public class Path : IList, IEquatable> { /// /// Constructor using single object /// Single object making up the path public Path(T last) { m_path = new T[1]; m_path[0] = last; } /// /// Constructor using sequence of objects /// Path, as sequence of objects public Path(IEnumerable path) { m_path = path.ToArray(); } /// /// Constructor using collection of objects /// Path, as collection of objects public Path(ICollection path) { m_path = new T[path.Count]; path.CopyTo(m_path, 0); } /// /// Gets or sets the first object in the path public T First { get { return m_path[0]; } set { m_path[0] = value; } } /// /// Gets or sets the last object in the path public T Last { get { return m_path[m_path.Length - 1]; } set { m_path[m_path.Length - 1] = value; } } /// /// Obtains a prefix with the specified length /// Prefix length /// Prefix with the specified length public Path Prefix(int length) { CheckSubPathLength(length); T[] path = new T[length]; Array.Copy(m_path, 0, path, 0, length); return new Path(path); } /// /// Obtains a suffix with the specified length /// Suffix length /// Suffix with the specified length public Path Suffix(int length) { CheckSubPathLength(length); T[] path = new T[length]; int offset = m_path.Length - length; Array.Copy(m_path, offset, path, 0, length); return new Path(path); } /// /// Converts path to a path of another type /// Path type to convert to /// Path of new type public Path Convert() where U : class { U[] converted = new U[m_path.Length]; for (int i = 0; i < m_path.Length; i++) converted[i] = Convert(m_path[i]); return new Path(converted); } /// /// Converts from the path type to another type /// Desired type /// Item to convert /// Item, converted to given type, or null protected virtual U Convert(T item) where U : class { U u = item as U; return u; } /// /// Tests path for equality /// Other path /// True iff this path is equivalent to other public bool Equals(Path other) { if (object.Equals(other, null)) return false; if (m_path.Length != other.m_path.Length) return false; for (int i = 0; i < m_path.Length; i++) if (!m_path[i].Equals(other.m_path[i])) return false; return true; } /// /// Tests object for equality /// Other object /// True iff this path is equivalent to other object public override bool Equals(object obj) { Path path = obj as Path; if (path != null) return Equals(path); return false; } /// /// Obtains hash code /// Hash code public override int GetHashCode() { int hash = 0; foreach (T obj in m_path) hash ^= obj.GetHashCode(); return hash; } /// /// Tests paths for equality /// First path /// Second path /// True iff paths are equivalent public static bool operator ==(Path o1, Path o2) { if (object.Equals(o1, null)) return object.Equals(o2, null); else return o1.Equals(o2); } /// /// Tests paths for inequality /// First path /// Second path /// True iff paths are not equivalent public static bool operator !=(Path o1, Path o2) { if (object.Equals(o1, null)) return !object.Equals(o2, null); else return !o1.Equals(o2); } /// /// Concatenates object with path /// Prefix object /// Optional path, may be null /// Concatenated path, with lhs as first object public static Path operator +(T lhs, Path rhs) { if (rhs == null) return new Path(lhs); T[] path = new T[1 + rhs.Count]; path[0] = lhs; Array.Copy(rhs.m_path, 0, path, 1, rhs.Count); return new Path(path); } /// /// Concatenates path with object /// Optional path, may be null /// Suffix object /// Concatenated path, with rhs as last object public static Path operator +(Path lhs, T rhs) { if (lhs == null) return new Path(rhs); T[] path = new T[lhs.Count + 1]; Array.Copy(lhs.m_path, 0, path, 0, lhs.Count); path[path.Length - 1] = rhs; return new Path(path); } /// /// Concatenates two paths /// First path. Can be null. /// Second path. Can be null. /// Concatenated path, with rhs as prefix and lhs as suffix. Is null if both lhs and rhs are null. public static Path operator +(Path lhs, Path rhs) { if (lhs == null) return rhs; if (rhs == null) return lhs; T[] path = new T[lhs.Count + rhs.Count]; Array.Copy(lhs.m_path, 0, path, 0, lhs.Count); Array.Copy(rhs.m_path, 0, path, lhs.Count, rhs.Count); return new Path(path); } /// /// Gets the enumeration of each path's last item; i.e., the property 'Last' /// Enumeration of Path objects, whose Last property is returned /// Last property of each Path in 'paths', in the same order as 'paths' public static IEnumerable GetLastItems(IEnumerable> paths) { foreach (Path path in paths) yield return path.Last; } #region IList Members /// /// Determines the index of a specific item in the /// The object to locate in the /// /// The index of item if found in the list; otherwise -1 /// public int IndexOf(T item) { for (int i = 0; i < m_path.Length; i++) if (m_path[i].Equals(item)) return i; return -1; } /// /// Inserts an item to the at the specified index /// The zero-based index at which item should be inserted /// The object to insert into the /// The is read-only /// index is not a valid index in the public void Insert(int index, T item) { throw new NotSupportedException(); } /// /// Removes the item at the specified index /// The zero-based index of the item to remove /// The is read-only /// index is not a valid index in the public void RemoveAt(int index) { throw new NotSupportedException(); } /// /// Gets or sets the item at the specified index /// Index at which to set value public T this[int index] { get { return m_path[index]; } set { m_path[index] = value; } } #endregion #region ICollection Members /// /// Adds an item to the /// The object to add to the /// The /// is read-only public void Add(T item) { throw new NotSupportedException(); } /// /// Removes all items from the /// The /// is read-only public void Clear() { throw new NotSupportedException(); } /// /// Determines whether the contains a specific value /// The object to locate in the /// /// True iff item is found in the /// public bool Contains(T item) { foreach (T obj in m_path) if (obj.Equals(item)) return true; return false; } /// /// Copies the elements of the to an , /// starting at a particular index /// The one-dimensional that is the destination of the elements /// copied from . /// The must have zero-based indexing. /// The zero-based index in array at which copying begins /// ArrayIndex is less than 0 /// Array is null /// Array is multidimensional.-or- /// arrayIndex is equal to or greater than the length of array.-or- /// The number of elements in the source is greater than /// the available space from arrayIndex to the end of the destination array.-or- /// Type T cannot be cast automatically to the type of the destination array. public void CopyTo(T[] array, int arrayIndex) { m_path.CopyTo(array, arrayIndex); } /// /// Gets the number of elements contained in the public int Count { get { return m_path.Length; } } /// /// Gets whether the is read-only public bool IsReadOnly { get { return false; } } /// /// Removes the first occurrence of a specific object from the /// The object to remove from the /// /// True iff item was successfully removed from the . /// This method also returns false if item is not found in the original . /// /// The is read-only public bool Remove(T item) { throw new NotSupportedException(); } #endregion #region IEnumerable Members /// /// Returns an enumerator that iterates through the collection /// /// A that can be used to iterate through the collection /// public IEnumerator GetEnumerator() { return ((IEnumerable)m_path).GetEnumerator(); } #endregion #region IEnumerable Members System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() { return m_path.GetEnumerator(); } #endregion /// /// Private constructor private Path(T[] path) { m_path = path; } private void CheckSubPathLength(int length) { if (length < 1) throw new InvalidOperationException("Length must be > 0"); if (length > m_path.Length) throw new InvalidOperationException("Length greater than path length"); } private readonly T[] m_path; } }