package org.jboss.installer.core;

import org.jboss.dmr.ModelNode;

import java.nio.file.Paths;
import java.util.Arrays;

public enum DatabaseDriver {

    ENTERPRISE_DB("EnterpriseDB Advanced Server",
            "edbas",
            "com.edb",
            "com.edb.xa.PGXADataSource",
            Paths.get("modules", "com", "edb", "main").toString(),
            "java:jboss/EnterpriseDBDS",
            "com.edb.Driver",
            "jdbc:edb://SERVER_NAME:PORT_NUMBER/DATABASE_NAME"),

    IBM_DB2("IBM DB2",
            "ibmdb2",
            "com.ibm.db2",
            "com.ibm.db2.jcc.DB2XADataSource",
            Paths.get("modules", "com", "ibm", "db2", "main").toString(),
            "java:/DB2DS",
            "com.ibm.db2.jcc.DB2Driver",
            "jdbc:db2://SERVER_NAME:PORT_NUMBER/DATABASE_NAME"),

    MARIA_DB("MariaDB",
            "mariadb",
            "org.mariadb",
            "org.mariadb.jdbc.MariaDbDataSource",
            Paths.get("modules", "org", "mariadb", "main").toString(),
            "java:jboss/MariaDS",
            "org.mariadb.jdbc.Driver",
            "jdbc:mariadb://SERVER_NAME:PORT_NUMBER/DATABASE_NAME"),

    MICROSOFT_SQL_SERVER("Microsoft SQL Server",
            "sqlserver",
            "com.microsoft.sqlserver",
            "com.microsoft.sqlserver.jdbc.SQLServerXADataSource",
            Paths.get("modules", "com", "microsoft", "sqlserver", "main").toString(),
            "java:/MSSQLDS",
            "com.microsoft.sqlserver.jdbc.SQLServerDriver",
            "jdbc:sqlserver://SERVER_NAME:PORT_NUMBER;DatabaseName=DATABASE_NAME"),

    MYSQL("MySQL",
            "mysql",
            "com.mysql",
            "com.mysql.cj.jdbc.MysqlXADataSource",
            Paths.get("modules", "com", "mysql", "main").toString(),
            "java:jboss/MySqlDS",
            "com.mysql.cj.jdbc.Driver",
            "jdbc:mysql://SERVER_NAME:PORT_NUMBER/DATABASE_NAME"),

    ORACLE("Oracle",
            "oracle",
            "oracle.jdbc",
            "oracle.jdbc.xa.client.OracleXADataSource",
            Paths.get("modules", "oracle", "jdbc", "main").toString(),
            "java:/OracleDS",
            "oracle.jdbc.OracleDriver",
            "jdbc:oracle:thin:@ORACLE_HOST:PORT:ORACLE_SID"),

    POSTGRE_SQL("PostgreSQL",
            "postgresql",
            "org.postgresql",
            "org.postgresql.xa.PGXADataSource",
            Paths.get("modules", "org", "postgresql", "main").toString(),
            "java:jboss/PostgresDS",
            "org.postgresql.Driver",
            "jdbc:postgresql://SERVER_NAME:PORT_NUMBER/DATABASE_NAME"),

    SYBASE_JCONN("Sybase jConn",
            "sybase",
            "com.sybase.jconn",
            "com.sybase.jdbc4.jdbc.SybXADataSource",
            Paths.get("modules", "com", "sybase", "jconn", "main").toString(),
            "java:jboss/SybaseDS",
            "com.sybase.jdbc4.jdbc.SybDriver",
            "jdbc:sybase:NETWORK_PROTOCOL:SERVER_NAME:PORT_NUMBER/DATABASE?JCONNECT_VERSION=6");


    public static final String EXCEPTION_SORTER = "exception-sorter-class-name";
    public static final String VALID_CONNECTION_CHECKER = "valid-connection-checker-class-name";
    public static final String STALE_CONNECTION_CHECKER = "stale-connection-checker-class-name";
    private final String vendorName;
    private final String jdbcName;
    private final String moduleName;
    private final String xaClassName;
    private final String directoryStructure;
    private final String jndiName;
    private final String driverClassName;
    private final String connectionUrl;


