// Copyright (C) 2011 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.project;

import com.google.common.cache.Cache;
import com.google.gerrit.common.data.AccessSection;
import com.google.gerrit.server.cache.CacheModule;
import com.google.gerrit.server.util.MostSpecificComparator;
import com.google.inject.Inject;
import com.google.inject.Module;
import com.google.inject.Singleton;
import com.google.inject.name.Named;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.Arrays;
import java.util.Collections;
import java.util.IdentityHashMap;
import java.util.List;

/** Caches the order AccessSections should be sorted for evaluation. */
@Singleton
public class SectionSortCache {
  private static final Logger log =
      LoggerFactory.getLogger(SectionSortCache.class);

  private static final String CACHE_NAME = "permission_sort";

  public static Module module() {
    return new CacheModule() {
      @Override
      protected void configure() {
        cache(CACHE_NAME, EntryKey.class, EntryVal.class);
        bind(SectionSortCache.class);
      }
    };
  }

  private final Cache<EntryKey, EntryVal> cache;

  @Inject
  SectionSortCache(@Named(CACHE_NAME) Cache<EntryKey, EntryVal> cache) {
    this.cache = cache;
  }

  void sort(String ref, List<AccessSection> sections) {
    final int cnt = sections.size();
    if (cnt <= 1) {
      return;
    }

    EntryKey key = new EntryKey(ref, sections);
    EntryVal val = cache.getIfPresent(key);
    if (val != null) {
      int[] srcIdx = val.order;
      if (srcIdx != null) {
        AccessSection[] srcList = copy(sections);
        for (int i = 0; i < cnt; i++) {
          sections.set(i, srcList[srcIdx[i]]);
        }
      } else {
        // Identity transform. No sorting is required.
      }

    } else {
      boolean poison = false;
      IdentityHashMap<AccessSection, Integer> srcMap =
          new IdentityHashMap<AccessSection, Integer>();
      for (int i = 0; i < cnt; i++) {
        poison |= srcMap.put(sections.get(i), i) != null;
      }

      Collections.sort(sections, new MostSpecificComparator(ref));

      int srcIdx[];
      if (isIdentityTransform(sections, srcMap)) {
        srcIdx = null;
      } else {
        srcIdx = new int[cnt];
        for (int i = 0; i < cnt; i++) {
          srcIdx[i] = srcMap.get(sections.get(i));
        }
      }

      if (poison) {
        log.error("Received duplicate AccessSection instances, not caching sort");
      } else {
        cache.put(key, new EntryVal(srcIdx));
      }
    }
  }

  private static AccessSection[] copy(List<AccessSection> sections) {
    return sections.toArray(new AccessSection[sections.size()]);
  }

  private static boolean isIdentityTransform(List<AccessSection> sections,
      IdentityHashMap<AccessSection, Integer> srcMap) {
    for (int i = 0; i < sections.size(); i++) {
      if (i != srcMap.get(sections.get(i))) {
        return false;
      }
    }
    return true;
  }

  static final class EntryKey {
    private final String ref;
    private final String[] patterns;
    private final int hashCode;

    EntryKey(String refName, List<AccessSection> sections) {
      int hc = refName.hashCode();
      ref = refName;
      patterns = new String[sections.size()];
      for (int i = 0; i < patterns.length; i++) {
        String n = sections.get(i).getName();
        patterns[i] = n;
        hc = hc * 31 + n.hashCode();
      }
      hashCode = hc;
    }

    @Override
    public int hashCode() {
      return hashCode;
    }

    @Override
    public boolean equals(Object other) {
      if (other instanceof EntryKey) {
        EntryKey b = (EntryKey) other;
        return ref.equals(b.ref) && Arrays.equals(patterns, b.patterns);
      }
      return false;
    }
  }

  static final class EntryVal {
    /**
     * Maps the input index to the output index.
     * <p>
     * For {@code x == order[y]} the expression means move the item at
     * source position {@code x} to the output position {@code y}.
     */
    final int[] order;

    EntryVal(int[] order) {
      this.order = order;
    }
  }


}
