/**
 * JOnAS: Java(TM) Open Application Server
 * Copyright (C) 1999-2010 Bull S.A.S.
 * Contact: jonas-team@ow2.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 of the License, or (at your option) 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.ow2.jonas.resource.internal.cm.sql.cache;

import java.util.Arrays;

import org.objectweb.util.monolog.api.BasicLevel;
import org.objectweb.util.monolog.api.Logger;


/**
 * Cache Key for the 'map' policy
 * @author pelletib
 */
public class PreparedStatementMapCacheKey {


    /**
     * User
     */
    private String user = null;

    /**
     * SQL statement
     */
    private String sql = null;

    /**
     * Hashcode of this object
     */
    private int hashCode;

    /**
     * Type of result set. one of <code>ResultSet.TYPE_FORWARD_ONLY</code>,
     * <code>ResultSet.TYPE_SCROLL_INSENSITIVE</code>, or
     * <code>ResultSet.TYPE_SCROLL_SENSITIVE</code>
     */
    private int resultSetType = -1;

    /**
     * Concurrency type for result set; one of
     * <code>ResultSet.CONCUR_READ_ONLY</code> or
     * <code>ResultSet.CONCUR_UPDATABLE</code>
     */
    private int resultSetConcurrency = -1;

    /**
     * Holdability, One of the value :
     * <code>ResultSet.HOLD_CURSORS_OVER_COMMIT</code> or
     * <code>ResultSet.CLOSE_CURSORS_AT_COMMIT</code>
     */
    private int resultSetHoldability = -1;

    /**
     * A flag indicating whether auto-generated keys should be returned; one of
     * <code>Statement.RETURN_GENERATED_KEYS</code> or
     * <code>Statement.NO_GENERATED_KEYS</code>
     */
    private int autoGeneratedKeys = -1;

    /**
     * An array of column indexes indicating the columns that should be returned
     * from the inserted row or rows
     */
    private int[] columnIndexes = null;

    /**
     * An array of column names indicating the columns that should be returned
     * from the inserted row or rows
     */
    private String[] columnNames = null;

    /**
     * Logger used for traces
     */
    private final Logger logger;


    /**
     * Creates a key object.
     * @param user the user used for accessing the connection
     * @param sql a <code>String</code> object that is the SQL statement to be
     *        sent to the database; may contain one or more ? IN parameters
     * @param resultSetType a result set type; one of
     *        <code>ResultSet.TYPE_FORWARD_ONLY</code>,
     *        <code>ResultSet.TYPE_SCROLL_INSENSITIVE</code>, or
     *        <code>ResultSet.TYPE_SCROLL_SENSITIVE</code>
     * @param resultSetConcurrency a concurrency type; one of
     *        <code>ResultSet.CONCUR_READ_ONLY</code> or
     *        <code>ResultSet.CONCUR_UPDATABLE</code>
     * @param resultSetHoldability one of the following <code>ResultSet</code>
     *        constants: <code>ResultSet.HOLD_CURSORS_OVER_COMMIT</code> or
     *        <code>ResultSet.CLOSE_CURSORS_AT_COMMIT</code>
     * @param autoGeneratedKeys a flag indicating whether auto-generated keys
     *        should be returned; one of
     *        <code>Statement.RETURN_GENERATED_KEYS</code> or
     *        <code>Statement.NO_GENERATED_KEYS</code>
     * @param columnIndexes an array of column indexes indicating the columns
     *        that should be returned from the inserted row or rows
     * @param columnNames an array of column names indicating the columns that
     *        should be returned from the inserted row or rows
     * @param trace the logger to use for logging purpose
     * @param isDebugLogging if true, log the debug event in the logger
     */
    public PreparedStatementMapCacheKey(final String user, final String sql, final int resultSetType,
            final int resultSetConcurrency, final int resultSetHoldability, final int autoGeneratedKeys,
            final int[] columnIndexes, final String[] columnNames, final int hashcode, final Logger logger) {

        this.user = user;
        this.sql = sql;
        this.resultSetType = resultSetType;
        this.resultSetConcurrency = resultSetConcurrency;
        this.resultSetHoldability = resultSetHoldability;
        this.autoGeneratedKeys = autoGeneratedKeys;
        this.columnIndexes = columnIndexes;
        this.columnNames = columnNames;
        this.hashCode = hashcode;
        this.logger = logger;

    }

