package gy4simpledb.dbclasses;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.HashMap;

public abstract class DBServer {

    protected String hostname;
    protected String username;
    protected String password;
    protected String dbname;
    protected HashMap<String, Protocol> protocols;
    protected Connection conn;
    protected Statement statement;
    protected Protocol activeProtocol = null;

    public void setPassword(String password) {
        this.password = password;
    }

    public void setHostname(String hostname) {
        this.hostname = hostname;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public void setDbname(String dbname) {
        this.dbname = dbname;
    }

    public String getDbname() {
        return dbname;
    }

    public String getHostname() {
        return hostname;
    }

    public String getPassword() {
        return password;
    }

    public String getUsername() {
        return username;
    }

    public DBServer() {
        hostname = null;
        username = null;
        password = null;
        dbname = null;
        protocols = new HashMap<String, Protocol>();
        protocols.put("mysql", new Protocol("mysql", "jdbc:mysql://%hostname%/%dbname%", "com.mysql.jdbc.Driver"));
        protocols.put("emb_derby", new Protocol("emb_derby", "jdbc:derby:%dbname%;create=true", "org.apache.derby.jdbc.EmbeddedDriver"));
    }

    public void setProtocol(String name) throws Exception {
        Protocol p = protocols.get(name);
        if (p == null) {
            throw new Exception("protocol cannot be found");
        } else {
            try {
                Class.forName(p.drverName).newInstance();
            } catch (ClassNotFoundException ex) {
                throw new Exception("driver class cannot be loaded: " + ex.getMessage());
            } catch (InstantiationException ex) {
                throw new Exception("driver class cannot be loaded: " + ex.getMessage());
            } catch (IllegalAccessException ex) {
                throw new Exception("driver class cannot be loaded: " + ex.getMessage());
            }
            activeProtocol = p;
        }
    }

    public void connect() throws SQLException {
        if (activeProtocol == null) {
            throw new SQLException("no protocol loaded");
        } else {
            System.out.println(activeProtocol.connectionString(hostname, dbname));
            conn = DriverManager.getConnection(
                    activeProtocol.connectionString(hostname, dbname), username, password);
            statement = conn.createStatement(ResultSet.TYPE_SCROLL_SENSITIVE, ResultSet.CONCUR_UPDATABLE);
        }
    }

    public void closeConnection() throws SQLException {
        conn.close();
    }

    protected ResultSet executeQuery(String sql) throws SQLException {
        return statement.executeQuery(sql);
    }

    protected void executeStatement(String sql) {
        try {
            statement.execute(sql);
        } catch (SQLException ex) {
            System.err.println(ex.getMessage());
        }
    }

    protected void commit() {
        try {
            conn.commit();
        } catch (SQLException ex) {
            System.err.println(ex.getMessage());
        }
    }

    public abstract void fillData() throws SQLException;

    public abstract void commitData() throws SQLException;
}
