/*
 * Licensed to Elasticsearch under one or more contributor
 * license agreements. See the NOTICE file distributed with
 * this work for additional information regarding copyright
 * ownership. Elasticsearch licenses this file to you 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 org.elasticsearch.common.settings;

import org.elasticsearch.common.inject.AbstractModule;

import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;

/**
 * A module that binds the provided settings to the {@link Settings} interface.
 *
 *
 */
public class SettingsModule extends AbstractModule {

    private final Settings settings;
    private final SettingsFilter settingsFilter;
    private final Map<String, Setting<?>> clusterSettings = new HashMap<>();
    private final Map<String, Setting<?>> indexSettings = new HashMap<>();

    public SettingsModule(Settings settings, SettingsFilter settingsFilter) {
        this.settings = settings;
        this.settingsFilter = settingsFilter;
        for (Setting<?> setting : ClusterSettings.BUILT_IN_CLUSTER_SETTINGS) {
            registerSetting(setting);
        }
        for (Setting<?> setting : IndexScopedSettings.BUILT_IN_INDEX_SETTINGS) {
            registerSetting(setting);
        }
    }

    @Override
    protected void configure() {
        final IndexScopedSettings indexScopedSettings = new IndexScopedSettings(settings, new HashSet<>(this.indexSettings.values()));
        // by now we are fully configured, lets check node level settings for unregistered index settings
        indexScopedSettings.validate(settings.filter(IndexScopedSettings.INDEX_SETTINGS_KEY_PREDICATE));
        bind(Settings.class).toInstance(settings);
        bind(SettingsFilter.class).toInstance(settingsFilter);
        final ClusterSettings clusterSettings = new ClusterSettings(settings, new HashSet<>(this.clusterSettings.values()));

        bind(ClusterSettings.class).toInstance(clusterSettings);
        bind(IndexScopedSettings.class).toInstance(indexScopedSettings);
    }

    public void registerSetting(Setting<?> setting) {
        switch (setting.getScope()) {
            case CLUSTER:
                if (clusterSettings.containsKey(setting.getKey())) {
                    throw new IllegalArgumentException("Cannot register setting [" + setting.getKey() + "] twice");
                }
                clusterSettings.put(setting.getKey(), setting);
                break;
            case INDEX:
                if (indexSettings.containsKey(setting.getKey())) {
                    throw new IllegalArgumentException("Cannot register setting [" + setting.getKey() + "] twice");
                }
                indexSettings.put(setting.getKey(), setting);
                break;
        }
    }

}

@@ -1944,24 +1944,149 @@
 values()));%0A
+        final ClusterSettings clusterSettings = new ClusterSettings(settings, new HashSet%3C%3E(this.clusterSettings.values()));%0A
         // b
@@ -2296,95 +2296,317 @@
     
-bind(Settings.class).toInstance(settings);%0A        bind(SettingsFilter.class).toInstanc
+// we can't call this method yet since we have not all node level settings registered.%0A        // yet we can validate the ones we have registered to not have invalid values. this is better than nothing%0A        // and progress over perfection and we fail as soon as possible.%0A        // clusterSettings.validat
 e(se
@@ -2615,139 +2615,491 @@
 ings
-F
+.f
 ilter
-);%0A        final ClusterSettings clusterSettings = new ClusterSettings(settings, new HashSet%3C%3E(this.clusterSettings.values())
+(IndexScopedSettings.INDEX_SETTINGS_KEY_PREDICATE.negate()));%0A        for (Map.Entry%3CString, String%3E entry : settings.filter(IndexScopedSettings.INDEX_SETTINGS_KEY_PREDICATE.negate()).getAsMap().entrySet()) %7B%0A            if (clusterSettings.get(entry.getKey()) != null) %7B%0A                clusterSettings.validate(entry.getKey(), settings);%0A            %7D%0A        %7D%0A%0A        bind(Settings.class).toInstance(settings);%0A        bind(SettingsFilter.class).toInstance(settingsFilter
 );%0A%0A

Validate known global settings on startup