package org.graalvm.visualvm.modules.tracer.swing.resources;

import org.openjdk.btrace.core.Profiler;
import org.openjdk.btrace.core.annotations.*;
import static org.openjdk.btrace.core.BTraceUtils.*;

@BTrace(name="SwingStats") public class SwingTracer {
    // <fragment name="swing_paint">
    @Property(name="jcPaintProfiler") private static Profiler jcPaintProfiler = Profiling.newProfiler(3);

    @OnMethod(
        clazz="+javax.swing.JComponent",
        method="/paint(Component|Border|Children)/"
    )
    public static void componentPaintBefore(@ProbeMethodName String pmn) {
        Profiling.recordEntry(jcPaintProfiler, pmn);
    }

    @OnMethod(
        clazz="+javax.swing.JComponent",
        method="/paint(Component|Border|Children)/",
        location=@Location(Kind.RETURN)
    )
    public static void componentPaintAfter(@Duration long time, @ProbeMethodName String pmn) {
        Profiling.recordExit(jcPaintProfiler, pmn, time);
    }
    // </fragment>

    // <fragment name="componentui">
    @Property(name="cuiProfiler") private static Profiler cuiProfiler = Profiling.newProfiler(5);
    @OnMethod(
        clazz="+javax.swing.plaf.ComponentUI",
        method="/(paint|update|getPreferredSize|getMinimumSize|getMaximumSize)/")
    public static void cuPaintEntry(@ProbeMethodName String pmn) {
        Profiling.recordEntry(cuiProfiler, pmn);
    }

    @OnMethod(
        clazz="+javax.swing.plaf.ComponentUI",
        method="/(paint|update|getPreferredSize|getMinimumSize|getMaximumSize)/",
        location=@Location(Kind.RETURN))
    public static void cuPaintExit(@Duration long time, @ProbeMethodName String pmn) {
        Profiling.recordExit(cuiProfiler, pmn, time);
    }
    // </fragment>

    // <fragment name="component_events">
    @Property(name="jcEventsProfiler") private static Profiler jcEventsProfiler = Profiling.newProfiler(10);

    @OnMethod(
        clazz="+java.awt.Component",
        method="/process(Component|Focus|Key|Mouse|MouseMotion|MouseWheel|InputMethod|Hierarchy)Event/"
    )
    public static void componentEventBefore(@ProbeMethodName String pmn) {
        Profiling.recordEntry(jcEventsProfiler, pmn);
    }

    @OnMethod(
        clazz="+java.awt.Component",
        method="/process(Component|Focus|Key|Mouse|MouseMotion|MouseWheel|InputMethod|Hierarchy)Event/",
        location=@Location(Kind.RETURN)
    )
    public static void componentEventsAfter(@Duration long time, @ProbeMethodName String pmn) {
        Profiling.recordExit(jcEventsProfiler, pmn, time);
    }
    // </fragment>

    // <fragment name="basic_events">
    @Property(name="eventsProfiler") private static Profiler eventsProfiler = Profiling.newProfiler(3);
    @OnMethod(
        clazz="+java.awt.event.ActionListener",
        method="actionPerformed")
    public static void apEntry(@ProbeMethodName String pmn) {
        Profiling.recordEntry(eventsProfiler, pmn);
    }

    @OnMethod(
        clazz="+java.awt.event.ActionListener",
        method="actionPerformed",
        location=@Location(Kind.RETURN))
    public static void apExit(@Duration long time, @ProbeMethodName String pmn) {
        Profiling.recordExit(eventsProfiler, pmn, time);
    }

    @OnMethod(
        clazz="+javax.swing.event.ChangeListener",
        method="stateChanged")
    public static void scEntry(@ProbeMethodName String pmn) {
        Profiling.recordEntry(eventsProfiler, pmn);
    }

    @OnMethod(
        clazz="+javax.swing.event.ChangeListener",
        method="stateChanged",
        location=@Location(Kind.RETURN))
    public static void scExit(@Duration long time, @ProbeMethodName String pmn) {
        Profiling.recordExit(eventsProfiler, pmn, time);
    }

    @OnMethod(
        clazz="+java.beans.PropertyChangeListener",
        method="propertyChange")
    public static void pcEntry(@ProbeMethodName String pmn) {
        Profiling.recordEntry(eventsProfiler, pmn);
    }

    @OnMethod(
        clazz="+java.beans.PropertyChangeListener",
        method="propertyChange",
        location=@Location(Kind.RETURN))
    public static void pcExit(@Duration long time, @ProbeMethodName String pmn) {
        Profiling.recordExit(eventsProfiler, pmn, time);
    }
    // </fragment>

    // <fragment name="layout">
    @Property(name="layoutProfiler") private static Profiler layoutProfiler = Profiling.newProfiler(3);
    @OnMethod(
        clazz="+java.awt.LayoutManager",
        method="/(preferredLayoutSize|minimumLayoutSize|layoutContainer)/")
    public static void layoutEntry(@ProbeMethodName String pmn) {
        Profiling.recordEntry(layoutProfiler, pmn);
    }

    @OnMethod(
        clazz="+java.awt.LayoutManager",
        method="/(preferredLayoutSize|minimumLayoutSize|layoutContainer)/",
        location=@Location(Kind.RETURN))
    public static void layoutExit(@Duration long time, @ProbeMethodName String pmn) {
        Profiling.recordExit(layoutProfiler, pmn, time);
    }
    // </fragment>

    @OnTimer(1000)
    public static void updateMBeans() {
        // <fragment name="swing_paint">
        Profiling.snapshotAndReset(jcPaintProfiler);
        // </fragment>

        // <fragment name="componentui">
        Profiling.snapshotAndReset(cuiProfiler);
        // </fragment>

        // <fragment name="component_events">
        Profiling.snapshotAndReset(jcEventsProfiler);
        // </fragment>

        // <fragment name="basic_events">
        Profiling.snapshotAndReset(eventsProfiler);
        // </fragment>

        // <fragment name="layout">
        Profiling.snapshotAndReset(layoutProfiler);
        // </fragment>
    }
}
