using System; using System.Threading.Tasks; using System.IO; using Elwig.Helpers; using System.Collections.Generic; using System.Linq; using Elwig.Helpers.Printing; using MimeKit; namespace Elwig.Documents { public abstract partial class Document : IDisposable { public static string Name => "Dokument"; protected static readonly double GenerationProportion = 0.125; protected TempFile? _pdfFile = null; protected string? _pdfPath; protected string? PdfPath => _pdfPath ?? _pdfFile?.FilePath; public int? TotalPages { get; private set; } public int? Pages => TotalPages / (DoublePaged ? 2 : 1); public bool ShowFoldMarks = App.Config.Debug; public bool DoublePaged = false; public string DataPath; public int CurrentNextSeason; public string? DocumentId; public string Title; public string Author; public string Header; public string Footer; public DateOnly Date; public Document(string title) { var c = App.Client; DataPath = App.DataPath; CurrentNextSeason = Utils.CurrentNextSeason; Title = title; Author = c.NameFull; Header = $"
{c.Name}
{c.NameSuffix}
{c.NameTypeFull}
"; Footer = Utils.GenerateFooter("
", " \u00b7 ") .Item(c.NameFull).NextLine() .Item(c.Address).Item($"{c.Plz} {c.Ort}").Item("Österreich").Item("Tel.", c.PhoneNr).Item("Fax", c.FaxNr).NextLine() .Item(c.EmailAddress != null ? $"\">{c.EmailAddress}" : null) .Item(c.Website != null ? $"{c.Website}" : null) .Item("Betriebs-Nr.", c.LfbisNr).Item("UID", c.UstIdNr).NextLine() .Item("BIC", c.Bic).Item("IBAN", c.Iban) .ToString(); Date = DateOnly.FromDateTime(Utils.Today); } ~Document() { Dispose(); } public void Dispose() { _pdfFile?.Dispose(); _pdfFile = null; GC.SuppressFinalize(this); } public static Document Merge(IEnumerable docs) { return new MergedDocument(docs); } public static Document FromPdf(string path) { return new PdfDocument(path); } private async Task Render() { string name; if (this is BusinessLetter) { name = "BusinessLetter"; } else if (this is DeliveryNote) { name = "DeliveryNote"; } else if (this is CreditNote) { name = "CreditNote"; } else if (this is DeliveryJournal) { name = "DeliveryJournal"; } else if (this is Letterhead) { name = "Letterhead"; } else if (this is DeliveryConfirmation) { name = "DeliveryConfirmation"; } else if (this is MemberDataSheet) { name = "MemberDataSheet"; } else if (this is MemberList) { name = "MemberList"; } else if (this is WineQualityStatistics) { name = "WineQualityStatistics"; } else if (this is PaymentVariantSummary) { name = "PaymentVariantSummary"; } else { throw new InvalidOperationException("Invalid document object"); } return await Render(name); } private async Task Render(string name) { return await Html.CompileRenderAsync(name, this); ; } public async Task Generate(IProgress? progress = null) { if (_pdfFile != null) return; progress?.Report(0.0); if (this is PdfDocument) { // nothing to do } else if (this is MergedDocument m) { var pdf = new TempFile("pdf"); var tmpHtmls = new List(); var tmpFiles = new List(); var n = m.Documents.Count(); int i = 0; foreach (var doc in m.Documents) { if (doc is PdfDocument) { tmpFiles.Add(doc.PdfPath!); continue; } var tmpHtml = new TempFile("html"); await File.WriteAllTextAsync(tmpHtml.FilePath, await doc.Render(), Utils.UTF8); tmpHtmls.Add(tmpHtml); tmpFiles.Add((doc is Letterhead ? "#" : "") + tmpHtml.FileName); i++; progress?.Report(GenerationProportion * 100 * i / n); } progress?.Report(GenerationProportion * 100); var pages = await Pdf.Convert(tmpFiles, pdf.FileName, DoublePaged, new Progress(v => progress?.Report(GenerationProportion * 100 + v * (1 - GenerationProportion)))); TotalPages = pages.Pages; foreach (var tmp in tmpHtmls) { tmp.Dispose(); } _pdfFile = pdf; } else { var pdf = new TempFile("pdf"); using (var tmpHtml = new TempFile("html")) { await File.WriteAllTextAsync(tmpHtml.FilePath, await Render(), Utils.UTF8); progress?.Report(50.0); var pages = await Pdf.Convert(tmpHtml.FilePath, pdf.FilePath, DoublePaged); TotalPages = pages.Pages; } _pdfFile = pdf; } progress?.Report(100.0); } public void SaveTo(string pdfPath) { if (PdfPath == null) throw new InvalidOperationException("Pdf file has not been generated yet"); File.Copy(PdfPath, pdfPath, true); } public async Task Print(int copies = 1) { if (PdfPath == null) throw new InvalidOperationException("Pdf file has not been generated yet"); await Pdf.Print(PdfPath, copies); } public void Show() { if (_pdfFile == null) throw new InvalidOperationException("Pdf file has not been generated yet"); Pdf.Show(_pdfFile.NewReference(), Title + (this is BusinessDocument b ? $" - {b.Member.Name}" : "")); } public MimePart AsEmailAttachment(string filename) { if (PdfPath == null) throw new InvalidOperationException("Pdf file has not been generated yet"); return new("application", "pdf") { Content = new MimeContent(File.OpenRead(PdfPath)), ContentDisposition = new ContentDisposition(ContentDisposition.Attachment), ContentTransferEncoding = ContentEncoding.Base64, FileName = filename }; } private class MergedDocument(IEnumerable docs) : Document("Mehrere Dokumente") { public IEnumerable Documents = docs; } private class PdfDocument : Document { public PdfDocument(string pdfPath) : base(Path.GetFileNameWithoutExtension(pdfPath)) { _pdfPath = pdfPath; } } } }