/*******************************************************************************
* Copyright (c) 2018 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
*     IBM Corporation - initial API and implementation
*******************************************************************************/
package com.ibm.ws.lars.rest.mongo;

import javax.enterprise.context.ApplicationScoped;
import javax.enterprise.inject.Disposes;
import javax.enterprise.inject.Produces;
import javax.inject.Inject;

import com.ibm.websphere.crypto.PasswordUtil;
import com.mongodb.MongoClient;
import com.mongodb.MongoClientOptions;
import com.mongodb.MongoCredential;
import com.mongodb.ServerAddress;
import com.mongodb.WriteConcern;
import com.mongodb.DB;

import java.util.ArrayList;
import java.util.Properties;
import java.util.Vector;
import java.util.Iterator;
import java.util.Collections;
import java.util.Enumeration;
import java.util.logging.Level;
import java.util.logging.Logger;


@ApplicationScoped
public class MongoProducer {
    private static final Logger logger = Logger.getLogger(MongoProducer.class.getCanonicalName());

    private String dbName = null;

    @Produces
    public MongoClient createMongo() {
        Properties sysprops = System.getProperties();

        ArrayList<ServerAddress> servers = new ArrayList<ServerAddress>(2);

        MongoClientOptions opts;

        // look for all lars.mongo.hostname* properties, in alphabetical order
        Enumeration keysEnum = sysprops.keys();
        Vector<String> keyList = new Vector<String>();
        while(keysEnum.hasMoreElements()){
            keyList.add((String)keysEnum.nextElement());
        }
        Collections.sort(keyList);
        Iterator<String> iterator = keyList.iterator();
        while (iterator.hasNext()) {
            String prop = iterator.next();
            if(prop.startsWith("lars.mongo.hostname")) {
                String hostname = sysprops.getProperty(prop,"localhost");
                int port = Integer.parseInt(sysprops.getProperty(prop.replace("hostname","port"),"27017"));
                ServerAddress sa = new ServerAddress(hostname, port);
                servers.add(sa);
                logger.info("createMongo: found mongodb server setting "+hostname+":"+port+" from property "+prop);
            }
        }

        // add default server if none defined
        if(servers.isEmpty()) {
            ServerAddress sa = new ServerAddress("localhost", 27017);
            servers.add(sa);
            logger.info("createMongo: no mongodb servers specified, defaulting to localhost:27017");
        }

        // database name
        this.dbName = sysprops.getProperty("lars.mongo.dbname", "larsDB");

        // user and password (optional - if not set, use unauthenticated access)
        String user = sysprops.getProperty("lars.mongo.user");
        String encodedPass = sysprops.getProperty("lars.mongo.pass.encoded");

        // writeConcern (optional - if not set use the default "ACKNOWLEDGED")
        String writeConcernStr = sysprops.getProperty("lars.mongo.writeConcern");
        if(writeConcernStr != null) {
            WriteConcern wc = new WriteConcern(writeConcernStr);
            opts = new MongoClientOptions.Builder().writeConcern(wc).build();
            logger.info("createMongo: using write concern "+opts.getWriteConcern().getWString());
        } else {
            opts = new MongoClientOptions.Builder().build();
            logger.info("createMongo: using default write concern");
        }

        if(encodedPass == null) {
            logger.info("createMongo: connecting to database "+dbName+" using unauthenticated access");
            return new MongoClient(servers, opts);
        } else {
            String password = PasswordUtil.passwordDecode(encodedPass);
            MongoCredential creds = MongoCredential.createCredential(user, dbName, password.toCharArray());
            logger.info("createMongo: connecting to database "+dbName+" as user "+user);
            return new MongoClient(servers, creds, opts);
        }
    }

    @Produces
    public DB createDB(MongoClient client) {
        return client.getDB(dbName);
    }

    public void close(@Disposes MongoClient toClose) {
        toClose.close();
    }
}

@@ -685,24 +685,63 @@
 t.Produces;%0A
+import javax.annotation.PostConstruct;%0A
 import javax
@@ -1423,225 +1423,778 @@
 ll;%0A
-%0A    @Produces%0A    public MongoClient createMongo() %7B%0A        Properties sysprops = System.getProperties();%0A%0A        ArrayList%3CServerAddress%3E servers = new ArrayList%3CServerAddress%3E(2);%0A%0A        MongoClientOptions opts
+    private String user = null;%0A    private String encodedPass = null;%0A    private String requestedWriteConcern = null;%0A    private ArrayList%3CServerAddress%3E servers = new ArrayList%3CServerAddress%3E(2);%0A%0A    @PostConstruct%0A    private void readConfig() %7B%0A        Properties sysprops = System.getProperties();%0A%0A        // database name%0A        dbName = sysprops.getProperty(%22lars.mongo.dbname%22, %22larsDB%22);%0A%0A        // user and password (optional - if not set, use unauthenticated access)%0A        user = sysprops.getProperty(%22lars.mongo.user%22);%0A        encodedPass = sysprops.getProperty(%22lars.mongo.pass.encoded%22);%0A%0A        // writeConcern (optional - if not set use the default %22ACKNOWLEDGED%22)%0A        requestedWriteConcern = sysprops.getProperty(%22lars.mongo.writeConcern%22)
 ;%0A%0A 
@@ -3431,505 +3431,123 @@
  %7D%0A%0A
-        // database name
 %0A    
+%7D%0A%0A
     
-this.dbName = sysprops.getProperty(%22lars.mongo.dbname%22, %22larsDB%22);%0A%0A        // user and password (optional - if not set, use unauthenticated access)%0A        String user = sysprops.getProperty(%22lars.mongo.user%22);%0A        String encodedPass = sysprops.getProperty(%22lars.mongo.pass.encoded%22);%0A%0A        // writeConcern (optional - if not set use the default %22ACKNOWLEDGED%22)%0A        String writeConcernStr = sysprops.getProperty(%22lars.mongo.writeConcern%22);%0A        if(w
+@Produces%0A    public MongoClient createMongo() %7B%0A        MongoClientOptions opts;%0A        if(requestedW
 rite
@@ -3553,19 +3553,16 @@
 eConcern
-Str
  != null
@@ -3612,17 +3612,26 @@
 Concern(
-w
+requestedW
 riteConc
@@ -3633,19 +3633,16 @@
 eConcern
-Str
 );%0A     

Move configuration of Mongo client into post constructor