/// /// Copyright (c) 2017 Sensus Metering Systems /// using System; using System.Collections.Generic; using System.Globalization; using System.IO; using System.Threading; using log4net; using Config.Entities; using TBF.BenchControl; using TBF.Resources; namespace TBF.BenchControl.Output.FileWriters.Xml { 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; string separatorStr; /// /// Items to print /// string header; string rootTag; string testTag; IList commonItems; IList testItems; Results.Entities.Batch batch; bool abort; public Writer() {} public Writer(Generic.IComponentCfg cfg) : base(cfg) { writerCfg = cfg as WriterCfg; ApplyConfig(); log.Debug(this.ToString()); } void ApplyConfig() { /// TODO: Apply culture info rootTag = writerCfg.RootTag; testTag = writerCfg.RootTag; header = string.IsNullOrEmpty(writerCfg.Header) ? string.Empty : writerCfg.Header.Replace("~", Environment.NewLine); commonItems = Results.WMeterRsltItemSpec.FromStrArray(writerCfg.CommonItems); testItems = Results.WMeterRsltItemSpec.FromStrArray(writerCfg.TestItems); /// TestID info will be overwritten later on } #region Configuration Change Handling public static void OnCfgChange(object sender, CfgChangeArgs args) { if (CfgChangeHandler == null) return; try { CfgChangeHandler(sender, args); } catch (Exception e) { log.Error("CfgChangeHandler(...) failed", e); } } public static event EventHandler CfgChangeHandler; public override void StartChangeHandler() { CfgChangeHandler += delegate(object sender, CfgChangeArgs args) { WriterCfg newCfg = args.Cfg as WriterCfg; if (newCfg != null && newCfg.Name.Equals(Name)) { if (args.Command == CfgChangeCmd.CfgChange) { writerCfg.DestinationPath = newCfg.DestinationPath; writerCfg.DestinationPath2 = newCfg.DestinationPath2; writerCfg.YearFolders = newCfg.YearFolders; writerCfg.MonthFolders = newCfg.MonthFolders; writerCfg.DayFolders = newCfg.DayFolders; writerCfg.FileNameFormat = newCfg.FileNameFormat; writerCfg.Culture = newCfg.Culture; writerCfg.Header = newCfg.Header; writerCfg.RootTag = newCfg.RootTag; writerCfg.TestTag = newCfg.TestTag; writerCfg.CommonItems = newCfg.CommonItems; writerCfg.TestItems = newCfg.TestItems; ApplyConfig(); } } }; } #endregion Configuration Change Handling /// /// 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, int wmPosition) { 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, wmPosition); } catch { return string.Format("{0}{1:yyMMdd-HHmm}-{2:D2}.xml", directory, time, wmPosition); } } /// /// Writes the test cycle results into a file /// Events: /// Event.ResultsWritten /// Event.Busy /// /// Results to write into files /// Reference to the operation public IOperation WriteResultsOp(Results.Entities.Batch batch) { this.batch = batch; return this; } /// Start this operation public void Start() { CultureInfo oriCulture = Thread.CurrentThread.CurrentCulture; try { Thread.CurrentThread.CurrentCulture = new CultureInfo(writerCfg.Culture.ToString()); } catch { } WriteRslts(batch, writerCfg.DestinationPath); WriteRslts(batch, writerCfg.DestinationPath2); Thread.CurrentThread.CurrentCulture = oriCulture; } /// Run this operation /// Event.ResultsWritten public Event Run() { return Event.ResultsWritten; } /// Stop this operation public void Stop() { } void WriteRslts(Results.Entities.Batch batch, string destination) { if (string.IsNullOrEmpty(destination)) return; foreach (var wm in batch.WaterMeters) { try { StreamWriter writer = File.AppendText(GetFilename(destination, batch.EndTime, wm.WMPosition)); WriteWM(writer, wm); writer.Close(); } catch { } } } /// /// Write one water meter results /// /// Water meter number (0-based) void WriteWM(StreamWriter wr, Results.Entities.WaterMeter wm) { /// Header if (!string.IsNullOrEmpty(writerCfg.Header)) wr.Write(header); wr.WriteLine(string.Format("<{0}>", rootTag)); /// Common items 1 foreach (var v in commonItems) { if (abort) return; /// Fetch the item and strip color information string itemText = v.Print(wm); string[] texts = itemText.Split(new char[] { '|' }); if (texts.Length == 2) { itemText = texts[0]; } wr.WriteLine(" <{0}>{1}", v.Caption, itemText); } /// Test items foreach (var mtr in wm.MeterTestRslts) { if (abort) return; if ((mtr != null) && (mtr.Publish() == Config.Entities.Publish.Always)) { wr.WriteLine(string.Format(" <{0}>", testTag)); for (int i = 0; i < testItems.Count; i++) { /// Fetch the item and strip color information string itemText = testItems[i].Print(wm, mtr.Name()); string[] texts = itemText.Split(new char[] { '|' }); if (texts.Length == 2) { itemText = texts[0]; } /// Print the item wr.WriteLine(" <{0}>{1}", testItems[i].Caption, itemText); } wr.WriteLine(string.Format(" ", testTag)); } } /// Footer wr.WriteLine(string.Format("", rootTag)); } } }