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