/*
 The Broad Institute
 SOFTWARE COPYRIGHT NOTICE AGREEMENT
 This software and its documentation are copyright (2006) by the
 Broad Institute/Massachusetts Institute of Technology. All rights are
 reserved.

 This software is supplied without any warranty or guaranteed support
 whatsoever. Neither the Broad Institute nor MIT can be responsible for its
 use, misuse, or functionality.
 */

package calhoun.gebo.internal.db;

import java.sql.Connection;
import java.sql.DatabaseMetaData;
import java.sql.DriverManager;
import java.util.prefs.Preferences;

import calhoun.gebo.db.ConnectionManager;
import calhoun.gebo.util.Informer;
import calhoun.gebo.util.P;
import calhoun.util.DbSession;

/**
 * Handle details of connecting to the calhoun oracle datebase.
 * 
 * @author <a href="mailto:reinhard@genome.wi.mit.edu">Reinhard Engels</a>
 */
public class CalhounConnectionManager extends ConnectionManager {

    private static Informer I = new Informer(CalhounConnectionManager.class);

    // //////////////////////////////////////////////////////////////////////////
    // Constructors.
    // //////////////////////////////////////////////////////////////////////////

    /**
     * Creates a new <code>OracleConnectionManager</code> instance.
     * 
     */
    private CalhounConnectionManager() {
        loadPreferences();
    }

    // //////////////////////////////////////////////////////////////////////////
    // Static Factory Methods.
    // //////////////////////////////////////////////////////////////////////////

    public static CalhounConnectionManager getInstance() {
        if (INSTANCE == null) {
            INSTANCE = new CalhounConnectionManager();
        }
        return INSTANCE;
    }

    // //////////////////////////////////////////////////////////////////////////
    // Accessors.
    // //////////////////////////////////////////////////////////////////////////

    /**
     * Are we connected to the oracle database?
     * 
     * @return a <code>boolean</code> value
     */
    public boolean isConnected() {
        return m_connection == null ? false : true;
    }

    public void connect() throws Exception {
        String url = "jdbc:oracle:thin:@" + m_machine + ":" + m_sid;
        DriverManager.registerDriver(new oracle.jdbc.driver.OracleDriver());
        m_connection = DriverManager.getConnection(url, getUsername(), getPassword());
        getDbSession();
        savePreferences();
    }

    public void connectAsGuest() throws Exception {
        this.setMachine("francium.broad.mit.edu:1521");
        this.setPassword("guest");
        this.setSid("annoprod");
        this.setUsername("annotguest");
        this.connect();
    }

    public Connection getConnection() {
        return m_connection;
    }

    public DbSession getDbSession() {
        if (m_dbSession == null) {
            m_dbSession = new DbSession(m_connection);
        }
        return m_dbSession;
    }

    /**
     * Machine and port on which the oracle database sits.
     * 
     * @return a <code>String</code> value
     */
    public String getMachine() {
        return m_machine;
    }

    /**
     * Return cached oracle connection metadata.
     * 
     * @return a <code>MetaData</code> value
     */
    public DatabaseMetaData getMetaData() {
        if (m_metaData == null) {
            try {
                m_metaData = m_connection.getMetaData();
            } catch (Exception e) {
                I.error("Error getting database metadata: " + e);
            }
        }
        return m_metaData;
    }

    /**
     * Logical database identifier.
     * 
     * @return a <code>String</code> value
     */
    public String getSid() {
        return m_sid;
    }

    // //////////////////////////////////////////////////////////////////////////
    // Mutators.
    // //////////////////////////////////////////////////////////////////////////

    /**
     * See getMachine.
     * 
     * @param machine
     *            a <code>String</code> value
     */
    public void setMachine(String machine) {
        m_machine = machine;
    }

    /**
     * See getSid.
     * 
     * @param sid
     *            a <code>String</code> value
     */
    public void setSid(String sid) {
        m_sid = sid;
    }


    // //////////////////////////////////////////////////////////////////////////
    // Private Methods.
    // //////////////////////////////////////////////////////////////////////////

    private void loadPreferences() {
        I.debug("loadPreferences");
        m_machine = getPrefs().get("machine", DEFAULT_MACHINE);
        m_sid = getPrefs().get("sid", DEFAULT_SID);
        m_username = getPrefs().get("username", DEFAULT_USERNAME).toLowerCase();
        m_password = getPrefs().get("obscurity", "");
        m_savePassword = getPrefs().getBoolean("saveObscurity", false);
    }

    private void savePreferences() {
        I.debug("savePreferences");
        getPrefs().put("machine", m_machine);
        getPrefs().put("sid", m_sid);
        getPrefs().put("username", m_username);
        getPrefs().putBoolean("saveObscurity", m_savePassword);
        if (m_savePassword) {
            getPrefs().put("obscurity", m_password);
        } else {
            getPrefs().remove("obscurity");
        }
    }

    // //////////////////////////////////////////////////////////////////////////
    // Data.
    // //////////////////////////////////////////////////////////////////////////

    private final static String DEFAULT_MACHINE = "francium.broad.mit.edu:1521";
    private final static String DEFAULT_SID = "annoprod";
    private final static String DEFAULT_USERNAME = "annotguest";

    private Connection m_connection;
    private DbSession m_dbSession;
    private String m_machine;
   
    private String m_sid;
    private DatabaseMetaData m_metaData;
    private static CalhounConnectionManager INSTANCE;
}
