// Copyright 2000-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
package com.intellij.ide.plugins;

import com.intellij.ide.IdeBundle;
import com.intellij.ide.plugins.marketplace.MarketplaceRequests;
import com.intellij.openapi.application.PathManager;
import com.intellij.openapi.application.PermanentInstallationID;
import com.intellij.openapi.application.ex.ApplicationInfoEx;
import com.intellij.openapi.application.impl.ApplicationInfoImpl;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.extensions.PluginId;
import com.intellij.openapi.progress.ProgressIndicator;
import com.intellij.openapi.updateSettings.impl.UpdateSettings;
import com.intellij.openapi.util.BuildNumber;
import com.intellij.openapi.util.io.FileUtilRt;
import com.intellij.util.Url;
import com.intellij.util.Urls;
import com.intellij.util.containers.ContainerUtil;
import com.intellij.util.io.URLUtil;
import com.intellij.util.text.VersionComparatorUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

import java.io.*;
import java.nio.charset.StandardCharsets;
import java.util.*;

import static com.intellij.ide.plugins.marketplace.MarketplaceRequests.parsePluginList;
import static java.util.Collections.singletonMap;

/**
 * @author stathik
 */
public final class RepositoryHelper {
  private static final Logger LOG = Logger.getInstance(RepositoryHelper.class);
  @SuppressWarnings("SpellCheckingInspection") private static final String PLUGIN_LIST_FILE = "availables.xml";

  private static final String MARKETPLACE_PLUGIN_ID = "com.intellij.marketplace";
  private static final String ULTIMATE_MODULE = "com.intellij.modules.ultimate";

  /**
   * Returns a list of configured plugin hosts.
   * Note that the list always ends with {@code null} element denoting a main plugin repository.
   */
  @NotNull
  public static List<String> getPluginHosts() {
    List<String> hosts = new ArrayList<>(UpdateSettings.getInstance().getPluginHosts());
    ContainerUtil.addIfNotNull(hosts, ApplicationInfoEx.getInstanceEx().getBuiltinPluginsUrl());
    hosts.add(null);  // main plugin repository
    return hosts;
  }

  /**
   * Loads list of plugins, compatible with a current build, from all configured repositories
   */
  @NotNull
  public static List<IdeaPluginDescriptor> loadPluginsFromAllRepositories(@Nullable ProgressIndicator indicator) {
    List<IdeaPluginDescriptor> result = new ArrayList<>();
    Set<PluginId> addedPluginIds = new HashSet<>();
    for (String host : getPluginHosts()) {
      try {
        List<IdeaPluginDescriptor> plugins = loadPlugins(host, indicator);
        for (IdeaPluginDescriptor plugin : plugins) {
          if (addedPluginIds.add(plugin.getPluginId())) {
            result.add(plugin);
          }
        }
      }
      catch (IOException e) {
        LOG.info("Couldn't load plugins from " + (host == null ? "main repository" : host) + ": " + e);
        LOG.debug(e);
      }
    }
    return result;
  }

  /**
   * Loads list of plugins, compatible with a current build, from a main plugin repository.
   */
  @NotNull
  public static List<IdeaPluginDescriptor> loadPlugins(@Nullable ProgressIndicator indicator) throws IOException {
    return loadPlugins(null, indicator);
  }

  @NotNull
  public static List<IdeaPluginDescriptor> loadPlugins(@Nullable String repositoryUrl, @Nullable ProgressIndicator indicator) throws IOException {
    return loadPlugins(repositoryUrl, null, indicator);
  }

