package net.md_5.bungee.reconnect;

import com.google.common.base.Throwables;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.HashSet;
import java.util.Set;
import java.util.logging.Level;
import net.md_5.bungee.api.ProxyServer;
import net.md_5.bungee.api.config.ServerInfo;
import net.md_5.bungee.api.connection.ProxiedPlayer;

public class SQLReconnectHandler extends AbstractReconnectManager
{

    private final Set<Connection> allConnections = new HashSet<>();
    private final ThreadLocal<Connection> connectionPool = new ThreadLocal<Connection>()
    {
        @Override
        protected Connection initialValue()
        {
            Connection con = null;
            try
            {
                con = DriverManager.getConnection( "jdbc:sqlite:bungee.sqlite" );
            } catch ( SQLException ex )
            {
                Throwables.propagate( ex );
            }

            allConnections.add( con );
            return con;
        }
    };

    public SQLReconnectHandler() throws ClassNotFoundException, SQLException
    {
        Class.forName( "org.sqlite.JDBC" );

        try ( PreparedStatement ps = connectionPool.get().prepareStatement(
                "CREATE TABLE IF NOT EXISTS players ("
                + "playerId INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,"
                + "username TEXT NOT NULL UNIQUE COLLATE NOCASE,"
                + "seen INTEGER,"
                + "server TEXT"
                + ");" ) )
        {
            ps.executeUpdate();
        }
    }

    @Override
    protected ServerInfo getStoredServer(ProxiedPlayer player)
    {
        String server = null;
        try ( PreparedStatement ps = connectionPool.get().prepareStatement( "SELECT server FROM players WHERE username = ?" ) )
        {
            ps.setString( 1, player.getName() );
            try ( ResultSet rs = ps.executeQuery() )
            {
                if ( rs.next() )
                {
                    server = rs.getString( 1 );
                } else
                {
                    try ( PreparedStatement playerUpdate = connectionPool.get().prepareStatement( "INSERT INTO players( username ) VALUES( ? )" ) )
                    {
                        playerUpdate.setString( 1, player.getName() );
                        playerUpdate.executeUpdate();
                    }
                }
            }
        } catch ( SQLException ex )
        {
            ProxyServer.getInstance().getLogger().log( Level.WARNING, "Could not load location for player " + player.getName(), ex );
        }

        return ProxyServer.getInstance().getServerInfo( server );
    }

    @Override
    public void setServer(ProxiedPlayer player)
    {

        try ( PreparedStatement ps = connectionPool.get().prepareStatement( "UPDATE players SET server = ?, seen = ? WHERE username = ?" ) )
        {
            ps.setString( 1, player.getServer().getInfo().getName() );
            ps.setInt( 2, (int) ( System.currentTimeMillis() / 1000L ) );
            ps.setString( 3, player.getName() );
            ps.executeUpdate();
        } catch ( SQLException ex )
        {
            ProxyServer.getInstance().getLogger().log( Level.WARNING, "Could not save location for player " + player.getName() + " on server " + player.getServer().getInfo().getName(), ex );
        }
    }

    @Override
    public void save()
    {
    }

    @Override
    public void close()
    {
        for ( Connection con : allConnections )
        {
            try
            {
                con.close();
            } catch ( SQLException ex )
            {
                ProxyServer.getInstance().getLogger().log( Level.WARNING, "Error closing SQLite connection", ex );
            }
        }
        allConnections.clear();
    }
}

@@ -33,50 +33,8 @@
 t;%0A%0A
-import com.google.common.base.Throwables;%0A
 impo
@@ -184,56 +184,8 @@
 on;%0A
-import java.util.HashSet;%0Aimport java.util.Set;%0A
 impo
@@ -439,20 +439,16 @@
 e final 
-Set%3C
 Connecti
@@ -453,14 +453,10 @@
 tion
-%3E allC
+ c
 onne
@@ -464,117 +464,87 @@
 tion
-s = new HashSet%3C%3E()
 ;%0A
+%0A
     p
-rivate final ThreadLocal%3CConnection%3E connectionPool = new ThreadLocal%3CConnec
+ublic SQLReconnectHandler() throws ClassNotFoundException, SQLExcep
 tion
-%3E()
 %0A   
@@ -558,535 +558,120 @@
     
-@Override%0A        protected Connection initialValue()%0A        %7B%0A            Connection con = null;%0A            try%0A            %7B%0A                con = DriverManager.getConnection( %22jdbc:sqlite:bungee.sqlite%22 );%0A            %7D catch ( SQLException ex )%0A            %7B%0A                Throwables.propagate( ex );%0A            %7D%0A%0A            allConnections.add( con );%0A            return con;%0A        %7D%0A    %7D;%0A%0A    public SQLReconnectHandler() throws ClassNotFoundException, SQLException%0A    %7B%0A        Class.forName( %22org.sqlite.JDBC
+Class.forName( %22org.sqlite.JDBC%22 );%0A        connection = DriverManager.getConnection( %22jdbc:sqlite:bungee.sqlite
 %22 );
@@ -715,34 +715,24 @@
 = connection
-Pool.get()
 .prepareStat
@@ -1240,34 +1240,24 @@
 = connection
-Pool.get()
 .prepareStat
@@ -1646,34 +1646,24 @@
 = connection
-Pool.get()
 .prepareStat
@@ -2304,18 +2304,8 @@
 tion
-Pool.get()
 .pre
@@ -2980,78 +2980,12 @@
     
-for ( Connection con : allConnections )%0A        %7B%0A            try%0A    
+try%0A
     
@@ -3002,21 +3002,24 @@
         
-    c
+connecti
 on.close
@@ -3018,28 +3018,24 @@
 on.close();%0A
-    
         %7D ca
@@ -3062,34 +3062,26 @@
 x )%0A        
-    %7B%0A    
+%7B%0A
             
@@ -3191,55 +3191,9 @@
     
-    %7D%0A        %7D%0A        allConnections.clear();
+%7D
 %0A   

Undo recent SQLite changes - might need to seek *another* DB engine - whats H2 like for concurrency?