using System; using System.Collections.Generic; using System.IO; using System.Xml; using Wti.Data; namespace Wti.IO { /// /// This class is responsible for reading an array of bytes and interpret this as a XML document, which contains information about /// the geometry of a . /// internal class PipingSoilLayerReader { private const string outerLoopElementName = "OuterLoop"; private const string innerLoopElementName = "InnerLoop"; private const string endPointElementName = "EndPoint"; private const string headPointElementName = "HeadPoint"; private const string xElementName = "X"; private const string yElementName = "Y"; private const string zElementName = "Z"; private readonly XmlTextReader xmlTextReader; /// /// Constructs a new , which uses the as the source of the /// geometry for a . /// /// An array of which contains the information of a /// in an XML document. internal PipingSoilLayerReader(byte[] geometry) { xmlTextReader = new XmlTextReader(new MemoryStream(geometry)); } /// /// Reads the XML document and from this obtains the required information and constructs a based /// on this information. /// /// A new with information taken from the XML document. /// When reading from the XML document of the failed. internal PipingSoilLayer Read() { var pipingSoilLayer = new PipingSoilLayer(); while (xmlTextReader.Read()) { HashSet outerLoop; HashSet innerLoop; if (TryParseLoop(outerLoopElementName, out outerLoop)) { pipingSoilLayer.OuterLoop = outerLoop; } if (TryParseLoop(innerLoopElementName, out innerLoop)) { pipingSoilLayer.InnerLoop = innerLoop; } } return pipingSoilLayer; } /// /// Tries to parse the element with the given , which the reader should be currently pointing at, as a loop. /// /// The name of the element which the reader should be currently pointing at. /// The result of parsing the element as a loop. null if the current element's name does not match . /// True if the reader currently points to an element with name . False otherwise. private bool TryParseLoop(String elementName, out HashSet loop) { loop = null; if (IsElementWithName(elementName)) { loop = new HashSet(); while (xmlTextReader.Read() && !IsEndElementWithName(elementName)) { Point3D parsedPoint; if (TryParsePoint(out parsedPoint)) { loop.Add(parsedPoint); } } return true; } return false; } /// /// Tries to parse the element which the reader is currently pointing at as a point. /// /// The result of parsing the element as a point. null if current element is not a head or end point. /// True if the reader currently points to an element with name or . False otherwise. private bool TryParsePoint(out Point3D point) { point = null; if (IsElementWithName(headPointElementName) || IsElementWithName(endPointElementName)) { var pointValues = ReadChildValues(); point = new Point3D { X = double.Parse(pointValues[xElementName]), Y = double.Parse(pointValues[yElementName]), Z = double.Parse(pointValues[zElementName]) }; return true; } return false; } /// /// Reads the name and values for the children of the current element and puts them in a name indexed dictionary. /// /// A . For each entry, key is equal to child element name and value is equal to the value of the child element's text node. private Dictionary ReadChildValues() { string elementName = xmlTextReader.Name; var nodeSibblings = new Dictionary(); while (xmlTextReader.Read() && !IsEndElementWithName(elementName)) { if (xmlTextReader.NodeType == XmlNodeType.Element) { nodeSibblings[xmlTextReader.Name] = xmlTextReader.ReadString(); } } return nodeSibblings; } /// /// Checks whether the element the reader is currently pointing at is of type and has a name equal to . /// /// The name which the element should have. /// True if the current element has type and its name is equal to . private bool IsElementWithName(string name) { var isElement = xmlTextReader.NodeType == XmlNodeType.Element; var isPoint = xmlTextReader.Name == name; return isElement && isPoint; } /// /// Checks whether the element the reader is currently pointing at is of type and has a name equal to . /// /// The name which the end element should have. /// True if the current element has type and its name is equal to . private bool IsEndElementWithName(string name) { var isElement = xmlTextReader.NodeType == XmlNodeType.EndElement; var isPoint = xmlTextReader.Name == name; return isElement && isPoint; } } }