package electrosphere.server.db;

import electrosphere.logger.LoggerInterface;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Properties;

/**
 * A controller for database logic
 */
public class DatabaseController {
    
    Connection conn;
    
    public DatabaseController(){
        
    }
    
    public void connect(String path){
        String dbms = "sqlite";
        Properties connectionProps = new Properties();
        String fullAddress = "jdbc:" + dbms + ":" + path;
        try {
            conn = DriverManager.getConnection(fullAddress, connectionProps);
        } catch (SQLException ex) {
            LoggerInterface.loggerFileIO.ERROR("Failure to connect to db", ex);
            ex.printStackTrace();
        }
    }

    /**
     * Executes a write statement to the database
     * @param statementRaw The raw string for the statement
     * @param arguments The arguments to be inserted into the raw sql
     */
    public boolean executePreparedStatement(String statementRaw, Object...arguments){
        try {
            PreparedStatement statement = conn.prepareStatement(statementRaw);
            //Set arguments for prepared statements
            int argumentIndex = 1;
            for(Object currentArg : arguments){
                if(currentArg instanceof String){
                    statement.setString(argumentIndex, (String)currentArg);
                } else if(currentArg instanceof Integer){
                    statement.setInt(argumentIndex, (int)currentArg);
                } else if(currentArg instanceof Float){
                    statement.setFloat(argumentIndex, (float)currentArg);
                } else if(currentArg instanceof Boolean){
                    statement.setBoolean(argumentIndex, (boolean)currentArg);
                } else if(currentArg instanceof Long){
                    statement.setLong(argumentIndex, (long)currentArg);
                } else if(currentArg instanceof Double){
                    statement.setDouble(argumentIndex, (double)currentArg);
                }
                argumentIndex++;
            }
            //actually execute
            return statement.execute();
        } catch (SQLException ex) {
            LoggerInterface.loggerFileIO.ERROR("SQL query execution error", ex);
        }
        return false;
    }

    /**
     * Executes a query against the database
     * @param statementRaw The raw sql
     * @param arguments The arguments to be injected into the raw sql
     * @return A DatabaseResult representing the results of the query, or null if there was no result
     */
    public DatabaseResult executePreparedQuery(String statementRaw, Object...arguments){
        DatabaseResult rVal = DatabaseResult.createQuery(statementRaw);
        try {
            PreparedStatement statement = conn.prepareStatement(statementRaw);

            //Set arguments for prepared statements
            int argumentIndex = 1;
            for(Object currentArg : arguments){
                if(currentArg instanceof String){
                    statement.setString(argumentIndex, (String)currentArg);
                } else if(currentArg instanceof Integer){
                    statement.setInt(argumentIndex, (int)currentArg);
                } else if(currentArg instanceof Float){
                    statement.setFloat(argumentIndex, (float)currentArg);
                } else if(currentArg instanceof Boolean){
                    statement.setBoolean(argumentIndex, (boolean)currentArg);
                } else if(currentArg instanceof Long){
                    statement.setLong(argumentIndex, (long)currentArg);
                } else if(currentArg instanceof Double){
                    statement.setDouble(argumentIndex, (double)currentArg);
                }
                argumentIndex++;
            }
            //actually execute
            ResultSet results = statement.executeQuery();
            if(results != null){
                rVal.addResultSet(results);
            }
        } catch (SQLException ex) {
            rVal.succeeded = false;
            rVal.hasResultSet = false;
            LoggerInterface.loggerFileIO.ERROR("SQL query execution error", ex);
        }
        return rVal;
    }
    
    public boolean isConnected(){
        boolean rVal = false;
        if(conn == null){
            return false;
        }
        try {
            rVal = conn.isValid(100);
        } catch (SQLException ex) {
            LoggerInterface.loggerFileIO.ERROR("SQL error validating status of db", ex);
        }
        return rVal;
    }
    
    public void disconnect(){
        try {
            conn.close();
        } catch (SQLException ex) {
            LoggerInterface.loggerEngine.ERROR("Error disconnecting from DB", ex);
        }
    }
    
}
