package fi.hsl.parkandride.config;

import java.sql.Connection;

import javax.annotation.PostConstruct;
import javax.annotation.Resource;
import javax.inject.Inject;
import javax.inject.Provider;
import javax.sql.DataSource;

import org.flywaydb.core.Flyway;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.PropertyPlaceholderAutoConfiguration;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Import;
import org.springframework.context.annotation.Profile;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.jdbc.datasource.DataSourceUtils;
import org.springframework.transaction.PlatformTransactionManager;

import com.mysema.query.sql.Configuration;
import com.mysema.query.sql.SQLTemplates;
import com.mysema.query.sql.postgres.PostgresQueryFactory;
import com.mysema.query.sql.spatial.PostGISTemplates;
import com.mysema.query.sql.types.EnumByNameType;
import com.zaxxer.hikari.HikariDataSource;

import fi.hsl.parkandride.core.domain.CapacityType;

@org.springframework.context.annotation.Configuration
@Import({
        PropertyPlaceholderAutoConfiguration.class,
        JdbcConfiguration.H2.class
    })
public class JdbcConfiguration {

    @org.springframework.context.annotation.Configuration
    @Profile({"!psql"})
    public static class H2 {

        public H2() {
            System.out.println("USING H2");
        }

        @Bean
        public String[] flywayLocations() {
            return new String[] { "classpath:db/common", "classpath:db/h2" };
        }

        @Bean
        public SQLTemplates sqlTemplates() {
            // TODO: use PostGISTemplates for Postgresql
            return new H2GISTemplates();
        }

    }

    @org.springframework.context.annotation.Configuration
    @Profile("psql")
    public static class Postgresql {

        public Postgresql() {
            System.out.println("USING POSTGRESQL");
        }

        @Bean
        public String[] flywayLocations() {
            return new String[] { "classpath:db/common" };
        }

        @Bean
        public SQLTemplates sqlTemplates() {
            // TODO: use PostGISTemplates for Postgresql
            return new PostGISTemplates();
        }
    }

    @Value("${jdbc.username}")
    String username;

    @Value("${jdbc.password}")
    String password;

    @Value("${jdbc.url}")
    String url;

    @Value("${jdbc.driver}")
    String driverClassName;

    @Resource String[] flywayLocations;

    @Inject SQLTemplates sqlTemplates;

    @Bean
    public PostgresQueryFactory queryFactory() {
        return new PostgresQueryFactory(querydslConfiguration(), connectionProvider());
    }

    @Bean
    public Provider<Connection> connectionProvider() {
        final DataSource dataSource = dataSource();
        return new Provider<Connection>() {
            @Override
            public Connection get() {
                Connection conn = DataSourceUtils.getConnection(dataSource);
                if (!DataSourceUtils.isConnectionTransactional(conn, dataSource)) {
                    throw new RuntimeException("Connection should be transactional");
                }
                return conn;
            }
        };
    }

    @Bean
    public DataSource dataSource() {

        try {
            HikariDataSource ds = new HikariDataSource();
            ds.setDriverClassName(driverClassName);
            ds.setUsername(username);
            ds.setPassword(password);
            ds.setJdbcUrl(url);
            return ds;
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    @Bean
    public PlatformTransactionManager transactionManager() {
        return new DataSourceTransactionManager(dataSource());
    }

    @PostConstruct
    public void dbMigration() {
        Flyway flyway = new Flyway();
        flyway.setDataSource(dataSource());
        flyway.setLocations(flywayLocations);
        flyway.migrate();
    }

    @Bean
    public Configuration querydslConfiguration() {
        Configuration conf = new Configuration(sqlTemplates);
        conf.register("CAPACITY", "CAPACITY_TYPE", new EnumByNameType<CapacityType>(CapacityType.class));
//        conf.register("FACILITY", "BORDER", H2PolygonType.DEFAULT);
        return conf;
    }

}

@@ -447,16 +447,77 @@
 n.Bean;%0A
+import org.springframework.context.annotation.Configuration;%0A
 import o
@@ -562,16 +562,16 @@
 Import;%0A
-
 import o
@@ -822,51 +822,8 @@
 r;%0A%0A
-import com.mysema.query.sql.Configuration;%0A
 impo
@@ -1125,47 +1125,8 @@
 ;%0A%0A@
-org.springframework.context.annotation.
 Conf
@@ -1282,47 +1282,8 @@
    @
-org.springframework.context.annotation.
 Conf
@@ -1749,52 +1749,13 @@
  %7D%0A%0A
+
     @
-org.springframework.context.annotation.
 Conf
@@ -3978,16 +3978,37 @@
  public 
+com.mysema.query.sql.
 Configur
@@ -4047,16 +4047,37 @@
         
+com.mysema.query.sql.
 Configur
@@ -4093,16 +4093,37 @@
 f = new 
+com.mysema.query.sql.
 Configur

Use FQN for Querydsl instead of Spring Configuration