// Copyright 2016 The Bazel Authors. All rights reserved.
//
// 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.google.devtools.build.skyframe;

import com.google.auto.value.AutoValue;
import com.google.common.base.Joiner;
import com.google.common.base.MoreObjects;
import com.google.common.collect.Maps;
import com.google.common.collect.Maps.EntryTransformer;
import com.google.devtools.build.lib.concurrent.ThreadSafety.ThreadSafe;
import com.google.devtools.build.lib.util.GroupedList;
import java.util.Collection;
import java.util.Map;
import java.util.Set;
import javax.annotation.Nullable;

/**
 * Class that allows clients to be notified on each access of the graph. Clients can simply track
 * accesses, or they can block to achieve desired synchronization. Clients should call {@link
 * TrackingAwaiter#INSTANCE#assertNoErrors} at the end of tests in case exceptions were swallowed in
 * async threads.
 */
public class NotifyingHelper {
  public static MemoizingEvaluator.GraphTransformerForTesting makeNotifyingTransformer(
      final Listener listener) {
    return new MemoizingEvaluator.GraphTransformerForTesting() {
      @Override
      public InMemoryGraph transform(InMemoryGraph graph) {
        return new NotifyingInMemoryGraph(graph, listener);
      }

      @Override
      public QueryableGraph transform(QueryableGraph graph) {
        return new NotifyingQueryableGraph(graph, listener);
      }

      @Override
      public ProcessableGraph transform(ProcessableGraph graph) {
        return new NotifyingProcessableGraph(graph, listener);
      }
    };
  }

  protected final Listener graphListener;

  protected final EntryTransformer<SkyKey, ThinNodeEntry, NodeEntry> wrapEntry =
      new EntryTransformer<SkyKey, ThinNodeEntry, NodeEntry>() {
        @Nullable
        @Override
        public NotifyingNodeEntry transformEntry(SkyKey key, @Nullable ThinNodeEntry nodeEntry) {
          return wrapEntry(key, nodeEntry);
        }
      };

  NotifyingHelper(Listener graphListener) {
    this.graphListener = new ErrorRecordingDelegatingListener(graphListener);
  }

  /** Subclasses should override if they wish to subclass NotifyingNodeEntry. */
  @Nullable
  protected NotifyingNodeEntry wrapEntry(SkyKey key, @Nullable ThinNodeEntry entry) {
    return entry == null ? null : new NotifyingNodeEntry(key, entry);
  }

  static class NotifyingQueryableGraph implements QueryableGraph {
    private final QueryableGraph delegate;
    protected final NotifyingHelper notifyingHelper;

    NotifyingQueryableGraph(QueryableGraph delegate, Listener graphListener) {
      this.notifyingHelper = new NotifyingHelper(graphListener);
      this.delegate = delegate;
    }

    NotifyingQueryableGraph(QueryableGraph delegate, NotifyingHelper helper) {
      this.notifyingHelper = helper;
      this.delegate = delegate;
    }

    @Override
    public Map<SkyKey, ? extends NodeEntry> getBatch(
        @Nullable SkyKey requestor, Reason reason, Iterable<? extends SkyKey> keys)
        throws InterruptedException {
      return Maps.transformEntries(
          delegate.getBatch(requestor, reason, keys),
          notifyingHelper.wrapEntry);
    }

    @Nullable
    @Override
    public NodeEntry get(@Nullable SkyKey requestor, Reason reason, SkyKey key)
        throws InterruptedException {
      return notifyingHelper.wrapEntry(key, delegate.get(requestor, reason, key));
    }

  }

  static class NotifyingProcessableGraph
      extends NotifyingQueryableGraph implements ProcessableGraph {
    protected final ProcessableGraph delegate;

    NotifyingProcessableGraph(ProcessableGraph delegate, Listener graphListener) {
      this(delegate, new NotifyingHelper(graphListener));
    }

    NotifyingProcessableGraph(ProcessableGraph delegate, NotifyingHelper helper) {
      super(delegate, helper);
      this.delegate = delegate;
    }

    @Override
    public void remove(SkyKey key) {
      delegate.remove(key);
    }

    @Override
    public Map<SkyKey, ? extends NodeEntry> createIfAbsentBatch(
        @Nullable SkyKey requestor, Reason reason, Iterable<SkyKey> keys)
        throws InterruptedException {
      for (SkyKey key : keys) {
        notifyingHelper.graphListener.accept(key, EventType.CREATE_IF_ABSENT, Order.BEFORE, null);
      }
      return Maps.transformEntries(
          delegate.createIfAbsentBatch(requestor, reason, keys),
          notifyingHelper.wrapEntry);
    }

    @Override
    public DepsReport analyzeDepsDoneness(SkyKey parent, Collection<SkyKey> deps)
        throws InterruptedException {
      return delegate.analyzeDepsDoneness(parent, deps);
    }
  }

