using System.Collections.Generic;
using System.Linq;
using System.Text;

public class LSystemNode
{
    public LSystemNodeLiteral literal { get; set; }
    public List<LSystemNode> children { get; set; }
    public LSystemNode mainChild { get; set; }

    private LSystemNode _parent;
    public LSystemNode parent
    {
        get
        {
            if (_parent is null) { return new LSystemNode(new LSystemNodeLiteral(" _ ", 0)); }
            else { return _parent; }
        }
        set { _parent = value; }
    }

    public LSystemNode(LSystemNodeLiteral nodeLiteral)
    {
        literal = nodeLiteral;
        children = new List<LSystemNode>();
        mainChild = null;
    }

    public LSystemNode(LSystemNodeLiteral nodeLiteral, List<LSystemNode> children, LSystemNode mainChild)
    {
        literal = nodeLiteral;
        this.children = children;
        this.mainChild = mainChild;
    }
    public LSystemNode(LSystemNodeLiteral nodeLiteral, List<LSystemNode> children)
    {
        literal = nodeLiteral;
        this.children = children;
        this.mainChild = null;
    }
    public List<LSystemNode> getAllChildren()
    {
        var result = new List<LSystemNode>(children);
        if (mainChild != null)
        {
            result.Add(mainChild);
        }
        return result;
    }

    public LSystemNode deep_copy()
    {
        if (children.Count() == 0 && mainChild == null)
        {
            return new LSystemNode(new LSystemNodeLiteral(literal));
        }
        else if (mainChild != null)
        {
            var result = new LSystemNode(new LSystemNodeLiteral(literal));
            result.mainChild = mainChild.deep_copy();
            return result;
        }
        else
        {
            var new_children = new List<LSystemNode>();
            foreach (var x in children)
            {
                new_children.Add(x.deep_copy());
            }
            return new LSystemNode(literal, new_children, this.mainChild.deep_copy());
        }
    }

    private static LSystemNode deepestNode(LSystemNode node)
    {
        while (node.mainChild != null)
        {
            node = node.mainChild;
        }
        return node;
    }

    public LSystemNode newParent()
    {
        return deepestNode(this);
    }

    public override string ToString()
    {
        StringBuilder sb = new StringBuilder(literal.ToString());
        var node = this;
        while (true)
        {
            foreach (var child in node.children)
            {
                sb.Append("[");
                sb.Append(child.ToString());
                sb.Append("]");
            }
            if (node.mainChild != null)
            {
                sb.Append(node.mainChild.literal.ToString());
                node = node.mainChild;
            }
            else
            {
                return sb.ToString();
            }
        }
    }
}