//******************************************************************************************************
// LogicalWriter.cs - Gbtc
//
// Copyright © 2015, Grid Protection Alliance. All Rights Reserved.
//
// Licensed to the Grid Protection Alliance (GPA) under one or more contributor license agreements. See
// the NOTICE file distributed with this work for additional information regarding copyright ownership.
// The GPA licenses this file to you under the MIT License (MIT), the "License"; you may
// not use this file except in compliance with the License. You may obtain a copy of the License at:
//
// http://opensource.org/licenses/MIT
//
// Unless agreed to in writing, the subject software distributed under the License is distributed on an
// "AS-IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. Refer to the
// License for the specific language governing permissions and limitations.
//
// Code Modification History:
// ----------------------------------------------------------------------------------------------------
// 09/14/2015 - Stephen C. Wills
// Generated original version of source code.
//
//******************************************************************************************************
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using GSF.PQDIF.Physical;
namespace GSF.PQDIF.Logical
{
///
/// Represents an exception
///
public sealed class MissingTag
{
#region [ Members ]
// Fields
private RecordType m_recordType;
private string m_tagName;
private Guid m_tag;
#endregion
#region [ Constructors ]
///
/// Creates a new instance of the class.
///
/// The type of record the tag is missing from.
/// The name of the tag.
/// The globally unique identifier for the tag.
public MissingTag(RecordType recordType, string tagName, Guid tag)
{
m_recordType = recordType;
m_tagName = tagName;
m_tag = tag;
}
#endregion
#region [ Properties ]
///
/// Gets the type of the record in which
/// the tag was identified as missing.
///
public RecordType RecordType
{
get
{
return m_recordType;
}
}
///
/// Gets the name of the missing tag.
///
public string TagName
{
get
{
return m_tagName;
}
}
///
/// Gets the globally unique identifier for the given tag.
///
public Guid Tag
{
get
{
return m_tag;
}
}
#endregion
}
///
/// Represents a writer used to create files using the PQDIF file format.
///
public sealed class LogicalWriter : IDisposable
{
#region [ Members ]
// Fields
private PhysicalWriter m_physicalWriter;
private ContainerRecord m_containerRecord;
private DataSourceRecord m_currentDataSource;
private MonitorSettingsRecord m_currentMonitorSettings;
private List m_missingTags;
private bool m_disposed;
#endregion
#region [ Constructors ]
///
/// Creates a new instance of the class.
///
/// The path to the file where the PQDIF data is to be written.
public LogicalWriter(string filePath)
{
m_physicalWriter = new PhysicalWriter(filePath);
m_missingTags = new List();
}
///
/// Creates a new instance of the class.
///
/// The stream to write the PQDIF data to.
/// Indicates whether to leave the stream open when disposing of the writer.
public LogicalWriter(Stream stream, bool leaveOpen = false)
{
m_physicalWriter = new PhysicalWriter(stream, leaveOpen);
m_missingTags = new List();
}
#endregion
#region [ Properties ]
///
/// Gets a collection of required tags identified as
/// missing from the records written to this PQDIF file.
///
public IReadOnlyCollection MissingTags
{
get
{
return m_missingTags.AsReadOnly();
}
}
#endregion
#region [ Methods ]
///
/// Writes the given container record to the file stream.
///
/// The container record to be written to the PQDIF file.
public void Write(ContainerRecord containerRecord)
{
if ((object)containerRecord == null)
throw new ArgumentNullException("containerRecord");
if (m_disposed)
throw new ObjectDisposedException(GetType().Name);
if ((object)m_containerRecord != null)
throw new InvalidOperationException("Only one container record can be written to a PQDIF file.");
ValidateContainerRecord(containerRecord);
m_containerRecord = containerRecord;
m_physicalWriter.WriteRecord(containerRecord.PhysicalRecord);
m_physicalWriter.CompressionAlgorithm = m_containerRecord.CompressionAlgorithm;
m_physicalWriter.CompressionStyle = m_containerRecord.CompressionStyle;
}
///
/// Writes the given observation record, as well as its data source
/// and monitor settings records if necessary, to the file stream.
///
/// The observation record to be written to the PQDIF file.
/// Indicates whether this observation record is the last record in the file.
public void Write(ObservationRecord observationRecord, bool lastRecord = false)
{
if ((object)observationRecord == null)
throw new ArgumentNullException("observationRecord");
if (m_disposed)
throw new ObjectDisposedException(GetType().Name);
if ((object)m_containerRecord == null)
throw new InvalidOperationException("Container record must be the first record in a PQDIF file.");
if ((object)observationRecord.DataSource == null)
throw new InvalidOperationException("An observation record must have a data source.");
if (!ReferenceEquals(m_currentDataSource, observationRecord.DataSource))
ValidateDataSourceRecord(observationRecord.DataSource);
if ((object)observationRecord.Settings != null && !ReferenceEquals(m_currentMonitorSettings, observationRecord.Settings))
ValidateMonitorSettingsRecord(observationRecord.Settings);
ValidateObservationRecord(observationRecord);
if (!ReferenceEquals(m_currentDataSource, observationRecord.DataSource))
{
m_currentMonitorSettings = null;
m_currentDataSource = observationRecord.DataSource;
m_physicalWriter.WriteRecord(observationRecord.DataSource.PhysicalRecord);
}
if ((object)observationRecord.Settings != null && !ReferenceEquals(m_currentMonitorSettings, observationRecord.Settings))
{
m_currentMonitorSettings = observationRecord.Settings;
m_physicalWriter.WriteRecord(observationRecord.Settings.PhysicalRecord);
}
m_physicalWriter.WriteRecord(observationRecord.PhysicalRecord, lastRecord);
}
///
/// Releases the unmanaged resources used by the object and optionally releases the managed resources.
///
public void Dispose()
{
if (!m_disposed)
{
try
{
m_physicalWriter.Dispose();
}
finally
{
m_disposed = true;
}
}
}
private void ValidateContainerRecord(ContainerRecord containerRecord)
{
if (!containerRecord.PhysicalRecord.Body.Collection.GetElementsByTag(ContainerRecord.VersionInfoTag).Any())
m_missingTags.Add(new MissingTag(RecordType.Container, "VersionInfoTag", ContainerRecord.VersionInfoTag));
if (!containerRecord.PhysicalRecord.Body.Collection.GetElementsByTag(ContainerRecord.FileNameTag).Any())
m_missingTags.Add(new MissingTag(RecordType.Container, "FileNameTag", ContainerRecord.FileNameTag));
if (!containerRecord.PhysicalRecord.Body.Collection.GetElementsByTag(ContainerRecord.VersionInfoTag).Any())
m_missingTags.Add(new MissingTag(RecordType.Container, "CreationTag", ContainerRecord.CreationTag));
}
private void ValidateDataSourceRecord(DataSourceRecord dataSourceRecord)
{
if (!dataSourceRecord.PhysicalRecord.Body.Collection.GetElementsByTag(DataSourceRecord.DataSourceTypeIDTag).Any())
m_missingTags.Add(new MissingTag(RecordType.DataSource, "DataSourceTypeTag", DataSourceRecord.DataSourceTypeIDTag));
if (!dataSourceRecord.PhysicalRecord.Body.Collection.GetElementsByTag(DataSourceRecord.DataSourceNameTag).Any())
m_missingTags.Add(new MissingTag(RecordType.DataSource, "DataSourceNameTag", DataSourceRecord.DataSourceNameTag));
if (!dataSourceRecord.PhysicalRecord.Body.Collection.GetElementsByTag(DataSourceRecord.EffectiveTag).Any())
m_missingTags.Add(new MissingTag(RecordType.DataSource, "EffectiveTag", DataSourceRecord.EffectiveTag));
if (!dataSourceRecord.PhysicalRecord.Body.Collection.GetElementsByTag(DataSourceRecord.ChannelDefinitionsTag).Any())
m_missingTags.Add(new MissingTag(RecordType.DataSource, "ChannelDefinitionsTag", DataSourceRecord.ChannelDefinitionsTag));
if (dataSourceRecord.ChannelDefinitions.Count == 0)
m_missingTags.Add(new MissingTag(RecordType.DataSource, "OneChannelDefinitionTag", DataSourceRecord.OneChannelDefinitionTag));
foreach (ChannelDefinition channelDefinition in dataSourceRecord.ChannelDefinitions)
{
if (!channelDefinition.PhysicalStructure.GetElementsByTag(ChannelDefinition.PhaseIDTag).Any())
m_missingTags.Add(new MissingTag(RecordType.DataSource, "PhaseIDTag", ChannelDefinition.PhaseIDTag));
if (!channelDefinition.PhysicalStructure.GetElementsByTag(ChannelDefinition.QuantityTypeIDTag).Any())
m_missingTags.Add(new MissingTag(RecordType.DataSource, "QuantityTypeIDTag", ChannelDefinition.QuantityTypeIDTag));
if (!channelDefinition.PhysicalStructure.GetElementsByTag(ChannelDefinition.QuantityMeasuredIDTag).Any())
m_missingTags.Add(new MissingTag(RecordType.DataSource, "QuantityMeasuredIDTag", ChannelDefinition.QuantityMeasuredIDTag));
if (!channelDefinition.PhysicalStructure.GetElementsByTag(ChannelDefinition.SeriesDefinitionsTag).Any())
m_missingTags.Add(new MissingTag(RecordType.DataSource, "SeriesDefinitionsTag", ChannelDefinition.SeriesDefinitionsTag));
if (channelDefinition.SeriesDefinitions.Count == 0)
m_missingTags.Add(new MissingTag(RecordType.DataSource, "OneSeriesDefinitionTag", ChannelDefinition.OneSeriesDefinitionTag));
foreach (SeriesDefinition seriesDefinition in channelDefinition.SeriesDefinitions)
{
if (!seriesDefinition.PhysicalStructure.GetElementsByTag(SeriesDefinition.ValueTypeIDTag).Any())
m_missingTags.Add(new MissingTag(RecordType.DataSource, "ValueTypeIDTag", SeriesDefinition.ValueTypeIDTag));
if (!seriesDefinition.PhysicalStructure.GetElementsByTag(SeriesDefinition.QuantityUnitsIDTag).Any())
m_missingTags.Add(new MissingTag(RecordType.DataSource, "QuantityUnitsIDTag", SeriesDefinition.QuantityUnitsIDTag));
if (!seriesDefinition.PhysicalStructure.GetElementsByTag(SeriesDefinition.QuantityCharacteristicIDTag).Any())
m_missingTags.Add(new MissingTag(RecordType.DataSource, "QuantityCharacteristicIDTag", SeriesDefinition.QuantityCharacteristicIDTag));
if (!seriesDefinition.PhysicalStructure.GetElementsByTag(SeriesDefinition.StorageMethodIDTag).Any())
m_missingTags.Add(new MissingTag(RecordType.DataSource, "StorageMethodIDTag", SeriesDefinition.StorageMethodIDTag));
}
}
}
private void ValidateMonitorSettingsRecord(MonitorSettingsRecord monitorSettingsRecord)
{
if (!monitorSettingsRecord.PhysicalRecord.Body.Collection.GetElementsByTag(MonitorSettingsRecord.EffectiveTag).Any())
m_missingTags.Add(new MissingTag(RecordType.MonitorSettings, "EffectiveTag", MonitorSettingsRecord.EffectiveTag));
if (!monitorSettingsRecord.PhysicalRecord.Body.Collection.GetElementsByTag(MonitorSettingsRecord.TimeInstalledTag).Any())
m_missingTags.Add(new MissingTag(RecordType.MonitorSettings, "TimeInstalledTag", MonitorSettingsRecord.TimeInstalledTag));
if (!monitorSettingsRecord.PhysicalRecord.Body.Collection.GetElementsByTag(MonitorSettingsRecord.UseCalibrationTag).Any())
m_missingTags.Add(new MissingTag(RecordType.MonitorSettings, "UseCalibrationTag", MonitorSettingsRecord.UseCalibrationTag));
if (!monitorSettingsRecord.PhysicalRecord.Body.Collection.GetElementsByTag(MonitorSettingsRecord.UseTransducerTag).Any())
m_missingTags.Add(new MissingTag(RecordType.MonitorSettings, "UseTransducerTag", MonitorSettingsRecord.UseTransducerTag));
if (!monitorSettingsRecord.PhysicalRecord.Body.Collection.GetElementsByTag(MonitorSettingsRecord.ChannelSettingsArrayTag).Any())
m_missingTags.Add(new MissingTag(RecordType.MonitorSettings, "ChannelSettingsArrayTag", MonitorSettingsRecord.ChannelSettingsArrayTag));
if (monitorSettingsRecord.ChannelSettings.Count == 0)
m_missingTags.Add(new MissingTag(RecordType.MonitorSettings, "OneChannelSettingTag", MonitorSettingsRecord.OneChannelSettingTag));
foreach (ChannelSetting channelSetting in monitorSettingsRecord.ChannelSettings)
{
if (!channelSetting.PhysicalStructure.GetElementsByTag(ChannelDefinition.ChannelDefinitionIndexTag).Any())
m_missingTags.Add(new MissingTag(RecordType.MonitorSettings, "ChannelDefinitionIndexTag", ChannelDefinition.ChannelDefinitionIndexTag));
}
}
private void ValidateObservationRecord(ObservationRecord observationRecord)
{
if (!observationRecord.PhysicalRecord.Body.Collection.GetElementsByTag(ObservationRecord.ObservationNameTag).Any())
m_missingTags.Add(new MissingTag(RecordType.Observation, "ObservationNameTag", ObservationRecord.ObservationNameTag));
if (!observationRecord.PhysicalRecord.Body.Collection.GetElementsByTag(ObservationRecord.TimeCreateTag).Any())
m_missingTags.Add(new MissingTag(RecordType.Observation, "TimeCreateTag", ObservationRecord.TimeCreateTag));
if (!observationRecord.PhysicalRecord.Body.Collection.GetElementsByTag(ObservationRecord.TimeStartTag).Any())
m_missingTags.Add(new MissingTag(RecordType.Observation, "TimeStartTag", ObservationRecord.TimeStartTag));
if (!observationRecord.PhysicalRecord.Body.Collection.GetElementsByTag(ObservationRecord.TriggerMethodTag).Any())
m_missingTags.Add(new MissingTag(RecordType.Observation, "TriggerMethodTag", ObservationRecord.TriggerMethodTag));
if (!observationRecord.PhysicalRecord.Body.Collection.GetElementsByTag(ObservationRecord.ChannelInstancesTag).Any())
m_missingTags.Add(new MissingTag(RecordType.Observation, "ChannelInstancesTag", ObservationRecord.ChannelInstancesTag));
if (observationRecord.ChannelInstances.Count == 0)
m_missingTags.Add(new MissingTag(RecordType.Observation, "OneChannelInstanceTag", ObservationRecord.OneChannelInstanceTag));
foreach (ChannelInstance channelInstance in observationRecord.ChannelInstances)
{
if (!channelInstance.PhysicalStructure.GetElementsByTag(ChannelDefinition.ChannelDefinitionIndexTag).Any())
m_missingTags.Add(new MissingTag(RecordType.Observation, "ChannelDefinitionIndexTag", ChannelDefinition.ChannelDefinitionIndexTag));
if (!channelInstance.PhysicalStructure.GetElementsByTag(ChannelInstance.SeriesInstancesTag).Any())
m_missingTags.Add(new MissingTag(RecordType.Observation, "SeriesInstancesTag", ChannelInstance.SeriesInstancesTag));
if (channelInstance.SeriesInstances.Count == 0)
m_missingTags.Add(new MissingTag(RecordType.Observation, "OneSeriesInstanceTag", ChannelInstance.OneSeriesInstanceTag));
foreach (SeriesInstance seriesInstance in channelInstance.SeriesInstances)
{
if (!seriesInstance.PhysicalStructure.GetElementsByTag(SeriesInstance.SeriesValuesTag).Any())
m_missingTags.Add(new MissingTag(RecordType.Observation, "SeriesValuesTag", SeriesInstance.SeriesValuesTag));
}
}
}
#endregion
}
}