using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Text;
using System.Xml;
namespace Wayne.Lib.Log
{
///
/// This class manages the path and file name to a log file,
/// composing the correct name depending on datetime, id-entity properties etc.
///
internal class LogConfigTextFilePath
{
#region Inner classes
#region Param
abstract class Param
{
public abstract string ToString(EntityCategory entityCategory);
}
#endregion
#region ConstantTextParam
class ConstantTextParam : Param
{
private string text;
public ConstantTextParam(string text)
{
this.text = text;
}
// MLA COMMENTED OUT THIS UNUSED CODE.
//public string Text
//{
// get { return text; }
//}
public override string ToString(EntityCategory entityCategory)
{
return text;
}
public override string ToString()
{
return text;
}
}
class PIDParam : Param
{
private string text;
public PIDParam()
{
text = Process.GetCurrentProcess().Id.ToString();
}
public override string ToString(EntityCategory entityCategory)
{
return text;
}
public override string ToString()
{
return text;
}
}
#endregion
#region EntityParamType enum
enum EntityParamType
{
EntityType,
EntitySubType
}
#endregion
#region EntityParam
class EntityParam : Param
{
private EntityParamType paramType;
public EntityParam(EntityParamType entityParamType)
{
this.paramType = entityParamType;
}
public override string ToString(EntityCategory entityCategory)
{
switch (paramType)
{
case EntityParamType.EntityType:
return entityCategory.Entity.EntityType;
case EntityParamType.EntitySubType:
return entityCategory.Entity.EntitySubType;
default:
return "";
}
}
public override string ToString()
{
return "<" + paramType.ToString() + "/>";
}
}
#endregion
#region DateParam
class DateParam : Param
{
private string dateTimeFormat;
public DateParam(string dateTimeFormat)
{
this.dateTimeFormat = dateTimeFormat;
}
public override string ToString(EntityCategory entityCategory)
{
return DateTime.Now.ToString(dateTimeFormat, System.Globalization.CultureInfo.InvariantCulture);
}
public override string ToString()
{
return "";
}
}
#endregion
#region IdParam
class IdParam : Param
{
private string fromEntityType;
private string fromEntitySubType;
public IdParam(string fromEntityType, string fromEntitySubType)
{
this.fromEntityType = fromEntityType;
this.fromEntitySubType = fromEntitySubType;
}
public override string ToString(EntityCategory entityCategory)
{
if ((fromEntityType != null) || (fromEntitySubType != null))
{
IIdentifiableEntity[] ancestors = IdentifiableEntity.GetAncestorArray(entityCategory.Entity);
if ((fromEntityType != null) && (fromEntitySubType != null))
{
foreach (IIdentifiableEntity ancestor in ancestors)
{
if (System.Text.RegularExpressions.Regex.IsMatch(ancestor.EntityType, fromEntityType, System.Text.RegularExpressions.RegexOptions.IgnoreCase) &&
System.Text.RegularExpressions.Regex.IsMatch(ancestor.EntitySubType, fromEntitySubType, System.Text.RegularExpressions.RegexOptions.IgnoreCase))
{
if (ancestor.Id != IdentifiableEntity.NoId)
return ancestor.Id.ToString(System.Globalization.CultureInfo.InvariantCulture);
return string.Empty;
}
}
}
else if (fromEntityType != null)
{
foreach (IIdentifiableEntity ancestor in ancestors)
{
if (System.Text.RegularExpressions.Regex.IsMatch(ancestor.EntityType, fromEntityType, System.Text.RegularExpressions.RegexOptions.IgnoreCase))
{
if (ancestor.Id != IdentifiableEntity.NoId)
return ancestor.Id.ToString(System.Globalization.CultureInfo.InvariantCulture);
return string.Empty;
}
}
}
else
{
foreach (IIdentifiableEntity ancestor in ancestors)
{
if (System.Text.RegularExpressions.Regex.IsMatch(ancestor.EntitySubType, fromEntitySubType, System.Text.RegularExpressions.RegexOptions.IgnoreCase))
{
if (ancestor.Id != IdentifiableEntity.NoId)
return ancestor.Id.ToString(System.Globalization.CultureInfo.InvariantCulture);
return string.Empty;
}
}
}
}
else if (entityCategory.Entity.Id != IdentifiableEntity.NoId)
return entityCategory.Entity.Id.ToString(System.Globalization.CultureInfo.InvariantCulture);
return string.Empty;
}
public override string ToString()
{
return string.Format("", fromEntityType);
}
}
#endregion
#region FileNameInvalidTimeResolution enum
///
/// The resolution of the time when the log file gets a new name.
///
enum FileNameInvalidTimeResolution
{
// The log file gets a new name every...
Second,
Minute,
Hour,
Day,
Month,
Year,
Never
}
#endregion
#endregion
#region Fields
private List paramList = new List();
private FileNameInvalidTimeResolution fileNameInvalidTimeResolution; // The log file gets a new name every...
private DateTime fileNameInvalidTime = DateTime.MinValue; // At this time the log file should get a new name.
private Dictionary cachedFileNames = new Dictionary();
private object cachedFileNamesLock = new object();
private string cachedToString;
private string cachedBaseName;
#endregion
#region Construction
///
/// Construct a LogPath object from an configuration XML element.
///
///
internal LogConfigTextFilePath(XmlElement logPathElement)
{
fileNameInvalidTimeResolution = FileNameInvalidTimeResolution.Never;
for (int i = 0; i < logPathElement.ChildNodes.Count; i++)
{
XmlNode node = logPathElement.ChildNodes[i];
if (node.NodeType == XmlNodeType.Text)
{
string text = node.Value.Replace("\r", "").Replace("\n", "");
if (i == 0)
text = text.TrimStart(' ');
if (i == logPathElement.ChildNodes.Count - 1)
text = text.TrimEnd(' ');
paramList.Add(new ConstantTextParam(text));
}
else if (node.NodeType == XmlNodeType.Element)
{
switch (node.Name)
{
case "Id":
XmlAttribute fromEntityTypeAttribute = node.Attributes["FromEntityType"];
string fromEntityType;
if (fromEntityTypeAttribute != null)
fromEntityType = fromEntityTypeAttribute.Value;
else
fromEntityType = null;
XmlAttribute fromEntitySubTypeAttribute = node.Attributes["FromEntitySubType"];
string fromEntitySubType;
if (fromEntitySubTypeAttribute != null)
fromEntitySubType = fromEntitySubTypeAttribute.Value;
else
fromEntitySubType = null;
paramList.Add(new IdParam(fromEntityType, fromEntitySubType));
break;
case "EntityType":
paramList.Add(new EntityParam(EntityParamType.EntityType));
break;
case "EntitySubType":
paramList.Add(new EntityParam(EntityParamType.EntitySubType));
break;
case "PID":
paramList.Add(new PIDParam());
break;
case "Date":
string dateFormat;
XmlAttribute formatAttribute = node.Attributes["Format"];
if (formatAttribute != null)
dateFormat = formatAttribute.Value;
else
dateFormat = "yyyyMMdd";
paramList.Add(new DateParam(dateFormat));
// Find the smallest time resolution in the date format. This often the file name will be refreshed.
if ((dateFormat.IndexOf("s", StringComparison.Ordinal) > -1) || (dateFormat.IndexOf("f", StringComparison.OrdinalIgnoreCase) > -1))
fileNameInvalidTimeResolution = FileNameInvalidTimeResolution.Second;
else if ((dateFormat.IndexOf("m", StringComparison.Ordinal) > -1) && (fileNameInvalidTimeResolution > FileNameInvalidTimeResolution.Minute))
fileNameInvalidTimeResolution = FileNameInvalidTimeResolution.Minute;
else if ((dateFormat.IndexOf("h", StringComparison.OrdinalIgnoreCase) > -1) && (fileNameInvalidTimeResolution > FileNameInvalidTimeResolution.Hour))
fileNameInvalidTimeResolution = FileNameInvalidTimeResolution.Hour;
else if ((dateFormat.IndexOf("d", StringComparison.Ordinal) > -1) && (fileNameInvalidTimeResolution > FileNameInvalidTimeResolution.Day))
fileNameInvalidTimeResolution = FileNameInvalidTimeResolution.Day;
else if ((dateFormat.IndexOf("M", StringComparison.Ordinal) > -1) && (fileNameInvalidTimeResolution > FileNameInvalidTimeResolution.Month))
fileNameInvalidTimeResolution = FileNameInvalidTimeResolution.Month;
else if ((dateFormat.IndexOf("y", StringComparison.Ordinal) > -1) && (fileNameInvalidTimeResolution > FileNameInvalidTimeResolution.Year))
fileNameInvalidTimeResolution = FileNameInvalidTimeResolution.Year;
break;
}
}
}
}
#endregion
#region Methods
///
/// Checks whether it's time for a new file name.
/// If it is, the datetime for the next name change is calculated and all cached file names
/// are deleted.
///
public bool IsTimeForNewFileName()
{
if (DateTime.Now > fileNameInvalidTime)
{
lock (cachedFileNamesLock)
{
// All the cached file names are now invalid.
cachedFileNames.Clear();
}
// Calculate the next time for file name change.
DateTime now = DateTime.Now;
switch (fileNameInvalidTimeResolution)
{
case FileNameInvalidTimeResolution.Second:
fileNameInvalidTime = new DateTime(now.Year, now.Month, now.Day, now.Hour, now.Minute, now.Second, DateTimeKind.Local).AddSeconds(1);
break;
case FileNameInvalidTimeResolution.Minute:
fileNameInvalidTime = new DateTime(now.Year, now.Month, now.Day, now.Hour, now.Minute, 0, DateTimeKind.Local).AddMinutes(1);
break;
case FileNameInvalidTimeResolution.Hour:
fileNameInvalidTime = new DateTime(now.Year, now.Month, now.Day, now.Hour, 0, 0, DateTimeKind.Local).AddHours(1);
break;
case FileNameInvalidTimeResolution.Day:
fileNameInvalidTime = new DateTime(now.Year, now.Month, now.Day, 0, 0, 0, DateTimeKind.Local).AddDays(1);
break;
case FileNameInvalidTimeResolution.Month:
fileNameInvalidTime = new DateTime(now.Year, now.Month, 1, 0, 0, 0, DateTimeKind.Local).AddMonths(1);
break;
case FileNameInvalidTimeResolution.Year:
fileNameInvalidTime = new DateTime(now.Year, 1, 1, 0, 0, 0, DateTimeKind.Local).AddYears(1);
break;
case FileNameInvalidTimeResolution.Never:
fileNameInvalidTime = DateTime.MaxValue;
break;
}
return true;
}
return false;
}
///
/// Equality operator
///
///
///
public override bool Equals(object obj)
{
return obj.ToString().Equals(this.ToString());
}
///
/// Hash code generator. Not correctly implemented I think....
///
///
public override int GetHashCode()
{
return this.ToString().GetHashCode();
}
///
/// Returns the log path using the specified identifiable entity.
///
///
public string ToString(EntityCategory entityCategory)
{
lock (cachedFileNamesLock)
{
string text;
if (cachedFileNames.TryGetValue(entityCategory, out text))
return text;
StringBuilder sb = new StringBuilder();
foreach (Param param in paramList)
sb.Append(param.ToString(entityCategory));
string fileName = sb.ToString();
cachedFileNames.Add(entityCategory, fileName);
return fileName;
}
}
///
/// ToString method.
///
///
public override string ToString()
{
if (cachedToString == null)
{
StringBuilder sb = new StringBuilder();
foreach (Param param in paramList)
sb.Append(param.ToString());
cachedToString = sb.ToString();
}
return cachedToString;
}
///
/// Clean the internal lists.
///
///
internal void PerformListCleaning(DateTime oldestAllowedTouch)
{
lock (cachedFileNamesLock)
{
List entityCategoriesToRemove = new List();
foreach (EntityCategory entityCategory in cachedFileNames.Keys)
{
if (entityCategory.LastTouched < oldestAllowedTouch)
entityCategoriesToRemove.Add(entityCategory);
}
//Remove from the list.
foreach (EntityCategory entityCategoryToRemove in entityCategoriesToRemove)
{
cachedFileNames.Remove(entityCategoryToRemove);
}
}
}
#endregion
#region Properties
///
/// Returns constant prefix base name - adds parameters until it finds a PID or Date parameter
///
///
public string BaseName
{
get
{
if (cachedBaseName == null)
{
StringBuilder sb = new StringBuilder();
PIDParam pp = null;
DateParam dp = null;
IdParam ip = null;
foreach (Param param in paramList)
{
pp = param as PIDParam;
if (pp != null)
{
break;
}
dp = param as DateParam;
if (dp != null)
{
break;
}
ip = param as IdParam;
if (ip != null)
{
break;
}
if (param.ToString().IndexOf('<') >= 0) break;
if (param.ToString().IndexOf('/') >= 0) break;
sb.Append(param.ToString());
}
cachedBaseName = sb.ToString();
}
return cachedBaseName;
}
}
#endregion // Properties
}
}