/**
 * JOnAS: Java(TM) Open Application Server
 * Copyright (C) 1999-2005 Bull S.A.
 * Contact: jonas-team@objectweb.org
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or any later version.
 *
 * This library 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
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307
 * USA
 *
 * --------------------------------------------------------------------------
 * $Id$
 * --------------------------------------------------------------------------
 */
package org.objectweb.jonas.jdbc;

import java.io.PrintWriter;
import java.io.Serializable;
import java.sql.Connection;
import java.util.Iterator;
import java.util.Set;

import javax.naming.InitialContext;
import javax.resource.ResourceException;
import javax.resource.spi.ConnectionManager;
import javax.resource.spi.ConnectionRequestInfo;
import javax.resource.spi.ManagedConnection;
import javax.resource.spi.ManagedConnectionFactory;
import javax.security.auth.Subject;

import org.objectweb.jonas.common.Log;
import org.objectweb.util.monolog.api.BasicLevel;
import org.objectweb.util.monolog.api.Logger;
import org.objectweb.util.monolog.api.LoggerFactory;
import org.objectweb.util.monolog.wrapper.printwriter.LoggerImpl;

/**
 * @author Eric hardesty
 */
public abstract class ManagedConnectionFactoryImpl implements ManagedConnectionFactory, Serializable {

    // Factory config data property
    MCFData mcfData = null;

    int hashcode = 0;

    PrintWriter pw;

    String logTopic = "";

    protected static final String LOGGER_FACTORY = "org.objectweb.util.monolog.loggerFactory";

    public Logger trace = null;

    /**
     * Debug level ?
     */
    private boolean isEnabledDebug = false;


    public ManagedConnectionFactoryImpl() {
        pw = null;
        mcfData = new MCFData();
    }

    /* Abstract methods, specific implementation is different
     * for each type of MCF
     */
    public abstract ManagedConnection createManagedConnection(Subject subject, ConnectionRequestInfo cxReq)
            throws ResourceException;

    public abstract boolean equals(Object obj);

    /* Common methods for each MCF type
     */
    public Object createConnectionFactory() throws ResourceException {
        return new DataSourceImpl(this, null);
    }

    public Object createConnectionFactory(ConnectionManager cxMgr) throws ResourceException {
        return new DataSourceImpl(this, cxMgr);
    }

    public void getLogger(String _logTopic) throws Exception {
        InitialContext ic = new InitialContext();

        if (trace == null || !(logTopic.equals(_logTopic))) {
            logTopic = _logTopic; // set the log topic value
            // Get the trace module:
            try {
                LoggerFactory mf = Log.getLoggerFactory();
                if (logTopic != null && logTopic.length() > 0) {
                    trace = mf.getLogger(logTopic);
                } else if (pw != null) {
                    trace = new LoggerImpl(pw);
                } else {
                    trace = mf.getLogger("org.objectweb.jonas.jdbc.RA");
                }
            } catch (Exception ex) {
                try {
                    if (pw != null) {
                        trace = new LoggerImpl(pw);
                    }
                } catch (Exception e3) {
                    throw new Exception("Cannot get logger");
                }
            }
        }
        isEnabledDebug = trace.isLoggable(BasicLevel.DEBUG);
        if (isEnabledDebug) {
            trace.log(BasicLevel.DEBUG, "getLogger(" + _logTopic + ")");
        }
    }

    public PrintWriter getLogWriter() throws ResourceException {
        return pw;
    }

    public int hashCode() {
        if (hashcode == 0) {
            hashcode = mcfData.hashCode();
            try {
                getLogger(mcfData.getMCFData(MCFData.LOGTOPIC));
            } catch (Exception ex) {
            }
        }

        return hashcode;
    }

