package com.thinkaurelius.titan.diskstorage.configuration.backend;

import com.google.common.base.Preconditions;
import com.google.common.collect.Lists;
import com.thinkaurelius.titan.diskstorage.configuration.ReadConfiguration;
import com.thinkaurelius.titan.diskstorage.configuration.WriteConfiguration;
import org.apache.commons.configuration.BaseConfiguration;
import org.apache.commons.configuration.Configuration;
import org.apache.commons.lang.StringUtils;

import java.util.Iterator;
import java.util.List;

/**
 * {@link ReadConfiguration} wrapper for Apache Configuration
 *
 * @author Matthias Broecheler (me@matthiasb.com)
 */
public class CommonsConfiguration implements WriteConfiguration {

    private final Configuration config;

    public CommonsConfiguration(Configuration config) {
        Preconditions.checkArgument(config!=null);
        this.config = config;
    }

    public Configuration getCommonConfiguration() {
        return config;
    }

    @Override
    public<O> O get(String key, Class<O> datatype) {
        if (!config.containsKey(key)) return null;

        if (datatype.isArray()) {
            Preconditions.checkArgument(datatype.getComponentType()==String.class,"Only string arrays are supported: %s",datatype);
            return (O)config.getStringArray(key);
        } else if (Number.class.isAssignableFrom(datatype)) {
            return (O)config.getProperty(key);
        } else if (datatype==String.class) {
            return (O)config.getString(key);
        } else if (datatype==Boolean.class) {
            return (O)new Boolean(config.getBoolean(key));
        } else if (datatype==Object.class) {
            return (O)config.getProperty(key);
        } else throw new IllegalArgumentException("Unsupported data type: " + datatype);
    }

    @Override
    public Iterable<String> getKeys(String prefix) {
        List<String> result = Lists.newArrayList();
        Iterator<String> keys;
        if (StringUtils.isNotBlank(prefix)) keys = config.getKeys(prefix);
        else keys = config.getKeys();
        while (keys.hasNext()) result.add(keys.next());
        return result;
    }

    @Override
    public void close() {
        //Do nothing
    }

    @Override
    public <O> void set(String key, O value) {
        config.setProperty(key,value);
    }

    @Override
    public void remove(String key) {
        config.clearProperty(key);
    }

    @Override
    public WriteConfiguration clone() {
        BaseConfiguration copy = new BaseConfiguration();
        copy.copy(config);
        return new CommonsConfiguration(copy);
    }

}

@@ -291,32 +291,33 @@
 eConfiguration;%0A
+%0A
 import org.apach
@@ -458,16 +458,111 @@
 gUtils;%0A
+import org.slf4j.Logger;%0Aimport org.slf4j.LoggerFactory;%0A%0Aimport java.lang.reflect.Constructor;
 %0Aimport 
@@ -836,16 +836,120 @@
 onfig;%0A%0A
+    private static final Logger log =%0A            LoggerFactory.getLogger(CommonsConfiguration.class);%0A%0A
     publ
@@ -1579,418 +1579,1413 @@
     
-return (O)config.getProperty(key);%0A        %7D else if (datatype==String.class) %7B%0A            return (O)config.getString(key);%0A        %7D else if (datatype==Boolean.class) %7B%0A            return (O)new Boolean(config.getBoolean(key));%0A        %7D else if (datatype==Object.class) %7B%0A            return (O)config.getProperty(key);%0A        %7D else throw new IllegalArgumentException(%22Unsupported data type: %22 + datatype);
+// A properties file configuration returns Strings even for numeric%0A            // values small enough to fit inside Integer (e.g. 5000). In-memory%0A            // configuration impls seem to be able to store and return actual%0A            // numeric types rather than String%0A            //%0A            // We try to handle either case here%0A            Object o = config.getProperty(key);%0A            if (datatype.isInstance(o)) %7B%0A                return (O)o;%0A            %7D else %7B%0A                return constructFromStringArgument(datatype, o.toString());%0A            %7D%0A        %7D else if (datatype==String.class) %7B%0A            return (O)config.getString(key);%0A        %7D else if (datatype==Boolean.class) %7B%0A            return (O)new Boolean(config.getBoolean(key));%0A        %7D else if (datatype==Object.class) %7B%0A            return (O)config.getProperty(key);%0A        %7D else throw new IllegalArgumentException(%22Unsupported data type: %22 + datatype);%0A    %7D%0A%0A    private %3CO%3E O constructFromStringArgument(Class%3CO%3E datatype, String arg) %7B%0A        try %7B%0A            Constructor%3CO%3E ctor = datatype.getConstructor(String.class);%0A            return ctor.newInstance(arg);%0A        %7D catch (ReflectiveOperationException e) %7B%0A            log.error(%22Failed to parse configuration string %5C%22%7B%7D%5C%22 into type %7B%7D due to the following reflection exception%22, arg, datatype, e);%0A            throw new RuntimeException(e);%0A        %7D
 %0A   

Fix broken unchecked cast of Number config opts