  /**
   * Graph/value entry events that the receiver can be informed of. When writing tests, feel free to
   * add additional events here if needed.
   */
  public enum EventType {
    CREATE_IF_ABSENT,
    ADD_REVERSE_DEP,
    ADD_EXTERNAL_DEP,
    REMOVE_REVERSE_DEP,
    GET_TEMPORARY_DIRECT_DEPS,
    SIGNAL,
    SET_VALUE,
    MARK_DIRTY,
    MARK_CLEAN,
    IS_CHANGED,
    GET_VALUE_WITH_METADATA,
    IS_DIRTY,
    IS_READY,
    CHECK_IF_DONE,
    GET_ALL_DIRECT_DEPS_FOR_INCOMPLETE_NODE
  }

  /**
   * Whether the given event is about to happen or has just happened. For some events, both will be
   * published, for others, only one. When writing tests, if you need an additional one to be
   * published, feel free to add it.
   */
  public enum Order {
    BEFORE,
    AFTER
  }

  /** Receiver to be informed when an event for a given key occurs. */
  public interface Listener {
    @ThreadSafe
    void accept(SkyKey key, EventType type, Order order, @Nullable Object context);

    Listener NULL_LISTENER = (key, type, order, context) -> {};
  }

  private static class ErrorRecordingDelegatingListener implements Listener {
    private final Listener delegate;

    private ErrorRecordingDelegatingListener(Listener delegate) {
      this.delegate = delegate;
    }

    @Override
    public void accept(SkyKey key, EventType type, Order order, @Nullable Object context) {
      try {
        delegate.accept(key, type, order, context);
      } catch (Exception e) {
        TrackingAwaiter.INSTANCE.injectExceptionAndMessage(
            e,
            "In NotifyingGraph: "
                + Joiner.on(", ").join(key, type, order, context == null ? "null" : context));
        throw e;
      }
    }
  }

  /** {@link NodeEntry} that informs a {@link Listener} of various method calls. */
  protected class NotifyingNodeEntry extends DelegatingNodeEntry {
    private final SkyKey myKey;
    private final ThinNodeEntry delegate;

    protected NotifyingNodeEntry(SkyKey key, ThinNodeEntry delegate) {
      myKey = key;
      this.delegate = delegate;
    }

    @Override
    protected NodeEntry getDelegate() {
      return (NodeEntry) delegate;
    }

    @Override
    protected ThinNodeEntry getThinDelegate() {
      return delegate;
    }

    @Override
    public DependencyState addReverseDepAndCheckIfDone(SkyKey reverseDep)
        throws InterruptedException {
      graphListener.accept(myKey, EventType.ADD_REVERSE_DEP, Order.BEFORE, reverseDep);
      DependencyState result = super.addReverseDepAndCheckIfDone(reverseDep);
      graphListener.accept(myKey, EventType.ADD_REVERSE_DEP, Order.AFTER, reverseDep);
      return result;
    }

    @Override
    public void addExternalDep() {
      super.addExternalDep();
      graphListener.accept(myKey, EventType.ADD_EXTERNAL_DEP, Order.AFTER, null);
    }

    @Override
    public void removeReverseDep(SkyKey reverseDep) throws InterruptedException {
      graphListener.accept(myKey, EventType.REMOVE_REVERSE_DEP, Order.BEFORE, reverseDep);
      super.removeReverseDep(reverseDep);
      graphListener.accept(myKey, EventType.REMOVE_REVERSE_DEP, Order.AFTER, reverseDep);
    }