    /**
     * @param stmt given statement for comparing it
     * @return true if given object is equals to this current object
     */
    @Override
    public boolean equals(final Object key) {
        if (key == null) {
            return false;
        }
        // different hashcode, cannot be equals
        if (this.hashCode != key.hashCode()) {
            return false;
        }

        // if got same hashcode, try to see if cast is ok.
        if (!(key instanceof PreparedStatementMapCacheKey)) {
            return false;
        }
        PreparedStatementMapCacheKey pstmtKey = (PreparedStatementMapCacheKey) key;

        if (sql == null && pstmtKey.sql != null) {
            if (logger.isLoggable(BasicLevel.DEBUG)) {
                logger.log(BasicLevel.DEBUG, "Stmt sql: " + pstmtKey.sql + " not equal to " + sql);
            }
            return false;
        }
        if (sql != null && !sql.equals(pstmtKey.sql)) {
            if (logger.isLoggable(BasicLevel.DEBUG)) {
                logger.log(BasicLevel.DEBUG, "Stmt sql: " + pstmtKey.sql + " not equal to " + sql);
            }
            return false;
        }
        if (user == null && pstmtKey.user != null) {
            if (logger.isLoggable(BasicLevel.DEBUG)) {
                logger.log(BasicLevel.DEBUG, "Stmt user: " + pstmtKey.user + " not equal to " + user);
            }
            return false;
        }
        if (user != null && !user.equals(pstmtKey.user)) {
            if (logger.isLoggable(BasicLevel.DEBUG)) {
                logger.log(BasicLevel.DEBUG, "Stmt user: " + pstmtKey.user + " not equal to " + user);
            }
            return false;
        }
        if (resultSetType != pstmtKey.resultSetType) {
            if (logger.isLoggable(BasicLevel.DEBUG)) {
                logger.log(BasicLevel.DEBUG, "Stmt resultSetType: " + pstmtKey.resultSetType + " not equal to "
                        + resultSetType);
            }
            return false;
        }
        if (resultSetConcurrency != pstmtKey.resultSetConcurrency) {
            if (logger.isLoggable(BasicLevel.DEBUG)) {
                logger.log(BasicLevel.DEBUG, "Stmt resultSetConcurrency: " + pstmtKey.resultSetConcurrency + " not equal to "
                        + resultSetConcurrency);
            }
            return false;
        }
        if (resultSetHoldability != pstmtKey.resultSetHoldability) {
            if (logger.isLoggable(BasicLevel.DEBUG)) {
                logger.log(BasicLevel.DEBUG, "Stmt resultSetHoldability: " + pstmtKey.resultSetHoldability + " not equal to "
                        + resultSetHoldability);
            }
            return false;
        }
        if (autoGeneratedKeys != pstmtKey.autoGeneratedKeys) {
            if (logger.isLoggable(BasicLevel.DEBUG)) {
                logger.log(BasicLevel.DEBUG, "Stmt autoGeneratedKeys: " + pstmtKey.autoGeneratedKeys + " not equal to "
                        + autoGeneratedKeys);
            }
            return false;
        }
        if (!Arrays.equals(columnIndexes, pstmtKey.columnIndexes)) {
            if (logger.isLoggable(BasicLevel.DEBUG)) {
                logger.log(BasicLevel.DEBUG, "Stmt columnIndexes: " + pstmtKey.columnIndexes + " not equal to "
                        + columnIndexes);
            }
            return false;
        }
        if (!Arrays.equals(columnNames, pstmtKey.columnNames)) {
            if (logger.isLoggable(BasicLevel.DEBUG)) {
                logger.log(BasicLevel.DEBUG, "Stmt columnNames: " + pstmtKey.columnNames + " not equal to " + columnNames);
            }
            return false;
        }
        if (logger.isLoggable(BasicLevel.DEBUG)) {
            logger.log(BasicLevel.DEBUG, "Stmt found at " + this);
        }
        return true;
    }

    @Override
    public int hashCode() {
        return this.hashCode;
    }
}
