// 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.account;

import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import com.google.gerrit.common.Nullable;
import com.google.gerrit.common.data.AccessSection;
import com.google.gerrit.common.data.GlobalCapability;
import com.google.gerrit.common.data.GroupReference;
import com.google.gerrit.common.data.Permission;
import com.google.gerrit.common.data.PermissionRange;
import com.google.gerrit.common.data.PermissionRule;
import com.google.gerrit.server.config.AdministrateServerGroups;
import com.google.gerrit.server.group.SystemGroupBackend;
import com.google.inject.Inject;
import com.google.inject.assistedinject.Assisted;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;

/** Caches active {@link GlobalCapability} set for a site. */
public class CapabilityCollection {
  public interface Factory {
    CapabilityCollection create(@Nullable AccessSection section);
  }

  private final SystemGroupBackend systemGroupBackend;
  private final ImmutableMap<String, ImmutableList<PermissionRule>> permissions;

  public final ImmutableList<PermissionRule> administrateServer;
  public final ImmutableList<PermissionRule> batchChangesLimit;
  public final ImmutableList<PermissionRule> emailReviewers;
  public final ImmutableList<PermissionRule> priority;
  public final ImmutableList<PermissionRule> readAs;
  public final ImmutableList<PermissionRule> queryLimit;
  public final ImmutableList<PermissionRule> createGroup;

  @Inject
  CapabilityCollection(
      SystemGroupBackend systemGroupBackend,
      @AdministrateServerGroups ImmutableSet<GroupReference> admins,
      @Assisted @Nullable AccessSection section) {
    this.systemGroupBackend = systemGroupBackend;

    if (section == null) {
      section = AccessSection.create(AccessSection.GLOBAL_CAPABILITIES);
    }

    Map<String, List<PermissionRule>> tmp = new HashMap<>();
    for (Permission permission : section.getPermissions()) {
      for (PermissionRule rule : permission.getRules()) {
        if (!permission.getName().equals(GlobalCapability.EMAIL_REVIEWERS)
            && rule.getAction() == PermissionRule.Action.DENY) {
          continue;
        }

        List<PermissionRule> r = tmp.get(permission.getName());
        if (r == null) {
          r = new ArrayList<>(2);
          tmp.put(permission.getName(), r);
        }
        r.add(rule);
      }
    }
    configureDefaults(tmp, section);
    if (!tmp.containsKey(GlobalCapability.ADMINISTRATE_SERVER) && !admins.isEmpty()) {
      tmp.put(GlobalCapability.ADMINISTRATE_SERVER, ImmutableList.of());
    }

    ImmutableMap.Builder<String, ImmutableList<PermissionRule>> m = ImmutableMap.builder();
    for (Map.Entry<String, List<PermissionRule>> e : tmp.entrySet()) {
      List<PermissionRule> rules = e.getValue();
      if (GlobalCapability.ADMINISTRATE_SERVER.equals(e.getKey())) {
        rules = mergeAdmin(admins, rules);
      }
      m.put(e.getKey(), ImmutableList.copyOf(rules));
    }
    permissions = m.build();

    administrateServer = getPermission(GlobalCapability.ADMINISTRATE_SERVER);
    batchChangesLimit = getPermission(GlobalCapability.BATCH_CHANGES_LIMIT);
    emailReviewers = getPermission(GlobalCapability.EMAIL_REVIEWERS);
    priority = getPermission(GlobalCapability.PRIORITY);
    readAs = getPermission(GlobalCapability.READ_AS);
    queryLimit = getPermission(GlobalCapability.QUERY_LIMIT);
    createGroup = getPermission(GlobalCapability.CREATE_GROUP);
  }

  private static List<PermissionRule> mergeAdmin(
      Set<GroupReference> admins, List<PermissionRule> rules) {
    if (admins.isEmpty()) {
      return rules;
    }

    List<PermissionRule> r = new ArrayList<>(admins.size() + rules.size());
    for (GroupReference g : admins) {
      r.add(PermissionRule.create(g));
    }
    for (PermissionRule rule : rules) {
      if (!admins.contains(rule.getGroup())) {
        r.add(rule);
      }
    }
    return r;
  }

  public ImmutableList<PermissionRule> getPermission(String permissionName) {
    ImmutableList<PermissionRule> r = permissions.get(permissionName);
    return r != null ? r : ImmutableList.of();
  }

  private void configureDefaults(Map<String, List<PermissionRule>> out, AccessSection section) {
    configureDefault(
        out,
        section,
        GlobalCapability.QUERY_LIMIT,
        systemGroupBackend.getGroup(SystemGroupBackend.ANONYMOUS_USERS));
  }

  private static void configureDefault(
      Map<String, List<PermissionRule>> out,
      AccessSection section,
      String capName,
      GroupReference group) {
    if (doesNotDeclare(section, capName)) {
      PermissionRange.WithDefaults range = GlobalCapability.getRange(capName);
      if (range != null) {
        PermissionRule.Builder rule = PermissionRule.builder(group);
        rule.setRange(range.getDefaultMin(), range.getDefaultMax());
        out.put(capName, Collections.singletonList(rule.build()));
      }
    }
  }

  private static boolean doesNotDeclare(AccessSection section, String capName) {
    return section.getPermission(capName) == null;
  }
}