  @NotNull
  public static List<IdeaPluginDescriptor> loadPlugins(@Nullable String repositoryUrl,
                                                       @Nullable BuildNumber build,
                                                       @Nullable ProgressIndicator indicator) throws IOException {
    File pluginListFile;
    Url url;
    if (repositoryUrl == null) {
      LOG.error("Should not be called! We are getting rid of this!");
      String base = ApplicationInfoImpl.getShadowInstance().getPluginsListUrl();
      url = Urls.newFromEncoded(base).addParameters(singletonMap("uuid", PermanentInstallationID.get()));
      pluginListFile = new File(PathManager.getPluginsPath(), PLUGIN_LIST_FILE);
    }
    else {
      url = Urls.newFromEncoded(repositoryUrl);
      pluginListFile = null;
    }

    if (!URLUtil.FILE_PROTOCOL.equals(url.getScheme())) {
      url = url.addParameters(singletonMap("build", build != null ? build.asString() : MarketplaceRequests.getBuildForPluginRepositoryRequests()));
    }

    if (indicator != null) {
      indicator.setText2(IdeBundle.message("progress.connecting.to.plugin.manager", url.getAuthority()));
    }

    List<PluginNode> descriptors = MarketplaceRequests.readOrUpdateFile(
      pluginListFile,
      url.toExternalForm(),
      indicator,
      IdeBundle.message("progress.downloading.list.of.plugins", url.getAuthority()),
      reader -> parsePluginList(reader)
    );
    return process(descriptors, repositoryUrl, build);
  }

  /**
   * Reads cached plugin descriptors from a file. Returns {@code null} if cache file does not exist.
   */
  @Nullable
  public static List<IdeaPluginDescriptor> loadCachedPlugins() throws IOException {
    File file = new File(PathManager.getPluginsPath(), PLUGIN_LIST_FILE);
    return file.length() > 0 ? process(loadPluginList(file), null, null) : null;
  }

  private static List<PluginNode> loadPluginList(File file) throws IOException {
    try (Reader reader = new InputStreamReader(new BufferedInputStream(new FileInputStream(file)), StandardCharsets.UTF_8)) {
      return parsePluginList(reader);
    }
  }

  private static @NotNull List<IdeaPluginDescriptor> process(@NotNull List<PluginNode> list, @Nullable String repositoryUrl, @Nullable BuildNumber build) {
    Map<PluginId, IdeaPluginDescriptor> result = new LinkedHashMap<>(list.size());
    if (build == null) {
      build = PluginManagerCore.getBuildNumber();
    }

    boolean isCommunityIDE = !ideContainsUltimateModule();
    boolean isVendorNotJetBrains = !ApplicationInfoImpl.getShadowInstance().isVendorJetBrains();
    boolean isPaidPluginsRequireMarketplacePlugin = isCommunityIDE || isVendorNotJetBrains;

    for (PluginNode node : list) {
      PluginId pluginId = node.getPluginId();

      if (pluginId == null || repositoryUrl != null && node.getDownloadUrl() == null) {
        LOG.debug("Malformed plugin record (id:" + pluginId + " repository:" + repositoryUrl + ")");
        continue;
      }

      if (PluginManagerCore.isBrokenPlugin(node) || PluginManagerCore.isIncompatible(node, build)) {
        LOG.debug("An incompatible plugin (id:" + pluginId + " repository:" + repositoryUrl + ")");
        continue;
      }

      if (repositoryUrl != null) {
        node.setRepositoryName(repositoryUrl);
      }
      if (node.getName() == null) {
        String url = node.getDownloadUrl();
        node.setName(FileUtilRt.getNameWithoutExtension(url.substring(url.lastIndexOf('/') + 1)));
      }

      IdeaPluginDescriptor previous = result.get(pluginId);
      if (previous == null || VersionComparatorUtil.compare(node.getVersion(), previous.getVersion()) > 0) {
        result.put(pluginId, node);
      }

      //if plugin is paid (has `productCode`) and IDE is not JetBrains "ultimate" then MARKETPLACE_PLUGIN_ID is required
      if (isPaidPluginsRequireMarketplacePlugin && node.getProductCode() != null) {
        node.addDepends(MARKETPLACE_PLUGIN_ID);
      }
    }

    return new ArrayList<>(result.values());
  }

  private static boolean ideContainsUltimateModule() {
    IdeaPluginDescriptor corePlugin = PluginManagerCore.getPlugin(PluginId.getId(PluginManagerCore.CORE_PLUGIN_ID));
    IdeaPluginDescriptorImpl corePluginImpl = (corePlugin instanceof IdeaPluginDescriptorImpl) ? (IdeaPluginDescriptorImpl)corePlugin : null;
    return corePluginImpl != null && corePluginImpl.getModules().contains(PluginId.getId(ULTIMATE_MODULE));
  }

}
@@ -3936,78 +3936,8 @@
 ) %7B%0A
-      LOG.error(%22Should not be called! We are getting rid of this!%22);%0A
     

remove log