    @Override
    public GroupedList<SkyKey> getTemporaryDirectDeps() {
      graphListener.accept(myKey, EventType.GET_TEMPORARY_DIRECT_DEPS, Order.BEFORE, null);
      return super.getTemporaryDirectDeps();
    }

    @Override
    public boolean signalDep(Version childVersion, @Nullable SkyKey childForDebugging) {
      graphListener.accept(myKey, EventType.SIGNAL, Order.BEFORE, childVersion);
      boolean result = super.signalDep(childVersion, childForDebugging);
      graphListener.accept(myKey, EventType.SIGNAL, Order.AFTER, childVersion);
      return result;
    }

    @Override
    public Set<SkyKey> setValue(
        SkyValue value, Version version, DepFingerprintList depFingerprintList)
        throws InterruptedException {
      graphListener.accept(myKey, EventType.SET_VALUE, Order.BEFORE, value);
      Set<SkyKey> result = super.setValue(value, version, depFingerprintList);
      graphListener.accept(myKey, EventType.SET_VALUE, Order.AFTER, value);
      return result;
    }

    @Override
    public MarkedDirtyResult markDirty(DirtyType dirtyType) throws InterruptedException {
      graphListener.accept(myKey, EventType.MARK_DIRTY, Order.BEFORE, dirtyType);
      MarkedDirtyResult result = super.markDirty(dirtyType);
      graphListener.accept(
          myKey,
          EventType.MARK_DIRTY,
          Order.AFTER,
          MarkDirtyAfterContext.create(dirtyType, result != null));
      return result;
    }

    @Override
    public Set<SkyKey> markClean() throws InterruptedException {
      graphListener.accept(myKey, EventType.MARK_CLEAN, Order.BEFORE, this);
      Set<SkyKey> result = super.markClean();
      graphListener.accept(myKey, EventType.MARK_CLEAN, Order.AFTER, this);
      return result;
    }

    @Override
    public boolean isChanged() {
      graphListener.accept(myKey, EventType.IS_CHANGED, Order.BEFORE, this);
      return super.isChanged();
    }

    @Override
    public boolean isDirty() {
      graphListener.accept(myKey, EventType.IS_DIRTY, Order.BEFORE, this);
      return super.isDirty();
    }

    @Override
    public boolean isReady() {
      graphListener.accept(myKey, EventType.IS_READY, Order.BEFORE, this);
      return super.isReady();
    }

    @Override
    public SkyValue getValueMaybeWithMetadata() throws InterruptedException {
      graphListener.accept(myKey, EventType.GET_VALUE_WITH_METADATA, Order.BEFORE, this);
      return super.getValueMaybeWithMetadata();
    }

    @Override
    public DependencyState checkIfDoneForDirtyReverseDep(SkyKey reverseDep)
        throws InterruptedException {
      graphListener.accept(myKey, EventType.CHECK_IF_DONE, Order.BEFORE, reverseDep);
      DependencyState dependencyState = super.checkIfDoneForDirtyReverseDep(reverseDep);
      graphListener.accept(myKey, EventType.CHECK_IF_DONE, Order.AFTER, reverseDep);
      return dependencyState;
    }

    @Override
    public Iterable<SkyKey> getAllDirectDepsForIncompleteNode() throws InterruptedException {
      graphListener.accept(
          myKey, EventType.GET_ALL_DIRECT_DEPS_FOR_INCOMPLETE_NODE, Order.BEFORE, this);
      return super.getAllDirectDepsForIncompleteNode();
    }

    @Override
    public String toString() {
      return MoreObjects.toStringHelper(this).add("delegate", getThinDelegate()).toString();
    }
  }

  /**
   * A pair of {@link ThinNodeEntry.DirtyType} and a bit saying whether the dirtying was successful,
   * emitted to the graph listener as the context {@link Order#AFTER} a call to {@link
   * EventType#MARK_DIRTY} a node.
   */
  @AutoValue
  public abstract static class MarkDirtyAfterContext {
    public abstract ThinNodeEntry.DirtyType dirtyType();

    public abstract boolean actuallyDirtied();

    static MarkDirtyAfterContext create(
        ThinNodeEntry.DirtyType dirtyType, boolean actuallyDirtied) {
      return new AutoValue_NotifyingHelper_MarkDirtyAfterContext(dirtyType, actuallyDirtied);
    }
  }
}
