<commit_before>package com.github.bjoernpetersen.jmusicbot;

import com.github.bjoernpetersen.jmusicbot.config.Config;
import com.github.bjoernpetersen.jmusicbot.config.DefaultConfigEntry;
import com.github.bjoernpetersen.jmusicbot.playback.PlaybackFactory;
import com.github.bjoernpetersen.jmusicbot.provider.Provider;
import com.github.bjoernpetersen.jmusicbot.provider.Suggester;
import java.io.Closeable;
import java.io.File;
import java.io.IOException;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Optional;
import java.util.Set;
import java.util.function.BiConsumer;
import java.util.function.Function;
import java.util.stream.Collectors;
import javax.annotation.Nonnull;

public final class ProviderManager implements Loggable, Closeable {

  public enum State {
    INACTIVE, CONFIG, ACTIVE
  }

  @Nonnull
  private final Config config;
  @Nonnull
  private final PlaybackFactoryManager playbackFactoryManager;

  @Nonnull
  private final PluginManager<Provider> providerManager;
  @Nonnull
  private final PluginManager<Suggester> suggesterManager;

  @Nonnull
  private final Map<Provider, List<Suggester>> suggestersForProvider;

  public ProviderManager(@Nonnull Config config,
      @Nonnull PlaybackFactoryManager playbackFactoryManager) {
    this.config = config;
    this.playbackFactoryManager = playbackFactoryManager;

    this.providerManager = new PluginManager<>(
        config,
        Provider.class,
        this::initializeProvider
    );

    this.suggesterManager = new PluginManager<>(
        config,
        Suggester.class,
        this::initializeSuggester
    );

    this.suggestersForProvider = new HashMap<>(providerManager.getPlugins().size() * 2);
  }

  private void initializeProvider(@Nonnull InitStateWriter initStateWriter, Provider provider)
      throws InitializationException, InterruptedException {
    for (Class<? extends PlaybackFactory> factoryType : provider.getPlaybackDependencies()) {
      if (!playbackFactoryManager.hasFactory(factoryType)) {
        throw new InitializationException(String.format(
            "Missing dependency for Provider '%s': '%s'.",
            provider.getReadableName(),
            factoryType.getName()
        ));
      }
    }
    provider.initialize(initStateWriter, playbackFactoryManager);
  }

  private void initializeSuggester(@Nonnull InitStateWriter initStateWriter,
      @Nonnull Suggester suggester) throws InitializationException, InterruptedException {
    Collection<String> dependencies = suggester.getDependencies();
    Map<String, Provider> loadedDependencies = new HashMap<>(dependencies.size() * 2);
    for (String dependencyName : dependencies) {
      Optional<Provider> foundDependency = this.providerManager.get(dependencyName);
      if (!foundDependency.isPresent()) {
        throw new InitializationException(String.format(
            "Missing dependency for suggester '%s': '%s'.",
            suggester.getReadableName(),
            dependencyName
        ));
      }

      Provider dependency = foundDependency.get();
      suggestersForProvider.computeIfAbsent(dependency, s -> new LinkedList<>()).add(suggester);
      loadedDependencies.put(dependencyName, dependency);
    }

    for (String dependencyName : suggester.getOptionalDependencies()) {
      Optional<Provider> foundDependency = this.providerManager.get(dependencyName);
      if (foundDependency.isPresent()) {
        Provider dependency = foundDependency.get();
        suggestersForProvider.computeIfAbsent(dependency, s -> new LinkedList<>()).add(suggester);
        loadedDependencies.put(dependencyName, dependency);
      }
    }

    suggester.initialize(initStateWriter, loadedDependencies);
  }

