//****************************************************************************************************** // ArchiveDataBlockPointer.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: // ---------------------------------------------------------------------------------------------------- // 02/18/2007 - Pinal C. Patel // Generated original version of code based on DatAWare system specifications by Brian B. Fox, GSF. // 04/20/2009 - Pinal C. Patel // Converted to C#. // 09/15/2009 - Stephen C. Wills // Added new header and license agreement. // 09/23/2009 - Pinal C. Patel // Edited code comments. // 10/11/2010 - Mihir Brahmbhatt // Updated header and license agreement. // 11/30/2011 - J. Ritchie Carroll // Modified to support buffer optimized ISupportBinaryImage. // 12/14/2012 - Starlynn Danyelle Gilliam // Modified Header. // //****************************************************************************************************** using System; using GSF.Parsing; namespace GSF.Historian.Files { /// /// Represents a pointer to an . /// /// /// public class ArchiveDataBlockPointer : IComparable, ISupportBinaryImage { #region [ Members ] // Constants /// /// Specifies the number of bytes in the binary image of . /// public const int FixedLength = 12; // Fields private readonly int m_index; private int m_historianID; private TimeTag m_startTime; private readonly ArchiveFile m_parent; #endregion #region [ Constructors ] /// /// Initializes a new instance of the class. /// /// An object. /// 0-based index of the . internal ArchiveDataBlockPointer(ArchiveFile parent, int index) { m_parent = parent; m_index = index; Reset(); } /// /// Initializes a new instance of the class. /// /// An object. /// 0-based index of the . /// Binary image to be used for initializing . /// 0-based starting index of initialization data in the . /// Valid number of bytes in from . internal ArchiveDataBlockPointer(ArchiveFile parent, int index, byte[] buffer, int startIndex, int length) : this(parent, index) { ParseBinaryImage(buffer, startIndex, length); } #endregion #region [ Properties ] /// /// Gets or sets the historian identifier of . /// /// The value being assigned is not positive or -1. public int HistorianID { get { return m_historianID; } set { if (value < 1 && value != -1) throw new ArgumentException("Value must be positive or -1"); m_historianID = value; } } /// /// Gets or sets the of first in the . /// /// The value being assigned is not between 01/01/1995 and 01/19/2063. public TimeTag StartTime { get { return m_startTime; } set { if (value.CompareTo(TimeTag.MinValue) < 0 || value.CompareTo(TimeTag.MaxValue) > 0) throw new ArgumentException("Value must between 01/01/1995 and 01/19/2063"); m_startTime = value; } } /// /// Gets the 0-based index of the . /// public int Index { get { return m_index; } } /// /// Gets the corresponding to the . /// public ArchiveDataBlock DataBlock { get { return GetDataBlock(true); } } /// /// Gets a boolean value that indicates whether the has been allocated to contain s. /// public bool IsAllocated { get { return m_historianID != -1 && m_startTime.CompareTo(TimeTag.MinValue) != 0; } } /// /// Gets the length of the . /// public int BinaryLength { get { return FixedLength; } } #endregion #region [ Methods ] /// /// Gets the associated with this . /// /// true to pre-read data to locate write cursor. /// The associated with this . public ArchiveDataBlock GetDataBlock(bool preRead) { return new ArchiveDataBlock(m_parent, m_index, m_historianID, preRead); } /// /// Deallocates the to store new s. /// public void Reset() { m_historianID = -1; m_startTime = TimeTag.MinValue; } /// /// Initializes from the specified . /// /// Binary image to be used for initializing . /// 0-based starting index of initialization data in the . /// Valid number of bytes in from . /// Number of bytes used from the for initializing . public int ParseBinaryImage(byte[] buffer, int startIndex, int length) { if (length >= FixedLength) { // Binary image has sufficient data. HistorianID = LittleEndian.ToInt32(buffer, startIndex); StartTime = new TimeTag((decimal)LittleEndian.ToDouble(buffer, startIndex + 4)); return FixedLength; } // Binary image does not have sufficient data. return 0; } /// /// Generates binary image of the and copies it into the given buffer, for bytes. /// /// Buffer used to hold generated binary image of the source object. /// 0-based starting index in the to start writing. /// The number of bytes written to the . /// is null. /// /// or is less than 0 -or- /// and will exceed length. /// public int GenerateBinaryImage(byte[] buffer, int startIndex) { int length = BinaryLength; buffer.ValidateParameters(startIndex, length); Buffer.BlockCopy(LittleEndian.GetBytes(m_historianID), 0, buffer, startIndex, 4); Buffer.BlockCopy(LittleEndian.GetBytes((double)m_startTime.Value), 0, buffer, startIndex + 4, 8); return length; } /// /// Compares the current object to . /// /// Object against which the current object is to be compared. /// /// Negative value if the current object is less than , /// Zero if the current object is equal to , /// Positive value if the current object is greater than . /// public virtual int CompareTo(object obj) { ArchiveDataBlockPointer other = obj as ArchiveDataBlockPointer; if ((object)other == null) return 1; int result = m_historianID.CompareTo(other.HistorianID); if (result != 0) return result; return m_startTime.CompareTo(other.StartTime); } /// /// Determines whether the current object is equal to . /// /// Object against which the current object is to be compared for equality. /// true if the current object is equal to ; otherwise false. public override bool Equals(object obj) { return (CompareTo(obj) == 0); } /// /// Returns the text representation of object. /// /// A value. public override string ToString() { return string.Format("ID: {0}; Start time: {1}", m_historianID, m_startTime); } /// /// Returns the hash code for the current object. /// /// A 32-bit signed integer value. public override int GetHashCode() { return m_historianID.GetHashCode(); } #endregion } /// /// Extension methods for the . /// public static class ArchiveDataBlockPointerExtensions { /// /// Tests if the matches the specified search criteria. /// /// to test. /// Desired historian ID. /// Desired start time. /// Desired end time. /// true if the specified is for and falls within the and ; otherwise false. public static bool Matches(this ArchiveDataBlockPointer dataBlockPointer, int historianID, TimeTag startTime, TimeTag endTime) { // Note: The StartTime value of the pointer is ignored if m_searchStartTime = TimeTag.MinValue and // m_searchEndTime = TimeTag.MaxValue. In this case only the PointID value is compared. This // comes in handy when the first or last pointer is to be found from the list of pointers for // a point ID in addition to all the pointers for a point ID. if ((object)dataBlockPointer != null) return dataBlockPointer.HistorianID == historianID && (startTime.CompareTo(TimeTag.MinValue) == 0 || dataBlockPointer.StartTime.CompareTo(startTime) >= 0) && (endTime.CompareTo(TimeTag.MaxValue) == 0 || dataBlockPointer.StartTime.CompareTo(endTime) <= 0); return false; } } }