/*
 * * Copyright (C) 2013-2014 Matt Baxter http://kitteh.org
 *
 * Permission is hereby granted, free of charge, to any person
 * obtaining a copy of this software and associated documentation
 * files (the "Software"), to deal in the Software without
 * restriction, including without limitation the rights to use, copy,
 * modify, merge, publish, distribute, sublicense, and/or sell copies
 * of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be
 * included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */
package org.kitteh.irc;

import java.net.InetSocketAddress;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * Stores an IRCBot's configured data from the {@link BotBuilder}.
 */
final class Config {
    /**
     * Represents a configuration entry.
     *
     * @param <Type>
     */
    static final class Entry<Type> {
        private final Type defaultValue;
        private final Class<Type> type;

        private Entry(Type defaultValue, Class<Type> type) {
            this.defaultValue = defaultValue;
            this.type = type;
        }

        /**
         * Gets the entry's default value.
         *
         * @return the default value
         */
        private Type getDefault() {
            return this.defaultValue;
        }

        /**
         * Gets the type of the entry.
         *
         * @return the entry type
         */
        private Class<Type> getType() {
            return this.type;
        }
    }

    static final Entry<String> BOT_NAME = new Entry<>("Unnamed", String.class);
    static final Entry<InetSocketAddress> BIND_ADDRESS = new Entry<>(null, InetSocketAddress.class);
    static final Entry<Integer> MESSAGE_DELAY = new Entry<>(1200, Integer.class);
    static final Entry<String> NICK = new Entry<>("Kitteh", String.class);
    static final Entry<String> REAL_NAME = new Entry<>("Kitteh", String.class);
    static final Entry<InetSocketAddress> SERVER_ADDRESS = new Entry<>(new InetSocketAddress("localhost", 6667), InetSocketAddress.class);
    static final Entry<String> SERVER_PASSWORD = new Entry<>(null, String.class);
    static final Entry<String> USER = new Entry<>("Kitteh", String.class);

    private static final Object NULL = new Object();

    private final Map<Entry<?>, Object> map = new ConcurrentHashMap<>();

    @Override
    protected Config clone() {
        Config config = new Config();
        config.map.putAll(this.map);
        return config;
    }

    /**
     * Gets a stored configuration entry.
     *
     * @param entry entry to acquire
     * @param <Type> entry type
     * @return the stored entry, or the default value if not set
     */
    <Type> Type get(Entry<Type> entry) {
        if (this.map.containsKey(entry)) {
            Object value = this.map.get(entry);
            if (!value.equals(NULL) && entry.getType().isAssignableFrom(value.getClass())) {
                @SuppressWarnings("unchecked")
                Type tValue = (Type) this.map.get(entry);
                return tValue;
            }
            return null;
        }
        return entry.getDefault();
    }

    /**
     * Sets a configuration entry.
     *
     * @param entry entry to set
     * @param value value to set for the given entry
     * @param <Type> entry type
     */
    <Type> void set(Entry<Type> entry, Type value) {
        this.map.put(entry, value != null ? value : NULL);
    }
}
@@ -2824,24 +2824,192 @@
 ng.class);%0A%0A
+    /**%0A     * Magical null value for %7B@link java.util.concurrent.ConcurrentHashMap%7D.%0A     * Must be static because this value is shared across cloned Configs.%0A     */%0A
     private 
@@ -3576,17 +3576,23 @@
  Object 
-v
+uncastV
 alue = t
@@ -3631,27 +3631,27 @@
 if (
-!value.equals(
+uncastValue != 
 NULL
-)
  && 
@@ -3683,17 +3683,23 @@
 bleFrom(
-v
+uncastV
 alue.get
@@ -3778,16 +3778,19 @@
    Type 
+cas
 tValue =
@@ -3797,35 +3797,27 @@
  (Type) 
-this.map.get(entry)
+uncastValue
 ;%0A      
@@ -3833,16 +3833,19 @@
  return 
+cas
 tValue;%0A

Clarify and improve Config