///// <summary>
        ///// Establish measurement key cache based on received meta-data.
        ///// </summary>
        ///// <param name="metadata">Meta-data received from a subscription.</param>
        ///// <param name="instanceName">Instance name of the historian.</param>
        ///// <remarks>
        ///// If you want the <see cref="IMeasurement.Key"/> values that are returned from a <see cref="GetHistorianData"/> query
        ///// to have properly assigned Guid based signal IDs, i.e., <see cref="MeasurementKey.SignalID"/>, establish the
        ///// measurement key cache as soon as you have received meta-data from a GEP subscription query.
        ///// </remarks>

        /// <summary>
        /// Reads interpolated historian data from server.
        /// </summary>
        /// <param name="connection">openHistorian connection.</param>
        /// <param name="startTime">Start time of query.</param>
        /// <param name="stopTime">Stop time of query.</param>
        /// <param name="interval">The sampling interval for the interpolated data.</param>
        /// <param name="measurementIDs">Comma separated list of measurement IDs to query.</param>
        /// <returns>Enumeration of <see cref="IMeasurement"/> values read for time range.</returns>
        /// <remarks>
        /// <example>
        /// <code>
        /// using (var connection = new Connection("127.0.0.1", "PPA"))
        ///     foreach(var measurement in GetInterpolatedData(connection, DateTime.UtcNow.AddMinutes(-1.0D), DateTime.UtcNow, TimeSpan.FromSeconds(2.0D), "7,5,15"))
        ///         Console.WriteLine("{0}:{1} @ {2} = {3}, quality: {4}", measurement.Key.Source, measurement.Key.ID, measurement.Timestamp, measurement.Value, measurement.StateFlags);
        /// </code>
        /// </example>
        /// </remarks>
        public static IEnumerable <IMeasurement> GetInterpolatedData(Connection connection, DateTime startTime, DateTime stopTime, TimeSpan interval, string measurementIDs)
        {
            if ((object)measurementIDs == null)
            {
                throw new ArgumentNullException(nameof(measurementIDs));
            }

            // TODO: This was based on code that aligns data and fills time - this function will
            // need to be re-worked to provide data on an interval based on slopes and time...
            Measurement[] values = measurementIDs.Split(',').Select(uint.Parse).Select(id => new Measurement()
            {
                Metadata = MeasurementKey.LookUpBySource(connection.InstanceName, id).Metadata
            }).ToArray();
            long tickInterval  = interval.Ticks;
            long lastTimestamp = 0L;

            foreach (IMeasurement measurement in GetHistorianData(connection, startTime, stopTime, measurementIDs))
            {
                long timestamp = measurement.Timestamp;

                // Start a new row for each encountered new timestamp
                if (timestamp != lastTimestamp)
                {
                    if (lastTimestamp > 0)
                    {
                        foreach (IMeasurement value in values)
                        {
                            yield return(value);
                        }
                    }

                    for (int i = 0; i < values.Length; i++)
                    {
                        values[i] = Measurement.Clone(values[i]);
                    }

                    if (lastTimestamp > 0 && timestamp > lastTimestamp)
                    {
                        long difference = timestamp - lastTimestamp;

                        if (difference > tickInterval)
                        {
                            long interpolated = lastTimestamp;

                            for (long i = 1; i < difference / tickInterval; i++)
                            {
                                interpolated = interpolated + tickInterval;

                                foreach (IMeasurement value in values)
                                {
                                    yield return(value);
                                }
                            }
                        }
                    }

                    lastTimestamp = timestamp;
                }
            }
        }