package com.tinkerpop.rexster.client;

import com.tinkerpop.rexster.protocol.filter.RexProMessageFilter;
import org.apache.commons.configuration.BaseConfiguration;
import org.apache.commons.configuration.CompositeConfiguration;
import org.apache.commons.configuration.Configuration;
import org.apache.commons.configuration.ConfigurationUtils;
import org.apache.commons.configuration.MapConfiguration;
import org.apache.log4j.Logger;
import org.glassfish.grizzly.filterchain.FilterChainBuilder;
import org.glassfish.grizzly.filterchain.TransportFilter;
import org.glassfish.grizzly.nio.transport.TCPNIOTransport;
import org.glassfish.grizzly.nio.transport.TCPNIOTransportBuilder;
import org.glassfish.grizzly.strategies.SameThreadIOStrategy;

import java.util.Map;

/**
 * Creates RexsterClient instances.
 *
 * @author Stephen Mallette (http://stephen.genoprime.com)
 */
public class RexsterClientFactory {
    private static final Logger logger = Logger.getLogger(RexsterClientFactory.class);

    private static final RexsterClientFactory factory = new RexsterClientFactory();

    private static final BaseConfiguration defaultConfiguration = new BaseConfiguration() {{
        addProperty(RexsterClientTokens.CONFIG_HOSTNAME, "localhost");
        addProperty(RexsterClientTokens.CONFIG_PORT, 8184);
        addProperty(RexsterClientTokens.CONFIG_TIMEOUT_CONNECTION_MS, 8000);
        addProperty(RexsterClientTokens.CONFIG_TIMEOUT_WRITE_MS, 4000);
        addProperty(RexsterClientTokens.CONFIG_TIMEOUT_READ_MS, 16000);
        addProperty(RexsterClientTokens.CONFIG_MAX_ASYNC_WRITE_QUEUE_BYTES, 512000);
        addProperty(RexsterClientTokens.CONFIG_MESSAGE_RETRY_COUNT, 16);
        addProperty(RexsterClientTokens.CONFIG_MESSAGE_RETRY_WAIT_MS, 50);
        addProperty(RexsterClientTokens.CONFIG_DESERIALIZE_ARRAY_SIZE_LIMIT, 4194304);
        addProperty(RexsterClientTokens.CONFIG_DESERIALIZE_MAP_SIZE_LIMIT, 2097152);
        addProperty(RexsterClientTokens.CONFIG_DESERIALIZE_RAW_SIZE_LIMIT, 134217728);
        addProperty(RexsterClientTokens.CONFIG_LANGUAGE, "groovy");
    }};

    private RexsterClientFactory() {

    }

    public static RexsterClientFactory getInstance() {
        return factory;
    }

    public RexsterClient createClient() throws Exception {
        return createClient(defaultConfiguration);
    }

    public RexsterClient createClient(final String host) throws Exception {
        final BaseConfiguration specificConfiguration = new BaseConfiguration();
        specificConfiguration.addProperty(RexsterClientTokens.CONFIG_HOSTNAME, host);

        final CompositeConfiguration jointConfig = new CompositeConfiguration();
        jointConfig.addConfiguration(specificConfiguration);
        jointConfig.addConfiguration(defaultConfiguration);
        return createClient(jointConfig);
    }

    public RexsterClient createClient(final String host, final int port) throws Exception {
        final BaseConfiguration specificConfiguration = new BaseConfiguration();
        specificConfiguration.addProperty(RexsterClientTokens.CONFIG_HOSTNAME, host);
        specificConfiguration.addProperty(RexsterClientTokens.CONFIG_PORT, port);

        final CompositeConfiguration jointConfig = new CompositeConfiguration();
        jointConfig.addConfiguration(specificConfiguration);
        jointConfig.addConfiguration(defaultConfiguration);
        return createClient(jointConfig);
    }

    public RexsterClient createClient(final Map<String,Object> configuration) throws Exception {
        return createClient(new MapConfiguration(configuration));
    }

    public RexsterClient createClient(final Configuration configuration) throws Exception {
        final RexsterClientHandler handler = new RexsterClientHandler();
        final FilterChainBuilder filterChainBuilder = FilterChainBuilder.stateless();
        filterChainBuilder.add(new TransportFilter());
        filterChainBuilder.add(new RexProMessageFilter());
        filterChainBuilder.add(handler);

        final TCPNIOTransport transport = TCPNIOTransportBuilder.newInstance().build();
        transport.setIOStrategy(SameThreadIOStrategy.getInstance());
        transport.setProcessor(filterChainBuilder.build());
        transport.start();

        final RexsterClient client = new RexsterClient(configuration, transport);
        handler.setClient(client);

        logger.info(String.format("Create RexsterClient instance: [%s]", ConfigurationUtils.toString(configuration)));

        return client;
    }
}

@@ -2591,241 +2591,49 @@
     
-final CompositeConfiguration jointConfig = new CompositeConfiguration();%0A        jointConfig.addConfiguration(specificConfiguration);%0A        jointConfig.addConfiguration(defaultConfiguration);%0A        return createClient(jointConfig
+return createClient(specificConfiguration
 );%0A 
@@ -2992,241 +2992,49 @@
     
-final CompositeConfiguration jointConfig = new CompositeConfiguration();%0A        jointConfig.addConfiguration(specificConfiguration);%0A        jointConfig.addConfiguration(defaultConfiguration);%0A        return createClient(jointConfig
+return createClient(specificConfiguration
 );%0A 
@@ -3267,17 +3267,25 @@
 uration 
-c
+specificC
 onfigura
@@ -3301,32 +3301,236 @@
 ows Exception %7B%0A
+%0A        final CompositeConfiguration jointConfig = new CompositeConfiguration();%0A        jointConfig.addConfiguration(specificConfiguration);%0A        jointConfig.addConfiguration(defaultConfiguration);%0A%0A
         final Re
@@ -4128,29 +4128,27 @@
 rClient(
-configuration
+jointConfig
 , transp
@@ -4290,29 +4290,27 @@
 oString(
-configuration
+jointConfig
 )));%0A%0A  

Make it so that default settings are available to all creational methods of the RexsterClientFactory.