|   |  | 1 |  | // Copyright (c) 2020-2024 dotBunny Inc. | 
|   |  | 2 |  | // dotBunny licenses this file to you under the BSL-1.0 license. | 
|   |  | 3 |  | // See the LICENSE file in the project root for more information. | 
|   |  | 4 |  |  | 
|   |  | 5 |  | #if !UNITY_DOTSRUNTIME | 
|   |  | 6 |  |  | 
|   |  | 7 |  | using System; | 
|   |  | 8 |  | using System.IO; | 
|   |  | 9 |  | using System.Runtime.CompilerServices; | 
|   |  | 10 |  | using System.Text; | 
|   |  | 11 |  |  | 
|   |  | 12 |  | namespace GDX.Developer.Reports.Resource | 
|   |  | 13 |  | { | 
|   |  | 14 |  |     /// <exception cref="UnsupportedRuntimeException">Not supported on DOTS Runtime.</exception> | 
|   |  | 15 |  |     public abstract class ResourceReport | 
|   |  | 16 |  |     { | 
|   |  | 17 |  |         /// <summary> | 
|   |  | 18 |  |         ///     A <see cref="string" /> array used to represent the end of a line for splitting purposes. | 
|   |  | 19 |  |         /// </summary> | 
|   | 1 | 20 |  |         static readonly string[] k_NewLineSplit = { Environment.NewLine }; | 
|   |  | 21 |  |  | 
|   |  | 22 |  |         /// <summary> | 
|   |  | 23 |  |         ///     Output the report format as an array of <see cref="string" />. | 
|   |  | 24 |  |         /// </summary> | 
|   |  | 25 |  |         /// <remarks>It is usually best to provide a <see cref="StringBuilder" /> or <see cref="StreamWriter" /> instead | 
|   |  | 26 |  |         /// <param name="context"></param> | 
|   |  | 27 |  |         /// <returns>A generated report as an array of <see cref="string" />.</returns> | 
|   |  | 28 |  |         public string[] Output(ResourceReportContext context = null) | 
|   | 3 | 29 |  |         { | 
|   | 3 | 30 |  |             StringBuilder builder = new StringBuilder(); | 
|   | 3 | 31 |  |             return Output(builder, context) | 
|   |  | 32 |  |                 ? builder.ToString().Split(k_NewLineSplit, StringSplitOptions.None) | 
|   |  | 33 |  |                 : null; | 
|   | 3 | 34 |  |         } | 
|   |  | 35 |  |  | 
|   |  | 36 |  |         /// <summary> | 
|   |  | 37 |  |         ///     Output the report format utilizing the provided <paramref name="writer" />, optionally limiting the | 
|   |  | 38 |  |         ///     write buffers by <paramref name="bufferSize" />. | 
|   |  | 39 |  |         /// </summary> | 
|   |  | 40 |  |         /// <param name="context">Contextual information regarding the generation of the report.</param> | 
|   |  | 41 |  |         /// <param name="writer">A <see cref="StreamWriter" /> instance to use for output.</param> | 
|   |  | 42 |  |         /// <param name="bufferSize">The write buffer size.</param> | 
|   |  | 43 |  |         /// <returns>true/false if the report was successfully written to the provided <paramref name="writer" />.</retu | 
|   |  | 44 |  |         public bool Output(StreamWriter writer, int bufferSize = 1024, ResourceReportContext context = null) | 
|   | 1 | 45 |  |         { | 
|   | 1 | 46 |  |             StringBuilder builder = new StringBuilder(); | 
|   | 1 | 47 |  |             if (!Output(builder, context)) | 
|   | 0 | 48 |  |             { | 
|   | 0 | 49 |  |                 return false; | 
|   |  | 50 |  |             } | 
|   |  | 51 |  |  | 
|   | 1 | 52 |  |             int contentLength = builder.Length; | 
|   | 1 | 53 |  |             char[] content = new char[bufferSize]; | 
|   | 1 | 54 |  |             int leftOvers = contentLength % bufferSize; | 
|   | 1 | 55 |  |             int writeCount = (contentLength - leftOvers) / bufferSize; | 
|   |  | 56 |  |  | 
|   |  | 57 |  |             // Fixed sized writes | 
|   | 210 | 58 |  |             for (int i = 0; i < writeCount; i++) | 
|   | 104 | 59 |  |             { | 
|   | 104 | 60 |  |                 builder.CopyTo(i * bufferSize, content, 0, bufferSize); | 
|   | 104 | 61 |  |                 writer.Write(content, 0, bufferSize); | 
|   | 104 | 62 |  |             } | 
|   |  | 63 |  |  | 
|   | 1 | 64 |  |             if (leftOvers > 0) | 
|   | 1 | 65 |  |             { | 
|   | 1 | 66 |  |                 builder.CopyTo(writeCount * bufferSize, content, 0, leftOvers); | 
|   | 1 | 67 |  |                 writer.Write(content, 0, leftOvers); | 
|   | 1 | 68 |  |             } | 
|   |  | 69 |  |  | 
|   | 1 | 70 |  |             writer.Flush(); | 
|   | 1 | 71 |  |             return true; | 
|   | 1 | 72 |  |         } | 
|   |  | 73 |  |  | 
|   |  | 74 |  |         /// <summary> | 
|   |  | 75 |  |         ///     Output the report format utilizing the provided <paramref name="builder" />. | 
|   |  | 76 |  |         /// </summary> | 
|   |  | 77 |  |         /// <param name="builder">A <see cref="StringBuilder" /> to use when generating the report.</param> | 
|   |  | 78 |  |         /// <param name="context">Contextual information regarding the generation of the report.</param> | 
|   |  | 79 |  |         /// <returns>true/false if report was added to <paramref name="builder" />.</returns> | 
|   |  | 80 |  |         public abstract bool Output(StringBuilder builder, ResourceReportContext context = null); | 
|   |  | 81 |  |  | 
|   |  | 82 |  |  | 
|   |  | 83 |  |         /// <summary> | 
|   |  | 84 |  |         ///     Create a sized divider string for use in generating reports. | 
|   |  | 85 |  |         /// </summary> | 
|   |  | 86 |  |         /// <param name="context">Contextual information regarding the generation of the report.</param> | 
|   |  | 87 |  |         /// <param name="divider">The optional character to use as the divider.</param> | 
|   |  | 88 |  |         /// <returns>A sized string to be used as a divider.</returns> | 
|   |  | 89 |  |         public static string CreateDivider(ResourceReportContext context, char divider = '-') | 
|   | 1 | 90 |  |         { | 
|   | 1 | 91 |  |             return "".PadRight(context.CharacterWidth, divider); | 
|   | 1 | 92 |  |         } | 
|   |  | 93 |  |  | 
|   |  | 94 |  |         /// <summary> | 
|   |  | 95 |  |         ///     Create a header with <paramref name="title" /> with repeated <paramref name="decorator" />s on the sides | 
|   |  | 96 |  |         ///     out to <see cref="ResourceReportContext.CharacterWidth" />. | 
|   |  | 97 |  |         /// </summary> | 
|   |  | 98 |  |         /// <param name="context">Contextual information regarding the generation of the report.</param> | 
|   |  | 99 |  |         /// <param name="title">The text to be treated as the title for the header.</param> | 
|   |  | 100 |  |         /// <param name="decorator">The optional character to be used as the decorator.</param> | 
|   |  | 101 |  |         /// <returns>A sized string to be used as a header.</returns> | 
|   |  | 102 |  |         public static string CreateHeader(ResourceReportContext context, string title, char decorator = '=') | 
|   | 59 | 103 |  |         { | 
|   | 59 | 104 |  |             string workingTitle = $" {title.Trim()} "; | 
|   |  | 105 |  |  | 
|   | 59 | 106 |  |             int titleWidth = workingTitle.Length; | 
|   | 59 | 107 |  |             int decoratorSideWidth = (context.CharacterWidth - titleWidth) / 2; | 
|   |  | 108 |  |  | 
|   |  | 109 |  |             // Pad left side first to ensure it is always the most accurate in length | 
|   | 59 | 110 |  |             workingTitle = workingTitle.PadLeft(titleWidth + decoratorSideWidth, decorator); | 
|   | 59 | 111 |  |             workingTitle = workingTitle.PadRight(context.CharacterWidth, decorator); | 
|   |  | 112 |  |  | 
|   | 59 | 113 |  |             return workingTitle; | 
|   | 59 | 114 |  |         } | 
|   |  | 115 |  |  | 
|   |  | 116 |  |         public static string CreateKeyValuePair(ResourceReportContext context, string itemKey, string itemValue) | 
|   | 131 | 117 |  |         { | 
|   | 131 | 118 |  |             string workingLine = $"{itemKey}: ".PadRight(context.KeyValuePairWidth); | 
|   | 131 | 119 |  |             if (workingLine.Length > context.KeyValuePairWidth) | 
|   | 0 | 120 |  |             { | 
|   | 0 | 121 |  |                 workingLine = workingLine.Substring(0, context.KeyValuePairWidth); | 
|   | 0 | 122 |  |             } | 
|   |  | 123 |  |  | 
|   | 131 | 124 |  |             workingLine = $"{workingLine}{itemValue}"; | 
|   | 131 | 125 |  |             if (workingLine.Length > context.CharacterWidth) | 
|   | 0 | 126 |  |             { | 
|   | 0 | 127 |  |                 workingLine = workingLine.Substring(0, context.CharacterWidth); | 
|   | 0 | 128 |  |             } | 
|   |  | 129 |  |  | 
|   | 131 | 130 |  |             return workingLine; | 
|   | 131 | 131 |  |         } | 
|   |  | 132 |  |  | 
|   |  | 133 |  |         [MethodImpl(MethodImplOptions.AggressiveInlining)] | 
|   |  | 134 |  |         public static string CreateYesNo(bool flag) | 
|   | 0 | 135 |  |         { | 
|   | 0 | 136 |  |             return flag ? "Y" : "N"; | 
|   | 0 | 137 |  |         } | 
|   |  | 138 |  |  | 
|   |  | 139 |  |         [MethodImpl(MethodImplOptions.AggressiveInlining)] | 
|   |  | 140 |  |         public static string PositiveSign(long targetValue) | 
|   | 12 | 141 |  |         { | 
|   | 12 | 142 |  |             return targetValue > 0 ? "+" : null; | 
|   | 12 | 143 |  |         } | 
|   |  | 144 |  |  | 
|   |  | 145 |  |         [MethodImpl(MethodImplOptions.AggressiveInlining)] | 
|   |  | 146 |  |         public static string PositiveSign(int targetValue) | 
|   | 1 | 147 |  |         { | 
|   | 1 | 148 |  |             return targetValue > 0 ? "+" : null; | 
|   | 1 | 149 |  |         } | 
|   |  | 150 |  |     } | 
|   |  | 151 |  | } | 
|   |  | 152 |  | #endif // !UNITY_DOTSRUNTIME |