// Copyright (C) Stichting Deltares 2018. All rights reserved.
//
// This file is part of the application DAM - Clients Library.
//
// DAM - UI is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see .
//
// All names, logos, and references to "Deltares" are registered trademarks of
// Stichting Deltares and remain full property of Stichting Deltares at all times.
// All rights reserved.
using System;
using System.Collections.Generic;
using Deltares.Standard;
using System.Reflection;
using System.Xml.Linq;
using System.Xml.Schema;
using System.IO;
using System.Xml;
using System.Globalization;
using Deltares.Standard.IO.DtoAssembler;
namespace Deltares.Dam.Data.Assemblers
{
using Standard.Extensions;
public class TimeSeriesAssembler : DtoAssembler
{
#region Constant declarations
///
/// Holds the xml element name
///
private const string XmlElementName = "TimeSeries";
///
/// Holds the name of the xml schema
///
private const string XmlSchemaName = "pi_timeseries";
private const string XmlSchemaNameSharedTypes = "pi_sharedtypes";
///
/// Holds the xml namespace
///
private const string XmlElementNamespace = "http://www.wldelft.nl/fews/PI";
///
/// Holds the common part of the path to the embedded resource
///
private const string EmbeddedResourcePath = "Deltares.Dam.Data.Xsd";
///
/// Holds the xsd resource path
///
private const string XsdEmbeddedResourcePath = EmbeddedResourcePath + "." + XmlSchemaName + ".xsd";
private const string XsdEmbeddedResourcePathSharedTypes = EmbeddedResourcePath + "." + XmlSchemaNameSharedTypes + ".xsd";
public const string XmlVersionAttributeName = "version";
public const string XmlTimeZoneElementName = "timeZone";
public const string XmlSeriesElementName = "series";
public const string XmlHeaderElementName = "header";
public const string XmlTypeElementName = "type";
public const string XmlLocationIdElementName = "locationId";
public const string XmlParameterIdElementName = "parameterId";
public const string XmlTimeStepElementName = "timeStep";
public const string XmlStartDateElementName = "startDate";
public const string XmlEndDateElementName = "endDate";
public const string XmlForecastDateElementName = "forecastDate";
public const string XmlMissValElementName = "missVal";
public const string XmlLongNameElementName = "longName";
public const string XmlStationNameElementName = "stationName";
public const string XmlUnitsElementName = "units";
public const string XmlSourceOrganisationElementName = "sourceOrganisation";
public const string XmlSourceSystemElementName = "sourceSystem";
public const string XmlFileDescriptionElementName = "fileDescription";
public const string XmlCreationDateElementName = "creationDate";
public const string XmlCreationTimeElementName = "creationTime";
public const string XmlRegionElementName = "region";
public const string XmlUnitAttributeName = "unit";
public const string XmlDividerAttributeName = "divider";
public const string XmlMultiplierAttributeName = "multiplier";
public const string XmlDateAttributeName = "date";
public const string XmlTimeAttributeName = "time";
public const string XmlEntryElementName = "event";
public const string XmlValueAttributeName = "value";
public const string XmlFlagAttributeName = "flag";
public const string XMLCommentElementName = "comment";
#endregion
public TimeSeriesAssembler()
: base(XmlElementName, XmlElementNamespace, Assembly.GetExecutingAssembly().GetEmbeddedFile(XsdEmbeddedResourcePath))
{
AddOrUpdateMapping("Version", XmlVersionAttributeName);
}
public override TimeSerieCollection CreateDomainObject(XElement dtoObj)
{
TimeSerieCollection timeSerieCollection = base.CreateDomainObject(dtoObj);
XNamespace tns = this.ElementNamespace;
// Time zone
XElement timeZoneElement = dtoObj.Element(tns + TimeSeriesAssembler.XmlTimeZoneElementName);
if (timeZoneElement != null)
{
timeSerieCollection.TimeZone = Double.Parse(timeZoneElement.Value, CultureInfo.InvariantCulture);
}
// Series
IEnumerable serieElementCollection = dtoObj.Elements(tns + TimeSeriesAssembler.XmlSeriesElementName);
foreach (XElement serieElement in serieElementCollection)
{
var timeSerie = new TimeSerie();
// Header
XElement headerElement = serieElement.Element(tns + TimeSeriesAssembler.XmlHeaderElementName);
timeSerie.Type = GetElementValue(headerElement, tns + XmlTypeElementName);
timeSerie.LocationId = GetElementValue(headerElement, tns + XmlLocationIdElementName);
timeSerie.ParameterId = GetElementValue(headerElement, tns + XmlParameterIdElementName);
XElement timeStepElement = headerElement.Element(tns + TimeSeriesAssembler.XmlTimeStepElementName);
timeSerie.TimeStep.Unit = (TimeStepUnit)Enum.Parse(typeof(TimeStepUnit), timeStepElement.AttributeAs(TimeSeriesAssembler.XmlUnitAttributeName), true);
timeSerie.TimeStep.Divider = timeStepElement.AttributeAs(TimeSeriesAssembler.XmlDividerAttributeName);
timeSerie.TimeStep.Multiplier = timeStepElement.AttributeAs(TimeSeriesAssembler.XmlMultiplierAttributeName);
XElement startDateElement = headerElement.Element(tns + TimeSeriesAssembler.XmlStartDateElementName);
timeSerie.StartDateTime = startDateElement.AttributeAs(TimeSeriesAssembler.XmlDateAttributeName).Date +
startDateElement.AttributeAs(TimeSeriesAssembler.XmlTimeAttributeName).TimeOfDay;
XElement endDateElement = headerElement.Element(tns + TimeSeriesAssembler.XmlEndDateElementName);
timeSerie.EndDateTime = endDateElement.AttributeAs(TimeSeriesAssembler.XmlDateAttributeName).Date +
endDateElement.AttributeAs(TimeSeriesAssembler.XmlTimeAttributeName).TimeOfDay;
XElement forecastDateElement = headerElement.Element(tns + TimeSeriesAssembler.XmlForecastDateElementName);
if (forecastDateElement != null)
{
timeSerie.ForecastDateTime = forecastDateElement.AttributeAs(TimeSeriesAssembler.XmlDateAttributeName).Date +
forecastDateElement.AttributeAs(TimeSeriesAssembler.XmlTimeAttributeName).TimeOfDay;
}
timeSerie.MissVal = GetElementValue(headerElement, tns + XmlMissValElementName);
timeSerie.LongName = GetElementValue(headerElement, tns + XmlLongNameElementName);
timeSerie.StationName = GetElementValue(headerElement, tns + XmlStationNameElementName);
timeSerie.Units = GetElementValue(headerElement, tns + XmlUnitsElementName);
timeSerie.SourceOrganisation = GetElementValue(headerElement, tns + XmlSourceOrganisationElementName);
timeSerie.SourceSystem = GetElementValue(headerElement, tns + XmlSourceSystemElementName);
timeSerie.FileDescription = GetElementValue(headerElement, tns + XmlFileDescriptionElementName);
XElement creationDateElement = headerElement.Element(tns + XmlCreationDateElementName);
XElement creationTimeElement = headerElement.Element(tns + XmlCreationTimeElementName);
if (creationDateElement != null)
{
timeSerie.CreationDateTime = creationDateElement.Value.ToType().Date;
if (creationTimeElement != null)
{
timeSerie.CreationDateTime += creationTimeElement.Value.ToType().TimeOfDay;
}
}
timeSerie.Region = GetElementValue(headerElement, tns + XmlRegionElementName);
// Entries
IEnumerable entryElementCollection = serieElement.Elements(tns + TimeSeriesAssembler.XmlEntryElementName);
foreach (XElement entryElement in entryElementCollection)
{
TimeSerieEntry entry = new TimeSerieEntry();
entry.DateTime = entryElement.AttributeAs(XmlDateAttributeName).Date +
entryElement.AttributeAs(XmlTimeAttributeName).TimeOfDay;
entry.Value = entryElement.AttributeAs(XmlValueAttributeName);
entry.Flag = entryElement.AttributeAs(XmlFlagAttributeName);
timeSerie.Entries.Add(entry);
}
// Comment
XElement commentElement = serieElement.Element(tns + XMLCommentElementName);
if (commentElement != null)
timeSerie.Comment = commentElement.Value;
timeSerieCollection.Series.Add(timeSerie);
}
return timeSerieCollection;
}
private static T GetElementValue(XContainer parent, XName name)
{
var element = parent.Element(name);
if (element != null)
return element.Value.ToType();
return default(T);
}
public override XElement CreateDataTransferObject(TimeSerieCollection timeSerieCollection)
{
XElement rootElement = base.CreateDataTransferObject(timeSerieCollection);
XNamespace tns = ElementNamespace;
// Time zone
rootElement.Add(new XElement(tns + XmlTimeZoneElementName, timeSerieCollection.TimeZone));
// Series
foreach (TimeSerie timeSerie in timeSerieCollection.Series)
{
XElement serieElement = new XElement(tns + XmlSeriesElementName);
XElement headerElement = new XElement(tns + XmlHeaderElementName);
headerElement.Add(new XElement(tns + XmlTypeElementName, timeSerie.Type));
headerElement.Add(new XElement(tns + XmlLocationIdElementName, timeSerie.LocationId));
headerElement.Add(new XElement(tns + XmlParameterIdElementName, timeSerie.ParameterId));
headerElement.Add(new XElement(tns + XmlTimeStepElementName,
new XAttribute(XmlUnitAttributeName, timeSerie.TimeStep.Unit.ToString().ToLower()),
(timeSerie.TimeStep.MultiplierSpecified ? new XAttribute(XmlMultiplierAttributeName, timeSerie.TimeStep.Multiplier) : null),
(timeSerie.TimeStep.DividerSpecified ? new XAttribute(XmlDividerAttributeName, timeSerie.TimeStep.Divider) : null)
));
headerElement.Add(new XElement(tns + XmlStartDateElementName,
new XAttribute(XmlDateAttributeName, timeSerie.StartDateTime.ToString("yyyy-MM-dd")),
new XAttribute(XmlTimeAttributeName, timeSerie.StartDateTime.ToString("HH:mm:ss"))));
headerElement.Add(new XElement(tns + XmlEndDateElementName,
new XAttribute(XmlDateAttributeName, timeSerie.EndDateTime.ToString("yyyy-MM-dd")),
new XAttribute(XmlTimeAttributeName, timeSerie.EndDateTime.ToString("HH:mm:ss"))));
if (!timeSerie.ForecastDateTime.Equals(DateTime.MinValue))
headerElement.Add(new XElement(tns + XmlForecastDateElementName,
new XAttribute(XmlDateAttributeName, timeSerie.ForecastDateTime.ToString("yyyy-MM-dd")),
new XAttribute(XmlTimeAttributeName, timeSerie.ForecastDateTime.ToString("HH:mm:ss"))));
headerElement.Add(new XElement(tns + XmlMissValElementName, timeSerie.MissVal));
if (timeSerie.LongName != null)
headerElement.Add(new XElement(tns + XmlLongNameElementName, timeSerie.LongName));
if (timeSerie.StationName != null)
headerElement.Add(new XElement(tns + XmlStationNameElementName, timeSerie.StationName));
if (timeSerie.Units != null)
headerElement.Add(new XElement(tns + XmlUnitsElementName, timeSerie.Units));
if (timeSerie.SourceOrganisation != null)
headerElement.Add(new XElement(tns + XmlSourceOrganisationElementName, timeSerie.SourceOrganisation));
if (timeSerie.SourceSystem != null)
headerElement.Add(new XElement(tns + XmlSourceSystemElementName, timeSerie.SourceSystem));
if (timeSerie.FileDescription != null)
headerElement.Add(new XElement(tns + XmlFileDescriptionElementName, timeSerie.FileDescription));
if (timeSerie.CreationDateTime != null)
{
headerElement.Add(new XElement(tns + XmlCreationDateElementName, timeSerie.CreationDateTime.Value.ToString("yyyy-MM-dd")));
headerElement.Add(new XElement(tns + XmlCreationTimeElementName, timeSerie.CreationDateTime.Value.ToString("HH:mm:ss")));
}
if (timeSerie.Region != null)
headerElement.Add(new XElement(tns + XmlRegionElementName, timeSerie.Region));
serieElement.Add(headerElement);
// Entries
foreach (var entry in timeSerie.Entries)
{
XElement entryElement = new XElement(tns + XmlEntryElementName,
new XAttribute(XmlDateAttributeName, entry.DateTime.ToString("yyyy-MM-dd")),
new XAttribute(XmlTimeAttributeName, entry.DateTime.ToString("HH:mm:ss")),
new XAttribute(XmlValueAttributeName, entry.Value),
new XAttribute(XmlFlagAttributeName, entry.Flag));
serieElement.Add(entryElement);
}
// Comment
if (timeSerie.Comment != null)
{
XElement commentElement = new XElement(tns + XMLCommentElementName, timeSerie.Comment);
serieElement.Add(commentElement);
}
rootElement.Add(serieElement);
}
return rootElement;
}
public XDocument CreateDataTransferDocument(TimeSerieCollection timeSerieCollection)
{
XDocument doc = new XDocument(new XDeclaration("1.0", "utf-8", "yes"));
XNamespace xsi = "http://www.w3.org/2001/XMLSchema-instance";
XElement root = CreateDataTransferObject(timeSerieCollection);
doc.Add(root);
root.Add(new XAttribute(XNamespace.Xmlns + "xsi", xsi.NamespaceName));
return doc;
}
public bool ValidateSchema(XDocument doc, out string message)
{
bool result = true;
string errorMessage = String.Empty;
XmlSchemaSet schemas = new XmlSchemaSet();
Stream xsdStream = Assembly.GetExecutingAssembly().GetEmbeddedFile(XsdEmbeddedResourcePath);
schemas.Add(XmlElementNamespace, XmlReader.Create(xsdStream));
xsdStream = Assembly.GetExecutingAssembly().GetEmbeddedFile(XsdEmbeddedResourcePathSharedTypes);
schemas.Add(XmlElementNamespace, XmlReader.Create(xsdStream));
doc.Validate(schemas, (o, e) => { result = false; errorMessage = e.Message; }, true);
message = errorMessage;
return result;
}
}
}