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;
}
}
}