// Copyright (C) 2010 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.common.data;

public class PermissionRule implements Comparable<PermissionRule> {
  public static final String FORCE_PUSH = "Force Push";
  public static final String FORCE_EDIT = "Force Edit";

  public enum Action {
    ALLOW,
    DENY,
    BLOCK,

    INTERACTIVE,
    BATCH
  }

  protected Action action = Action.ALLOW;
  protected boolean force;
  protected int min;
  protected int max;
  protected GroupReference group;

  public PermissionRule() {}

  public PermissionRule(GroupReference group) {
    this.group = group;
  }

  public Action getAction() {
    return action;
  }

  public void setAction(Action action) {
    if (action == null) {
      throw new NullPointerException("action");
    }
    this.action = action;
  }

  public boolean isDeny() {
    return action == Action.DENY;
  }

  public void setDeny() {
    action = Action.DENY;
  }

  public boolean isBlock() {
    return action == Action.BLOCK;
  }

  public void setBlock() {
    action = Action.BLOCK;
  }

  public Boolean getForce() {
    return force;
  }

  public void setForce(Boolean newForce) {
    force = newForce;
  }

  public int getMin() {
    return min;
  }

  public void setMin(int min) {
    this.min = min;
  }

  public void setMax(int max) {
    this.max = max;
  }

  public int getMax() {
    return max;
  }

  public void setRange(int newMin, int newMax) {
    if (newMax < newMin) {
      min = newMax;
      max = newMin;
    } else {
      min = newMin;
      max = newMax;
    }
  }

  public GroupReference getGroup() {
    return group;
  }

  public void setGroup(GroupReference newGroup) {
    group = newGroup;
  }

  void mergeFrom(PermissionRule src) {
    if (getAction() != src.getAction()) {
      if (getAction() == Action.BLOCK || src.getAction() == Action.BLOCK) {
        setAction(Action.BLOCK);

      } else if (getAction() == Action.DENY || src.getAction() == Action.DENY) {
        setAction(Action.DENY);

      } else if (getAction() == Action.BATCH || src.getAction() == Action.BATCH) {
        setAction(Action.BATCH);
      }
    }

    setForce(getForce() || src.getForce());
    setRange(Math.min(getMin(), src.getMin()), Math.max(getMax(), src.getMax()));
  }

  @Override
  public int compareTo(PermissionRule o) {
    int cmp = action(this) - action(o);
    if (cmp == 0) {
      cmp = range(o) - range(this);
    }
    if (cmp == 0) {
      cmp = group(this).compareTo(group(o));
    }
    return cmp;
  }

  private static int action(PermissionRule a) {
    switch (a.getAction()) {
      case DENY:
        return 0;
      case ALLOW:
      case BATCH:
      case BLOCK:
      case INTERACTIVE:
      default:
        return 1 + a.getAction().ordinal();
    }
  }

  private static int range(PermissionRule a) {
    return Math.abs(a.getMin()) + Math.abs(a.getMax());
  }

  private static String group(PermissionRule a) {
    return a.getGroup().getName() != null ? a.getGroup().getName() : "";
  }

  @Override
  public String toString() {
    return asString(true);
  }

  public String asString(boolean canUseRange) {
    StringBuilder r = new StringBuilder();

    switch (getAction()) {
      case ALLOW:
        break;

      case DENY:
        r.append("deny ");
        break;

      case BLOCK:
        r.append("block ");
        break;

      case INTERACTIVE:
        r.append("interactive ");
        break;

      case BATCH:
        r.append("batch ");
        break;
    }

    if (getForce()) {
      r.append("+force ");
    }

    if (canUseRange && (getMin() != 0 || getMax() != 0)) {
      if (0 <= getMin()) {
        r.append('+');
      }
      r.append(getMin());
      r.append("..");
      if (0 <= getMax()) {
        r.append('+');
      }
      r.append(getMax());
      r.append(' ');
    }

    r.append(getGroup().toConfigValue());

    return r.toString();
  }

  public static PermissionRule fromString(String src, boolean mightUseRange) {
    final String orig = src;
    final PermissionRule rule = new PermissionRule();

    src = src.trim();

    if (src.startsWith("deny ")) {
      rule.setAction(Action.DENY);
      src = src.substring("deny ".length()).trim();

    } else if (src.startsWith("block ")) {
      rule.setAction(Action.BLOCK);
      src = src.substring("block ".length()).trim();

    } else if (src.startsWith("interactive ")) {
      rule.setAction(Action.INTERACTIVE);
      src = src.substring("interactive ".length()).trim();

    } else if (src.startsWith("batch ")) {
      rule.setAction(Action.BATCH);
      src = src.substring("batch ".length()).trim();
    }

    if (src.startsWith("+force ")) {
      rule.setForce(true);
      src = src.substring("+force ".length()).trim();
    }

    if (mightUseRange && !GroupReference.isGroupReference(src)) {
      int sp = src.indexOf(' ');
      String range = src.substring(0, sp);

      if (range.matches("^([+-]?\\d+)\\.\\.([+-]?\\d+)$")) {
        int dotdot = range.indexOf("..");
        int min = parseInt(range.substring(0, dotdot));
        int max = parseInt(range.substring(dotdot + 2));
        rule.setRange(min, max);
      } else {
        throw new IllegalArgumentException("Invalid range in rule: " + orig);
      }

      src = src.substring(sp + 1).trim();
    }

    String groupName = GroupReference.extractGroupName(src);
    if (groupName != null) {
      GroupReference group = new GroupReference();
      group.setName(groupName);
      rule.setGroup(group);
    } else {
      throw new IllegalArgumentException("Rule must include group: " + orig);
    }

    return rule;
  }

  public boolean hasRange() {
    return getMin() != 0 || getMax() != 0;
  }

  public static int parseInt(String value) {
    if (value.startsWith("+")) {
      value = value.substring(1);
    }
    return Integer.parseInt(value);
  }

  @Override
  public boolean equals(Object obj) {
    if (!(obj instanceof PermissionRule)) {
      return false;
    }
    final PermissionRule other = (PermissionRule) obj;
    return action.equals(other.action)
        && force == other.force
        && min == other.min
        && max == other.max
        && group.equals(other.group);
  }

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

@@ -1631,17 +1631,17 @@
  public 
-B
+b
 oolean g
@@ -1698,17 +1698,17 @@
 etForce(
-B
+b
 oolean n

Change parameter and return type for force to boolean