<commit_before>package guice.config;

import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Properties;

import com.google.inject.AbstractModule;
import com.google.inject.Binder;
import com.google.inject.Guice;
import com.google.inject.Injector;
import com.google.inject.Module;
import com.google.inject.binder.AnnotatedBindingBuilder;
import com.google.inject.binder.LinkedBindingBuilder;
import com.google.inject.multibindings.Multibinder;
import com.google.inject.name.Names;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * @author <a href="mailto:<EMAIL>">kimi</a> 2017-06-26
 */
public class InjectorBuilder {

    private static final Logger LOG = LoggerFactory.getLogger(InjectorBuilder.class);

    final List<BindingConfig> bindings   = new ArrayList<>();
    final Properties          properties = new Properties();

    Injector injector;

    public InjectorBuilder() {
        super();
    }

    public void register(BindingConfig binding) {
        if (bindings.contains(binding)) {
            throw new IllegalStateException("Duplicate bindings " + binding);
        }
        bindings.add(binding);
    }

    public Object setProperty(String key, String value) {
        return properties.setProperty(key, value);
    }

    public String getProperty(String key) {
        return properties.getProperty(key);
    }

    public synchronized Injector build() {
        if (injector != null) {
            return injector;
        }

        final BindingSelector selector = new BindingSelector(properties);
        final List<BindingConfig> selectedBindings = selector.select(bindings);
        final Map<Class<?>, List<BindingConfig>> map = convert(selectedBindings);
        showBindings(map);
        final Module module = new AbstractModule() {
            @Override
            protected void configure() {
                for (Map.Entry<Class<?>, List<BindingConfig>> entry : map.entrySet()) {
                    final Class<?> key = entry.getKey();
                    final List<BindingConfig> value = entry.getValue();
                    // FIXME scope
                    if (value.size() == 1) {
                        buildBinding(binder(), value.get(0));
                    } else if (value.size() > 1) {
                        buildMultibinding(binder(), entry.getKey(), entry.getValue());
                    } else {
                        if (LOG.isWarnEnabled()) {
                            LOG.warn("Unknown how to config bindings: " + key + " -> " + value);
                        }
                    }
                }
            }
        };
        injector = Guice.createInjector(module);
        return injector;
    }

    void buildBinding(Binder binder, BindingConfig binding) {
        AnnotatedBindingBuilder annotatedBindingBuilder = binder.bind(binding.getType());
        LinkedBindingBuilder linkedBindingBuilder = null;
        if (StringUtils.isNotBlank(binding.getName())) {
            linkedBindingBuilder = annotatedBindingBuilder.annotatedWith(Names.named(binding.getName()));
        }

        if (linkedBindingBuilder == null) {
            linkedBindingBuilder = annotatedBindingBuilder;
        }

        if (!binding.getType().equals(binding.getImplementation())) {
            linkedBindingBuilder.to(binding.getImplementation());
        }
    }

    void buildMultibinding(Binder binder, Class<?> type, List<BindingConfig> list) {
        Multibinder multibinder = Multibinder.newSetBinder(binder, (Class) type);
        for (int i = 0; i < list.size(); i++) {
            multibinder.addBinding().to(list.get(i).getImplementation());
        }
    }

    Map<Class<?>, List<BindingConfig>> convert(List<BindingConfig> bindings) {
        final Map<Class<?>, List<BindingConfig>> result = new HashMap<>();
        for (int i = 0; i < bindings.size(); i++) {
            final BindingConfig binding = bindings.get(i);
            List<BindingConfig> list = result.get(binding.getType());
            if (list == null) {
                result.put(binding.getType(), new ArrayList<>());
                list = result.get(binding.getType());
            }
            list.add(binding);
        }
        return result;
    }

