package ch.usi.inf.sp.callgraph.renderer;

import org.objectweb.asm.Opcodes;

import java.util.Map;

public class InvokeEdge implements DotEdge {
    private final DotMethodNode from;

    private final DotMethodNode to;

    private final int invokeOpCode;

    private final boolean isDeclared;

    public InvokeEdge(DotMethodNode from, DotMethodNode to, int invokeOpCode, boolean isDeclared) {
        if (invokeOpCode != Opcodes.INVOKESTATIC &&
                invokeOpCode != Opcodes.INVOKESPECIAL &&
                invokeOpCode != Opcodes.INVOKEVIRTUAL &&
                invokeOpCode != Opcodes.INVOKEINTERFACE) {
            throw new IllegalArgumentException("invokeOpCode must be a invoke instruction opcode");
        }

        this.from = from;
        this.to = to;
        this.invokeOpCode = invokeOpCode;
        this.isDeclared = isDeclared;
    }

    private String getStyle() {
        switch (invokeOpCode) {
            case Opcodes.INVOKESTATIC:
            case Opcodes.INVOKESPECIAL:
                return "solid";
            case Opcodes.INVOKEVIRTUAL:
                return "dashed";
            case Opcodes.INVOKEINTERFACE:
                return "dotted";
            default:
                throw new IllegalStateException("unreachable");
        }
    }


    @Override
    public Map<String, String> getProperties() {
        return Map.of(
                "style", getStyle(),
                "color", isDeclared ? "blue" : "red"
        );
    }

    public DotMethodNode getFrom() {
        return from;
    }

    public DotMethodNode getTo() {
        return to;
    }

    @Override
    public String toString() {
        return "InvokeEdge{" +
                "from=" + from.getMethodLike().prettyName() +
                ", to=" + to.getMethodLike().prettyName() +
                ", invokeOpCode=" + invokeOpCode +
                ", isDeclared=" + isDeclared +
                '}';
    }
}
