package ch.usi.inf.sp.dbi.profiler;

import java.util.*;

public class CCTNode {
    private static final String INDENTATION = "  ";

    private final IFrame frame;
    private final Map<IFrame, CCTNode> children = new HashMap<>();

    public CCTNode(IFrame frame) {
        this.frame = frame;
    }

    public IFrame getFrame() {
        return frame;
    }

    public CCTNode getOrAddChild(IFrame frame) {
        return children.computeIfAbsent(frame, CCTNode::new);
    }

    public String toString() {
        final StringBuilder text = new StringBuilder();
        int indentationLevel = 0;

        // build a stack of "list-of-children" stacks
        final Deque<Deque<CCTNode>> toVisit = new ArrayDeque<>();
        toVisit.push(new ArrayDeque<>(Collections.singletonList(this)));

        while (!toVisit.isEmpty()) {
            // peek the first "list-of-children" stack. If it's empty, we're done so we de-indent and we pop
            final Deque<CCTNode> nodes = toVisit.getFirst();
            if (nodes.isEmpty()) {
                indentationLevel--;
                toVisit.pop();
                continue;
            }

            // otherwise, we consume one of the children
            final CCTNode node = nodes.pop();

            // add indentation indentationLevel times
            for (int i = 0; i < indentationLevel; i++) {
                text.append(INDENTATION);
            }

            // and we print it in the tree
            text.append(node.frame.getName());
            text.append('\n');

            // if this node has children, we explore them in DFS fashion by adding an element to the "list-of-children"
            // stack
            if (!node.children.isEmpty()) {
                toVisit.push(new ArrayDeque<>(node.children.values()));
                indentationLevel++;
            }
        }

        return text.toString();
    }
}
