using System; using System.Collections; using System.Collections.Generic; using System.Linq; using System.Reflection; using LinqToDB.Extensions; using Pf2e.Database.Model.Common.I18n; namespace Pf2e.WPF.EntityViewer.EntityViewStructure; /// /// Поле стркутуры с объектом. /// internal class StructureFieldComplex : StructureField { /// public override StructureFieldType FieldType => StructureFieldType.Complex; /// /// Набор полей объекта. /// public readonly List Fields = []; /// /// Тип значения поля. /// public readonly Type Type; /// /// Флаг, указывающий, отображается ли поля объекта. /// public bool Collapsed { get => _collapsed; set { _collapsed = value; UpdateFieldVisibility(); OnPropertyChanged(); } } private bool _collapsed; /// /// Флаг, указывающий, что у этот элемент можно свернуть. /// public bool Collapsable { get => Fields.Count > 0; } /// /// Значение поля идентификатора элемента. /// public string? IdValue { get; private set; } /// public override bool Visible { get => base.Visible; set { base.Visible = value; UpdateFieldVisibility(); } } /// /// Конструктор класса поля структуры с объектом. /// /// Класс построения структуры данных. /// Значение поля. /// Название поля. /// Глубина поля. public StructureFieldComplex(StructureBuilder builder, object value, string name, int depth) : base(builder, name, depth) { Type = value.GetType(); SetFields((dynamic)value); } /// /// Обновить видимость полей структуры. /// private void UpdateFieldVisibility() { foreach (StructureField field in Fields) { field.Visible = Visible && !Collapsed; } } /// /// Установить поля структуры `LocaleString`. /// /// Объект строки локализации. private void SetFields(LocaleString localeString) { SetFieldsFromRecords( localeString .Select(field => new FieldRecord(field.Locale.ToString(), field.Value)) .ToList() ); } /// /// Установить поля структуры `IEnumerable`. /// /// Объект-перечисление. private void SetFields(IEnumerable enumerable) { int i = 0; List records = []; foreach (object? item in enumerable) { records.Add(new($"[{i++}]", item)); } SetFieldsFromRecords(records); } /// /// Установить поля структуры общего объекта. /// /// Объект. private void SetFields(object value) { Type type = value.GetType(); PropertyInfo[] properties = type.GetProperties(BindingFlags.Public | BindingFlags.Instance); var records = properties .Where(property => property.GetAttribute() is null) .Select(property => new FieldRecord(property.Name, property.GetValue(value, null))) .ToList(); var idRecord = records.FirstOrDefault(record => record.Name == "Id"); if (idRecord is not null && idRecord.Value is not null) { records.Remove(idRecord); IdValue = idRecord.Value.ToString(); } SetFieldsFromRecords(records); } /// /// Установить поля структуры из списка записей. /// /// private void SetFieldsFromRecords(List records) { foreach ( FieldRecord record in records.Where(record => record.FieldType == StructureFieldType.Complex ) ) { record.Allowed = Builder.RegisterProcessed(record.Value!); } foreach (FieldRecord record in records) { Fields.Add( record is { FieldType: StructureFieldType.Complex, Allowed: true } ? Builder.Create(record.Name, record.Value!, Depth + 1) : Builder.Resolve(record.Name, record.Value!, Depth + 1) ); } } /// /// Запись поля структуры. /// /// Название поля. /// Значение поля. private class FieldRecord(string name, object? value) { /// /// Название поля. /// public readonly string Name = name; /// /// Значение поля. /// public readonly object? Value = value; /// /// Тип поля структуры. /// public StructureFieldType FieldType => StructureBuilder.GetFieldType(Value); /// /// Флаг, указывающий, использовать ли поле. /// public bool Allowed = true; } /// public override string GetTypeString() { if (Type.IsGenericEnumerableType()) { Type elementType = Type.GetGenericArguments().Single(); return $"{elementType.Name}[]"; } else { return Type.Name; } } /// public override string GetValueString() { if (Type.IsGenericEnumerableType()) { return Fields.Count.ToString() + (Fields.Count == 1 ? " item" : " items"); } if (IdValue is not null) { return $"#{IdValue}"; } return ""; } /// public override ICollection GetRows(Func func) { return [.. base.GetRows(func), .. Fields.SelectMany(f => f.GetRows(func)).ToList()]; } }