/*
 * Copyright 2015-present Facebook, Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License"); you may
 * not use this file except in compliance with the License. You may obtain
 * a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 * License for the specific language governing permissions and limitations
 * under the License.
 */

package com.facebook.buck.event.api;

import java.util.Collections;
import java.util.Map;

/**
 * Allows annotation processors and other compiler plug-ins to output tracing information
 * to Buck's trace files (when being run in-process in Buck). These methods do nothing if
 * called within another build system.
 */
public final class BuckTracing {
  /**
   * Buck can technically be invoked recursively within the same process, so we can't assume
   * a single process-wide implementation of {@link BuckTracingInterface}.
   */
  private static final InheritableThreadLocal<BuckTracingInterface> curThreadTracingInterface =
      new InheritableThreadLocal<>();

  private final String pluginName;

  /**
   * Gets an instance of {@link BuckTracing} for tracing in the given plugin. All
   * {@link BuckTracing} instances are backed by the same trace buffer, so
   * {@link #begin(String, Map)} and {@link #end(Map)}} calls on a given thread must nest across
   * all instances.
   */
  public static BuckTracing getInstance(String pluginName) {
    return new BuckTracing(pluginName);
  }

  private BuckTracing(String pluginName) {
    this.pluginName = pluginName;
  }

  /**
   * Records the beginning of a traced section. The section will appear in the trace labeled with
   * eventName.
   *
   * For best results, this call should be immediately before a try block, and a corresponding call
   * to {@link #end(Map)} should be in the finally block.
   */
  public void begin(final String eventName) {
    begin(eventName, Collections.emptyMap());
  }

  /**
   * Records the beginning of a traced section. The section will appear in the trace labeled with
   * eventName, and the supplied arguments will be visible when the section is selected.
   *
   * For best results, this call should be immediately before a try block, and a corresponding call
   * to {@link #end(Map)} should be in the finally block.
   */
  public void begin(final String eventName, final Map<String, String> args) {
    final BuckTracingInterface tracingInterface = curThreadTracingInterface.get();
    if (tracingInterface == null) {
      return;
    }

    tracingInterface.begin(pluginName, eventName, args);
  }

  /**
   * Records the end of the traced section started by the most recent call to
   * {@link #begin(String, Map)}, on <em>any</em> {@link BuckTracing} object, on the current thread.
   *
   * For best results, this call should be in a finally block, with the corresponding
   * {@link #begin(String, Map)} call immediately before the try.
   */
  public void end() {
    end(Collections.emptyMap());
  }

  /**
   * Records the end of the traced section started by the most recent call to
   * {@link #begin(String, Map)}, on <em>any</em> {@link BuckTracing} object, on the current thread.
   * Arguments supplied here will be added to those supplied to {@link #begin(String, Map)};
   * conflicting entries will be overwritten.
   *
   * For best results, this call should be in a finally block, with the corresponding
   * {@link #begin(String, Map)} call immediately before the try.
   */
  public void end(final Map<String, String> args) {
    final BuckTracingInterface tracingInterface = curThreadTracingInterface.get();
    if (tracingInterface == null) {
      return;
    }

    tracingInterface.end(args);
  }

  /**
   * Used by Buck to connect this class to its tracing mechanism. There is no need to call
   * this method manually.
   */
  public static void setCurrentThreadTracingInterfaceFromJsr199Javac(
      final BuckTracingInterface buckTracingInterface) {
    curThreadTracingInterface.set(buckTracingInterface);
  }

  /**
   * Used by Buck to disconnect this class from its tracing mechanism. There is no need to call
   * this method manually.
   */
  public static void clearCurrentThreadTracingInterfaceFromJsr199Javac() {
    curThreadTracingInterface.set(null);
  }
}

@@ -1302,22 +1302,87 @@
 nName;%0A%0A
+  private final TraceSection traceSection = new TraceSection();%0A%0A
   /**%0A
-
    * Get
@@ -1837,24 +1837,529 @@
 nName;%0A  %7D%0A%0A
+  public TraceSection traceSection(final String eventName) %7B%0A    begin(eventName);%0A%0A    return traceSection;%0A  %7D%0A%0A  /**%0A   * Records the beginning of a traced section, and returns an object that can be used within a%0A   * try-with-resources block to automatically end the section. The section will appear in the trace%0A   * labeled with eventName.%0A   */%0A  public TraceSection traceSection(final String eventName, final Map%3CString, String%3E args) %7B%0A    begin(eventName, args);%0A%0A    return traceSection;%0A  %7D%0A%0A%0A
   /**%0A   * R
@@ -2620,32 +2620,121 @@
 e finally block.
+ Consider using%0A   * %7B@link #traceSection(String)%7D in a try-with-resources block instead.
 %0A   */%0A  public 
@@ -3176,16 +3176,110 @@
 y block.
+ Consider using%0A   * %7B@link #traceSection(String, Map)%7D in a try-with-resources block instead.
 %0A   */%0A 
@@ -5206,24 +5206,24 @@
 99Javac() %7B%0A
-
     curThrea
@@ -5254,11 +5254,436 @@
 ll);%0A  %7D
+%0A%0A  /**%0A   * An %7B@link AutoCloseable%7D that can be used in a try-with-resources block to ensure a trace%0A   * section is ended properly when exited.%0A   */%0A  public class TraceSection implements AutoCloseable %7B%0A    @Override%0A    public void close() %7B%0A      // We're just going to use the same instance of this thing over and over again, so don't%0A      // bother doing any kind of duplicate-close checking.%0A      end();%0A    %7D%0A  %7D
 %0A%7D%0A

Enable try-with-resources