using System; using System.Collections.Generic; using System.Text; using System.Xml; using System.ComponentModel; namespace VEPROMS.CSLA.Library { #region vlnFormatDocument public class vlnFormatDocument:XmlDocument { private static XmlElement mydocele; public vlnFormatDocument(IFormatOrFormatInfo myFormat) { MyFormat = myFormat; LoadXml(MyFormat.Data); mydocele = DocumentElement; } public IFormatOrFormatInfo MyFormat { get; set; } public static XmlNode LookupSingleNode(XmlNode xmlNode, string path) { if (xmlNode == null) return null; XmlNode xn = xmlNode.SelectSingleNode(path); if (xmlNode.Name == "Box") return xn; // if box, don't do inheritance. if (xmlNode.Name == "DocStyle") return xn; //C2025-023 - Electronic Procedures - Modifications to PROMS if (xmlNode.Name == "EPField") return xn; // if Electronic Procedure Field, don't do inheritance. if (xmlNode.Name == "StructureStyle") { Volian.Base.Library.DebugText.WriteLine("vlnFormatDocument:LookupSingleNode:StructureStyle - shouldn't get to this line of code.\r\nPath = {0}", path); return xn; // User Format (sub format) - shouldn't? inherit? -need to check } if (xn != null) return xn; //if (path.Contains("Font")) Console.WriteLine("vlnFormatDocument.LookupSingleNode {0},{1}", xmlNode.Name == "Step" ? "Step." + xmlNode.Attributes["Type"].Value : xmlNode.Name, path); if (xmlNode.Name == "Step") xn = LookupSingleStepNode(xmlNode, path); // Check for Step Inheritance if (xmlNode.ParentNode.Name == "Step") xn = LookupSingleStepNode(xmlNode.ParentNode, xmlNode.Name + "/" + path); // Check for Step Inheritance if (xn != null) return xn; if (path.StartsWith("Font")) return LookupSingleFontNode(xmlNode, path); // Then do Font Inheritance return InheritLookup(xmlNode, path, false); } public static XmlNode LookupSingleFontNode(XmlNode xmlNode, string path) { if (xmlNode == null) return null; XmlNode tmpNode = xmlNode; XmlNode xn = xmlNode.SelectSingleNode(path); // RHM 2008-12-15 - Added logic to keep looking if a blank attribute is found while (xn == null || (xn is XmlAttribute && (xn as XmlAttribute).Value == ""))//Walk-up the format tree to find a font node { // if the font is not specified in the PageStyle (PageList), then see if oneis set in the DocStyle (default for that section) // if (xmlNode.Name == "PageStyle") { string psIdx = (xmlNode.Attributes.GetNamedItem("Index") as XmlAttribute).Value; XmlNode docStyle = xmlNode.OwnerDocument.SelectSingleNode(string.Format("//DocStyle[@PageStyle='{0}']",psIdx)); xn = docStyle.SelectSingleNode(path); if (xn != null) return xn; // could not find a font in the DocStyle, so use the format default return LookupSingleNode(tmpNode.OwnerDocument.DocumentElement, "/PlantFormat/FormatData/" + path); } if (xmlNode.NodeType == XmlNodeType.Document) { //if (path.Contains("Font")) Console.WriteLine("vlnFormatDocument.LookupSingleFontNode {0},{1}", tmpNode.Name == "Step" ? "Step." + tmpNode.Attributes["Type"].Value : tmpNode.Name, path); return LookupSingleNode(tmpNode.OwnerDocument.DocumentElement, "/PlantFormat/FormatData/" + path); } xmlNode = xmlNode.ParentNode; xn = xmlNode.SelectSingleNode(path); } return xn; } public static XmlNode LookupSingleStepNode(XmlNode xmlNode, string path) { if (xmlNode == null) return null; XmlNode xn = xmlNode.SelectSingleNode(path); XmlNode tmpNode2 = xmlNode; while (xn == null) //Walk-up the format tree to find a step node { //if (path.Contains("Font")) Console.WriteLine("vlnFormatDocument.LookupSingleStepNode -> Loop {0},{1}", xmlNode.Name == "Step" ? "Step." + xmlNode.Attributes["Type"].Value : xmlNode.Name, path); // RHM 20090831 Try doing a lookup of the parent. If no parent, go back to the original and do an inheritance lookup XmlAttribute attr = xmlNode.Attributes["ParentType"]; if (attr == null || attr.Value == string.Empty) // Cannot find ParentType so do an InheritanceLookup return InheritLookup(tmpNode2, path, true); xmlNode = xmlNode.ParentNode.SelectSingleNode(string.Format("Step[@Type='{0}']", xmlNode.Attributes["ParentType"].InnerText)); xn = xmlNode.SelectSingleNode(path); } return xn; } public static XmlNodeList LookupNodes(XmlNode xmlNode, string path) { if (xmlNode == null) return null; XmlNodeList xl = xmlNode.SelectNodes(path); if (xl == null||xl.Count==0) xl = InheritLookupNodes(xmlNode, path); if (xl == null) return null; return xl; } public static string Lookup(XmlNode xmlNode, string path) { XmlNode xn = LookupSingleNode(xmlNode, path); return xn?.InnerText; } public static T EnumLookup(XmlNode xmlNode, string path) { string str = Lookup(xmlNode,path); return str == null ? default : (T)Enum.Parse(typeof(T), str); } public static int? IntLookup(XmlNode xmlNode, string path) { string str = Lookup(xmlNode, path); return str == null ? null : (int?)int.Parse(str); } public static int SiblingCount(XmlNode xmlNode) { int retval = 0; string nodeName = xmlNode.Name; for (XmlNode xn = xmlNode; xn != null; xn = xn.PreviousSibling) { if (xn.Name == nodeName) retval++; } return retval; } public static string Path(XmlNode xmlNode) { // Walk the path string parentPath = xmlNode.ParentNode == xmlNode.OwnerDocument ? "" : Path(xmlNode.ParentNode); // Count Siblings with the Same Name int sibCount = SiblingCount(xmlNode); return string.Format("{0}/{1}[{2}]", parentPath, xmlNode.Name, sibCount); } public static XmlNode InheritLookup(XmlNode xmlNode, string path, bool stepLookup) { //stepLookup = false; // 8/2 change for inheritance if (xmlNode == null) return null;// No path to match string xPath = Path(xmlNode);// Build xPath from xmlNode if (xmlNode.Name == "TransTypes") { string TransIndex = xmlNode.Attributes["Index"].Value; xPath = System.Text.RegularExpressions.Regex.Replace(xPath, @"\[[0-9]*\]$", @"[@Index='" + TransIndex + @"']"); } vlnFormatDocument fd = (vlnFormatDocument)xmlNode.OwnerDocument;//First Get the vlnFormatDocument - This also ties it to a FormatInfo object while(fd.MyFormat.MyIParent != null) { fd = fd.MyFormat.MyIParent.PlantFormat.XmlDoc;// Get the parents vlnFormatDocument if (fd != null) { XmlNode xp; if (path.StartsWith("/")) xp = fd.DocumentElement; else xp = fd.SelectSingleNode(xPath);// Get the related node if (xp != null) { XmlNode xn; if (stepLookup) { //if (path.Contains("Font")) Console.WriteLine("vlnFormatItem.SelectSingleNode {0},{1}", xp.Name == "Step" ? "Step." + xp.Attributes["Type"].Value : xp.Name, path); xn = LookupSingleStepNode(xp, path); } else xn = xp.SelectSingleNode(path); if(xn != null) return xn; } } } return null; } public static XmlNodeList InheritLookupNodes(XmlNode xmlNode, string path) { if (xmlNode == null) return null;// No path to match string xPath = Path(xmlNode);// Build xPath from xmlNode vlnFormatDocument fd = (vlnFormatDocument)xmlNode.OwnerDocument;//First Get the vlnFormatDocument - This also ties it to a FormatInfo object while (fd.MyFormat.MyIParent != null) { fd = fd.MyFormat.MyIParent.PlantFormat.XmlDoc;// Get the parents vlnFormatDocument if (fd != null) { XmlNode xp = fd.SelectSingleNode(xPath);// Get the related node if (xp != null) { XmlNodeList xl = xp.SelectNodes(path); if (xl != null && xl.Count > 0) return xl; } } } return null; } } #endregion #region vlnFormatItem [TypeConverter(typeof(ExpandableObjectConverter))] public class vlnFormatItem { public vlnFormatItem(XmlNode xmlNode) => XmlNode = xmlNode; public vlnFormatItem() { } internal XmlNode XmlNode { get; set; } private IFormatOrFormatInfo _MyFormat; public IFormatOrFormatInfo MyFormat { get { if (_MyFormat == null) { if (XmlNode.OwnerDocument is vlnFormatDocument doc) _MyFormat = doc.MyFormat; } return _MyFormat; } } public IFormatOrFormatInfo MyParentFormat => MyFormat.MyIParent; public virtual string GetPDDisplayName() => ToString(); public virtual string GetPDName() => ToString(); public virtual string GetPDDescription() => ToString(); public virtual string GetPDCategory() => ToString(); public XmlNodeList SelectNodes(string path) => vlnFormatDocument.LookupNodes(XmlNode, path); public XmlNode SelectSingleNode(string path) { //if(path.Contains("Font")) Console.WriteLine("vlnFormatItem.SelectSingleNode {0},{1}", _XmlNode.Name == "Step" ? "Step." + _XmlNode.Attributes["Type"].Value : _XmlNode.Name, path); return vlnFormatDocument.LookupSingleNode(XmlNode, path); } public XmlNode SelectSingleFontNode(string path) => vlnFormatDocument.LookupSingleFontNode(XmlNode, path); public string Lookup(string path) => vlnFormatDocument.Lookup(XmlNode, path); public string Lookup(string path, ref string local) => local ?? (local = Lookup(path)); public int? IntLookup(string path) => vlnFormatDocument.IntLookup(XmlNode, path); public int? IntLookup(string path, ref int? local) => local != null ? local : local = IntLookup(path); public T EnumLookup(string path) => vlnFormatDocument.EnumLookup(XmlNode, path); public bool LazyLoad(ref LazyLoad ll, string xPath) { if (ll == null) { XmlNode xn = SelectSingleNode(xPath); ll = new LazyLoad(RetrieveBool(xn)); } return ll.Value; } protected static bool RetrieveBool(XmlNode xn) => xn != null && xn.InnerText.ToUpper() == "TRUE"; // a LazyLoad that allows you to pass in the default setting public bool LazyLoad(ref LazyLoad ll, string xPath, bool defaultReturn) { if (ll == null) { XmlNode xn = SelectSingleNode(xPath); ll = new LazyLoad(RetrieveBool(xn, defaultReturn)); } return ll.Value; } // if nothing is set for this node, then use the passed in default value protected static bool RetrieveBool(XmlNode xn, bool defaultReturn) => (xn != null) ? xn.InnerText.ToUpper() == "TRUE" : defaultReturn; public string LazyLoad(ref LazyLoad ll, string xPath) { if (ll == null) { XmlNode xn = SelectSingleNode(xPath); ll = new LazyLoad(RetrieveString(xn)); } return ll.Value; } protected static string RetrieveString(XmlNode xn) => xn?.InnerText; public string MyPath { get { StringBuilder sb = new StringBuilder(); XmlNode node = XmlNode; string prefix = ""; while (node != null) { sb.Insert(0, node.Name + prefix); prefix = "/"; node = node.ParentNode; } return sb.ToString(); } } public int? LazyLoad(ref LazyLoad ll, string xPath) { if (ll == null) { XmlNode xn = SelectSingleNode(xPath); ll = new LazyLoad(RetrieveInt(xPath, xn)); } return ll.Value; } public float? LazyLoad(ref LazyLoad ll, string xPath) { if (ll == null) { XmlNode xn = SelectSingleNode(xPath); ll = new LazyLoad(RetrieveFloat(xPath, xn)); } return ll.Value; } protected int? RetrieveInt(string xPath, XmlNode xn) { int? value = null; if (xn != null) { if (!int.TryParse(xn.InnerText, out int iValue)) { if (xn.InnerText == "") return null; Console.WriteLine(string.Format("'{0}'\r\n'{1}'\r\n'{2}' could not be converted to int?", MyFormat.FullName, MyPath + "/" + xPath, xn.InnerText)); throw new Exception(string.Format("{0} = '{1}' could not be converted to int?", xPath, xn.InnerText)); } value = iValue; } return value; } protected float? RetrieveFloat(string xPath, XmlNode xn) { float? value = null; if (xn != null) { if (!float.TryParse(xn.InnerText, out float fValue)) { Console.WriteLine(string.Format("'{0}'\r\n'{1}'\r\n'{2}' could not be converted to float?", MyFormat.FullName, MyPath + "/" + xPath, xn.InnerText)); throw new Exception(string.Format("{0} = '{1}' could not be converted to float?", xPath, xn.InnerText)); } value = fValue; } return value; } public Nullable LazyLoad(ref LazyLoad> ll, string xPath) where T:struct { if (ll == null) { XmlNode xn = SelectSingleNode(xPath); if (xn == null) ll = new LazyLoad(null); else if (xn.Value == "")// No value specified - Use zero value if it is defined - GetName returns a null if it is not defined ll = new LazyLoad>(Enum.GetName(typeof(T), 0) != null ? (Nullable) Enum.Parse(typeof(T), "0") : null); else try { ll = new LazyLoad>((Nullable)Enum.Parse(typeof(T), xn.InnerText)); } catch (Exception ex) { Console.WriteLine("{0} - '{1}'", ex.Message, xn.InnerText); ll = new LazyLoad(null); } } return ll.Value; } } #endregion #region IVlnIndexedFormatItem public partial interface IVlnIndexedFormatItem { int? Index { get; } } #endregion #region IVlnNamedFormatItem public partial interface IVlnNamedFormatItem { string Name { get; } bool Inherited { get; } } #endregion #region LazyLoad public class LazyLoad { public LazyLoad(T value) => Value = value; public T Value { get; set; } } #endregion #region vlnFormatList, new() public class vlnFormatList : List, ICustomTypeDescriptor where T : vlnFormatItem, new() { private XmlNodeList _XmlNodeList=null; internal XmlNodeList XmlNodeList { get { return _XmlNodeList; } set { _XmlNodeList = value; foreach (XmlNode xn in _XmlNodeList) { T tt = new T { XmlNode = xn }; Add(tt); } } } public vlnFormatList(XmlNodeList xmlNodeList) { if (xmlNodeList == null) return; XmlNodeList = xmlNodeList; } public vlnFormatList() { } private IFormatOrFormatInfo _MyFormat; public IFormatOrFormatInfo MyFormat { get { if (_MyFormat == null) { XmlNode node = _XmlNodeList[0]; // Get the first node in a list vlnFormatDocument doc = null; if (node != null) doc = node.OwnerDocument as vlnFormatDocument; // Get the owner document as a vlnFormatDocument if (doc != null) _MyFormat = doc.MyFormat; // Get the Format associated with the vlnFormatDocument } return _MyFormat; } set { _MyFormat = value; } } #region ICustomTypeDescriptor public string GetClassName() => TypeDescriptor.GetClassName(this, true); public AttributeCollection GetAttributes() => TypeDescriptor.GetAttributes(this, true); public string GetComponentName() => TypeDescriptor.GetComponentName(this, true); public TypeConverter GetConverter() => TypeDescriptor.GetConverter(this, true); public EventDescriptor GetDefaultEvent() => TypeDescriptor.GetDefaultEvent(this, true); public PropertyDescriptor GetDefaultProperty() => TypeDescriptor.GetDefaultProperty(this, true); public object GetEditor(Type editorBaseType) => TypeDescriptor.GetEditor(this, editorBaseType, true); public EventDescriptorCollection GetEvents(Attribute[] attributes) => TypeDescriptor.GetEvents(this, attributes, true); public EventDescriptorCollection GetEvents() => TypeDescriptor.GetEvents(this, true); public object GetPropertyOwner(PropertyDescriptor pd) => this; public PropertyDescriptorCollection GetProperties(Attribute[] attributes) => GetProperties(); public virtual PropertyDescriptorCollection GetProperties() { // Create a collection object to hold property descriptors PropertyDescriptorCollection pds = new PropertyDescriptorCollection(null); // Iterate the list for (int i = 0; i < Count; i++) { // Create a property descriptor for the item and add to the property descriptor collection pds.Add(new vlnPropertyDescriptor, T>(this, i)); } // return the property descriptor collection return pds; } #endregion } #endregion #region vlnIndexedFormatList public class vlnIndexedFormatList : vlnFormatList, ICustomTypeDescriptor where T : vlnFormatItem,IVlnIndexedFormatItem, new() { public vlnIndexedFormatList(XmlNodeList xmlNodeList, IFormatOrFormatInfo myFormat) : base(xmlNodeList) => MyFormat = myFormat; public vlnIndexedFormatList() : base() { } public virtual vlnIndexedFormatList InheritedList => null; public new T this[int index] { get { foreach (T tmp in this) { if (tmp.Index == index) return tmp; } vlnIndexedFormatList ttlParent = InheritedList; //Check Inherited Value if (ttlParent != null) return ttlParent[index]; return null; } } public int MaxIndex { get { int max = base.Count; foreach (T tmp in this) { if (tmp.Index >= max) max = ((int)tmp.Index) + 1; } vlnIndexedFormatList parent = InheritedList; //Check Inherited Value if (parent != null) { int max2 = parent.MaxIndex; if (max2 > max) return max2; } return max; } } public int MaxIndexNoInherit { get { int max = base.Count; foreach (T tmp in this) { if (tmp.Index >= max) max = ((int)tmp.Index) + 1; } return max; } } #region ICustomTypeDescriptor public new string GetClassName() => TypeDescriptor.GetClassName(this, true); public new AttributeCollection GetAttributes() => TypeDescriptor.GetAttributes(this, true); public new string GetComponentName() => TypeDescriptor.GetComponentName(this, true); public new TypeConverter GetConverter() => TypeDescriptor.GetConverter(this, true); public new EventDescriptor GetDefaultEvent() => TypeDescriptor.GetDefaultEvent(this, true); public new PropertyDescriptor GetDefaultProperty() => TypeDescriptor.GetDefaultProperty(this, true); public new object GetEditor(Type editorBaseType) => TypeDescriptor.GetEditor(this, editorBaseType, true); public new EventDescriptorCollection GetEvents(Attribute[] attributes) { return TypeDescriptor.GetEvents(this, attributes, true); } public new EventDescriptorCollection GetEvents() => TypeDescriptor.GetEvents(this, true); public new object GetPropertyOwner(PropertyDescriptor pd) => this; public new PropertyDescriptorCollection GetProperties(Attribute[] attributes) => GetProperties(); public new virtual PropertyDescriptorCollection GetProperties() { // Create a collection object to hold property descriptors PropertyDescriptorCollection pds = new PropertyDescriptorCollection(null); // Iterate the list for (int i = 0; i < Count; i++) { // Create a property descriptor for the item and add to the property descriptor collection pds.Add(new vlnPropertyDescriptor, T>(this, i)); } // return the property descriptor collection return pds; } #endregion } #endregion #region vlnNamedFormatList public class vlnNamedFormatList : vlnFormatList, ICustomTypeDescriptor where T : vlnFormatItem, IVlnNamedFormatItem, new() { public vlnNamedFormatList(XmlNodeList xmlNodeList, IFormatOrFormatInfo myFormat) : base(xmlNodeList) => MyFormat = myFormat; public vlnNamedFormatList() : base() { } public virtual vlnNamedFormatList InheritedList => null; public T this[string name] { get { foreach (T tmp in this) { if (tmp.Name == name) return tmp; } vlnNamedFormatList ttlParent = InheritedList; //Check Inherited Value if (ttlParent != null) return ttlParent[name]; return null; } } public new T this[int index] { get { if(base.Count > index) return base[index]; vlnNamedFormatList ttlParent = InheritedList; //Check Inherited Value if (ttlParent != null) return ttlParent[index]; return null; } } public new int Count => base.Count; #region ICustomTypeDescriptor public new string GetClassName() => TypeDescriptor.GetClassName(this, true); public new AttributeCollection GetAttributes() => TypeDescriptor.GetAttributes(this, true); public new string GetComponentName() => TypeDescriptor.GetComponentName(this, true); public new TypeConverter GetConverter() => TypeDescriptor.GetConverter(this, true); public new EventDescriptor GetDefaultEvent() => TypeDescriptor.GetDefaultEvent(this, true); public new PropertyDescriptor GetDefaultProperty() => TypeDescriptor.GetDefaultProperty(this, true); public new object GetEditor(Type editorBaseType) => TypeDescriptor.GetEditor(this, editorBaseType, true); public new EventDescriptorCollection GetEvents(Attribute[] attributes) => TypeDescriptor.GetEvents(this, attributes, true); public new EventDescriptorCollection GetEvents() => TypeDescriptor.GetEvents(this, true); public new object GetPropertyOwner(PropertyDescriptor pd) => this; public new PropertyDescriptorCollection GetProperties(Attribute[] attributes) => GetProperties(); public new virtual PropertyDescriptorCollection GetProperties() { // Create a collection object to hold property descriptors PropertyDescriptorCollection pds = new PropertyDescriptorCollection(null); // Iterate the list for (int i = 0; i < Count; i++) { // Create a property descriptor for the item and add to the property descriptor collection pds.Add(new vlnPropertyDescriptor, T>(this, i)); } // return the property descriptor collection return pds; } #endregion } #endregion #region vlnListConverter internal class vlnListConverter : ExpandableObjectConverter where T : vlnFormatList where C : vlnFormatItem, new() { private string Plural(string name) { if (name.EndsWith("y")) return $"{name.Substring(0, name.Length - 1)}ies"; if (name.EndsWith("ss")) return $"{name}es"; else return $"{name}s"; } public override object ConvertTo(ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value, Type destType) { if (destType == typeof(string) && value is T vart) { // Return department and department role separated by comma. return $"{vart.Count} {(vart.Count == 1 ? typeof(C).Name : Plural(typeof(C).Name))}"; } return base.ConvertTo(context, culture, value, destType); } } #endregion #region vlnIndexedListConverter internal class vlnIndexedListConverter : ExpandableObjectConverter where T : vlnIndexedFormatList where C : vlnFormatItem,IVlnIndexedFormatItem, new() { private string Plural(string name) { if (name.EndsWith("y")) return $"{name.Substring(0, name.Length - 1)}ies"; if (name.EndsWith("ss")) return $"{name}es"; return name.EndsWith("x") ? $"{name}es" : $"{name}s"; } public override object ConvertTo(ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value, Type destType) { if (destType == typeof(string) && value is T vart) { // Return department and department role separated by comma. return $"{vart.MaxIndex} {(vart.MaxIndex == 1 ? typeof(C).Name : Plural(typeof(C).Name))}"; } return base.ConvertTo(context, culture, value, destType); } } #endregion #region vlnPropertyDescriptor public class vlnPropertyDescriptor : PropertyDescriptor where T : vlnFormatList where C : vlnFormatItem, new() { protected C _Item = null; public vlnPropertyDescriptor(T itemList, int index) : base("#" + index.ToString(), null) => _Item = itemList[index]; public override bool CanResetValue(object component) => true; public override Type ComponentType => _Item.GetType(); public override object GetValue(object component) => _Item; public override bool IsReadOnly => true; public override Type PropertyType => _Item.GetType(); public override void ResetValue(object component) { ;} public override bool ShouldSerializeValue(object component) => true; public override void SetValue(object component, object value) { /*_Item = value*/;} public override string DisplayName => _Item.GetPDDisplayName(); public override string Description => _Item.GetPDDescription(); public override string Name => _Item.GetPDName(); public override string Category => _Item.GetPDCategory(); } // Class #endregion }