tbf/TBF/BenchControl/Output/FileWriters/Elde/Writer.cs

471 lines
18 KiB
C#

///
/// Copyright (c) 2019 Sensus Slovensko a.s.
///
using System;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Threading;
using log4net;
using TBF.Resources;
namespace TBF.BenchControl.Output.FileWriters.Elde
{
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;
IList<Results.WMeterRsltItemSpec> commonItems;
IList<Results.WMeterRsltItemSpec> testItems;
string footer;
Results.Entities.Batch batch;
bool abort;
public Writer() {}
public Writer(Generic.IComponentCfg cfg)
: base(cfg)
{
writerCfg = cfg as WriterCfg;
ApplyConfig();
log.Warn(this.ToString());
}
void ApplyConfig()
{
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 = string.IsNullOrEmpty(writerCfg.Header) ? string.Empty : writerCfg.Header.Replace("~", Environment.NewLine);
commonItems = Results.WMeterRsltItemSpec.FromStrArray(new string[] {
"72~Date / Time~~None~: {0:yyyy/MM/dd} / {0:HH:mm} Page : 1/1~~0~Left",
"50~Watermeter Type~~None~: {0}~~0~Left",
"64~Device No~~None~: {0}~~0~Left",
"66~Personal~~None~: {0}~~0~Left",
} );
testItems = Results.WMeterRsltItemSpec.FromStrArray(new string[] {
"1~Test~~None~~~0~Left",
"258~Met. t.~~None~~~0~Left",
"257~Fl.~~None~~~0~Left",
"25~Dev. [%]~~Pct~~~0~Left",
"202~Flow [m3/h]~~m3ph~~F6~0~Left",
"14~Test time [s]~~s~~F1~0~Left",
"16~T1 [°C]~~C~~F1~0~Left",
"17~T2 [°C]~~C~~F1~0~Left",
"5~Density [kg/m3]~~kgpm3~~F3~0~Left",
"131~Mass [kg]~~kg~~F3~0~Left",
"19~Pressure [MPa]~~MPa~~F2~0~Left",
"229~Volume [L]~~l~~F4~0~Left",
} );
footer = string.IsNullOrEmpty(writerCfg.Footer) ? string.Empty : writerCfg.Footer.Replace("~", Environment.NewLine);
}
#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<CfgChangeArgs> 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.Separator = newCfg.Separator;
writerCfg.EliminateSpaces = newCfg.EliminateSpaces;
writerCfg.Header = newCfg.Header;
writerCfg.CommonItems = newCfg.CommonItems;
writerCfg.SelectedItems = newCfg.SelectedItems;
writerCfg.Footer = newCfg.Footer;
ApplyConfig();
}
}
};
}
#endregion Configuration Change Handling
/// <summary>
/// Eliminate spaces conditionally, depesing on bool WriterCfg.EliminateSpaces
/// </summary>
/// <param name="item">Input string</param>
/// <returns>Output string</returns>
string ElSpaces(string item)
{
if (writerCfg.EliminateSpaces)
return item.Replace(" ", string.Empty);
else
return item;
}
/// <summary>
/// Returns a file name derived from a DateTime structure.
/// Creates directories on this path as a side effect.
/// </summary>
/// <param name="time">Date and time</param>
/// <returns>File name</returns>
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);
}
}
/// <summary>
/// Writes the test cycle results into a file
/// Events:
/// Event.ResultsWritten
/// Event.Busy
/// </summary>
/// <param name="batch">Results to write into a file</param>
/// <returns>Reference to the operation</returns>
public IOperation ProcessResultsOp(Results.Entities.Batch batch)
{
this.batch = batch;
return this;
}
/// <summary>Start this operation</summary>
public void Start()
{
CultureInfo oriCulture = Thread.CurrentThread.CurrentCulture;
if (writerCfg.Culture != Culture.system)
{
Thread.CurrentThread.CurrentCulture = new CultureInfo(writerCfg.Culture.ToString());
}
abort = false;
WriteRslts(batch, writerCfg.DestinationPath);
WriteRslts(batch, writerCfg.DestinationPath2);
Thread.CurrentThread.CurrentCulture = oriCulture;
}
/// <summary>Run this operation</summary>
/// <returns>Event.ResultsWritten</returns>
public Event Run()
{
return Event.ResultsWritten;
}
/// <summary>Stop this operation</summary>
public void Stop()
{
}
void WriteRslts(Results.Entities.Batch batch, string destination)
{
if (batch == null || batch.WaterMeters == null || batch.WaterMeters.Count <= 0) return;
if (!string.IsNullOrEmpty(destination))
{
StreamWriter writer = StreamWriter.Null;
try
{
writer = File.AppendText(GetFilename(destination, batch.EndTime));
WriteRsltsEx(batch, writer);
log.WarnFormat("Batch {0} written by {1} to file {2}", batch.BatchNr, Name, destination);
}
catch
{
log.ErrorFormat("Error writing batch {0} by {1} to file {2}", batch.BatchNr, Name, destination);
}
finally
{
writer.Close();
}
}
}
void WriteRsltsEx(Results.Entities.Batch batch, StreamWriter wrtr)
{
string toPrint;
///
/// Get a sample water meter (to save common and test items)
///
Results.Entities.WaterMeter sampleWM = null;
foreach (var wm in batch.WaterMeters)
{
if (wm != null)
{
sampleWM = wm;
break;
}
}
if (sampleWM == null) return; /// No water meters
///----------
/// Header
///----------
if (!string.IsNullOrEmpty(writerCfg.Header)) wrtr.Write(header);
wrtr.WriteLine();
///----------------
/// Common items
///----------------
string[] leftColumn = new string[commonItems.Count];
string[] rightColumn = new string[commonItems.Count];
int cnt = 0;
foreach (var item in commonItems)
{
leftColumn[cnt] = item.Caption;
rightColumn[cnt] = item.Print(sampleWM);
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++)
{
if (abort) return;
wrtr.Write(leftColumn[i]);
if (!writerCfg.EliminateSpaces)
{
wrtr.Write(new string(' ', maxLen - leftColumn[i].Length + 3));
}
wrtr.Write(separatorStr);
wrtr.WriteLine(rightColumn[i]);
}
///---------
/// Tests
///---------
wrtr.WriteLine();
wrtr.WriteLine("Test Met. Fl. Dev. Flow Test time T1 T2 Density Mass Pressure Volume");
wrtr.WriteLine(" t. [%] [m3/h] [s] [°C] [°C] [kg/m3] [kg] [MPa] [L]");
wrtr.WriteLine("------------------------------------------------------------------------------------------------------------------");
int emptyTestsLeft = 5;
int[] widths = new int[] { 11, 5, 6, 9, 12, 12, 8, 11, 10, 15, 8, 1 }; /// Widths of columns
foreach (var testRslt in batch.RegularTestRslts())
{
if (testRslt.Publish() == Config.Entities.Publish.Always)
{
for (int i = 0; i < Math.Min(testItems.Count, widths.Length); i++)
{
wrtr.Write(toPrint = testItems[i].Print(sampleWM, testRslt.Name()));
for (int j = 0; j < Math.Max(1, widths[i] - toPrint.Length); j++) wrtr.Write(' ');
}
wrtr.WriteLine();
wrtr.WriteLine();
if (emptyTestsLeft > 0) emptyTestsLeft--;
}
}
///----------------
/// Water meters
///----------------
wrtr.WriteLine();
wrtr.WriteLine();
wrtr.WriteLine("------------------------------------------------------------------------------------------------------------------------------------------------");
wrtr.WriteLine("No | Prod. No | Initial Volume [L] | End Volume [L] | Deviation [%] |Sen| Result.");
wrtr.WriteLine("------------------------------------------------------------------------------------------------------------------------------------------------");
wrtr.Write(" ");
for (int i = 0; i < 3; i++)
{
foreach (var testRslt in batch.RegularTestRslts())
{
if (testRslt.Publish() == Config.Entities.Publish.Always)
{
wrtr.Write(toPrint = testRslt.Name());
for (int j = 0; j < Math.Max(1, (i<2 ? 8 : 7) - toPrint.Length); j++) wrtr.Write(' ');
}
}
for (int k = 0; k < emptyTestsLeft; k++) wrtr.Write("- ");
}
wrtr.WriteLine();
wrtr.WriteLine("------------------------------------------------------------------------------------------------------------------------------------------------");
foreach (var wm in batch.WaterMeters)
{
if (wm != null)
{
wrtr.Write(' ');
wrtr.Write(toPrint = wm.WMPosition.ToString());
for (int j = 0; j < Math.Max(1, 3 - toPrint.Length); j++) wrtr.Write(' ');
wrtr.Write(toPrint = wm.SerialNr);
for (int j = 0; j < Math.Max(1, 14 - toPrint.Length); j++) wrtr.Write(' ');
/// Volume start
foreach (var mtr in wm.RegularMeterTestRslts())
{
if (mtr.Publish() == Config.Entities.Publish.Always)
{
wrtr.Write(toPrint = mtr.VolumeStart.ToString("F2"));
for (int j = 0; j < Math.Max(1, 8 - toPrint.Length); j++) wrtr.Write(' ');
}
}
for (int k = 0; k < emptyTestsLeft; k++) wrtr.Write(" ");
/// Volume end
foreach (var mtr in wm.RegularMeterTestRslts())
{
if (mtr.Publish() == Config.Entities.Publish.Always)
{
wrtr.Write(toPrint = mtr.VolumeEnd.ToString("F2"));
for (int j = 0; j < Math.Max(1, 8 - toPrint.Length); j++) wrtr.Write(' ');
}
}
for (int k = 0; k < emptyTestsLeft; k++) wrtr.Write(" ");
/// Error
foreach (var mtr in wm.RegularMeterTestRslts())
{
if (mtr.Publish() == Config.Entities.Publish.Always)
{
wrtr.Write(toPrint = mtr.Error.ToString("F2"));
for (int j = 0; j < Math.Max(1, 7 - toPrint.Length); j++) wrtr.Write(' ');
}
}
for (int k = 0; k < emptyTestsLeft; k++) wrtr.Write(" ");
wrtr.Write(" ");
wrtr.Write(wm.Passed ? "OK" : "Not suitable");
wrtr.WriteLine();
}
}
wrtr.WriteLine("------------------------------------------------------------------------------------------------------------------------------------------------");
wrtr.WriteLine();
wrtr.Write("Producer: ");
wrtr.Write(toPrint = sampleWM.WaterMeterData.Producer);
for (int j = 0; j < Math.Max(1, 30 - toPrint.Length); j++) wrtr.Write(' ');
wrtr.WriteLine("Explanation :");
wrtr.WriteLine(" M - Mass Method");
wrtr.WriteLine(" V - Volumetric Method");
wrtr.WriteLine(" P - Start / Stop");
wrtr.WriteLine(" F - Flow start");
wrtr.WriteLine(" S - Synchro");
wrtr.WriteLine(" C - Count imp.");
wrtr.WriteLine();
wrtr.WriteLine("-------------------------------------------------------------------------");
///----------
/// Footer
///----------
if (!string.IsNullOrEmpty(writerCfg.Footer)) wrtr.Write(footer);
wrtr.Write('\f'); /// Form feed
}
}
}