using CsvHelper; using InABox.Core; using InABox.Core.Postable; using InABox.Scripting; using Microsoft.Win32; using System.Collections.Generic; using System.Globalization; using System.IO; using System.Linq; using System.Text; using System.Threading.Tasks; namespace InABox.Poster.CSV; public class CSVPosterEngine : PosterEngine, CSVPosterSettings> where TPostable : Entity, IPostable, IRemotable, IPersistent, new() { private ScriptDocument? _script; private bool _hasCheckedScript; private ScriptDocument? GetScriptDocument() { if (_hasCheckedScript) { return _script; } var settings = GetSettings(); if (settings.ScriptEnabled && !string.IsNullOrWhiteSpace(settings.Script)) { var document = new ScriptDocument(settings.Script); document.Properties.Add(new ScriptProperty("Results", null)); if (!document.Compile()) { throw new Exception("Script failed to compile!"); } _script = document; } else { _script = null; } _hasCheckedScript = true; return _script; } public override bool BeforePost(IDataModel model) { if(GetScriptDocument() is ScriptDocument script) { return script.Execute(methodname: "BeforePost", parameters: new object[] { model }); } else { return Poster.BeforePost(model); } } protected override IPostResult DoProcess(IDataModel model) { var settings = GetSettings(); ICSVExport results; if (GetScriptDocument() is ScriptDocument script) { if (!script.Execute(methodname: "Process", parameters: new object[] { model })) { throw new Exception("Post Failed."); } var resultsObject = script.GetValue("Results"); results = (resultsObject as ICSVExport) ?? throw new Exception($"Script 'Results' property expected to be ICSVExport<{typeof(TPostable)}>, got {resultsObject}"); } else { results = Poster.Process(model); } var dlg = new SaveFileDialog() { FileName = settings.DefaultOutputFile, Filter = "CSV Files (*.csv)|*.csv" }; if(dlg.ShowDialog() == true) { using var writer = new StreamWriter(dlg.FileName); using var csv = new CsvWriter(writer, CultureInfo.InvariantCulture); csv.Context.RegisterClassMap(results.ClassMap.ClassMap); var method = typeof(CsvWriter).GetMethods() .Where(x => x.Name == nameof(CsvWriter.WriteRecords) && x.GetGenericArguments().Length == 1).First() .MakeGenericMethod(results.Type); method.Invoke(csv, new object?[] { results.Records }); return results; } else { throw new PostCancelledException(); } } public override void AfterPost(IDataModel model, IPostResult result) { if (GetScriptDocument() is ScriptDocument script) { // Ignoring 'result', because this is actually the 'Results' field of the script class. script.Execute(methodname: "AfterPost", parameters: new object[] { model }); } else { Poster.AfterPost(model, result); } } }