package org.apache.commons.configuration;

import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.OutputStream;
import java.net.URL;
import java.util.Iterator;
import java.util.List;

import java.sql.*;
import javax.naming.*;
import javax.sql.*;

/**
 * Base class for reading an configuration file from a sql database.
 *
 * @author <a href="mailto:trygvela@ifi.uio.no">Trygve Laugstøl</a>
 * @since 0.8.2
 */
public class SQLConfiguration extends BaseConfiguration
{
    public final static boolean DEFAULT_AUTO_SAVE = true;

    private Connection con;
    private boolean autoSave;

    private SQLConfiguration(Connection con)
        throws ConfigurationException {
        this.con = con;

        autoSave = DEFAULT_AUTO_SAVE;

        load();
    }

    protected void finalize() throws Throwable {
        close();

        super.finalize();
    }

    /**
     * If true, changes are automatically persisted.
     * @param autoSave
     */
    public void setAutoSave(boolean autoSave)
    {
        this.autoSave = autoSave;
    }

    public static Configuration getConfigurationJndi(String jndiName)
        throws ConfigurationException {
        Context ctx;
        DataSource ds;

        try {
            ctx = new InitialContext();
            ds = (DataSource)ctx.lookup(jndiName);
            return new SQLConfiguration(ds.getConnection());
        }
        catch(SQLException ex) {
            throw new ConfigurationException("Exception getting configuration.", ex);
        }
        catch(NamingException ex) {
            throw new ConfigurationException("Exception getting configuration.", ex);
        }
    }

    public static Configuration getConfigurationCon(Connection con)
        throws ConfigurationException {
        return new SQLConfiguration(con);
    }

    public static Configuration getConfiguration(String url, String username, String password)
        throws ConfigurationException {
        try {
            return new SQLConfiguration(DriverManager.getConnection(url, username, password));
        }
        catch(SQLException ex) {
            throw new ConfigurationException("Exception getting configuration.", ex);
        }
    }

    public void close() {
        closeCon(con);
    }

    public final void load()
        throws ConfigurationException {
        PreparedStatement stmt = null;
        ResultSet rs = null;
        String key, value;

        try {
            stmt = con.prepareStatement(getQuerySelectAll());
            rs = stmt.executeQuery();

            while(rs.next()) {
                key = rs.getString(1);
                value = rs.getString(2);

                addProperty(key, value);
            }
        }
        catch(SQLException ex) {
            throw new ConfigurationException("Exception while loading the configuration", ex);
        }
    }

///////////////////////////////////////////////////////////////////////////////
// To be overridden

    protected String getQuerySelectAll() {
        return "select key, value from Property";
    }

///////////////////////////////////////////////////////////////////////////////
// Utils

    protected void closeCon(Connection con) {
        try {
            if(con != null)
                con.close();
        }
        catch(SQLException ex) {
        }
    }

    protected void closeStmt(Statement stmt) {
        try {
            if(stmt != null)
                stmt.close();
        }
        catch(SQLException ex) {
        }
    }

    protected void closeRs(ResultSet rs) {
        try {
            if(rs != null)
                rs.close();
        }
        catch(SQLException ex) {
        }
    }
}
