/*
 * Copyright 2006-2007 Queplix Corp.
 *
 * Licensed under the Queplix Public License, Version 1.1.1 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.queplix.com/solutions/commercial-open-source/queplix-public-license/
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 * License for the specific language governing permissions and limitations under
 * the License.
 *
 */

package com.queplix.core.modules.eql.parser;

import com.queplix.core.error.GenericSystemException;
import com.queplix.core.jxb.entity.Efield;
import com.queplix.core.modules.config.utils.EntityHelper;
import com.queplix.core.modules.eql.EQLDateObject;
import com.queplix.core.modules.eql.EQLNullObject;
import com.queplix.core.modules.eql.EQLNumberObject;
import com.queplix.core.modules.eql.EQLObject;
import com.queplix.core.modules.eql.EQLReqEntity;
import com.queplix.core.modules.eql.EQLReqField;
import com.queplix.core.modules.eql.EQLSql;
import com.queplix.core.modules.eql.EQLStringObject;
import com.queplix.core.modules.eql.EQLTimeObject;
import com.queplix.core.modules.eql.conds.LikeCond;
import com.queplix.core.modules.eql.error.EQLException;

import java.util.ArrayList;
import java.util.List;

/**
 * <p>Base SQL builder abstract class</p>
 *
 * @author Baranov Andrey [ALB]
 * @version $Revision: 1.1.1.1 $ $Date: 2005/09/12 15:30:27 $
 */

public abstract class SQLBuilder
        extends SQLEQLPluggableModule {

// ----------------- PUBLIC CONSTANTS ----------------------

    public static final char EQL_ESCAPE_CHARACTER = LikeCond.ESCAPE_CHARACTER;

// -------------------- VARIABLES --------------------------

    // SQL query object
    protected final EQLSql eqlSql = new EQLSql();

    // List of SQL bindings
    private List sqlParameters = new ArrayList();

// -------------- PROTECTED ABSTRACT METHODS ---------------

    //
    // Get SQL values
    //

    protected abstract String getSQLValue(EQLNullObject o)
            throws EQLException;

    protected abstract String getSQLValue(EQLStringObject o)
            throws EQLException;

    protected abstract String getSQLValue(EQLNumberObject o)
            throws EQLException;

    protected abstract String getSQLValue(EQLDateObject o)
            throws EQLException;

    protected abstract String getSQLValue(EQLTimeObject o)
            throws EQLException;

// ----------------- PROTECTED METHODS ---------------------

    /**
     * Clone current builder and return child object
     *
     * @return Object child builder
     */
    public final Object createChildBuilder() {
        SQLBuilder child;
        try {
            child = (SQLBuilder) getClass().newInstance();
        } catch (Exception ex) {
            throw new GenericSystemException(ex);
        }

        // set SQL parameters to parent
        child.sqlParameters = sqlParameters;

        return child;
    }

    /**
     * Add EQLObject as SQL parameter
     *
     * @param o given EQLObject
     */
    protected void addSqlParameter(EQLObject o) {
        sqlParameters.add(o);
    }

    /**
     * Get Sql parameters
     *
     * @return array of parameters or NULL
     */
    protected EQLObject[] getSqlParameters() {
        return (sqlParameters.size() == 0) ? null:
                (EQLObject[]) sqlParameters.toArray(new EQLObject[0]);
    }

    /**
     * Get Last Sql parameter
     *
     * @return EQLObject
     */
    protected EQLObject getLastSqlParameter() {
        int size = sqlParameters.size();
        if(size == 0) {
            return null;
        } else {
            return (EQLObject) sqlParameters.get(size - 1);
        }
    }

    /**
     * Call getSQLValue() by type of <code>o</code>
     *
     * @param o EQL object
     * @return always return "?"
     * @throws EQLException
     */
    protected final String _getSQLValue(EQLObject o)
            throws EQLException {

        if(o instanceof EQLNullObject) {
            return getSQLValue((EQLNullObject) o);
        } else if(o instanceof EQLNumberObject) {
            return getSQLValue((EQLNumberObject) o);
        } else if(o instanceof EQLDateObject) {
            return getSQLValue((EQLDateObject) o);
        } else if(o instanceof EQLTimeObject) {
            return getSQLValue((EQLTimeObject) o);
        }

        //
        // For other types...
        //

        // add sql parameter
        addSqlParameter(o);

        // return '?'
        return "?";
    }

    /**
     * Get table alias
     *
     * @param reqEntity EQLReqEntity object
     * @return String alias
     */
    protected String getDbAlias(EQLReqEntity reqEntity) {
        return reqEntity.getEntity().getDbobjAlias();
    }

    /**
     * Get table name
     *
     * @param reqEntity EQLReqEntity
     * @return String
     */
    protected String getDbName(EQLReqEntity reqEntity) {
        return reqEntity.getEntity().getDbobject();
    }

    /**
     * Build full SQL table name
     *
     * @param reqEntity EQLReqEntity
     * @return String SQL table
     */
    protected String getSQLTableName(EQLReqEntity reqEntity) {
        return getDbName(reqEntity) + " " + getDbAlias(reqEntity);
    }

    /**
     * Build full SQL column name
     *
     * @param reqField EQLReqField object
     * @return String SQL column
     */
    protected String getSQLColumnName(EQLReqField reqField) {
        EQLReqEntity reqEntity = reqField.getReqEntity();
        Efield field = reqField.getField();
        return EntityHelper.getFieldFullName(getDbAlias(reqEntity),
                field.getName());
    }
}
