using System; using System.IO; using SabreTools.Core; using SabreTools.DatFiles; using SabreTools.Reports.Formats; namespace SabreTools.Reports { /// /// Base class for a report output format /// /// TODO: Can this be overhauled to have all types write like DatFiles? public abstract class BaseReport { protected string _name; protected long _machineCount; protected ItemDictionary _stats; protected StreamWriter _writer; protected bool _baddumpCol; protected bool _nodumpCol; /// /// Create a new report from the filename /// /// Name of the file to write out to /// True if baddumps should be included in output, false otherwise /// True if nodumps should be included in output, false otherwise public BaseReport(string filename, bool baddumpCol = false, bool nodumpCol = false) { var fs = File.Create(filename); if (fs != null) _writer = new StreamWriter(fs); _baddumpCol = baddumpCol; _nodumpCol = nodumpCol; } /// /// Create a new report from the stream /// /// Output stream to write to /// True if baddumps should be included in output, false otherwise /// True if nodumps should be included in output, false otherwise public BaseReport(Stream stream, bool baddumpCol = false, bool nodumpCol = false) { if (!stream.CanWrite) throw new ArgumentException(nameof(stream)); _writer = new StreamWriter(stream); _baddumpCol = baddumpCol; _nodumpCol = nodumpCol; } /// /// Create a specific type of BaseReport to be used based on a format and user inputs /// /// Format of the Statistics Report to be created /// Name of the file to write out to /// True if baddumps should be included in output, false otherwise /// True if nodumps should be included in output, false otherwise /// BaseReport of the specific internal type that corresponds to the inputs public static BaseReport Create(StatReportFormat statReportFormat, string filename, bool baddumpCol, bool nodumpCol) { #if NET_FRAMEWORK switch (statReportFormat) { case StatReportFormat.None: return new Textfile(Console.OpenStandardOutput(), baddumpCol, nodumpCol); case StatReportFormat.Textfile: return new Textfile(filename, baddumpCol, nodumpCol); case StatReportFormat.CSV: return new SeparatedValue(filename, ',', baddumpCol, nodumpCol); case StatReportFormat.HTML: return new Html(filename, baddumpCol, nodumpCol); case StatReportFormat.SSV: return new SeparatedValue(filename, ';', baddumpCol, nodumpCol); case StatReportFormat.TSV: return new SeparatedValue(filename, '\t', baddumpCol, nodumpCol); default: return null; } #else return statReportFormat switch { StatReportFormat.None => new Textfile(Console.OpenStandardOutput(), baddumpCol, nodumpCol), StatReportFormat.Textfile => new Textfile(filename, baddumpCol, nodumpCol), StatReportFormat.CSV => new SeparatedValue(filename, ',', baddumpCol, nodumpCol), StatReportFormat.HTML => new Html(filename, baddumpCol, nodumpCol), StatReportFormat.SSV => new SeparatedValue(filename, ';', baddumpCol, nodumpCol), StatReportFormat.TSV => new SeparatedValue(filename, '\t', baddumpCol, nodumpCol), _ => null, }; #endif } /// /// Replace the statistics that is being output /// public void ReplaceStatistics(string datName, long machineCount, ItemDictionary datStats) { _name = datName; _machineCount = machineCount; _stats = datStats; } /// /// Write the report to the output stream /// public abstract void Write(); /// /// Write out the header to the stream, if any exists /// public abstract void WriteHeader(); /// /// Write out the mid-header to the stream, if any exists /// public abstract void WriteMidHeader(); /// /// Write out the separator to the stream, if any exists /// public abstract void WriteMidSeparator(); /// /// Write out the footer-separator to the stream, if any exists /// public abstract void WriteFooterSeparator(); /// /// Write out the footer to the stream, if any exists /// public abstract void WriteFooter(); /// /// Returns the human-readable file size for an arbitrary, 64-bit file size /// The default format is "0.### XB", e.g. "4.2 KB" or "1.434 GB" /// /// /// Human-readable file size /// http://www.somacon.com/p576.php protected static string GetBytesReadable(long input) { // Get absolute value long absolute_i = (input < 0 ? -input : input); // Determine the suffix and readable value string suffix; double readable; if (absolute_i >= 0x1000000000000000) // Exabyte { suffix = "EB"; readable = (input >> 50); } else if (absolute_i >= 0x4000000000000) // Petabyte { suffix = "PB"; readable = (input >> 40); } else if (absolute_i >= 0x10000000000) // Terabyte { suffix = "TB"; readable = (input >> 30); } else if (absolute_i >= 0x40000000) // Gigabyte { suffix = "GB"; readable = (input >> 20); } else if (absolute_i >= 0x100000) // Megabyte { suffix = "MB"; readable = (input >> 10); } else if (absolute_i >= 0x400) // Kilobyte { suffix = "KB"; readable = input; } else { return input.ToString("0 B"); // Byte } // Divide by 1024 to get fractional value readable /= 1024; // Return formatted number with suffix return readable.ToString("0.### ") + suffix; } } }