Unified · Split
| @@ -29,8 +29,13 @@ using System.IO; · 28 unmodified lines | |||
| 29 | using System.Linq; | 29 | using System.Linq; |
| 30 | using System.Text; | 30 | using System.Text; |
| 31 | using System.Windows.Forms.DataVisualization.Charting; | 31 | using System.Windows.Forms.DataVisualization.Charting; |
| 32 | using System.Xml.Linq; | ||
| 33 | using GSF.Configuration; | ||
| 34 | using GSF.Data; | ||
| 35 | using GSF.Data.Model; | ||
| 32 | using GSF.Historian; | 36 | using GSF.Historian; |
| 33 | using GSF.Historian.Files; | 37 | using GSF.Historian.Files; |
| 38 | using GSF.IO; | ||
| 34 | using GSF.Units; | 39 | using GSF.Units; |
| 35 | using Root.Reports; | 40 | using Root.Reports; |
| 36 | using Encoder = System.Drawing.Imaging.Encoder; | 41 | using Encoder = System.Drawing.Imaging.Encoder; |
| @@ -54,6 +59,15 @@ namespace StatHistorianReportGenerator · 17 unmodified lines | |||
| 54 | public double[] MeasurementsExpected; | 59 | public double[] MeasurementsExpected; |
| 55 | } | 60 | } |
| 56 | 61 | ||
| 62 | private class DataAvailability | ||
| 63 | { | ||
| 64 | [PrimaryKey(true)] | ||
| 65 | public int ID { get; set; } | ||
| 66 | public float GoodAvailableData { get; set; } | ||
| 67 | public float BadAvailableData { get; set; } | ||
| 68 | public float TotalAvailableData { get; set; } | ||
| 69 | } | ||
| 70 | |||
| 57 | // Constants | 71 | // Constants |
| 58 | 72 | ||
| 59 | // Note: Many of the calculations in this class use conversion | 73 | // Note: Many of the calculations in this class use conversion |
| @@ -285,9 +299,12 @@ namespace StatHistorianReportGenerator · 225 unmodified lines | |||
| 285 | double verticalMillimeters; | 299 | double verticalMillimeters; |
| 286 | 300 | ||
| 287 | ReadStatistics(); | 301 | ReadStatistics(); |
| 302 | |||
| 288 | if (m_generateCsvReport && m_reportFilePath != null) | 303 | if (m_generateCsvReport && m_reportFilePath != null) |
| 289 | GenerateCsvReportFunction(m_reportFilePath); | 304 | GenerateCsvReportFunction(m_reportFilePath); |
| 290 | 305 | ||
| 306 | PopulateDataAvailabilityTable(); | ||
| 307 | |||
| 291 | // Page one | 308 | // Page one |
| 292 | verticalMillimeters = PageMarginMillimeters; | 309 | verticalMillimeters = PageMarginMillimeters; |
| 293 | verticalMillimeters += InsertTitle(fontDefinition, pageOne, verticalMillimeters) + SpacingMillimeters; | 310 | verticalMillimeters += InsertTitle(fontDefinition, pageOne, verticalMillimeters) + SpacingMillimeters; |
| @@ -316,6 +333,83 @@ namespace StatHistorianReportGenerator · 22 unmodified lines | |||
| 316 | return report; | 333 | return report; |
| 317 | } | 334 | } |
| 318 | 335 | ||
| 336 | private void PopulateDataAvailabilityTable() | ||
| 337 | { | ||
| 338 | const int DefaultRecordDepth = 14; | ||
| 339 | |||
| 340 | try | ||
| 341 | { | ||
| 342 | string configFile = GetConfigurationFileName(); | ||
| 343 | |||
| 344 | if (!File.Exists(configFile)) | ||
| 345 | throw new FileNotFoundException($"Config file \"{configFile}\" was not found."); | ||
| 346 | |||
| 347 | XDocument serviceConfig = XDocument.Load(configFile); | ||
| 348 | |||
| 349 | // ReSharper disable once AssignNullToNotNullAttribute | ||
| 350 | string connectionString = serviceConfig | ||
| 351 | .Descendants("systemSettings") | ||
| 352 | .SelectMany(systemSettings => systemSettings.Elements("add")) | ||
| 353 | .Where(element => "ConnectionString".Equals((string)element.Attribute("name"), StringComparison.OrdinalIgnoreCase)) | ||
| 354 | .Select(element => (string)element.Attribute("value")) | ||
| 355 | .FirstOrDefault(); | ||
| 356 | |||
| 357 | string dataProviderString = serviceConfig | ||
| 358 | .Descendants("systemSettings") | ||
| 359 | .SelectMany(systemSettings => systemSettings.Elements("add")) | ||
| 360 | .Where(element => "DataProviderString".Equals((string)element.Attribute("name"), StringComparison.OrdinalIgnoreCase)) | ||
| 361 | .Select(element => (string)element.Attribute("value")) | ||
| 362 | .FirstOrDefault(); | ||
| 363 | |||
| 364 | using (AdoDataConnection connection = new AdoDataConnection(connectionString, dataProviderString)) | ||
| 365 | { | ||
| 366 | TableOperations<DataAvailability> dataAvailabilityTable = new TableOperations<DataAvailability>(connection); | ||
| 367 | DataAvailability[] records = dataAvailabilityTable.QueryRecords().ToArray(); | ||
| 368 | |||
| 369 | if (records.Length == 0) | ||
| 370 | { | ||
| 371 | records = new DataAvailability[DefaultRecordDepth]; | ||
| 372 | |||
| 373 | for (int i = 0; i < records.Length; i++) | ||
| 374 | records[i] = dataAvailabilityTable.NewRecord(); | ||
| 375 | } | ||
| 376 | |||
| 377 | for (int i = records.Length - 1; i >= 0; i--) | ||
| 378 | { | ||
| 379 | List<DeviceStats>[] levels = GetLevels(ReportDays - (i + 1)); | ||
| 380 | DataAvailability record = records[i]; | ||
| 381 | |||
| 382 | record.GoodAvailableData = levels[4].Count; | ||
| 383 | record.BadAvailableData = levels.Take(4).Sum(level => level.Count); | ||
| 384 | record.TotalAvailableData = levels.Sum(level => level.Count); | ||
| 385 | |||
| 386 | dataAvailabilityTable.AddNewOrUpdateRecord(record); | ||
| 387 | } | ||
| 388 | } | ||
| 389 | } | ||
| 390 | catch (Exception ex) | ||
| 391 | { | ||
| 392 | // TODO: Someone needs to add a logger to this tool :-( | ||
| 393 | System.Diagnostics.Debug.WriteLine($"Failed to populate data availability table: {ex.Message}"); | ||
| 394 | } | ||
| 395 | } | ||
| 396 | |||
| 397 | private static string GetConfigurationFileName() | ||
| 398 | { | ||
| 399 | string[] knownConfigurationFileNames = { "openPDC.exe.config", "SIEGate.exe.config", "openHistorian.exe.config", "substationSBG.exe.config", "openMIC.exe.config", "PDQTracker.exe.config" }; | ||
| 400 | |||
| 401 | // Search for the file name in the list of known configuration files | ||
| 402 | foreach (string fileName in knownConfigurationFileNames) | ||
| 403 | { | ||
| 404 | string absolutePath = FilePath.GetAbsolutePath(fileName); | ||
| 405 | |||
| 406 | if (File.Exists(absolutePath)) | ||
| 407 | return absolutePath; | ||
| 408 | } | ||
| 409 | |||
| 410 | return ConfigurationFile.Current.Configuration.FilePath; | ||
| 411 | } | ||
| 412 | |||
| 319 | private void GenerateCsvReportFunction(string filepath) | 413 | private void GenerateCsvReportFunction(string filepath) |
| 320 | { | 414 | { |
| 321 | filepath = Path.ChangeExtension(filepath, ".csv"); | 415 | filepath = Path.ChangeExtension(filepath, ".csv"); |