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

import java.util.ArrayDeque;
import java.util.Collections;
import java.util.Deque;

public class Profiler {
    private static final CCTNode rootNode = new CCTNode(RootFrame.INSTANCE);
    private static final Deque<CCTNode> callStack = new ArrayDeque<>(Collections.singletonList(rootNode));

    static {
        Runtime.getRuntime().addShutdownHook(new Thread(() -> {
            System.out.println("\nCalling Context Tree:");
            System.out.println(rootNode);
        }));
    }

    private static String indent(int n) {
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < n; i++) {
            sb.append("  ");
        }
        return sb.toString();
    }

    public static void entry(String clazz, String method, String desc) {
        final CCTNode parent = callStack.getFirst();

        final Frame frame = new Frame(clazz, method, desc);
        callStack.push(parent.getOrAddChild(frame));

//        System.out.println("profiler captured: > " + indent(callStack.size()) + callStack.getFirst().getFrame().getName());
    }

    public static void exit(String clazz, String method, String desc) {
        final Frame exitingFrom = new Frame(clazz, method, desc);
        final IFrame lastCalled = callStack.isEmpty() ? null : callStack.getFirst().getFrame();

        if (!exitingFrom.equals(lastCalled)) {
            throw new IllegalStateException("Expecting to exit from " + lastCalled + ", but found " + exitingFrom);
        }

//        System.out.println("profiler captured: < " + indent(callStack.size()) + callStack.getFirst().getFrame().getName());

        callStack.pop();
    }
}
