package io.advant.orm;

import io.advant.orm.internal.DBConnectionParams;
import io.advant.orm.type.DBType;

import java.io.IOException;
import java.io.InputStream;
import java.util.Enumeration;
import java.util.HashSet;
import java.util.Properties;
import java.util.Set;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 * @author Marco Romagnolo
 */
public class DBConfig {

    private static final Logger LOGGER = Logger.getLogger(DBConfig.class.getName());
    private String datasource;
    private DBType dbType;
    private String driver;
    private String host;
    private int port;
    private String database;
    private String user;
    private String password;
    private Properties properties;
    private Set<String> entities = new HashSet<>();

    public DBConfig(Properties configProps) {
        configureProperties(configProps);
    }

    public DBConfig(InputStream inputStream) {
        try {
            Properties configProps = new Properties();
            configProps.load(inputStream);
            configureProperties(configProps);
        } catch (IOException e) {
            LOGGER.log(Level.SEVERE, e.getMessage(), e);
        }
    }

    private void configureProperties(Properties configProps) {
        datasource = configProps.getProperty("datasource");
        dbType = DBType.valueOf(configProps.getProperty("db.type").toUpperCase());
        driver = dbType.getDriver();
        host = configProps.getProperty("db.host");
        port = Integer.valueOf(configProps.getProperty("db.port", "0"));
        database = configProps.getProperty("db.database");
        user = configProps.getProperty("db.user", null);
        password = configProps.getProperty("db.password", null);
        Enumeration enumKey = configProps.keys();
        while (enumKey.hasMoreElements()) {
            String key = (String) enumKey.nextElement();
            String dbProperty = "db.property.";
            if (key.startsWith(dbProperty)) {
                if (properties == null) {
                    properties = new Properties();
                }
                String value = configProps.getProperty(key);
                properties.put(key.substring(dbProperty.length()), value);
            } else if (key.startsWith("entity.")) {
                if (entities == null) {
                    entities = new HashSet<>();
                }
                String value = configProps.getProperty(key);
                entities.add(value);
            }
        }
    }

    public DBConfig(String datasource) {
        this.datasource = datasource;
    }

    public DBConfig(DBType dbType, String host, int port, String database, String user, String password) {
        this(dbType, database, user ,password);
        this.host = host;
        this.port = port;
    }

    public DBConfig(DBType dbType, String database, String user, String password) {
        this.driver = dbType.getDriver();
        this.dbType = dbType;
        this.database = database;
        this.user = user;
        this.password = password;
    }

    public DBConnectionParams getParams() {
        if (properties == null) {
            properties = new Properties();
        }
        if (user != null) {
            properties.put("user", user);
        }
        if (password != null) {
            properties.put("password", password);
        }
        return new DBConnectionParams() {

            @Override
            public String getDataSource() {
                return datasource;
            }

            @Override
            public String getUri() {
                return getDBTypeUri();
            }

            @Override
            public Properties getProperties() {
                return properties;
            }
        };
    }

    private String getDBTypeUri() {
        switch (dbType) {
            case MYSQL:
                return "jdbc:mysql://" + host + ":" + port + "/" + database;
            case POSTGRESQL:
                return "jdbc:postgresql://" + host + ":" + port + "/" + database;
            case IBMDB2:
                return "jdbc:db2://" + host + ":" + port + "/" + database;
            case MSSQL:
                return "jdbc:microsoft:sqlserver://" + host + ":" + port + "/" + database;
            case SYBASE:
                return "jdbc:jtds:sybase://" + host + ":" + port + "/" + database;
            case ORACLE:
                return "jdbc:oracle:thin:@" + host + ":" + port + ":" + database;
            case DERBY:
                return "jdbc:derby:" + database;
            case H2:
                return "jdbc:h2:" + database;
            case HSQLDB:
                return "jdbc:hsqldb:" + database;
            case SQLITE:
                return "jdbc:sqlite:" + database;
            default:
                LOGGER.log(Level.SEVERE, "DBType not known or isn't a Local connection");
                return null;
        }
    }

    public String getDatasource() {
        return datasource;
    }

    public void setDatasource(String datasource) {
        this.datasource = datasource;
    }

    public DBType getDbType() {
        return dbType;
    }

    public void setDbType(DBType dbType) {
        this.dbType = dbType;
    }

    public String getDriver() {
        return driver;
    }

    public void setDriver(String driver) {
        this.driver = driver;
    }

    public String getHost() {
        return host;
    }

    public void setHost(String host) {
        this.host = host;
    }

    public int getPort() {
        return port;
    }

    public void setPort(int port) {
        this.port = port;
    }

    public String getDatabase() {
        return database;
    }

    public void setDatabase(String database) {
        this.database = database;
    }

    public String getUser() {
        return user;
    }

    public void setUser(String user) {
        this.user = user;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    public Properties getProperties() {
        return properties;
    }

    public void setProperties(Properties properties) {
        this.properties = properties;
    }

    public Set<String> getEntities() {
        return entities;
    }

    public void setEntities(Set<String> entities) {
        this.entities = entities;
    }
}

@@ -1661,22 +1661,16 @@
 db.user%22
-, null
 );%0A     
@@ -1724,14 +1724,8 @@
 ord%22
-, null
 );%0A 
@@ -3003,32 +3003,52 @@
      this.user =
+ user == null ? %22%22 :
  user;%0A        t
@@ -3053,32 +3053,56 @@
  this.password =
+ password == null ? %22%22 :
  password;%0A    %7D

Fix User Password default value