// Copyright (C) 2019 The Android Open Source Project
//
// 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.gerrit.server.git.receive;

import static com.google.common.collect.ImmutableList.toImmutableList;

import com.google.common.base.Supplier;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ListMultimap;
import com.google.common.collect.MultimapBuilder;
import com.google.gerrit.entities.Change;
import com.google.gerrit.entities.PatchSet;
import com.google.gerrit.entities.RefNames;
import java.io.IOException;
import java.util.Map;
import java.util.Objects;
import org.eclipse.jgit.annotations.Nullable;
import org.eclipse.jgit.lib.ObjectId;
import org.eclipse.jgit.lib.Ref;
import org.eclipse.jgit.lib.RefDatabase;

/**
 * Simple cache for accessing refs by name, prefix or {@link ObjectId}. Intended to be used when
 * processing a {@code git push}.
 *
 * <p>This class is not thread safe.
 */
public interface ReceivePackRefCache {

  /**
   * Returns an instance that delegates all calls to the provided {@link RefDatabase}. To be used in
   * tests or when the ref database is fast with forward (name to {@link ObjectId}) and inverse
   * ({@code ObjectId} to name) lookups.
   */
  static ReceivePackRefCache noCache(RefDatabase delegate) {
    return new NoCache(delegate);
  }

  /**
   * Returns an instance that answers calls based on refs previously advertised and captured in
   * {@link AllRefsWatcher}. Speeds up inverse lookups by building a {@code Map<ObjectId,
   * List<Ref>>} and a {@code Map<Change.Id, List<Ref>>}.
   *
   * <p>This implementation speeds up lookups when the ref database does not support inverse ({@code
   * ObjectId} to name) lookups.
   */
  static ReceivePackRefCache withAdvertisedRefs(Supplier<Map<String, Ref>> allRefsSupplier) {
    return new WithAdvertisedRefs(allRefsSupplier);
  }

  /** Returns a list of {@link com.google.gerrit.entities.PatchSet.Id}s that point to {@code id}. */
  ImmutableList<PatchSet.Id> patchSetIdsFromObjectId(ObjectId id) throws IOException;

  /** Returns all refs whose name starts with {@code prefix}. */
  ImmutableList<Ref> byPrefix(String prefix) throws IOException;

  /** Returns a ref whose name matches {@code ref} or {@code null} if such a ref does not exist. */
  @Nullable
  Ref exactRef(String ref) throws IOException;

  class NoCache implements ReceivePackRefCache {
    private final RefDatabase delegate;

    private NoCache(RefDatabase delegate) {
      this.delegate = delegate;
    }

    @Override
    public ImmutableList<PatchSet.Id> patchSetIdsFromObjectId(ObjectId id) throws IOException {
      return delegate.getTipsWithSha1(id).stream()
          .map(r -> PatchSet.Id.fromRef(r.getName()))
          .filter(Objects::nonNull)
          .collect(toImmutableList());
    }

    @Override
    public ImmutableList<Ref> byPrefix(String prefix) throws IOException {
      return delegate.getRefsByPrefix(prefix).stream().collect(toImmutableList());
    }

    @Override
    @Nullable
    public Ref exactRef(String name) throws IOException {
      return delegate.exactRef(name);
    }
  }

  class WithAdvertisedRefs implements ReceivePackRefCache {
    /** We estimate that a change has an average of 4 patch sets plus the meta ref. */
    private static final int ESTIMATED_NUMBER_OF_REFS_PER_CHANGE = 5;

    private final Supplier<Map<String, Ref>> allRefsSupplier;

    // Collections lazily populated during processing.
    private Map<String, Ref> allRefs;
    /** Contains only patch set refs. */
    private ListMultimap<Change.Id, Ref> refsByChange;
    /** Contains all refs. */
    private ListMultimap<ObjectId, Ref> refsByObjectId;

    private WithAdvertisedRefs(Supplier<Map<String, Ref>> allRefsSupplier) {
      this.allRefsSupplier = allRefsSupplier;
    }

    @Override
    public ImmutableList<PatchSet.Id> patchSetIdsFromObjectId(ObjectId id) {
      lazilyInitRefMaps();
      return refsByObjectId.get(id).stream()
          .map(r -> PatchSet.Id.fromRef(r.getName()))
          .filter(Objects::nonNull)
          .collect(toImmutableList());
    }

    @Override
    public ImmutableList<Ref> byPrefix(String prefix) {
      lazilyInitRefMaps();
      if (RefNames.isRefsChanges(prefix)) {
        Change.Id cId = Change.Id.fromRefPart(prefix);
        if (cId != null) {
          return refsByChange.get(cId).stream()
              .filter(r -> r.getName().startsWith(prefix))
              .collect(toImmutableList());
        }
      }
      return allRefs().values().stream()
          .filter(r -> r.getName().startsWith(prefix))
          .collect(toImmutableList());
    }

    @Override
    @Nullable
    public Ref exactRef(String name) {
      return allRefs().get(name);
    }

    private Map<String, Ref> allRefs() {
      if (allRefs == null) {
        allRefs = allRefsSupplier.get();
      }
      return allRefs;
    }

    private void lazilyInitRefMaps() {
      if (refsByChange != null) {
        return;
      }

      refsByObjectId = MultimapBuilder.hashKeys().arrayListValues().build();
      refsByChange =
          MultimapBuilder.hashKeys(allRefs().size() / ESTIMATED_NUMBER_OF_REFS_PER_CHANGE)
              .arrayListValues(ESTIMATED_NUMBER_OF_REFS_PER_CHANGE)
              .build();
      for (Ref ref : allRefs().values()) {
        ObjectId objectId = ref.getObjectId();
        if (objectId != null) {
          refsByObjectId.put(objectId, ref);
          Change.Id changeId = Change.Id.fromRef(ref.getName());
          if (changeId != null) {
            refsByChange.put(changeId, ref);
          }
        }
      }
    }
  }
}
