package com.atlassian.bitbucket.ao;

import net.java.ao.test.jdbc.AbstractJdbcConfiguration;
import net.java.ao.test.jdbc.H2Memory;
import net.java.ao.test.jdbc.JdbcConfiguration;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class SystemPropertyJdbcConfiguration implements JdbcConfiguration {

    private static final String PROP_JDBC_PREFIX = "jdbc.";
    private static final String PROP_JDBC_USER = PROP_JDBC_PREFIX + "user";
    private static final String PROP_JDBC_PASSWORD = PROP_JDBC_PREFIX + "password";
    private static final String PROP_JDBC_SCHEMA = PROP_JDBC_PREFIX + "schema";
    static final String PROP_JDBC_URL = PROP_JDBC_PREFIX + "url";
    static final String PROTOCOL_JTDS = "jdbc:jtds:sqlserver";
    static final String PROTOCOL_SQLSERVER = "jdbc:sqlserver";

    private static final Logger log = LoggerFactory.getLogger(SystemPropertyJdbcConfiguration.class);

    private final JdbcConfiguration delegate;

    public SystemPropertyJdbcConfiguration() {
        String url = System.getProperty(PROP_JDBC_URL);
        String user = System.getProperty(PROP_JDBC_USER);
        String password = System.getProperty(PROP_JDBC_PASSWORD);
        String schema = System.getProperty(PROP_JDBC_SCHEMA);

        if (url != null && user != null && password != null) {
            if (url.startsWith(PROTOCOL_JTDS)) {
                String temp = PROTOCOL_SQLSERVER + url.substring(PROTOCOL_JTDS.length());
                log.warn("Rewrote jTDS JDBC URL to Microsoft equivalent. {} -> {}", url, temp);

                url = temp;
            }
            // Hack for SQLServer 2012. Currently ActiveObjects test module uses the default implementation of
            // net.java.ao.SchemaConfiguration.shouldManageTable() which always returns true, which in the case
            // of SQLServer 2012 picks up system tables. This does not happen at runtime as the ActiveObjects table
            // uses com.atlassian.activeobjects.ao.PrefixedSchemaConfiguration which is what the unit tests should use
            // as well
            if (schema == null && url.startsWith(PROTOCOL_SQLSERVER)) {
                schema = "dbo";
            }
            delegate = new SimpleJdbcConfiguration(url, user, password, schema);
            log.info("Using custom database configurations for AO test. url={}, user={}, password={}, schema={}",
                    url, user, password, schema);
        } else {
            //H2Memory doesn't configure DB_CLOSE_DELAY, so after the first connection is closed the schema is
            //destroyed and the tests all fail
            H2Memory h2 = new H2Memory();
            delegate = new SimpleJdbcConfiguration(h2.getUrl() + ";DB_CLOSE_DELAY=-1;DB_CLOSE_ON_EXIT=TRUE",
                    h2.getUsername(), h2.getPassword(), h2.getSchema());
            log.info("Using in-memory H2 database for AO test");
        }
    }

    @Override
    public String getPassword() {
        return delegate.getPassword();
    }

    @Override
    public String getSchema() {
        return delegate.getSchema();
    }

    @Override
    public String getUrl() {
        return delegate.getUrl();
    }

    @Override
    public String getUsername() {
        return delegate.getUsername();
    }

    @Override
    public void init() {
        delegate.init();
    }

    private static class SimpleJdbcConfiguration extends AbstractJdbcConfiguration {

        private SimpleJdbcConfiguration(String url, String user, String password, String schema) {
            super(url, user, password, schema);
        }

        @Override
        protected String getDefaultSchema() {
            return "";
        }

        @Override
        protected String getDefaultUrl() {
            return "";
        }
    }
}
