Reads certain device and input stream statistics from the statistics archive. The statistics that are read are the total frame count, the missing frame count, connectivity, average latency, the actual data rate, data quality errors, and time quality errors.
Inheritance: IDisposable
        private void ReadCorrectnessData()
        {
            DateTime startTime;
            DateTime endTime;

            Dictionary <MetadataRecord, IEnumerable <IDataPoint> > measurementsExpected;
            Dictionary <MetadataRecord, IEnumerable <IDataPoint> > measurementsReceived;
            Dictionary <MetadataRecord, IEnumerable <IDataPoint> > measurementsLatched;
            Dictionary <MetadataRecord, IEnumerable <IDataPoint> > measurementsUnreasonable;

            // Create the statistics reader for reading statistics from the archive
            using (StatisticsReader statisticsReader = new StatisticsReader())
            {
                endTime   = DateTime.Today.AddDays(1.0D); // Tomorrow
                startTime = endTime - TimeSpan.FromDays(ReportPeriod);

                // Set up and open the statistics reader
                statisticsReader.StartTime = startTime;
                statisticsReader.EndTime   = endTime;

                statisticsReader.ArchiveFilePath = FilePath.GetAbsolutePath("Statistics\\stat_archive.d");
                statisticsReader.Open();

                measurementsExpected     = statisticsReader.Read("PMU", 5);
                measurementsReceived     = statisticsReader.Read("PMU", 4);
                measurementsLatched      = statisticsReader.Read(980);
                measurementsUnreasonable = statisticsReader.Read(900);

                float[] totalExpected =
                {
                    measurementsExpected
                    .SelectMany(kvp => kvp.Value)
                    .Where(dataPoint => dataPoint.Time.ToDateTime().Date == DateTime.Today.AddDays(-1.0D))
                    .Select(dataPoint => dataPoint.Value)
                    .DefaultIfEmpty(0.0F)
                    .Sum(),
                    measurementsExpected
                    .SelectMany(kvp => kvp.Value)
                    .Where(dataPoint => dataPoint.Time.ToDateTime().Date == DateTime.Today)
                    .Select(dataPoint => dataPoint.Value)
                    .DefaultIfEmpty(0.0F)
                    .Sum()
                };


                float[] totalReceived =
                {
                    measurementsReceived
                    .SelectMany(kvp => kvp.Value)
                    .Where(dataPoint => dataPoint.Time.ToDateTime().Date == DateTime.Today.AddDays(-1.0D))
                    .Select(dataPoint => dataPoint.Value)
                    .DefaultIfEmpty(0.0F)
                    .Sum(),
                    measurementsReceived
                    .SelectMany(kvp => kvp.Value)
                    .Where(dataPoint => dataPoint.Time.ToDateTime().Date == DateTime.Today)
                    .Select(dataPoint => dataPoint.Value)
                    .DefaultIfEmpty(0.0F)
                    .Sum()
                };

                float[] totalLatched =
                {
                    measurementsLatched
                    .SelectMany(kvp => kvp.Value)
                    .Where(dataPoint => dataPoint.Time.ToDateTime().Date == DateTime.Today.AddDays(-1.0D))
                    .Select(dataPoint => dataPoint.Value)
                    .DefaultIfEmpty(0.0F)
                    .Sum(),
                    measurementsLatched
                    .SelectMany(kvp => kvp.Value)
                    .Where(dataPoint => dataPoint.Time.ToDateTime().Date == DateTime.Today)
                    .Select(dataPoint => dataPoint.Value)
                    .DefaultIfEmpty(0.0F)
                    .Sum()
                };

                float[] totalUnreasonable =
                {
                    measurementsUnreasonable
                    .SelectMany(kvp => kvp.Value)
                    .Where(dataPoint => dataPoint.Time.ToDateTime().Date == DateTime.Today.AddDays(-1.0D))
                    .Select(dataPoint => dataPoint.Value)
                    .DefaultIfEmpty(0.0F)
                    .Sum(),
                    measurementsUnreasonable
                    .SelectMany(kvp => kvp.Value)
                    .Where(dataPoint => dataPoint.Time.ToDateTime().Date == DateTime.Today)
                    .Select(dataPoint => dataPoint.Value)
                    .DefaultIfEmpty(0.0F)
                    .Sum()
                };

                Dispatcher.BeginInvoke(new Action(() =>
                {
                    if (totalExpected[0] == 0)
                    {
                        totalExpected[0] = 1;
                    } // Not allowed to divide by zero
                    CreateGridTextItem(1, 1, HorizontalAlignment.Right, ((totalReceived[0] - totalLatched[0] - totalUnreasonable[0]) / totalExpected[0]).ToString("0.00%"), CorrectnesssGrid);
                    CreateGridTextItem(2, 1, HorizontalAlignment.Right, (totalLatched[0] / totalExpected[0]).ToString("0.00%"), CorrectnesssGrid);
                    CreateGridTextItem(3, 1, HorizontalAlignment.Right, (totalUnreasonable[0] / totalExpected[0]).ToString("0.00%"), CorrectnesssGrid);
                    if (totalExpected[1] == 0)
                    {
                        totalExpected[1] = 1;
                    } // Not allowed to divide by zero
                    CreateGridTextItem(1, 2, HorizontalAlignment.Right, ((totalReceived[1] - totalLatched[1] - totalUnreasonable[1]) / totalExpected[1]).ToString("0.00%"), CorrectnesssGrid);
                    CreateGridTextItem(2, 2, HorizontalAlignment.Right, (totalLatched[1] / totalExpected[1]).ToString("0.00%"), CorrectnesssGrid);
                    CreateGridTextItem(3, 2, HorizontalAlignment.Right, (totalUnreasonable[1] / totalExpected[1]).ToString("0.00%"), CorrectnesssGrid);
                }));
            }
        }
        private void ReadCompletenessData()
        {
            Dictionary <string, DeviceStats> deviceStatsLookup = new Dictionary <string, DeviceStats>();
            DateTime startTime;
            DateTime endTime;

            Dictionary <MetadataRecord, IEnumerable <IDataPoint> > measurementsReceived;
            Dictionary <MetadataRecord, IEnumerable <IDataPoint> > measurementsExpected;

            List <DeviceStats>[] todaysStats;
            List <DeviceStats>[] yesterdaysStats;

            string signalReference;
            string deviceName;
            int    index;

            // Create the statistics reader for reading statistics from the archive
            using (StatisticsReader statisticsReader = new StatisticsReader())
            {
                endTime   = DateTime.Today.AddDays(1.0D); // Tomorrow
                startTime = endTime - TimeSpan.FromDays(ReportDays);

                // Set up and open the statistics reader
                statisticsReader.StartTime = startTime;
                statisticsReader.EndTime   = endTime;

                statisticsReader.ArchiveFilePath = FilePath.GetAbsolutePath("Statistics\\stat_archive.d");
                statisticsReader.Open();

                measurementsReceived = statisticsReader.Read("PMU", 4);
                measurementsExpected = statisticsReader.Read("PMU", 5);

                // Determine which devices in the archive have stats for both measurements received and measurements expected
                foreach (Tuple <MetadataRecord, MetadataRecord> tuple in measurementsReceived.Keys.Join(measurementsExpected.Keys, GetDeviceName, GetDeviceName, Tuple.Create))
                {
                    DeviceStats deviceStats;
                    signalReference = tuple.Item1.Synonym1;
                    deviceName      = GetDeviceName(tuple.Item1);

                    // Ignore statistics that were calculated by an intermediate gateway
                    if (!signalReference.StartsWith("LOCAL$") && signalReference.Contains("LOCAL$"))
                    {
                        continue;
                    }

                    // Make sure LOCAL$ statistics take precedence over other statistics calculated for the same device
                    if (deviceStatsLookup.ContainsKey(deviceName) && !signalReference.StartsWith("LOCAL$"))
                    {
                        continue;
                    }

                    // Create arrays to hold the total sum of the stats for each day being reported
                    deviceStats = new DeviceStats()
                    {
                        Name = deviceName,
                        MeasurementsReceived = new double[ReportDays],
                        MeasurementsExpected = new double[ReportDays]
                    };

                    // Calculate the total measurements received for each day being reported
                    foreach (IDataPoint dataPoint in measurementsReceived[tuple.Item1])
                    {
                        index = (dataPoint.Time.ToDateTime() - startTime).Days;

                        if (index >= 0 && index < ReportDays)
                        {
                            deviceStats.MeasurementsReceived[index] += dataPoint.Value;
                        }
                    }

                    // Calculate the total measurements expected for each day being reported
                    foreach (IDataPoint dataPoint in measurementsExpected[tuple.Item2])
                    {
                        index = (dataPoint.Time.ToDateTime() - startTime).Days;

                        if (index >= 0 && index < ReportDays)
                        {
                            deviceStats.MeasurementsExpected[index] += dataPoint.Value;
                        }
                    }

                    // Store the calculated stats per device
                    deviceStatsLookup[deviceName] = deviceStats;
                }
            }

            // Store the statistics data to be used in the UI
            m_deviceStatsList = deviceStatsLookup.Values.ToList();

            todaysStats     = GetLevels(ReportDays);
            yesterdaysStats = GetLevels(ReportDays - 1);

            Dispatcher.BeginInvoke(new Action(() =>
            {
                int total = yesterdaysStats[0].Count + yesterdaysStats[1].Count + yesterdaysStats[2].Count + yesterdaysStats[3].Count + yesterdaysStats[4].Count;
                CreateGridTextItem(1, 1, HorizontalAlignment.Right, yesterdaysStats[4].Count.ToString(), CompletenessGrid);
                CreateGridTextItem(2, 1, HorizontalAlignment.Right, yesterdaysStats[3].Count.ToString(), CompletenessGrid);
                CreateGridTextItem(3, 1, HorizontalAlignment.Right, yesterdaysStats[2].Count.ToString(), CompletenessGrid);
                CreateGridTextItem(4, 1, HorizontalAlignment.Right, yesterdaysStats[1].Count.ToString(), CompletenessGrid);
                CreateGridTextItem(5, 1, HorizontalAlignment.Right, yesterdaysStats[0].Count.ToString(), CompletenessGrid);
                CreateGridTextItem(7, 1, HorizontalAlignment.Right, total.ToString(), CompletenessGrid);

                total = todaysStats[0].Count + todaysStats[1].Count + todaysStats[2].Count + todaysStats[3].Count + todaysStats[4].Count;
                CreateGridTextItem(1, 2, HorizontalAlignment.Right, todaysStats[4].Count.ToString(), CompletenessGrid);
                CreateGridTextItem(2, 2, HorizontalAlignment.Right, todaysStats[3].Count.ToString(), CompletenessGrid);
                CreateGridTextItem(3, 2, HorizontalAlignment.Right, todaysStats[2].Count.ToString(), CompletenessGrid);
                CreateGridTextItem(4, 2, HorizontalAlignment.Right, todaysStats[1].Count.ToString(), CompletenessGrid);
                CreateGridTextItem(5, 2, HorizontalAlignment.Right, todaysStats[0].Count.ToString(), CompletenessGrid);
                CreateGridTextItem(7, 2, HorizontalAlignment.Right, total.ToString(), CompletenessGrid);
            }));
        }