// Copyright (C) 2015 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 static com.google.gerrit.server.config.ConfigUtil.loadSection;
import static com.google.gerrit.server.config.ConfigUtil.skipField;
import static com.google.gerrit.server.git.UserConfigSections.CHANGE_TABLE;
import static com.google.gerrit.server.git.UserConfigSections.CHANGE_TABLE_COLUMN;
import static com.google.gerrit.server.git.UserConfigSections.KEY_ID;
import static com.google.gerrit.server.git.UserConfigSections.KEY_MATCH;
import static com.google.gerrit.server.git.UserConfigSections.KEY_TARGET;
import static com.google.gerrit.server.git.UserConfigSections.KEY_TOKEN;
import static com.google.gerrit.server.git.UserConfigSections.KEY_URL;
import static com.google.gerrit.server.git.UserConfigSections.URL_ALIAS;

import com.google.common.base.Strings;
import com.google.common.collect.Lists;
import com.google.gerrit.extensions.client.GeneralPreferencesInfo;
import com.google.gerrit.extensions.client.MenuItem;
import com.google.gerrit.reviewdb.client.Account;
import com.google.gerrit.server.config.AllUsersName;
import com.google.gerrit.server.git.GitRepositoryManager;
import com.google.gerrit.server.git.UserConfigSections;
import com.google.inject.Inject;
import com.google.inject.Singleton;
import java.io.IOException;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.eclipse.jgit.errors.ConfigInvalidException;
import org.eclipse.jgit.errors.RepositoryNotFoundException;
import org.eclipse.jgit.lib.Config;
import org.eclipse.jgit.lib.Repository;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

@Singleton
public class GeneralPreferencesLoader {
  private static final Logger log = LoggerFactory.getLogger(GeneralPreferencesLoader.class);

  private final GitRepositoryManager gitMgr;
  private final AllUsersName allUsersName;

  @Inject
  public GeneralPreferencesLoader(GitRepositoryManager gitMgr, AllUsersName allUsersName) {
    this.gitMgr = gitMgr;
    this.allUsersName = allUsersName;
  }

  public GeneralPreferencesInfo load(Account.Id id)
      throws IOException, ConfigInvalidException, RepositoryNotFoundException {
    return read(id, null);
  }

  public GeneralPreferencesInfo merge(Account.Id id, GeneralPreferencesInfo in)
      throws IOException, ConfigInvalidException, RepositoryNotFoundException {
    return read(id, in);
  }

  private GeneralPreferencesInfo read(Account.Id id, GeneralPreferencesInfo in)
      throws IOException, ConfigInvalidException, RepositoryNotFoundException {
    try (Repository allUsers = gitMgr.openRepository(allUsersName)) {
      // Load all users default prefs
      VersionedAccountPreferences dp = VersionedAccountPreferences.forDefault();
      dp.load(allUsers);

      // Load user prefs
      VersionedAccountPreferences p = VersionedAccountPreferences.forUser(id);
      p.load(allUsers);
      GeneralPreferencesInfo r =
          loadSection(
              p.getConfig(),
              UserConfigSections.GENERAL,
              null,
              new GeneralPreferencesInfo(),
              readDefaultsFromGit(dp.getConfig(), in),
              in);
      loadChangeTableColumns(r, p, dp);
      return loadMyMenusAndUrlAliases(r, p, dp);
    }
  }

  public GeneralPreferencesInfo readDefaultsFromGit(Repository git, GeneralPreferencesInfo in)
      throws ConfigInvalidException, IOException {
    VersionedAccountPreferences dp = VersionedAccountPreferences.forDefault();
    dp.load(git);
    return readDefaultsFromGit(dp.getConfig(), in);
  }

  private GeneralPreferencesInfo readDefaultsFromGit(Config config, GeneralPreferencesInfo in)
      throws ConfigInvalidException {
    GeneralPreferencesInfo allUserPrefs = new GeneralPreferencesInfo();
    loadSection(
        config,
        UserConfigSections.GENERAL,
        null,
        allUserPrefs,
        GeneralPreferencesInfo.defaults(),
        in);
    return updateDefaults(allUserPrefs);
  }

  private GeneralPreferencesInfo updateDefaults(GeneralPreferencesInfo input) {
    GeneralPreferencesInfo result = GeneralPreferencesInfo.defaults();
    try {
      for (Field field : input.getClass().getDeclaredFields()) {
        if (skipField(field)) {
          continue;
        }
        Object newVal = field.get(input);
        if (newVal != null) {
          field.set(result, newVal);
        }
      }
    } catch (IllegalAccessException e) {
      log.error("Cannot get default general preferences from " + allUsersName.get(), e);
      return GeneralPreferencesInfo.defaults();
    }
    return result;
  }

  public GeneralPreferencesInfo loadMyMenusAndUrlAliases(
      GeneralPreferencesInfo r, VersionedAccountPreferences v, VersionedAccountPreferences d) {
    r.my = my(v);
    if (r.my.isEmpty() && !v.isDefaults()) {
      r.my = my(d);
    }
    if (r.my.isEmpty()) {
      r.my.add(new MenuItem("Changes", "#/dashboard/self", null));
      r.my.add(new MenuItem("Draft Comments", "#/q/has:draft", null));
      r.my.add(new MenuItem("Edits", "#/q/has:edit", null));
      r.my.add(new MenuItem("Watched Changes", "#/q/is:watched+is:open", null));
      r.my.add(new MenuItem("Starred Changes", "#/q/is:starred", null));
      r.my.add(new MenuItem("Groups", "#/groups/self", null));
    }

    r.urlAliases = urlAliases(v);
    if (r.urlAliases == null && !v.isDefaults()) {
      r.urlAliases = urlAliases(d);
    }
    return r;
  }

  private static List<MenuItem> my(VersionedAccountPreferences v) {
    List<MenuItem> my = new ArrayList<>();
    Config cfg = v.getConfig();
    for (String subsection : cfg.getSubsections(UserConfigSections.MY)) {
      String url = my(cfg, subsection, KEY_URL, "#/");
      String target = my(cfg, subsection, KEY_TARGET, url.startsWith("#") ? null : "_blank");
      my.add(new MenuItem(subsection, url, target, my(cfg, subsection, KEY_ID, null)));
    }
    return my;
  }

  private static String my(Config cfg, String subsection, String key, String defaultValue) {
    String val = cfg.getString(UserConfigSections.MY, subsection, key);
    return !Strings.isNullOrEmpty(val) ? val : defaultValue;
  }

  public GeneralPreferencesInfo loadChangeTableColumns(
      GeneralPreferencesInfo r, VersionedAccountPreferences v, VersionedAccountPreferences d) {
    r.changeTable = changeTable(v);

    if (r.changeTable.isEmpty() && !v.isDefaults()) {
      r.changeTable = changeTable(d);
    }
    return r;
  }

  private static List<String> changeTable(VersionedAccountPreferences v) {
    return Lists.newArrayList(v.getConfig().getStringList(CHANGE_TABLE, null, CHANGE_TABLE_COLUMN));
  }

  private static Map<String, String> urlAliases(VersionedAccountPreferences v) {
    HashMap<String, String> urlAliases = new HashMap<>();
    Config cfg = v.getConfig();
    for (String subsection : cfg.getSubsections(URL_ALIAS)) {
      urlAliases.put(
          cfg.getString(URL_ALIAS, subsection, KEY_MATCH),
          cfg.getString(URL_ALIAS, subsection, KEY_TOKEN));
    }
    return !urlAliases.isEmpty() ? urlAliases : null;
  }
}