  /**
   * Gets the provider with the specified name.
   * Only returns active providers.
   *
   * @param name the provider name
   * @return a Provider
   * @throws IllegalArgumentException if there is no such provider
   */
  @Nonnull
  public Provider getProvider(@Nonnull String name) {<commit_msg>Add InitStateWriter calls for dependency checking<commit_after>package com.github.bjoernpetersen.jmusicbot;

import com.github.bjoernpetersen.jmusicbot.config.Config;
import com.github.bjoernpetersen.jmusicbot.config.DefaultConfigEntry;
import com.github.bjoernpetersen.jmusicbot.playback.PlaybackFactory;
import com.github.bjoernpetersen.jmusicbot.provider.Provider;
import com.github.bjoernpetersen.jmusicbot.provider.Suggester;
import java.io.Closeable;
import java.io.File;
import java.io.IOException;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Optional;
import java.util.Set;
import java.util.function.BiConsumer;
import java.util.function.Function;
import java.util.stream.Collectors;
import javax.annotation.Nonnull;

public final class ProviderManager implements Loggable, Closeable {

  public enum State {
    INACTIVE, CONFIG, ACTIVE
  }

  @Nonnull
  private final Config config;
  @Nonnull
  private final PlaybackFactoryManager playbackFactoryManager;

  @Nonnull
  private final PluginManager<Provider> providerManager;
  @Nonnull
  private final PluginManager<Suggester> suggesterManager;

  @Nonnull
  private final Map<Provider, List<Suggester>> suggestersForProvider;

  public ProviderManager(@Nonnull Config config,
      @Nonnull PlaybackFactoryManager playbackFactoryManager) {
    this.config = config;
    this.playbackFactoryManager = playbackFactoryManager;

    this.providerManager = new PluginManager<>(
        config,
        Provider.class,
        this::initializeProvider
    );

    this.suggesterManager = new PluginManager<>(
        config,
        Suggester.class,
        this::initializeSuggester
    );

    this.suggestersForProvider = new HashMap<>(providerManager.getPlugins().size() * 2);
  }

  private void initializeProvider(@Nonnull InitStateWriter initStateWriter, Provider provider)
      throws InitializationException, InterruptedException {
    initStateWriter.state("Checking dependencies...");
    for (Class<? extends PlaybackFactory> factoryType : provider.getPlaybackDependencies()) {
      if (!playbackFactoryManager.hasFactory(factoryType)) {
        throw new InitializationException(String.format(
            "Missing dependency for Provider '%s': '%s'.",
            provider.getReadableName(),
            factoryType.getName()
        ));
      }
    }
    initStateWriter.state("Initializing...");
    provider.initialize(initStateWriter, playbackFactoryManager);
  }

  private void initializeSuggester(@Nonnull InitStateWriter initStateWriter,
      @Nonnull Suggester suggester) throws InitializationException, InterruptedException {
    initStateWriter.state("Checking dependencies...");
    Collection<String> dependencies = suggester.getDependencies();
    Map<String, Provider> loadedDependencies = new HashMap<>(dependencies.size() * 2);
    for (String dependencyName : dependencies) {
      Optional<Provider> foundDependency = this.providerManager.get(dependencyName);
      if (!foundDependency.isPresent()) {
        throw new InitializationException(String.format(
            "Missing dependency for suggester '%s': '%s'.",
            suggester.getReadableName(),
            dependencyName
        ));
      }

      Provider dependency = foundDependency.get();
      suggestersForProvider.computeIfAbsent(dependency, s -> new LinkedList<>()).add(suggester);
      loadedDependencies.put(dependencyName, dependency);
    }

    initStateWriter.state("Checking optional dependencies...");
    for (String dependencyName : suggester.getOptionalDependencies()) {
      Optional<Provider> foundDependency = this.providerManager.get(dependencyName);
      if (foundDependency.isPresent()) {
        Provider dependency = foundDependency.get();
        suggestersForProvider.computeIfAbsent(dependency, s -> new LinkedList<>()).add(suggester);
        loadedDependencies.put(dependencyName, dependency);
      }
    }

    initStateWriter.state("Initializing...");
    suggester.initialize(initStateWriter, loadedDependencies);
  }

  /**
   * Gets the provider with the specified name.
   * Only returns active providers.
   *
   * @param name the provider name
   * @return a Provider
   * @throws IllegalArgumentException if there is no such provider
   */
  @Nonnull
  public Provider getProvider(@Nonnull String name) {
{'fraction_non_alphanumeric': 0.09500230308613543, 'fraction_numerical': 0.00046061722708429296, 'mean_word_length': 4.14819205690575, 'pattern_counts': {'":': 0, '<': 33, '<?xml version=': 0, '>': 37, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5108323', 'n_tokens_mistral': 2392, 'n_tokens_neox': 2279, 'n_words': 504}