using InnovEnergy.Lib.Utils;
using Sawmill;

namespace InnovEnergy.Lib.SrcGen.Trees;

public class Tree<T> :IRewritable<Tree<T>> where T : notnull
{
    private readonly ForwardTree<T> _Tree;
    public Tree<T>? Parent { get; }
    
    public Boolean IsRoot => Parent is null;
    public Boolean IsLeaf => !Children.Any();
    
    public Tree(ForwardTree<T> tree, Tree<T>? parent = default)
    {
        _Tree  = tree;
        Parent = parent;
    }

    public T Node => _Tree.Node;
    
    public IEnumerable<Tree<T>> Children => _Tree
                                            .Children
                                            .Select(c => new Tree<T>(c, this));

    public IEnumerable<Tree<T>> Ancestors => Parent.Unfold(t => t.Parent);

    public override String ToString() => _Tree.ToString();

    public Tree<T> Root => this.Unfold(t => t.Parent).Last();
    
    Int32 IRewritable<Tree<T>>.CountChildren() => _Tree.Children.Count;

    void IRewritable<Tree<T>>.GetChildren(Span<Tree<T>> childrenReceiver)
    {
        var i = 0;
        foreach (var child in Children)
            childrenReceiver[i++] = child;
    }

    Tree<T> IRewritable<Tree<T>>.SetChildren(ReadOnlySpan<Tree<T>> newChildren)
    {
        var forwardTree = new ForwardTree<T>(Node, _Tree.Children.ToArray());
        
        return new Tree<T>(forwardTree, Parent);
    }
}