using System; using System.Collections.Generic; using System.Collections.ObjectModel; using System.ComponentModel; using System.Linq; using System.Linq.Expressions; namespace InABox.Core { public interface ICoreTreeNode { object? ID { get; set; } object? Parent { get; set; } object? Image { get; set; } CoreRow? Row { get; set; } object? this[string column] { get; set; } string Number { get; } } public class CoreTreeNode : INotifyPropertyChanged, ICoreTreeNode { private CoreTreeNodes _owner; public ObservableCollection> Children => new ObservableCollection>(_owner.GetChildrenOfParent(_id)); object? ICoreTreeNode.ID { get => ID; set => ID = (TKey)value!; } private TKey _id; public TKey ID { get { return _id; } set { _id = value; RaisedOnPropertyChanged("ID"); } } object? ICoreTreeNode.Parent { get => Parent; set => Parent = (TKey)value!; } private TKey _parent; public TKey Parent { get { return _parent; } set { _parent = value; RaisedOnPropertyChanged("Parent"); } } private object? _image; public object? Image { get => _image; set { _image = value; RaisedOnPropertyChanged("Image"); } } private CoreRow _row; public CoreRow Row { get => _row; set { _row = value; RaisedOnPropertyChanged("Row"); RaisedOnPropertyChanged("Item[]"); } } public object? this[string column] { get => Row[column]; set { Row[column] = value; _owner.DoColumnChanged(this, column); } } public event PropertyChangedEventHandler? PropertyChanged; public void RaisedOnPropertyChanged(string propertyName) { PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); } public CoreTreeNode(CoreTreeNodes owner, CoreRow row) { _owner = owner; _row = row; } public CoreTreeNode(CoreTreeNodes owner, TKey id, TKey parent, CoreRow row) : this(owner, row) { _id = id; _parent = parent; } public CoreTreeNode? GetParent() => _owner[_parent]; public int Index() { var parent = GetParent(); return parent != null ? parent.Children.IndexOf(this) + 1 : _owner.Nodes.IndexOf(this) + 1; } public void InvalidateData() { RaisedOnPropertyChanged("Row"); RaisedOnPropertyChanged("Item[]"); } public String Number { get { String result = Index().ToString(); var parent = GetParent(); while (parent != null) { int index = parent.Index(); result = $"{index}.{result}"; parent = parent.GetParent(); } return result; } } public int Depth() { var result = 0; foreach (var child in Children) result = Math.Max(result, child.Depth()); return 1 + result; } } public class CoreTreeNodes { private List> _nodes; private Dictionary> _nodeMap; public TKey DefaultKey { get; set; } public ObservableCollection> Nodes { get; } = new ObservableCollection>(); public CoreTreeNode? this[TKey id] => _nodeMap.GetValueOrDefault(id); public CoreTreeNodes(TKey defaultKey) { _nodes = new List>(); _nodeMap = new Dictionary>(); DefaultKey = defaultKey; } public CoreTreeNode Add(TKey id, TKey parent, CoreRow row) { var node = new CoreTreeNode(this, id, parent, row); _nodes.Add(node); _nodeMap[id] = node; if(Equals(node.Parent, DefaultKey)) { Nodes.Add(node); } return node; } public void Clear() { _nodes.Clear(); _nodeMap.Clear(); Nodes.Clear(); } public CoreTreeNode Find(TKey id) => _nodeMap.GetValueOrDefault(id); public CoreTreeNode? Find(CoreRow row) => _nodes.FirstOrDefault(x => x.Row == row); /// /// Gets a given node and recursively all its children given by . /// /// /// public IEnumerable> GetChildren(TKey id) { if(!_nodeMap.TryGetValue(id, out var node)) { yield break; } yield return node; var children = GetChildrenOfParent(id); foreach (var child in children) foreach (var item in GetChildren(child.ID)) yield return item; } /// /// Get all the direct children of the parent given by . /// /// /// public IEnumerable> GetChildrenOfParent(TKey id) { return _nodes.Where(x => object.Equals(x.Parent, id) && !object.Equals(x.ID, id)); } public void Load(CoreTable table, Expression> id, Expression> parentid) { _nodes.Clear(); foreach (var row in table.Rows) { var _id = row.Get(id); var _parent = row.Get(parentid); Add(_id, _parent, row); } } public delegate void ColumnChangedEventHandler(CoreTreeNode node, string column); public event ColumnChangedEventHandler? ColumnChanged; internal void DoColumnChanged(CoreTreeNode node, string column) { ColumnChanged?.Invoke(node, column); } public int Depth() { var result = 0; var roots = Nodes.Where(x => Equals(DefaultKey, x.Parent)); foreach (var root in roots) result = Math.Max(result, root.Depth()); return result; } } }