private HistoryReadRequest CreateHistoryReadRequest()

in src/Azure.IIoT.OpcUa.Publisher.Testing/src/HistoricalAccess/HistoricalAccessNodeManager.cs [1193:1369]


        private HistoryReadRequest CreateHistoryReadRequest(
            ServerSystemContext context,
            ReadRawModifiedDetails details,
            NodeHandle handle,
            HistoryReadValueId nodeToRead)
        {
            var sizeLimited = details.StartTime == DateTime.MinValue || details.EndTime == DateTime.MinValue;
            var applyIndexRangeOrEncoding = nodeToRead.ParsedIndexRange != NumericRange.Empty || !QualifiedName.IsNull(nodeToRead.DataEncoding);
            var returnBounds = !details.IsReadModified && details.ReturnBounds;
            var timeFlowsBackward = (details.StartTime == DateTime.MinValue) || (details.EndTime != DateTime.MinValue && details.EndTime < details.StartTime);

            // find the archive item.
            var item = Reload(context, handle);

            if (item == null)
            {
                throw new ServiceResultException(StatusCodes.BadNotSupported);
            }

            var values = new LinkedList<DataValue>();
            LinkedList<ModificationInfo> modificationInfos = null;

            if (details.IsReadModified)
            {
                modificationInfos = new LinkedList<ModificationInfo>();
            }

            // read history.
            var view = item.ReadHistory(details.StartTime, details.EndTime, details.IsReadModified, handle.Node.BrowseName);

            var startBound = -1;
            var endBound = -1;
            var ii = timeFlowsBackward ? view.Count - 1 : 0;

            while (ii >= 0 && ii < view.Count)
            {
                try
                {
                    var timestamp = (DateTime)view[ii].Row[0];

                    // check if looking for start of data.
                    if (values.Count == 0)
                    {
                        if (timeFlowsBackward)
                        {
                            if ((details.StartTime != DateTime.MinValue && timestamp >= details.StartTime) || (details.StartTime == DateTime.MinValue && timestamp >= details.EndTime))
                            {
                                startBound = ii;

                                if (timestamp > details.StartTime)
                                {
                                    continue;
                                }
                            }
                        }
                        else
                        {
                            if (timestamp <= details.StartTime)
                            {
                                startBound = ii;

                                if (timestamp < details.StartTime)
                                {
                                    continue;
                                }
                            }
                        }
                    }

                    // check if absolute max values specified.
                    if (sizeLimited && details.NumValuesPerNode > 0 && details.NumValuesPerNode < values.Count)
                    {
                        break;
                    }

                    // check for end bound.
                    if (details.EndTime != DateTime.MinValue && timestamp >= details.EndTime)
                    {
                        if (timeFlowsBackward)
                        {
                            if (timestamp <= details.EndTime)
                            {
                                endBound = ii;
                                break;
                            }
                        }
                        else
                        {
                            if (timestamp >= details.EndTime)
                            {
                                endBound = ii;
                                break;
                            }
                        }
                    }

                    // check if the start bound needs to be returned.
                    if (returnBounds && values.Count == 0 && startBound != ii && details.StartTime != DateTime.MinValue)
                    {
                        // add start bound.
                        if (startBound == -1)
                        {
                            values.AddLast(new DataValue(Variant.Null, StatusCodes.BadBoundNotFound, details.StartTime, details.StartTime));
                        }
                        else
                        {
                            values.AddLast(RowToDataValue(context, nodeToRead, view[startBound], applyIndexRangeOrEncoding));
                        }

                        // check if absolute max values specified.
                        if (sizeLimited && details.NumValuesPerNode > 0 && details.NumValuesPerNode < values.Count)
                        {
                            break;
                        }
                    }

                    // add value.
                    values.AddLast(RowToDataValue(context, nodeToRead, view[ii], applyIndexRangeOrEncoding));

                    modificationInfos?.AddLast((ModificationInfo)view[ii].Row[6]);
                }
                finally
                {
                    if (timeFlowsBackward)
                    {
                        ii--;
                    }
                    else
                    {
                        ii++;
                    }
                }
            }

            // add late bound.
            while (returnBounds && details.EndTime != DateTime.MinValue)
            {
                // add start bound.
                if (values.Count == 0)
                {
                    if (startBound == -1)
                    {
                        values.AddLast(new DataValue(Variant.Null, StatusCodes.BadBoundNotFound, details.StartTime, details.StartTime));
                    }
                    else
                    {
                        values.AddLast(RowToDataValue(context, nodeToRead, view[startBound], applyIndexRangeOrEncoding));
                    }
                }

                // check if absolute max values specified.
                if (sizeLimited && details.NumValuesPerNode > 0 && details.NumValuesPerNode < values.Count)
                {
                    break;
                }

                // add end bound.
                if (endBound == -1)
                {
                    values.AddLast(new DataValue(Variant.Null, StatusCodes.BadBoundNotFound, details.EndTime, details.EndTime));
                }
                else
                {
                    values.AddLast(RowToDataValue(context, nodeToRead, view[endBound], applyIndexRangeOrEncoding));
                }

                break;
            }

            return new HistoryReadRequest
            {
                Values = values,
                ModificationInfos = modificationInfos,
                NumValuesPerNode = details.NumValuesPerNode,
                Filter = null
            };
        }