/// /// Copyright (c) 2016 Sensus Metering Systems /// using System; using System.Collections.Generic; using System.IO; using log4net; using Config.Entities; using TBF.BenchControl; using TBF.Resources; namespace TBF.BenchControl.Output.FileWriters.Enhanced { public class Writer : ComponentBase, IOperation, GenericDevices.IResultsWriter { private static readonly ILog log = LogManager.GetLogger(typeof(Writer)); public override string ToString() { return string.Format("Output.FileWriters.Enhanced({0})", Cfg.ToString(1)); } readonly WriterCfg writerCfg; readonly string separatorStr; readonly string header; readonly string footer; /// /// Items to print /// readonly IList commonItems; readonly IList testItems; /// /// Results to print /// Results.Entities.Batch batch; StreamWriter writer; StreamWriter writer2; public Writer() {} public Writer(Generic.IComponentCfg cfg) : base(cfg) { writerCfg = cfg as WriterCfg; switch (writerCfg.Separator) { default: case Separator.None: separatorStr = string.Empty; break; case Separator.Space: separatorStr = " "; break; case Separator.Tabulator: separatorStr = "\t"; break; case Separator.Comma: separatorStr = ","; break; case Separator.Semicolon: separatorStr = ";"; break; } header = writerCfg.Header.Replace("~", "\r\n"); commonItems = Results.WMeterRsltItemSpec.FromStrArray(writerCfg.CommonItems); testItems = Results.ItemSpec.FromStrArray(writerCfg.SelectedItems); footer = writerCfg.Footer.Replace("~", "\r\n"); log.Debug(this.ToString()); } /// /// Eliminate spaces conditionally, depesing on bool WriterCfg.EliminateSpaces /// /// Input string /// Output string string ElSpaces(string item) { if (writerCfg.EliminateSpaces) return item.Replace(" ", string.Empty); else return item; } /// /// Returns a file name derived from a DateTime structure. /// Creates directories on this path as a side effect. /// /// Date and time /// File name string GetFilename(string destinationPath, DateTime time) { string directory = destinationPath; /// Ends with "\\"; switch (writerCfg.YearFolders) { case YearFolders.FourDigit: directory = string.Format("{0}{1:yyyy}\\", directory, time); break; case YearFolders.TwoDigit: directory = string.Format("{0}{1:yy}\\", directory, time); break; } switch (writerCfg.MonthFolders) { case MonthFolders.Name: { string monthStr; switch (time.Month) { default: case 1: monthStr = "January"; break; case 2: monthStr = "February"; break; case 3: monthStr = "March"; break; case 4: monthStr = "April"; break; case 5: monthStr = "May"; break; case 6: monthStr = "June"; break; case 7: monthStr = "July"; break; case 8: monthStr = "August"; break; case 9: monthStr = "September"; break; case 10: monthStr = "October"; break; case 11: monthStr = "November"; break; case 12: monthStr = "December"; break; } directory = string.Format("{0}{1}\\", directory, monthStr); break; } case MonthFolders.Digit: directory = string.Format("{0}{1}\\", directory, time.Month.ToString()); break; case MonthFolders.TwoDigit: directory = string.Format("{0}{1:MM}\\", directory, time); break; } switch (writerCfg.DayFolders) { case DayFolders.Digit: directory = string.Format("{0}{1}\\", directory, time.Day.ToString()); break; case DayFolders.TwoDigit: directory = string.Format("{0}{1:dd}\\", directory, time); break; } Directory.CreateDirectory(directory); try { if (string.IsNullOrEmpty(writerCfg.FileNameFormat)) throw new Exception(); return directory + string.Format(writerCfg.FileNameFormat, time); } catch { return string.Format("{0}{1:yyMMdd-HHmm}.txt", directory, time); } } /// /// Writes the test cycle results into a file, Events: Event.ResultsWritten /// /// Procedure to print the results of /// Results to write into the file /// Reference to the operation public IOperation WriteResultsOp(Results.Entities.Batch batchResults) { this.batch = batchResults; if (batch.WaterMeters.Count <= 0) { writer = null; writer2 = null; return this; } writer = null; if (!string.IsNullOrEmpty(writerCfg.DestinationPath)) { try { writer = File.AppendText(GetFilename(writerCfg.DestinationPath, batch.EndTime)); } catch { }; } writer2 = null; if (!string.IsNullOrEmpty(writerCfg.DestinationPath2)) { try { writer2 = File.AppendText(GetFilename(writerCfg.DestinationPath2, batch.EndTime)); } catch { }; } return this; } /// Start this operation public void Start() { if (writer != null) WriteRslts(writer); if (writer2 != null) WriteRslts(writer2); } void WriteRslts(StreamWriter wr) { ///---------- /// Header ///---------- if (!string.IsNullOrEmpty(writerCfg.Header)) wr.Write(header); wr.WriteLine(batch.ProtocolTitle); wr.WriteLine(string.Empty); ///---------------- /// Common items ///---------------- string[] leftColumn = new string[commonItems.Count]; string[] rightColumn = new string[commonItems.Count]; int cnt = 0; foreach (var v in commonItems) { leftColumn[cnt] = v.Caption; rightColumn[cnt] = v.Print(batch.WaterMeters[0]); cnt++; } /// Determine max. left column width in characters int maxLen = 0; foreach (var s in leftColumn) if (s.Length > maxLen) maxLen = s.Length; /// Write aligned columns for (int i = 0; i < Math.Min(leftColumn.Length, rightColumn.Length); i++) { wr.Write(leftColumn[i]); wr.Write(new string(' ', maxLen - leftColumn[i].Length + 3)); wr.WriteLine(rightColumn[i]); } ///-------- /// Body ///-------- foreach (var wm in batch.WaterMeters) WriteWM(wr, wm); ///---------- /// Footer ///---------- if (!string.IsNullOrEmpty(writerCfg.Footer)) wr.Write(footer); } /// /// Write one water meter results /// /// Water meter number (0-based) void WriteWM(StreamWriter wr, Results.Entities.WaterMeter wm) { wr.WriteLine(string.Empty); /// Write water meter number and s/n wr.Write(string.Format(Strings.Water_Meter_nr, wm.WMPosition)); if (!wm.Compound()) { if (!string.IsNullOrEmpty(wm.SerialNr)) wr.Write(string.Format(", {0} {1}", Strings.SerialNr, wm.SerialNr)); } else { if (!string.IsNullOrEmpty(wm.SerialNr)) wr.Write(string.Format(", {0} {1}", Strings.Main_WM_SerialNr, wm.SerialNr)); if (!string.IsNullOrEmpty(wm.SerialNrAux)) wr.Write(string.Format(", {0} {1}", Strings.Aux_WM_SerialNr, wm.SerialNrAux)); } wr.WriteLine(string.Empty); /// Determine column widths int[] columnWidths = new int[testItems.Count]; int totalWidth = 0; for (int i = 0; i < testItems.Count; i++) { columnWidths[i] = ElSpaces(testItems[i].ClmnHeaderText).Length; foreach (var mtr in wm.MeterTestRslts) { if ((mtr != null) && (mtr.Publish() == Config.Entities.Publish.Always)) { string itemText; if (!wm.Compound()) { /// Single water meter itemText = testItems[i].Print(mtr); } else if (mtr.CompoundMeterId == (byte)CompoundMeterId.Compound) { Results.Entities.MeterTestRslt mainMtr = wm.GetMeterTestRslt(mtr.Name(), CompoundMeterId.CompoundMain); Results.Entities.MeterTestRslt auxMtr = wm.GetMeterTestRslt(mtr.Name(), CompoundMeterId.CompoundAux); itemText = testItems[i].PrintCombined(mainMtr, auxMtr, mtr); } else { continue; } /// Strip color information string[] texts = itemText.Split(new char[] { '|' }); if (texts.Length == 2) { itemText = texts[0]; } int len = ElSpaces(itemText).Length; if (len > columnWidths[i]) columnWidths[i] = len; } } totalWidth += columnWidths[i]; } totalWidth += 3 * (testItems.Count - 1); if (totalWidth < 0) totalWidth = 0; wr.WriteLine(new String('-', totalWidth)); /// Horizontal line above the header /// Write column headers for (int i = 0; i < testItems.Count; i++) { wr.Write(ElSpaces(testItems[i].ClmnHeaderText)); if (i < testItems.Count - 1) { if (!writerCfg.EliminateSpaces) { wr.Write(new string(' ', columnWidths[i] - testItems[i].ClmnHeaderText.Length + 3)); } wr.Write(separatorStr); } else { wr.WriteLine(string.Empty); } } wr.WriteLine(new String('-', totalWidth)); /// Horizontal line between the header and the body /// Write table data foreach (var mtr in wm.MeterTestRslts) { if ((mtr != null) && (mtr.Publish() == Config.Entities.Publish.Always)) { for (int i = 0; i < testItems.Count; i++) { string itemText; /// /// Fetch an item /// if (!wm.Compound()) { /// Single water meter itemText = testItems[i].Print(mtr); } else if (mtr.CompoundMeterId == (byte)CompoundMeterId.Compound) { Results.Entities.MeterTestRslt mainMtr = wm.GetMeterTestRslt(mtr.Name(), CompoundMeterId.CompoundMain); Results.Entities.MeterTestRslt auxMtr = wm.GetMeterTestRslt(mtr.Name(), CompoundMeterId.CompoundAux); itemText = testItems[i].PrintCombined(mainMtr, auxMtr, mtr); } else { continue; } /// /// Print the item /// string[] texts = itemText.Split(new char[] { '|' }); if (texts.Length == 2) { itemText = texts[0]; } /// Strip color information wr.Write(ElSpaces(itemText)); if (i < testItems.Count - 1) { if (!writerCfg.EliminateSpaces) { wr.Write(new string(' ', columnWidths[i] - itemText.Length + 3)); } wr.Write(separatorStr); } else { wr.WriteLine(string.Empty); } } } } wr.WriteLine(new String('-', totalWidth)); /// Horizontal line below the body } /// Run this operation /// Event.ResultsWritten public Event Run() { return Event.ResultsWritten; } /// Stop this operation public void Stop() { if (writer != null) writer.Close(); if (writer2 != null) writer2.Close(); } } }