/******************************************************************************
 *                                                                            *
 *                    Copyright 2017 Subterranean Security                    *
 *                                                                            *
 *  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.sandpolis.core.instance;

import java.util.Map;
import java.util.HashMap;
import java.util.Objects;

/**
 * This singleton contains the instance configuration.
 *
 * @author cilki
 * @since 5.0.0
 */
public final class Config {

	/**
	 * The global configuration.
	 */
	private static final Map<String, Object> config = new HashMap<>();

	/**
	 * Check that the configuration contains a property.
	 * 
	 * @param property The property to request
	 * @return Whether the property exists in the configuration
	 */
	public static boolean has(String property) {
		return config.containsKey(property);
	}

	/**
	 * Get the value of a String property.
	 * 
	 * @param property The property to request
	 * @return The property value
	 */
	public static String get(String property) {
		return (String) config.get(property);
	}

	/**
	 * Get the value of a Boolean property.
	 * 
	 * @param property The property to request
	 * @return The property value
	 */
	public static boolean getBoolean(String property) {
		return (boolean) config.get(property);
	}

	/**
	 * Get the value of an Integer property.
	 * 
	 * @param property The property to request
	 * @return The property value
	 */
	public static int getInteger(String property) {
		return (int) config.get(property);
	}

	/**
	 * Insist that the runtime environment provide the given property of the given
	 * type.
	 * 
	 * @param property The property name
	 * @param type     The property type
	 * @return Whether the environment fufills the requirement
	 */
	public static boolean require(String property, Class<?> type) {
		Objects.requireNonNull(property);
		Objects.requireNonNull(type);

		String value = getValue(property);

		if (value == null)
			return false;

		if (type == String.class)
			config.put(property, value);
		else if (type == Boolean.class)
			config.put(property, Boolean.parseBoolean(value));
		else if (type == Integer.class)
			config.put(property, Integer.parseInt(value));
		else
			throw new IllegalArgumentException("Unsupported type: " + type.getName());

		return true;
	}

	/**
	 * Get a property from the runtime environment or a default value.
	 * 
	 * @param property The property name
	 * @param def      The default value
	 */
	public static void register(String property, Object def) {
		Objects.requireNonNull(property);

		String value = getValue(property);
		if (value == null)
			if (def != null)
				config.put(property, def);
			else if (def instanceof String)
				config.put(property, value);
			else if (def instanceof Boolean)
				config.put(property, Boolean.parseBoolean(value));
			else if (def instanceof Integer)
				config.put(property, Integer.parseInt(value));
			else
				throw new IllegalArgumentException();
	}

	/**
	 * Query a property.
	 * 
	 * @param property The property name
	 * @return The property value
	 */
	private static String getValue(String property) {

		// Query environment variable
		// TODO remove this translation or document
		String value = System.getenv().get(property.toUpperCase().replace('.', '_'));
		if (value != null)
			return value;

		// Query system property
		return System.getProperty(property);
	}

	private Config() {
	}
}

@@ -3497,17 +3497,101 @@
 t value.
+ A default of%0A%09 * %7B@code null%7D implies the property's type should be %7B@link String%7D.
 %0A
-
 %09 * %0A%09 *
@@ -3830,26 +3830,23 @@
 %0A%09%09%09
-if (def != null)%0A%09
+// Set default%0A
 %09%09%09c
@@ -3877,82 +3877,61 @@
 ;%0A%09%09
-%09
 else 
-if (def instanceof String)%0A%09%09%09%09config.put(property,
+%7B%0A%09%09%09// Use default to predict type of
  value
-);
 %0A%09%09%09
-else 
 if (
@@ -4112,45 +4112,40 @@
 %09%09%09%09
-throw new IllegalArgumentException();
+config.put(property, value);%0A%09%09%7D
 %0A%09%7D%0A

Fix property handling with null default