using System; using System.Collections.Generic; using System.Data; using System.Linq; using System.Reflection; namespace Elwig.Models.Dtos { public class DataTable { public string Name { get; set; } public string FullName { get; set; } public string? Subtitle { get; set; } public IEnumerable<(string? Name, IEnumerable Rows)> Sections { get; private set; } public IEnumerable Rows => Sections.SelectMany(s => s.Rows); public int RowNum => Rows.Count(); public int ColNum => ColumnNames.Count(); public IEnumerable<(string Name, Type? Type)> ColumnDefs => _map.Select(m => (m.Name, m.PInfo?.PropertyType ?? m.FInfo?.FieldType)); public IEnumerable ColumnNames => ColumnDefs.Select(m => m.Name); public IEnumerable ColumnTypes => ColumnDefs.Select(m => m.Type); public IEnumerable ColumnFlatTypes { get; private set; } public IEnumerable ColumnSpans { get; private set; } public IEnumerable ColumnWidths { get; private set; } public IEnumerable ColumnUnits { get; private set; } private readonly PropertyInfo[] _properties; private readonly FieldInfo[] _fields; private readonly (string Name, PropertyInfo? PInfo, FieldInfo? FInfo)[] _map; public DataTable(string name, string fullName, string subtitle, IEnumerable<(string? Name, IEnumerable Rows)> sections, IEnumerable<(string Property, string Name, string? Unit, int? Width)>? colNames = null) : this(name, fullName, sections, colNames) { Subtitle = subtitle; } public DataTable(string name, string fullName, string subtitle, IEnumerable rows, IEnumerable<(string Property, string Name, string? Unit, int? Width)>? colNames = null) : this(name, fullName, subtitle, [(null, rows)], colNames) { } public DataTable(string name, string fullName, IEnumerable<(string? Name, IEnumerable Rows)> sections, IEnumerable<(string Property, string Name, string? Unit, int? Width)>? colNames = null) { _fields = typeof(T).GetFields(); _properties = typeof(T).GetProperties(); colNames ??= [.. _properties.Select(p => p.Name).Union(_fields.Select(f => f.Name)).Select(i => (i, i, (string?)null, (int?)null))]; _map = [.. colNames.Select(n => (n.Name, _properties.FirstOrDefault(p => p?.Name == n.Property, null), _fields.FirstOrDefault(f => f?.Name == n.Property, null)))]; Name = name; FullName = fullName; Sections = sections; ColumnFlatTypes = [.. ColumnTypes.SelectMany(type => { var elType = type?.GetElementType(); return type != null && type.IsValueType && type.Name.StartsWith("ValueTuple") ? type.GetFields().Select(f => (Type?)f.FieldType) : type != null && elType != null && type.IsArray && elType.IsValueType && elType.Name.StartsWith("ValueTuple") ? elType.GetFields().Select(f => (Type?)f.FieldType) : [type]; })]; ColumnSpans = [.. ColumnTypes.Select(type => { var elType = type?.GetElementType(); return type != null && type.IsValueType && type.Name.StartsWith("ValueTuple") ? type.GetFields().Length : type != null && elType != null && type.IsArray && elType.IsValueType && elType.Name.StartsWith("ValueTuple") ? elType.GetFields().Length : 1; })]; ColumnWidths = [.. colNames.Select(c => c.Width)]; ColumnUnits = [.. colNames.Select(c => c.Unit?.Split("|").Select(p => p.Length == 0 ? null : p).ToArray() ?? [])]; } public DataTable(string name, string fullName, IEnumerable rows, IEnumerable<(string Property, string Name, string? Unit, int? Width)>? colNames = null) : this(name, fullName, [(null, rows)], colNames) { } public DataTable(string name, string fullName, IEnumerable rows, IEnumerable<(string Property, string Name, string? Unit)>? colNames = null) : this(name, fullName, rows, colNames?.Select(c => (c.Property, c.Name, c.Unit, (int?)null))) { } public DataTable(string name, string fullName, IEnumerable rows, IEnumerable<(string Property, string Name, string? Unit, int Width)>? colNames = null) : this(name, fullName, rows, colNames?.Select(c => (c.Property, c.Name, c.Unit, (int?)c.Width))) { } public DataTable(string name, IEnumerable rows, IEnumerable<(string Property, string Name, string? Unit, int? Width)>? colNames = null) : this(name, name, rows, colNames) { } public DataTable(string name, IEnumerable rows, IEnumerable<(string Property, string Name, string? Unit)>? colNames = null) : this(name, name, rows, colNames) { } public DataTable(string name, IEnumerable rows, IEnumerable<(string Property, string Name, string? Unit, int Width)>? colNames = null) : this(name, name, rows, colNames) { } public DataTable(string name, string fullName, IEnumerable<(string? Name, IEnumerable Rows)> sections, IEnumerable<(string Property, string Name, string? Unit)>? colNames = null) : this(name, fullName, sections, colNames?.Select(c => (c.Property, c.Name, c.Unit, (int?)null))) { } public DataTable(string name, string fullName, IEnumerable<(string? Name, IEnumerable Rows)> sections, IEnumerable<(string Property, string Name, string? Unit, int Width)>? colNames = null) : this(name, fullName, sections, colNames?.Select(c => (c.Property, c.Name, c.Unit, (int?)c.Width))) { } protected IEnumerable<(string Name, object? Value)> GetNamedRowValues(T row) { return _map.Select(i => (i.Name, i.PInfo?.GetValue(row) ?? i.FInfo?.GetValue(row))); } protected IEnumerable GetRowValues(T row) { return GetNamedRowValues(row).Select(i => i.Value); } public IEnumerable<(string? Name, IEnumerable> Rows)> GetData() { return Sections.Select(s => (s.Name, s.Rows.Select(GetRowValues))); } public IEnumerable<(string? Name, IEnumerable> Rows)> GetNamedData() { return Sections.Select(s => (s.Name, s.Rows.Select(GetNamedRowValues))); } } }