    DatabaseDriver(String vendorName, String jdbcName, String moduleName, String xaClassName, String directoryStructure, String jndiName, String driverClassName, String connectionUrl) {
        this.vendorName = vendorName;
        this.jdbcName = jdbcName;
        this.moduleName = moduleName;
        this.xaClassName = xaClassName;
        this.directoryStructure = directoryStructure;
        this.jndiName = jndiName;
        this.driverClassName = driverClassName;
        this.connectionUrl = connectionUrl;
    }

    public static DatabaseDriver fromName(String vendorName) {
        for (DatabaseDriver databaseDriver : DatabaseDriver.values()) {
            if (databaseDriver.vendorName.equals(vendorName)) {
                return databaseDriver;
            }
        }
        throw new InstallerRuntimeException("Could not find chosen driver settings");
    }

    public static void setUniqueDatasourceElements(ModelNode modelNode, DatabaseDriver driver) {
        switch (driver) {
            case IBM_DB2:
                modelNode.get(EXCEPTION_SORTER).set("org.jboss.jca.adapters.jdbc.extensions.db2.DB2ExceptionSorter");
                modelNode.get(VALID_CONNECTION_CHECKER).set("org.jboss.jca.adapters.jdbc.extensions.db2.DB2ValidConnectionChecker");
                modelNode.get(STALE_CONNECTION_CHECKER).set("org.jboss.jca.adapters.jdbc.extensions.db2.DB2StaleConnectionChecker");
                break;
            case SYBASE_JCONN:
                modelNode.get(EXCEPTION_SORTER).set("org.jboss.jca.adapters.jdbc.extensions.sybase.SybaseExceptionSorter");
                modelNode.get(VALID_CONNECTION_CHECKER).set("org.jboss.jca.adapters.jdbc.extensions.sybase.SybaseValidConnectionChecker");
                break;
            case MYSQL:
            case MARIA_DB:
                modelNode.get(EXCEPTION_SORTER).set("org.jboss.jca.adapters.jdbc.extensions.mysql.MySQLExceptionSorter");
                modelNode.get(VALID_CONNECTION_CHECKER).set("org.jboss.jca.adapters.jdbc.extensions.mysql.MySQLValidConnectionChecker");
                break;
            case ENTERPRISE_DB:
            case POSTGRE_SQL:
                modelNode.get(EXCEPTION_SORTER).set("org.jboss.jca.adapters.jdbc.extensions.postgres.PostgreSQLExceptionSorter");
                modelNode.get(VALID_CONNECTION_CHECKER).set("org.jboss.jca.adapters.jdbc.extensions.postgres.PostgreSQLValidConnectionChecker");
                break;
            case MICROSOFT_SQL_SERVER:
                modelNode.get(VALID_CONNECTION_CHECKER).set("org.jboss.jca.adapters.jdbc.extensions.mssql.MSSQLValidConnectionChecker");
                break;
            case ORACLE:
                modelNode.get(EXCEPTION_SORTER).set("org.jboss.jca.adapters.jdbc.extensions.oracle.OracleExceptionSorter");
                modelNode.get(VALID_CONNECTION_CHECKER).set("org.jboss.jca.adapters.jdbc.extensions.oracle.OracleValidConnectionChecker");
                modelNode.get(STALE_CONNECTION_CHECKER).set("org.jboss.jca.adapters.jdbc.extensions.oracle.OracleStaleConnectionChecker");
                break;
        }
    }

    public static String[] getDriverVendorNames() {
        return Arrays.stream(DatabaseDriver.values()).map(DatabaseDriver::getVendorName).sorted().toArray(String[]::new);
    }

    public String getVendorName() {
        return vendorName;
    }

    public String getJdbcName() {
        return jdbcName;
    }

    public String getModuleName() {
        return moduleName;
    }

    public String getXaClassName() {
        return xaClassName;
    }

    public String getDirectoryStructure() {
        return directoryStructure;
    }

    public String getJndiName() {
        return jndiName;
    }

    public String getDriverClassName() {
        return driverClassName;
    }

    public String getConnectionUrl() {
        return connectionUrl;
    }
}
