// Copyright (C) 2016 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.googlesource.gerrit.plugins.hooks;

import static com.google.common.base.MoreObjects.firstNonNull;

import com.google.common.base.Strings;
import com.google.common.collect.ImmutableList;
import com.google.gerrit.common.Nullable;
import com.google.gerrit.extensions.common.AccountInfo;
import com.google.gerrit.extensions.common.ApprovalInfo;
import com.google.gerrit.extensions.common.ChangeInfo;
import com.google.gerrit.reviewdb.client.Account;
import com.google.gerrit.server.IdentifiedUser;
import com.google.gerrit.server.config.CanonicalWebUrl;
import com.google.gerrit.server.config.SitePaths;
import com.google.gerrit.server.git.GitRepositoryManager;
import com.google.inject.Inject;
import com.google.inject.Provider;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

class HookArgs {
  interface Factory {
    HookArgs create();
  }

  final IdentifiedUser.GenericFactory identifiedUserFactory;
  final Provider<String> urlProvider;
  final HookMetrics metrics;
  final GitRepositoryManager gitManager;
  final SitePaths sitePaths;

  private final List<String> args;

  @Inject
  HookArgs(
      IdentifiedUser.GenericFactory identifiedUserFactory,
      @CanonicalWebUrl @Nullable Provider<String> urlProvider,
      HookMetrics metrics,
      GitRepositoryManager gitManager,
      SitePaths sitePaths) {
    this.identifiedUserFactory = identifiedUserFactory;
    this.urlProvider = urlProvider;
    this.metrics = metrics;
    this.gitManager = gitManager;
    this.sitePaths = sitePaths;

    this.args = new ArrayList<>();
  }

  public ImmutableList<String> get() {
    return ImmutableList.copyOf(args);
  }

  public void add(String name, String value) {
    args.add(name);
    args.add(Strings.nullToEmpty(value));
  }

  public void add(String name, int value) {
    args.add(name);
    args.add(String.valueOf(value));
  }

  public void add(String name, Integer value) {
    args.add(name);
    args.add(value.toString());
  }

  public void add(String name, Boolean value) {
    args.add(name);
    args.add(firstNonNull(value, false).toString());
  }

  public void add(String name, AccountInfo account) {
    if (account != null) {
      args.add(name);
      args.add(format(account));

      add(name + "-username", account.username);
    }
  }

  public void addUrl(ChangeInfo change) {
    args.add("--change-url");
    String url = urlProvider.get();
    if (change != null && url != null) {
      args.add(url + change._number);
    } else {
      args.add("");
    }
  }

  public void addApprovals(
      Map<String, ApprovalInfo> approvals, Map<String, ApprovalInfo> oldApprovals) {
    for (Map.Entry<String, ApprovalInfo> approval : approvals.entrySet()) {
      if (approval.getValue() != null) {
        args.add("--" + approval.getKey());
        args.add(approval.getValue().value.toString());
        if (oldApprovals != null && !oldApprovals.isEmpty()) {
          ApprovalInfo oldValue = oldApprovals.get(approval.getKey());
          if (oldValue != null && oldValue.value != null) {
            args.add("--" + approval.getKey() + "-oldValue");
            args.add(oldValue.value.toString());
          }
        }
      }
    }
  }

  private String format(AccountInfo account) {
    return String.format(
        "\"%s\"", identifiedUserFactory.create(new Account.Id(account._accountId)).getNameEmail());
  }

  @Override
  public String toString() {
    return String.format("HookArgs: %s", args.toString());
  }
}

@@ -805,50 +805,8 @@
 st;%0A
-import com.google.gerrit.common.Nullable;%0A
 impo
@@ -1019,16 +1019,115 @@
 ccount;%0A
+import com.google.gerrit.reviewdb.client.Change;%0Aimport com.google.gerrit.reviewdb.client.Project;%0A
 import c
@@ -1205,31 +1205,25 @@
 .config.
-CanonicalWebUrl
+SitePaths
 ;%0Aimport
@@ -1251,33 +1251,36 @@
 rver.config.
-SitePaths
+UrlFormatter
 ;%0Aimport com
@@ -1364,43 +1364,8 @@
 ct;%0A
-import com.google.inject.Provider;%0A
 impo
@@ -1566,46 +1566,8 @@
 ry;%0A
-  final Provider%3CString%3E urlProvider;%0A
   fi
@@ -1656,24 +1656,59 @@
 s sitePaths;
+%0A  final UrlFormatter urlFormatter;
 %0A%0A  private 
@@ -1824,61 +1824,31 @@
     
-@CanonicalWebUrl @Nullable Provider%3CString%3E urlProvid
+UrlFormatter urlFormatt
 er,%0A
@@ -2014,22 +2014,23 @@
 .url
-Provid
+Formatt
 er = url
 Prov
@@ -2025,22 +2025,23 @@
 er = url
-Provid
+Formatt
 er;%0A    
@@ -2978,44 +2978,8 @@
 %22);%0A
-    String url = urlProvider.get();%0A
     
@@ -2995,23 +2995,8 @@
 e !=
- null && url !=
  nul
@@ -3019,28 +3019,157 @@
 add(
-url + change._number
+%0A          urlFormatter%0A              .getChangeViewUrl(new Project.NameKey(change.project), new Change.Id(change._number))%0A              .orElse(%22%22)
 );%0A 

Use UrlFormatter to create review URL.