// Copyright (C) 2013 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.change;

import static java.nio.charset.StandardCharsets.UTF_8;

import com.google.common.base.Function;
import com.google.common.base.Joiner;
import com.google.common.base.Objects;
import com.google.common.base.Throwables;
import com.google.common.collect.Iterables;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.gerrit.common.data.SubmitRecord;
import com.google.gerrit.extensions.restapi.AuthException;
import com.google.gerrit.extensions.restapi.BadRequestException;
import com.google.gerrit.extensions.restapi.DefaultInput;
import com.google.gerrit.extensions.restapi.RestModifyView;
import com.google.gerrit.reviewdb.server.ReviewDb;
import com.google.gerrit.rules.RulesCache;
import com.google.gerrit.server.account.AccountInfo;
import com.google.gerrit.server.change.TestSubmitRule.Input;
import com.google.gerrit.server.project.RuleEvalException;
import com.google.gerrit.server.project.SubmitRuleEvaluator;
import com.google.gerrit.server.query.change.ChangeData;
import com.google.gwtorm.server.OrmException;
import com.google.inject.Inject;

import com.googlecode.prolog_cafe.lang.Term;

import org.kohsuke.args4j.Option;

import java.io.ByteArrayInputStream;
import java.util.List;
import java.util.Map;

public class TestSubmitRule implements RestModifyView<RevisionResource, Input> {
  public enum Filters {
    RUN, SKIP
  }

  public static class Input {
    @DefaultInput
    public String rule;
    public Filters filters;
  }

  private final ReviewDb db;
  private final ChangeData.Factory changeDataFactory;
  private final RulesCache rules;
  private final AccountInfo.Loader.Factory accountInfoFactory;

  @Option(name = "--filters", usage = "impact of filters in parent projects")
  private Filters filters = Filters.RUN;

  @Inject
  TestSubmitRule(ReviewDb db,
      ChangeData.Factory changeDataFactory,
      RulesCache rules,
      AccountInfo.Loader.Factory infoFactory) {
    this.db = db;
    this.changeDataFactory = changeDataFactory;
    this.rules = rules;
    this.accountInfoFactory = infoFactory;
  }

  @Override
  public List<Record> apply(RevisionResource rsrc, Input input)
      throws AuthException, BadRequestException, OrmException {
    if (input == null) {
      input = new Input();
    }
    if (input.rule != null && !rules.isProjectRulesEnabled()) {
      throw new AuthException("project rules are disabled");
    }
    input.filters = Objects.firstNonNull(input.filters, filters);

    SubmitRuleEvaluator evaluator = new SubmitRuleEvaluator(
        db,
        rsrc.getPatchSet(),
        rsrc.getControl().getProjectControl(),
        rsrc.getControl(),
        rsrc.getChange(),
        changeDataFactory.create(db, rsrc.getChange()),
        false,
        "locate_submit_rule", "can_submit",
        "locate_submit_filter", "filter_submit_results",
        input.filters == Filters.SKIP,
        input.rule != null
          ? new ByteArrayInputStream(input.rule.getBytes(UTF_8))
          : null);

    List<Term> results;
    try {
      results = eval(evaluator);
    } catch (RuleEvalException e) {
      String msg = Joiner.on(": ").skipNulls().join(Iterables.transform(
          Throwables.getCausalChain(e),
          new Function<Throwable, String>() {
            @Override
            public String apply(Throwable in) {
              return in.getMessage();
            }
          }));
      throw new BadRequestException("rule failed: " + msg);
    }
    if (results.isEmpty()) {
      throw new BadRequestException(String.format(
          "rule %s has no solutions",
          evaluator.getSubmitRule().toString()));
    }

    List<SubmitRecord> records = rsrc.getControl().resultsToSubmitRecord(
        evaluator.getSubmitRule(),
        results);
    List<Record> out = Lists.newArrayListWithCapacity(records.size());
    AccountInfo.Loader accounts = accountInfoFactory.create(true);
    for (SubmitRecord r : records) {
      out.add(new Record(r, accounts));
    }
    accounts.fill();
    return out;
  }

  private static List<Term> eval(SubmitRuleEvaluator evaluator)
      throws RuleEvalException {
    return evaluator.evaluate();
  }

  static class Record {
    SubmitRecord.Status status;
    String errorMessage;
    Map<String, AccountInfo> ok;
    Map<String, AccountInfo> reject;
    Map<String, None> need;
    Map<String, AccountInfo> may;
    Map<String, None> impossible;

    Record(SubmitRecord r, AccountInfo.Loader accounts) {
      this.status = r.status;
      this.errorMessage = r.errorMessage;

      if (r.labels != null) {
        for (SubmitRecord.Label n : r.labels) {
          AccountInfo who = n.appliedBy != null
              ? accounts.get(n.appliedBy)
              : new AccountInfo(null);
          label(n, who);
        }
      }
    }

    private void label(SubmitRecord.Label n, AccountInfo who) {
      switch (n.status) {
        case OK:
          if (ok == null) {
            ok = Maps.newLinkedHashMap();
          }
          ok.put(n.label, who);
          break;
        case REJECT:
          if (reject == null) {
            reject = Maps.newLinkedHashMap();
          }
          reject.put(n.label, who);
          break;
        case NEED:
          if (need == null) {
            need = Maps.newLinkedHashMap();
          }
          need.put(n.label, new None());
          break;
        case MAY:
          if (may == null) {
            may = Maps.newLinkedHashMap();
          }
          may.put(n.label, who);
          break;
        case IMPOSSIBLE:
          if (impossible == null) {
            impossible = Maps.newLinkedHashMap();
          }
          impossible.put(n.label, new None());
          break;
      }
    }
  }

  static class None {
  }
}
