package org.springframework.cloud.service.document;

import java.net.UnknownHostException;

import org.springframework.cloud.service.AbstractServiceConnectorCreator;
import org.springframework.cloud.service.ServiceConnectorConfig;
import org.springframework.cloud.service.ServiceConnectorCreationException;
import org.springframework.cloud.service.common.MongoServiceInfo;
import org.springframework.data.authentication.UserCredentials;
import org.springframework.data.mongodb.MongoDbFactory;
import org.springframework.data.mongodb.core.SimpleMongoDbFactory;

import com.mongodb.MongoClient;
import com.mongodb.MongoClientOptions;
import com.mongodb.MongoException;
import com.mongodb.ServerAddress;
import com.mongodb.WriteConcern;

/**
 * Simplified access to creating MongoDB service objects.
 *
 * @author Ramnivas Laddad
 * @author Thomas Risberg
 *
 */
public class MongoDbFactoryCreator extends AbstractServiceConnectorCreator<MongoDbFactory, MongoServiceInfo> {
	@Override
	public MongoDbFactory create(MongoServiceInfo serviceInfo, ServiceConnectorConfig config) {
		try {
			MongoClientOptions mongoOptionsToUse = getMongoOptions((MongoDbFactoryConfig) config);
			ServerAddress serverAddress = null;
			if (serviceInfo.getPort() == -1) {
			    serverAddress = new ServerAddress(serviceInfo.getHost());
			} else {
			    serverAddress = new ServerAddress(serviceInfo.getHost(), serviceInfo.getPort());
			}
			MongoClient mongo = new MongoClient(serverAddress, mongoOptionsToUse);
            UserCredentials credentials = new UserCredentials(serviceInfo.getUserName(), serviceInfo.getPassword());
			SimpleMongoDbFactory mongoDbFactory = new SimpleMongoDbFactory(mongo, serviceInfo.getDatabase(), credentials);
			return configure(mongoDbFactory, (MongoDbFactoryConfig) config);
		} catch (UnknownHostException e) {
			throw new ServiceConnectorCreationException(e);
		} catch (MongoException e) {
			throw new ServiceConnectorCreationException(e);
		}
	}

	private MongoClientOptions getMongoOptions(MongoDbFactoryConfig config) {
		MongoClientOptions.Builder builder = MongoClientOptions.builder();

		if (config != null) {
	        if (config.getConnectionsPerHost() != null) {
	            builder.connectionsPerHost(config.getConnectionsPerHost());
	        }
	        if (config.getMaxWaitTime() != null) {
	            builder.maxWaitTime(config.getMaxWaitTime());
	        }
	        if (config.getWriteConcern() != null) {
	            builder.writeConcern(new WriteConcern(config.getWriteConcern()));
	        }
        }
		    
		return builder.build();
	}

	
	public SimpleMongoDbFactory configure(SimpleMongoDbFactory mongoDbFactory, MongoDbFactoryConfig config) {
		if (config != null && config.getWriteConcern() != null) {
			WriteConcern writeConcern = WriteConcern.valueOf(config.getWriteConcern());
			if (writeConcern != null) {
				mongoDbFactory.setWriteConcern(writeConcern);
			}
		}
		return mongoDbFactory;
	}
	
}

@@ -46,16 +46,139 @@
 ument;%0A%0A
+import java.lang.reflect.Constructor;%0Aimport java.lang.reflect.InvocationTargetException;%0Aimport java.lang.reflect.Method;%0A
 import j
@@ -207,16 +207,16 @@
 eption;%0A
-
 %0Aimport 
@@ -675,16 +675,109 @@
 Factory;
+%0Aimport org.springframework.util.ClassUtils;%0Aimport org.springframework.util.ReflectionUtils;
 %0A%0Aimport
@@ -841,16 +841,63 @@
 ptions;%0A
+import com.mongodb.MongoClientOptions.Builder;%0A
 import c
@@ -2345,37 +2345,862 @@
 r = 
-MongoClientOptions.builder();
+null;%0A%09%09%0A%09%09Method builderMethod = ClassUtils.getMethodIfAvailable(MongoClientOptions.class, %22builder%22);%0A%09%09if (builderMethod != null) %7B%0A%09%09    builder = (Builder) ReflectionUtils.invokeMethod(builderMethod, null);%0A%09%09%7D else %7B%0A%09%09    Constructor%3CBuilder%3E builderConstructor = ClassUtils.getConstructorIfAvailable(MongoClientOptions.Builder.class);%0A%09%09    try %7B%0A                builder = builderConstructor.newInstance(new Object%5B0%5D);%0A            %7D catch (InstantiationException e) %7B%0A                throw new IllegalStateException(e);%0A            %7D catch (IllegalAccessException e) %7B%0A                throw new IllegalStateException(e);%0A            %7D catch (IllegalArgumentException e) %7B%0A                throw new IllegalStateException(e);%0A            %7D catch (InvocationTargetException e) %7B%0A                throw new IllegalStateException(e);%0A            %7D%0A%09%09%7D
 %0A%0A%09%09

Fix compatibility with spring-data-mongodb 1.2.x and 1.3.x