// Copyright 2012 Google Inc. 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.gitiles;

import static com.google.common.base.MoreObjects.toStringHelper;
import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.base.Predicates.not;
import static com.google.common.collect.Collections2.filter;
import static java.util.Objects.hash;
import static org.eclipse.jgit.lib.Constants.R_HEADS;
import static org.eclipse.jgit.lib.Constants.R_TAGS;

import com.google.common.base.Function;
import com.google.common.base.Predicate;
import com.google.common.base.Predicates;
import com.google.common.base.Throwables;
import com.google.common.cache.Cache;
import com.google.common.cache.CacheBuilder;
import com.google.common.collect.Collections2;
import com.google.common.util.concurrent.ExecutionError;

import org.eclipse.jgit.errors.IncorrectObjectTypeException;
import org.eclipse.jgit.errors.MissingObjectException;
import org.eclipse.jgit.lib.ObjectId;
import org.eclipse.jgit.lib.Ref;
import org.eclipse.jgit.lib.RefDatabase;
import org.eclipse.jgit.lib.Repository;
import org.eclipse.jgit.revwalk.RevCommit;
import org.eclipse.jgit.revwalk.RevSort;
import org.eclipse.jgit.revwalk.RevWalk;

import java.io.IOException;
import java.util.Arrays;
import java.util.Collection;
import java.util.Objects;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;

/** Cache of per-user object visibility. */
public class VisibilityCache {
  private static class Key {
    private final Object user;
    private final String repositoryName;
    private final ObjectId objectId;

    private Key(Object user, String repositoryName, ObjectId objectId) {
      this.user = checkNotNull(user, "user");
      this.repositoryName = checkNotNull(repositoryName, "repositoryName");
      this.objectId = checkNotNull(objectId, "objectId").copy();
    }

    @Override
    public boolean equals(Object o) {
      if (o instanceof Key) {
        Key k = (Key) o;
        return Objects.equals(user, k.user)
            && Objects.equals(repositoryName, k.repositoryName)
            && Objects.equals(objectId, k.objectId);
      }
      return false;
    }

    @Override
    public int hashCode() {
      return hash(user, repositoryName, objectId);
    }

    @Override
    public String toString() {
      return toStringHelper(this)
        .add("user", user)
        .add("repositoryName", repositoryName)
        .add("objectId", objectId)
        .toString();
    }
  }

  private final Cache<Key, Boolean> cache;
  private final boolean topoSort;

  public static CacheBuilder<Object, Object> defaultBuilder() {
    return CacheBuilder.newBuilder()
        .maximumSize(1 << 10)
        .expireAfterWrite(30, TimeUnit.MINUTES);
  }

  public VisibilityCache(boolean topoSort) {
    this(topoSort, defaultBuilder());
  }

  public VisibilityCache(boolean topoSort, CacheBuilder<Object, Object> builder) {
    this.cache = builder.build();
    this.topoSort = topoSort;
  }

  public Cache<?, Boolean> getCache() {
    return cache;
  }

  boolean isVisible(final Repository repo, final RevWalk walk, GitilesAccess access,
      final ObjectId id, final ObjectId... knownReachable) throws IOException {
    try {
      return cache.get(
          new Key(access.getUserKey(), access.getRepositoryName(), id),
          new Callable<Boolean>() {
            @Override
            public Boolean call() throws IOException {
              return isVisible(repo, walk, id, Arrays.asList(knownReachable));
            }
          });
    } catch (ExecutionException e) {
      Throwables.propagateIfInstanceOf(e.getCause(), IOException.class);
      throw new IOException(e);
    } catch (ExecutionError e) {
      // markUninteresting may overflow on pathological repos with very long
      // merge chains. Play it safe and return false rather than letting the
      // error propagate.
      if (e.getCause() instanceof StackOverflowError) {
        return false;
      }
      throw e;
    }
  }

  private boolean isVisible(Repository repo, RevWalk walk, ObjectId id,
      Collection<ObjectId> knownReachable) throws IOException {
    RevCommit commit;
    try {
      commit = walk.parseCommit(id);
    } catch (IncorrectObjectTypeException e) {
      return false;
    }

    // If any reference directly points at the requested object, permit display.
    // Common for displays of pending patch sets in Gerrit Code Review, or
    // bookmarks to the commit a tag points at.
    Collection<Ref> allRefs = repo.getRefDatabase().getRefs(RefDatabase.ALL).values();
    for (Ref ref : allRefs) {
      ref = repo.getRefDatabase().peel(ref);
      if (id.equals(ref.getObjectId()) || id.equals(ref.getPeeledObjectId())) {
        return true;
      }
    }

    // Check heads first under the assumption that most requests are for refs
    // close to a head. Tags tend to be much further back in history and just
    // clutter up the priority queue in the common case.
    return isReachableFrom(walk, commit, knownReachable)
        || isReachableFromRefs(walk, commit, filter(allRefs, refStartsWith(R_HEADS)))
        || isReachableFromRefs(walk, commit, filter(allRefs, refStartsWith(R_TAGS)))
        || isReachableFromRefs(walk, commit, filter(allRefs, otherRefs()));
  }

  private static Predicate<Ref> refStartsWith(final String prefix) {
    return new Predicate<Ref>() {
      @Override
      public boolean apply(Ref ref) {
        return ref.getName().startsWith(prefix);
      }
    };
  }

  @SuppressWarnings("unchecked")
  private static Predicate<Ref> otherRefs() {
    return not(Predicates.<Ref> or(
        refStartsWith(R_HEADS), refStartsWith(R_TAGS), refStartsWith("refs/changes/")));
  }

  private boolean isReachableFromRefs(RevWalk walk, RevCommit commit,
      Collection<Ref> refs) throws IOException {
    return isReachableFrom(walk, commit,
        Collections2.transform(refs, new Function<Ref, ObjectId>() {
          @Override
          public ObjectId apply(Ref ref) {
            if (ref.getPeeledObjectId() != null) {
              return ref.getPeeledObjectId();
            } else {
              return ref.getObjectId();
            }
          }
        }));
  }

  private boolean isReachableFrom(RevWalk walk, RevCommit commit, Collection<ObjectId> ids)
      throws IOException {
    if (ids.isEmpty()) {
      return false;
    }
    walk.reset();
    if (topoSort) {
      walk.sort(RevSort.TOPO);
    }
    walk.markStart(commit);
    for (ObjectId id : ids) {
      markUninteresting(walk, id);
    }
    // If the commit is reachable from any given tip, it will appear to be
    // uninteresting to the RevWalk and no output will be produced.
    return walk.next() == null;
  }

  private static void markUninteresting(RevWalk walk, ObjectId id) throws IOException {
    if (id == null) {
      return;
    }
    try {
      walk.markUninteresting(walk.parseCommit(id));
    } catch (IncorrectObjectTypeException | MissingObjectException e) {
      // Do nothing, doesn't affect reachability.
    }
  }
}
