using System;
using System.Text;
using System.Collections.Generic;
namespace Wayne.Lib
{
///
/// The IIdentifiableEntity represents an entity of some sort that has an integer ID and a possible parent.
///
public interface IIdentifiableEntity
{
#region Properties
///
/// The ID of the entity.
///
int Id { get; }
///
/// The main type of entity.
///
string EntityType { get; }
///
/// This is used by the logger and should never be set by inheriting classes
///
string FullEntityName { get; set; }
///
/// A more refined type of the entity, e.g. a specific implementation or brand.
///
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1702:CompoundWordsShouldBeCasedCorrectly", MessageId = "SubType")]
string EntitySubType { get; }
///
/// Reference to a possible parent device.
///
IIdentifiableEntity ParentEntity { get; }
#endregion
}
///
/// A class implementing the IIdentifiableEntity interface.
/// Also contains static properties and methods that handles IIdentifiableEntity.
///
public class IdentifiableEntity : IIdentifiableEntity
{
#region Fields
private readonly int id;
private readonly string entityType;
private readonly string entitySubType;
private readonly IIdentifiableEntity parentEntity;
#endregion
#region Construction
static IdentifiableEntity()
{
Empty = new IdentifiableEntity(NoId, string.Empty, string.Empty, null);
}
///
/// Construction
///
/// The ID of the entity.
/// The main type of entity.
/// A more refined type of the entity, e.g. a specific implementation or brand.
/// Reference to a possible parent device.
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1702:CompoundWordsShouldBeCasedCorrectly", MessageId = "SubType")]
public IdentifiableEntity(int id, string entityType, string entitySubType, IIdentifiableEntity parentEntity)
{
this.id = id;
this.entityType = entityType;
this.entitySubType = entitySubType;
this.parentEntity = parentEntity;
}
#endregion
#region IIdentifiableEntity Members
///
/// The ID of the entity.
///
public int Id
{
get { return id; }
}
///
/// The main type of entity.
///
public string EntitySubType
{
get { return entitySubType; }
}
///
/// A more refined type of the entity, e.g. a specific implementation or brand.
///
public string EntityType
{
get { return entityType; }
}
///
/// This is used by the logger and should never be set by inheriting classes
///
public string FullEntityName { get; set; }
///
/// Reference to a possible parent device.
///
public IIdentifiableEntity ParentEntity
{
get { return parentEntity; }
}
#endregion
#region Misc Static Members
///
/// A value representing a non-Id.
///
public const int NoId = int.MinValue;
///
/// An empty IdentifiableEntity.
///
public static IdentifiableEntity Empty { get; private set; }
///
/// Gets an IIdentifiableEntity-array of the ancestors of the given entity.
/// The first one in the list is the given entity itself, and the last one is the root-parent.
///
///
///
public static IIdentifiableEntity[] GetAncestorArray(IIdentifiableEntity entity)
{
List ancestors = new List();
while (entity != null)
{
ancestors.Add(entity);
entity = entity.ParentEntity;
}
return ancestors.ToArray();
}
///
/// Tests equality between two identifieable entities on the regards on the
/// Id, EntityType, EntitySubtype, and the parent ancestry.
///
///
///
///
public static bool Equals(IIdentifiableEntity entity1, IIdentifiableEntity entity2)
{
if (entity1 == null)
throw new ArgumentNullException("entity1");
if (entity2 == null)
throw new ArgumentNullException("entity2");
if (entity1 == entity2)
return true;
EnsureFullEntityName(entity1);
EnsureFullEntityName(entity2);
return entity1.FullEntityName == entity2.FullEntityName;
}
private static void EnsureFullEntityName(IIdentifiableEntity entity1)
{
if (string.IsNullOrEmpty(entity1.FullEntityName))
{
entity1.FullEntityName = ToString(entity1, true);
}
}
#endregion
#region ToString
///
/// Composes a string from this IIdentifiableEntity.
///
///
public override string ToString()
{
if (string.IsNullOrEmpty(FullEntityName))
{
FullEntityName = ToString(this, true);
}
return FullEntityName;
}
///
/// Composes a string from an IIdentifiableEntity.
///
/// The entity to convert to a string.
///
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1062:ValidateArgumentsOfPublicMethods")]
public static string ToString(IIdentifiableEntity entity)
{
return ToString(entity, false);
}
///
/// Composes a string from an IIdentifiableEntity, possibly with the ancestors included.
///
/// The entity to convert to a string.
/// Should the ancestors be included?
///
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1062:ValidateArgumentsOfPublicMethods")]
public static string ToString(IIdentifiableEntity entity, bool ancestors)
{
if ((entity == null) || (entity == Empty))
return string.Empty;
StringBuilder builder = new StringBuilder();
if (ancestors)
{
List entities = new List();
do
{
// The EntityType
builder.Append(entity.EntityType);
// The EntitySubType
if (!string.IsNullOrEmpty(entity.EntitySubType))
{
builder.Append("{");
builder.Append(entity.EntitySubType);
builder.Append("}");
}
// The Id
if (entity.Id != NoId)
{
builder.Append('#');
builder.Append(entity.Id.ToString(System.Globalization.CultureInfo.InvariantCulture));
}
entity = entity.ParentEntity;
entities.Add(builder.ToString());
builder.Length = 0;
}
while (entity != null);
for (int i = entities.Count - 1; i >= 0; i--)
{
builder.Append("\\");
builder.Append(entities[i]);
}
}
else
{
// The EntityType
builder.Append(entity.EntityType);
// The EntitySubType
if (!string.IsNullOrEmpty(entity.EntitySubType))
{
builder.Append("{");
builder.Append(entity.EntitySubType);
builder.Append("}");
}
// The Id
if (entity.Id != NoId)
builder.Append(entity.Id.ToString(System.Globalization.CultureInfo.InvariantCulture));
}
return builder.ToString();
}
#endregion
#region Parse
///
/// Parses an Ancestor string into a list of Identifiable entities, where the first item is the bottommost parent,
///
///
///
public static IIdentifiableEntity[] ParseAncestorString(string ancestryString)
{
string[] entityStrings = ancestryString.Split('\\');
List identifiableEntityList = new List();
IIdentifiableEntity currentParent = null;
System.Text.RegularExpressions.Regex allowedEntityStringFormat = new System.Text.RegularExpressions.Regex(@"^[a-zA-Z0-9_\.]+({[a-zA-Z0-9_\.]+})?(#[0-9]+)?$");
foreach (string entityString in entityStrings)
{
if (string.IsNullOrEmpty(entityString))
continue;
if (!allowedEntityStringFormat.IsMatch(entityString))
return new IIdentifiableEntity[0];
string entityType;
string entitySubType = string.Empty;
int id = NoId;
//Entity string can have the following formats:
// 1. Entity
// 2. Entity{SubType}
// 3. Entity{SubType}#Id
// 4. Entity#Id
string[] firstSplit = entityString.Split('#');
if (firstSplit.Length >= 1)
{
//Is it case 1 or 2?
List secondSplit = new List(firstSplit[0].Split('{', '}'));
while (secondSplit.Contains(string.Empty))
secondSplit.Remove(string.Empty);
if (secondSplit.Count == 1)
{
//Was Case 1
entityType = secondSplit[0];
}
else if (secondSplit.Count == 2)
{
//Was Case 2
entityType = secondSplit[0];
entitySubType = secondSplit[1];
}
else
return new IIdentifiableEntity[0];
if (firstSplit.Length == 2)
id = int.Parse(firstSplit[1], System.Globalization.CultureInfo.InvariantCulture);
else if (firstSplit.Length > 2)
return new IIdentifiableEntity[0];
}
else
return new IIdentifiableEntity[0];
IIdentifiableEntity entity = new IdentifiableEntity(id, entityType, entitySubType, currentParent);
identifiableEntityList.Add(entity);
currentParent = entity;
}
return identifiableEntityList.ToArray();
}
///
/// Parses an ancestry string entity into an IdentifiableEntity object whith newly created Identifiable entities for parents.
///
///
///
public static IIdentifiableEntity Parse(string path)
{
System.Text.RegularExpressions.Regex allowedEntityStringFormat = new System.Text.RegularExpressions.Regex(@"^[a-zA-Z0-9_\.]+({[a-zA-Z0-9_\.]+})?(#[0-9]+)?$");
string[] entityStrings = path.TrimStart('\\').Split('\\');
IdentifiableEntity currentParent = null;
foreach (string entityString in entityStrings)
{
if (!allowedEntityStringFormat.IsMatch(entityString))
return null;
string entityType;
string entitySubType = string.Empty;
int id = NoId;
//Entity string can have the following formats:
// 1. Entity
// 2. Entity{SubType}
// 3. Entity{SubType}#Id
// 4. Entity#Id
string[] firstSplit = entityString.Split('#');
if (firstSplit.Length >= 1)
{
//Is it case 1 or 2?
List secondSplit = new List(firstSplit[0].Split('{', '}'));
while (secondSplit.Contains(string.Empty))
secondSplit.Remove(string.Empty);
if (secondSplit.Count == 1)
{
//Was Case 1
entityType = secondSplit[0];
}
else if (secondSplit.Count == 2)
{
//Was Case 2
entityType = secondSplit[0];
entitySubType = secondSplit[1];
}
else
return null;
if (firstSplit.Length == 2)
id = int.Parse(firstSplit[1], System.Globalization.CultureInfo.InvariantCulture);
else if (firstSplit.Length > 2)
return null;
}
else
return null;
IdentifiableEntity entity = new IdentifiableEntity(id, entityType, entitySubType, currentParent);
currentParent = entity;
}
return currentParent;
}
public class EqualityComparer : IEqualityComparer
{
public bool Equals(IIdentifiableEntity x, IIdentifiableEntity y)
{
return IdentifiableEntity.Equals(x, y);
}
public int GetHashCode(IIdentifiableEntity obj)
{
EnsureFullEntityName(obj);
return obj.FullEntityName.GetHashCode();
}
}
#endregion
}
}