package com.proofpoint.dbpool;

import com.google.common.base.Preconditions;
import com.google.inject.Inject;
import com.proofpoint.dbpool.H2EmbeddedDataSourceConfig.Cipher;
import org.h2.jdbcx.JdbcDataSource;
import org.h2.util.ScriptReader;

import java.io.FileReader;
import java.io.File;
import java.io.Reader;
import java.io.InputStreamReader;
import java.io.InputStream;
import java.io.FileNotFoundException;
import static java.lang.Math.ceil;
import java.sql.Connection;
import java.sql.SQLException;
import java.sql.Statement;
import static java.util.concurrent.TimeUnit.SECONDS;

public class H2EmbeddedDataSource extends ManagedDataSource
{
    @Inject
    public H2EmbeddedDataSource(H2EmbeddedDataSourceConfig config)
            throws Exception
    {
        super(createH2EmbeddedConnectionPoolDataSource(config),
                config.getMaxConnections(),
                config.getMaxConnectionWait());

        Preconditions.checkNotNull(config.getFilename());
        if (config.getFilename().isEmpty()) {
            throw new IllegalArgumentException("filename is empty");
        }

        Connection connection = getConnection();
        try {
            setConfig(connection, "CACHE_SIZE", config.getCacheSize());
            setConfig(connection, "COMPRESS_LOB", config.getCompressLob());
            setConfig(connection, "DB_CLOSE_DELAY ", "-1");

            Reader fileReader;
            String fileName = config.getInitScript();
            if (new File(fileName).exists()) {
                fileReader = new FileReader(fileName);
            } else {
                InputStream stream = getClass().getClassLoader().getResourceAsStream(fileName);
                if (stream == null) {
                    throw new FileNotFoundException(fileName);
                }
                fileReader = new InputStreamReader(stream);
            }
            try {
                ScriptReader scriptReader = new ScriptReader(fileReader);
                for (String statement = scriptReader.readStatement(); statement != null; statement = scriptReader.readStatement()) {
                    executeCommand(connection, statement);
                }
            }
            finally {
                fileReader.close();
            }

            // run last so script can contain literals
            setConfig(connection, "ALLOW_LITERALS", config.getAllowLiterals());
        }
        finally {
            closeQuietly(connection);
        }
    }

    private static JdbcDataSource createH2EmbeddedConnectionPoolDataSource(H2EmbeddedDataSourceConfig config)
            throws Exception
    {

        StringBuilder urlBuilder = new StringBuilder()
                .append("jdbc:h2:").append(config.getFilename())
                .append(";ALLOW_LITERALS=").append(config.getAllowLiterals())
                .append(";CACHE_SIZE=").append(config.getCacheSize());

        if (config.getCipher() != Cipher.NONE) {
            urlBuilder.append(";CIPHER=").append(config.getCipher());
        }

        String url = urlBuilder.toString();

        JdbcDataSource dataSource = new JdbcDataSource();
        dataSource.setURL(url);
        dataSource.setUser(config.getUsername());
        if (config.getCipher() != Cipher.NONE) {
            dataSource.setPassword(config.getFilePassword() + " " + config.getPassword());
        }
        else {
            dataSource.setPassword(config.getPassword());
        }
        dataSource.setLoginTimeout((int) ceil(config.getMaxConnectionWait().convertTo(SECONDS)));

        return dataSource;
    }

    private void setConfig(Connection connection, String name, Object value)
            throws SQLException
    {
        Statement statement = connection.createStatement();
        try {
            String command = String.format("SET %s %s", name, value);
            int count = statement.executeUpdate(command);
            if (count != 0) {
                throw new SQLException("Failed to execute command: " + command);
            }
        }
        finally {
            closeQuietly(statement);
        }
    }


    private void executeCommand(Connection connection, String command)
            throws SQLException
    {
        Statement statement = connection.createStatement();
        try {
            statement.executeUpdate(command);
        }
        finally {
            closeQuietly(statement);
        }
    }

    private static void closeQuietly(Statement statement)
    {
        try {
            statement.close();
        }
        catch (SQLException ignored) {
        }
    }

    private static void closeQuietly(Connection connection)
    {
        try {
            connection.close();
        }
        catch (SQLException ignored) {
        }
    }
}

@@ -55,28 +55,107 @@
 on.base.
-Precondition
+Charsets;%0Aimport com.google.common.base.Preconditions;%0Aimport com.google.common.io.Resource
 s;%0Aimpor
@@ -320,35 +320,8 @@
 r;%0A%0A
-import java.io.FileReader;%0A
 impo
@@ -364,70 +364,8 @@
 er;%0A
-import java.io.InputStreamReader;%0Aimport java.io.InputStream;%0A
 impo
@@ -432,16 +432,38 @@
 th.ceil;
+%0A%0Aimport java.net.URL;
 %0Aimport 
@@ -1387,39 +1387,8 @@
 );%0A%0A
-            Reader fileReader;%0A
     
@@ -1433,24 +1433,25 @@
 itScript();%0A
+%0A
             
@@ -1450,20 +1450,28 @@
         
-if (
+File file = 
 new File
@@ -1484,73 +1484,105 @@
 ame)
-.exists()) %7B%0A                fileReader = new FileReader(fileName
+;%0A            URL url;%0A            if (file.exists()) %7B%0A                url = file.toURI().toURL(
 );%0A 
@@ -1593,16 +1593,28 @@
        %7D
+%0A           
  else %7B%0A
@@ -1633,56 +1633,23 @@
     
-InputStream stream = getClass().getClassLoader()
+url = Resources
 .get
@@ -1660,16 +1660,8 @@
 urce
-AsStream
 (fil
@@ -1667,32 +1667,40 @@
 leName);%0A       
+     %7D%0A%0A
          if (str
@@ -1696,18 +1696,18 @@
     
+   
 if (
-stream
+url
  == 
@@ -1710,28 +1710,24 @@
  == null) %7B%0A
-    
             
@@ -1781,34 +1781,27 @@
             
-    %7D%0A    
+%7D%0A%0A
             
@@ -1804,65 +1804,84 @@
     
-file
 Reader 
-= new InputStreamReader(stream);%0A            %7D
+reader = Resources.newReaderSupplier(url, Charsets.UTF_8).getInput();
 %0A   
@@ -1956,21 +1956,17 @@
 tReader(
-fileR
+r
 eader);%0A
@@ -2231,13 +2231,9 @@
     
-fileR
+r
 eade

clean up code that reads init script