using System; using System.Collections; using System.Collections.Generic; using System.Linq; namespace pkNX.Structures; public static class TableUtil { /// /// Converts an enumerable list of to a tab separated sheet. /// /// Object Type /// Array of type T /// 2 dimensional sheet of cells public static string GetTable(IEnumerable arr) where T : notnull => string.Join(Environment.NewLine, GetTableRaw(arr)); private const char sep = '\t'; private static IEnumerable GetTableRaw(IEnumerable arr) where T : notnull => Table(arr).Select(row => string.Join(sep, row)); private static IEnumerable GetTableRaw(IEnumerable arr, Type t) where T : notnull => Table(arr, t).Select(row => string.Join(sep, row)); public static string GetNamedTable(IEnumerable arr, IList names, string? name = null) where T : notnull { var list = GetTableRaw(arr).ToArray(); // slap in name to column header list[0] = $"Index{sep}{name ?? typeof(T).Name}{sep}{list[0]}"; // slap in row name to row for (int i = 1; i < list.Length; i++) list[i] = $"{i - 1}{sep}{names[i - 1]}{sep}{list[i]}"; return string.Join(Environment.NewLine, list); } public static string GetNamedTypeTable(IList arr, IList names, string? name = null) where T : notnull { var t = arr[0].GetType(); if (t.Name.StartsWith("tableReader_")) // FlatBuffer generated wrapper t = t.BaseType; if (t is null) throw new ArgumentException("Type is null"); var list = GetTableRaw(arr, t).ToArray(); // slap in name to column header list[0] = $"Index{sep}{name ?? t.Name}{sep}{list[0]}"; // slap in row name to row for (int i = 1; i < names.Count + 1; i++) list[i] = $"{i - 1}{sep}{names[i - 1]}{sep}{list[i]}"; return string.Join(Environment.NewLine, list); } private static IEnumerable> Table(IEnumerable arr) where T : notnull { var type = typeof(T); yield return GetNames(type); foreach (var z in arr) yield return GetValues(z, type); } private static IEnumerable> Table(IEnumerable arr, Type type) where T : notnull { yield return GetNames(type); foreach (var z in arr) yield return GetValues(z, type); } private static IEnumerable GetNames(Type type) { foreach (var z in type.GetProperties()) yield return z.Name; foreach (var z in type.GetFields()) yield return z.Name; } private static IEnumerable GetValues(object obj, Type type) { foreach (var z in type.GetProperties()) yield return GetFormattedString(z.GetValue(obj, null)); foreach (var z in type.GetFields()) yield return GetFormattedString(z.GetValue(obj)); } private static string GetFormattedString(object? obj) { if (obj == null) return string.Empty; if (obj is ulong u) return u.ToString("X16"); if (obj is IEnumerable x and not string) return string.Join('|', JoinEnumerator(x.GetEnumerator()).Select(GetFormattedString)); var objType = obj.GetType(); if (objType.IsEnum) return obj.ToString() ?? string.Empty; var mi = objType.GetMethods().First(z => z.Name == nameof(obj.ToString)); if (mi.DeclaringType == objType) return obj.ToString() ?? string.Empty; var props = objType.GetProperties().Select(z => GetFormattedString(z.GetValue(obj))); var fields = objType.GetFields().Select(z => GetFormattedString(z.GetValue(obj))); return string.Join('|', props.Concat(fields)); } private static IEnumerable JoinEnumerator(IEnumerator x) { while (x.MoveNext()) yield return x.Current; } }