    public ManagedConnection matchManagedConnections(Set connectionSet, Subject subject, ConnectionRequestInfo cxReq)
            throws ResourceException {
        if (isEnabledDebug) {
            trace.log(BasicLevel.DEBUG, "matchManagedConnection(" + connectionSet + "," + subject + "," + cxReq + ")");
        }
        if (connectionSet == null) {
            return null;
        }
        javax.resource.spi.security.PasswordCredential pc = Utility.getPasswordCredential(this, subject, cxReq, pw);
        Iterator it = connectionSet.iterator();
        Object obj = null;
        ManagedConnectionImpl mc = null;
        while (it.hasNext()) {
            try {
                obj = it.next();
                if (obj instanceof ManagedConnectionImpl) {
                    ManagedConnectionImpl mc1 = (ManagedConnectionImpl) obj;
                    if (pc == null && equals(mc1.mcf)) {
                        mc = mc1;
                        break;
                    }
                    if (pc != null && pc.equals(mc1.pc)) {
                        mc = mc1;
                        break;
                    }
                }
            } catch (Exception ex) {
                throw new ResourceException(ex.getMessage());
            }
        }
        if (isEnabledDebug) {
            trace.log(BasicLevel.DEBUG, "matchManagedConnection returns(" + mc + ")");
        }
        return mc;
    }

    public void setLogWriter(PrintWriter _pw) throws ResourceException {
        pw = _pw;
    }

    /* Common getter/setters */
    public String getDbSpecificMethods() {
        return mcfData.getMCFData(MCFData.DBSPECIFICMETHODS);
    }

    public void setDbSpecificMethods(String val) {
        mcfData.setMCFData(MCFData.DBSPECIFICMETHODS, val);
    }

    public String getDsClass() {
        return mcfData.getMCFData(MCFData.DSCLASS);
    }

    public void setDsClass(String val) {
        mcfData.setMCFData(MCFData.DSCLASS, val);
    }

    public String getIsolationLevel() {
        String str = mcfData.getMCFData(MCFData.ISOLATIONLEVEL);
        String retStr = "default";

        if (str.length() == 0 || str.equals("-1")) {
            return retStr;
        }

        int isolationLevel;
        try {
            isolationLevel = Integer.parseInt(str);
        } catch (Exception ex) {
            return retStr;
        }

        if (isolationLevel == Connection.TRANSACTION_SERIALIZABLE) {
            retStr = "serializable";
        } else if (isolationLevel == Connection.TRANSACTION_NONE) {
            retStr = "none";
        } else if (isolationLevel == Connection.TRANSACTION_READ_COMMITTED) {
            retStr = "read_committed";
        } else if (isolationLevel == Connection.TRANSACTION_READ_UNCOMMITTED) {
            retStr = "read_uncommitted";
        } else if (isolationLevel == Connection.TRANSACTION_REPEATABLE_READ) {
            retStr = "repeatable_read";
        }
        return retStr;
    }

    public void setIsolationLevel(String val) {
        int isolationLevel = -1;

        if (val.equals("serializable")) {
            isolationLevel = Connection.TRANSACTION_SERIALIZABLE;
        } else if (val.equals("none")) {
            isolationLevel = Connection.TRANSACTION_NONE;
        } else if (val.equals("read_committed")) {
            isolationLevel = Connection.TRANSACTION_READ_COMMITTED;
        } else if (val.equals("read_uncommitted")) {
            isolationLevel = Connection.TRANSACTION_READ_UNCOMMITTED;
        } else if (val.equals("repeatable_read")) {
            isolationLevel = Connection.TRANSACTION_REPEATABLE_READ;
        }

        mcfData.setMCFData(MCFData.ISOLATIONLEVEL, "" + isolationLevel);
    }

    public String getLoginTimeout() {
        return mcfData.getMCFData(MCFData.LOGINTIMEOUT);
    }

    public void setLoginTimeout(String val) {
        mcfData.setMCFData(MCFData.LOGINTIMEOUT, val);
    }

    public String getLogTopic() {
        return mcfData.getMCFData(MCFData.LOGTOPIC);
    }

    public void setLogTopic(String val) {
        mcfData.setMCFData(MCFData.LOGTOPIC, val);
        try {
            getLogger(val.trim());
        } catch (Exception ex) {
        }
    }

    public String getMapperName() {
        return mcfData.getMCFData(MCFData.MAPPERNAME);
    }

    public void setMapperName(String val) {
        mcfData.setMCFData(MCFData.MAPPERNAME, val);
    }

    public String getPassword() {
        return mcfData.getMCFData(MCFData.PASSWORD);
    }

    public void setPassword(String val) {
        mcfData.setMCFData(MCFData.PASSWORD, val);
    }

    public String getUser() {
        return mcfData.getMCFData(MCFData.USER);
    }

    public void setUser(String val) {
        mcfData.setMCFData(MCFData.USER, val);
    }

}