    void showBindings(final Map<Class<?>, List<BindingConfig>> map) {
        if (Boolean.getBoolean("show.bindings")) {<commit_msg>refactor<commit_after>package guice.config;

import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Properties;

import com.google.inject.AbstractModule;
import com.google.inject.Binder;
import com.google.inject.Guice;
import com.google.inject.Injector;
import com.google.inject.Module;
import com.google.inject.binder.AnnotatedBindingBuilder;
import com.google.inject.binder.LinkedBindingBuilder;
import com.google.inject.multibindings.Multibinder;
import com.google.inject.name.Names;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * @author <a href="mailto:<EMAIL>">kimi</a> 2017-06-26
 */
public class InjectorBuilder {

    private static final Logger LOG = LoggerFactory.getLogger(InjectorBuilder.class);

    final List<BindingConfig> bindings   = new ArrayList<>();
    final Properties          properties = new Properties();

    Injector injector;

    public InjectorBuilder() {
        super();
    }

    public void register(BindingConfig binding) {
        if (bindings.contains(binding)) {
            throw new IllegalStateException("Duplicate bindings " + binding);
        }
        bindings.add(binding);
    }

    public Object setProperty(String key, String value) {
        return properties.setProperty(key, value);
    }

    public String getProperty(String key) {
        return properties.getProperty(key);
    }

    public synchronized Injector build() {
        if (injector != null) {
            return injector;
        }

        final BindingSelector selector = new BindingSelector(properties);
        final List<BindingConfig> selectedBindings = selector.select(bindings);
        final Map<Class<?>, List<BindingConfig>> map = convert(selectedBindings);
        showBindings(map);
        final Module module = new AbstractModule() {
            @Override
            protected void configure() {
                for (Map.Entry<Class<?>, List<BindingConfig>> entry : map.entrySet()) {
                    final Class<?> key = entry.getKey();
                    final List<BindingConfig> value = entry.getValue();
                    // FIXME scope
                    if (value.size() == 1) {
                        buildBinding(binder(), value.get(0));
                    } else if (value.size() > 1) {
                        buildMultibinding(binder(), entry.getKey(), entry.getValue());
                    } else {
                        if (LOG.isWarnEnabled()) {
                            LOG.warn("Unknown how to config bindings: " + key + " -> " + value);
                        }
                    }
                }
            }
        };
        injector = Guice.createInjector(module);
        return injector;
    }

    void buildBinding(Binder binder, BindingConfig binding) {
        AnnotatedBindingBuilder annotatedBindingBuilder = binder.bind(binding.getType());
        LinkedBindingBuilder linkedBindingBuilder = annotatedBindingBuilder;
        if (StringUtils.isNotBlank(binding.getName())) {
            linkedBindingBuilder = annotatedBindingBuilder.annotatedWith(Names.named(binding.getName()));
        }

        if (!binding.getType().equals(binding.getImplementation())) {
            linkedBindingBuilder.to(binding.getImplementation());
        }
    }

    void buildMultibinding(Binder binder, Class<?> type, List<BindingConfig> list) {
        Multibinder multibinder = Multibinder.newSetBinder(binder, (Class) type);
        for (int i = 0; i < list.size(); i++) {
            multibinder.addBinding().to(list.get(i).getImplementation());
        }
    }

    Map<Class<?>, List<BindingConfig>> convert(List<BindingConfig> bindings) {
        final Map<Class<?>, List<BindingConfig>> result = new HashMap<>();
        for (int i = 0; i < bindings.size(); i++) {
            final BindingConfig binding = bindings.get(i);
            List<BindingConfig> list = result.get(binding.getType());
            if (list == null) {
                result.put(binding.getType(), new ArrayList<>());
                list = result.get(binding.getType());
            }
            list.add(binding);
        }
        return result;
    }

    void showBindings(final Map<Class<?>, List<BindingConfig>> map) {
        if (Boolean.getBoolean("show.bindings")) {
{'fraction_non_alphanumeric': 0.11776558826821897, 'fraction_numerical': 0.003582223217284227, 'mean_word_length': 2.4295585412667946, 'pattern_counts': {'":': 0, '<': 65, '<?xml version=': 0, '>': 65, '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': '1554433', 'n_tokens_mistral': 2419, 'n_tokens_neox': 2333, 'n_words': 503}