/*
 * Copyright 2009 Lari Natri <lari.natri@gmail.com>
 *
 *  This program is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation, either version 3 of the License, or
 *  (at your option) any later version.
 * 
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 * 
 *  You should have received a copy of the GNU General Public License
 *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */


package compid.data;

import compid.data.db_derby.DAOFactoryDerby;
import java.sql.Connection;
import java.sql.DatabaseMetaData;
import java.sql.ResultSet;
import java.sql.SQLException;

/**
 *
 * @author Lari Natri
 */
public abstract class DAOFactory {

    public static enum DBType { DERBYEMBEDDED };

    private static final DBType defaultDbType = DBType.DERBYEMBEDDED;
    private static DAOFactory instance = null;

    protected DAOFactory() {}

    public synchronized final static DAOFactory getInstance()
            throws DAOException
    {
        if(DAOFactory.instance == null) {
            throw new DAOException(DAOException.ExceptionType.NOTCONNECTED);
        }
        return DAOFactory.instance;
    }

    public synchronized final static boolean connectDB(DBType dbType,
                                                       String DbUrl,
                                                       String username,
                                                       String password,
                                                       boolean createIfNotExists)
            throws DAOException
    {
        if (DAOFactory.instance!=null) {
            DAOFactory.disconnectDB();
        }
        DAOFactory tempInst = DAOFactory.getTemporaryInstance(dbType);
        boolean created = tempInst.connect(DbUrl, username, password, createIfNotExists);
        DAOFactory.instance = tempInst;
        return created;
    }

    public synchronized final static void disconnectDB() {
        if (DAOFactory.isConnectedToDB()) {
            DAOFactory.instance.disconnect();
        }
        DAOFactory.instance = null;
    }

    public synchronized final static boolean isConnectedToDB() {
        if (DAOFactory.instance==null) return false;
        return DAOFactory.instance.isConnected();
    }

    public synchronized final static boolean dbExists(DBType dbType,
                                                      String dbUrl,
                                                      String username,
                                                      String password)
                                                      throws DAOException
    {
        boolean exists = false;
        try {
            DAOFactory inst = DAOFactory.getTemporaryInstance(dbType);
            inst.connect(dbUrl, username, password, false);
            Connection conn = inst.getConnection();
            DatabaseMetaData metaData = conn.getMetaData();

            ResultSet rs = metaData.getTables(null, null, null, new String[]{"TABLE"});
            while (rs.next()) {
                exists = true;
                System.out.println("DEBUG: table "+rs.getString("TABLE_NAME")+" exists");
            }
            conn.close();
            return exists;
        } catch (DAOException ex) {
            if (ex.getExceptionType().equals(DAOException.ExceptionType.ANOTHERINSTANCEHASBOOTED)) {
                throw ex;
            }
            System.out.println(ex.getMessage());
            return false;
        } catch (SQLException ex) {
            System.out.println(ex.getMessage());
            return false;
        }
    }

    private synchronized final static DAOFactory getTemporaryInstance(DBType dbType) {
        switch (dbType) {
            case DERBYEMBEDDED:
            default:
                return new DAOFactoryDerby();
        }
    }

    /**
     * Returns a connection object. Should return null if not connected.
     * @return database connection
     */
    public abstract Connection getConnection() throws DAOException;
    
    public abstract PeptideDAO getPeptideDAO();
    
    public abstract PeptideHitDAO getPeptideHitDAO();
    
    public abstract ProteinDAO getProteinDAO();
    
    public abstract ProteinHitDAO getProteinHitDAO();
    
    public abstract DatasetInfoDAO getDataSetInfoDAO();
    
    public abstract QueryDAO getQueryDAO();
    
    public abstract ProtHitPeptHitJoinDAO getProtHitPeptHitJoinDAO();

    public abstract ProtDbInfoDAO getProtDbInfoDAO();

    public abstract ProtSeqDAO getProtSeqDAO();

    public abstract SettingDAO getSettingDAO();

    public abstract QueryHandler getQueryHandler();

    public abstract UpdateHandler getUpdateHandler();



    /**
     * Checks database existance
     * @param url URL to search for
     * @return true if database exists, false otherwise
     */
    //protected abstract boolean dbExists(String url);

    /**
     * Connects to a database
     * @param url database location URL
     * @param username username
     * @param password password
     * @param createIfNotExists true, if database should be created if it
     *        doesn't exist
     * @return true if a new database was created (because it didn't exist),
     *         false otherwise
     * @throws DAOException if any problems
     */
    protected abstract boolean connect(String url, String username,
                                    String password, boolean createIfNotExists)
                                    throws DAOException;

    /**
     * Returns true if connected to a database, false otherwise
     * @return connected status
     */
    protected abstract boolean isConnected();

    public abstract String getDatabaseUrl();

    /**
     * Disconnects from a database. Should do nothing if not connected.
     */
    protected abstract void disconnect();


}
