//******************************************************************************************************
// LogicalParser.cs - Gbtc
//
// Copyright © 2012, 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://www.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:
// ----------------------------------------------------------------------------------------------------
// 05/03/2012 - Stephen C. Wills, Grid Protection Alliance
// Generated original version of source code.
// 12/17/2012 - Starlynn Danyelle Gilliam
// Modified Header.
//
//******************************************************************************************************
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.IO;
using GSF.PQDIF.Physical;
namespace GSF.PQDIF.Logical
{
///
/// Represents a parser which parses the logical structure of a PQDIF file.
///
///
///
/// This class makes the data from PQD files readily available to applications and defines several
/// redundant properties throughout the logical hierarchy of the PQDIF file to also facilitate
/// the association of definitions with instances within the logical structure. The following
/// list enumerates some of the more useful associations within the hierarchy.
///
///
///
///
///
///
///
///
///
///
///
/// Usage consists of iterating through observations () to
/// examine each of the the measurements recorded in the file. As was noted in the list above,
/// the data source () and settings for the monitor
/// () associated with each observation is exposed as a
/// property on the observation record. Note that the same data source and monitor settings
/// records may be referenced by multiple observation records in the file.
///
///
///
/// The following example demonstrates how to read all observation records from a PQDIF file
/// using the logical parser.
///
///
/// observationRecords = new List();
/// string fileName = args[0];
///
/// using (LogicalParser parser = new LogicalParser(fileName))
/// {
/// parser.Open();
/// containerRecord = parser.ContainerRecord;
///
/// while (parser.HasNextObservationRecord())
/// observationRecords.Add(parser.NextObservationRecord());
/// }
/// ]]>
///
public class LogicalParser : IDisposable
{
#region [ Members ]
// Fields
private readonly PhysicalParser m_physicalParser;
private ContainerRecord m_containerRecord;
private DataSourceRecord m_currentDataSourceRecord;
private MonitorSettingsRecord m_currentMonitorSettingsRecord;
private ObservationRecord m_nextObservationRecord;
private List m_allDataSourceRecords;
#endregion
#region [ Constructors ]
///
/// Creates a new instance of the class.
///
/// Path to the PQDIF file to be parsed.
public LogicalParser(string filePath)
{
m_physicalParser = new PhysicalParser(filePath);
m_allDataSourceRecords = new List();
}
///
/// Creates a new instance of the class.
///
/// The stream containing the PQDIF file data.
/// True if the stream should be closed when the parser is closed; false otherwise.
/// is null.
/// is not both readable and seekable.
public LogicalParser(Stream stream, bool leaveOpen = false)
{
m_physicalParser = new PhysicalParser(null);
m_allDataSourceRecords = new List();
Open(stream, leaveOpen);
}
#endregion
#region [ Properties ]
///
/// Gets or sets the file path (not just the name) of the PQDIF file to be parsed.
/// Obsolete in favor of .
///
[Obsolete("Property is deprecated. Please use FilePath instead.")]
[EditorBrowsable(EditorBrowsableState.Never)]
public string FileName
{
get
{
return m_physicalParser.FilePath;
}
set
{
m_physicalParser.FilePath = value;
}
}
///
/// Gets or sets the file path of the PQDIF file to be parsed.
///
public string FilePath
{
get
{
return m_physicalParser.FilePath;
}
set
{
m_physicalParser.FilePath = value;
}
}
///
/// Gets the container record from the PQDIF file. This is
/// parsed as soon as the parser is ed.
///
public ContainerRecord ContainerRecord
{
get
{
return m_containerRecord;
}
}
///
/// Gets a list of all DataSource records from the PQDIF file. This is
/// parsed when passing throug the observation records ed.
///
public List DataSourceRecords
{
get
{
return m_allDataSourceRecords;
}
}
#endregion
#region [ Methods ]
///
/// Opens the parser and parses the .
///
/// has not been defined.
/// An unsupported compression mode was defined in the PQDIF file.
public void Open()
{
m_physicalParser.Open();
m_containerRecord = ContainerRecord.CreateContainerRecord(m_physicalParser.NextRecord());
m_physicalParser.CompressionAlgorithm = m_containerRecord.CompressionAlgorithm;
m_physicalParser.CompressionStyle = m_containerRecord.CompressionStyle;
}
///
/// Opens the parser and parses the .
///
/// The stream containing the PQDIF file data.
/// True if the stream should be closed when the parser is closed; false otherwise.
/// is null.
/// is not both readable and seekable.
/// An unsupported compression mode was defined in the PQDIF file.
public void Open(Stream stream, bool leaveOpen = false)
{
m_physicalParser.Open(stream, leaveOpen);
m_containerRecord = ContainerRecord.CreateContainerRecord(m_physicalParser.NextRecord());
m_physicalParser.CompressionAlgorithm = m_containerRecord.CompressionAlgorithm;
m_physicalParser.CompressionStyle = m_containerRecord.CompressionStyle;
}
///
/// Determines whether there are any more
/// s to be
/// read from the PQDIF file.
///
/// true if there is another observation record to be read from PQDIF file; false otherwise
public bool HasNextObservationRecord()
{
Record physicalRecord;
RecordType recordType;
// Read records from the file until we encounter an observation record or end of file
while ((object)m_nextObservationRecord == null && m_physicalParser.HasNextRecord())
{
physicalRecord = m_physicalParser.NextRecord();
recordType = physicalRecord.Header.TypeOfRecord;
switch (recordType)
{
case RecordType.DataSource:
// Keep track of the latest data source record in order to associate it with observation records
m_currentDataSourceRecord = DataSourceRecord.CreateDataSourceRecord(physicalRecord);
m_allDataSourceRecords.Add(m_currentDataSourceRecord);
break;
case RecordType.MonitorSettings:
// Keep track of the latest monitor settings record in order to associate it with observation records
m_currentMonitorSettingsRecord = MonitorSettingsRecord.CreateMonitorSettingsRecord(physicalRecord);
break;
case RecordType.Observation:
// Found an observation record!
m_nextObservationRecord = ObservationRecord.CreateObservationRecord(physicalRecord, m_currentDataSourceRecord, m_currentMonitorSettingsRecord);
break;
case RecordType.Container:
// The container record is parsed when the file is opened; it should never be encountered here
throw new InvalidOperationException("Found more than one container record in PQDIF file.");
default:
// Ignore unrecognized record types as the rest of the file might be valid.
//throw new ArgumentOutOfRangeException(string.Format("Unknown record type: {0}", physicalRecord.Header.RecordTypeTag));
break;
}
}
return (object)m_nextObservationRecord != null;
}
///
/// Gets the next observation record from the PQDIF file.
///
/// The next observation record.
public ObservationRecord NextObservationRecord()
{
ObservationRecord nextObservationRecord;
// Call this first to read ahead to the next
// observation record if we haven't already
HasNextObservationRecord();
// We need to set m_nextObservationRecord to null so that
// subsequent calls to HasNextObservationRecord() will
// continue to parse new records
nextObservationRecord = m_nextObservationRecord;
m_nextObservationRecord = null;
return nextObservationRecord;
}
///
/// Resets the parser to the beginning of the PQDIF file.
///
public void Reset()
{
m_currentDataSourceRecord = null;
m_currentMonitorSettingsRecord = null;
m_nextObservationRecord = null;
m_allDataSourceRecords = new List();
m_physicalParser.Reset();
m_physicalParser.NextRecord(); // skip container record
}
///
/// Closes the PQDIF file.
///
public void Close()
{
m_physicalParser.Close();
}
///
/// Releases resources held by the parser.
///
public void Dispose()
{
m_physicalParser.Dispose();
}
#endregion
}
}