/*
 * The contents of this file are subject to the terms 
 * of the Common Development and Distribution License 
 * (the "License").  You may not use this file except 
 * in compliance with the License.
 * 
 * You can obtain a copy of the license at 
 * glassfish/bootstrap/legal/CDDLv1.0.txt or 
 * https://glassfish.dev.java.net/public/CDDLv1.0.html. 
 * See the License for the specific language governing 
 * permissions and limitations under the License.
 * 
 * When distributing Covered Code, include this CDDL 
 * HEADER in each file and include the License file at 
 * glassfish/bootstrap/legal/CDDLv1.0.txt.  If applicable, 
 * add the following below this CDDL HEADER, with the 
 * fields enclosed by brackets "[]" replaced with your 
 * own identifying information: Portions Copyright [yyyy] 
 * [name of copyright owner]
 */
// Copyright (c) 1998, 2006, Oracle. All rights reserved.  
package oracle.toplink.essentials.internal.expressions;

import java.io.*;
import java.util.*;
import oracle.toplink.essentials.exceptions.*;
import oracle.toplink.essentials.expressions.Expression;
import oracle.toplink.essentials.queryframework.*;
import oracle.toplink.essentials.internal.databaseaccess.DatabaseCall;
import oracle.toplink.essentials.internal.helper.*;
import oracle.toplink.essentials.internal.sessions.AbstractSession;

/**
 * <p><b>Purpose</b>: Print DELETE statement with non trivial WHERE clause
 * <p><b>Responsibilities</b>:<ul>
 * <li> Print DELETE statement.
 * </ul>
 * @author Andrei Ilitchev
 * @since TOPLink 10.1.3
 */
public class SQLDeleteAllStatement extends SQLDeleteStatement {

    protected Expression inheritanceExpression;

    protected SQLCall selectCallForExist;
    protected String tableAliasInSelectCallForExist;

    protected SQLCall selectCallForNotExist;
    protected String tableAliasInSelectCallForNotExist;
    
    // A pair of Vectors for join expression
    protected Vector aliasedFields;
    protected Vector originalFields;
    
    public void setSelectCallForExist(SQLCall selectCallForExist) {
        this.selectCallForExist = selectCallForExist;
    }
    public SQLCall getSelectCallForExist() {
        return selectCallForExist;
    }
    public void setSelectCallForNotExist(SQLCall selectCallForNotExist) {
        this.selectCallForNotExist = selectCallForNotExist;
    }
    public SQLCall getSelectCallForNotExist() {
        return selectCallForNotExist;
    }
    public void setTableAliasInSelectCallForExist(String tableAliasInSelectCallForExist) {
        this.tableAliasInSelectCallForExist = tableAliasInSelectCallForExist;
    }
    public String getTableAliasInSelectCallForExist() {
        return tableAliasInSelectCallForExist;
    }
    public void setTableAliasInSelectCallForNotExist(String tableAliasInSelectCallForNotExist) {
        this.tableAliasInSelectCallForNotExist = tableAliasInSelectCallForNotExist;
    }
    public String getTableAliasInSelectCallForNotExist() {
        return tableAliasInSelectCallForNotExist;
    }
    public void setPrimaryKeyFieldsForAutoJoin(Collection primaryKeyFields) {
        if(primaryKeyFields instanceof Vector) {
            setOriginalFieldsForJoin((Vector)primaryKeyFields);
        } else {
            setOriginalFieldsForJoin(new Vector(primaryKeyFields));
        }
        setAliasedFieldsForJoin((Vector)getOriginalFieldsForJoin().clone());
    }
    public void setOriginalFieldsForJoin(Vector originalFields) {
        this.originalFields = originalFields;
    }
    public Vector getOriginalFieldsForJoin() {
        return originalFields;
    }
    public void setAliasedFieldsForJoin(Vector aliasedFields) {
        this.aliasedFields = aliasedFields;
    }
    public Vector getAliasedFieldsForExpression() {
        return aliasedFields;
    }
    public void setInheritanceExpression(Expression inheritanceExpression) {
        this.inheritanceExpression = inheritanceExpression;
    }
    public Expression getInheritanceExpression() {
        return inheritanceExpression;
    }

    /**
     * Append the string containing the SQL insert string for the given table.
     */
    public DatabaseCall buildCall(AbstractSession session) {
        SQLCall call = (SQLCall)super.buildCall(session);

        Writer writer = new CharArrayWriter(100);
        try {
            // because where clause is null, 
            // call.sqlString == "DELETE FROM getTable().getQualifiedName()"
            writer.write(call.getSQLString());

            boolean whereWasPrinted = true;
            if(selectCallForExist != null) {
                writer.write(" WHERE EXISTS(");
                // EXIST Example: selectCall.sqlString:
                // "SELECT t0.EMP_ID FROM EMPLOYEE t0, SALARY t1 WHERE (((t0.F_NAME LIKE 'a') AND (t1.SALARY = 0)) AND (t1.EMP_ID = t0.EMP_ID))"
                writeSelect(writer, selectCallForExist, tableAliasInSelectCallForExist, call);
                // closing bracket for EXISTS
                writer.write(")");
            } else if (inheritanceExpression != null) {
                writer.write(" WHERE ");
                // Example: (PROJ_TYPE = 'L')
                ExpressionSQLPrinter printer = new ExpressionSQLPrinter(session, getTranslationRow(), call, false);
                printer.setWriter(writer);
                printer.printExpression(inheritanceExpression);
            } else {
                whereWasPrinted = false;
            }

            if(selectCallForNotExist != null) {
                if(whereWasPrinted) {
                    writer.write(" AND");
                } else {
                    writer.write(" WHERE");
                }
                writer.write(" NOT EXISTS(");
                // NOT EXIST Example: selectCall.sqlString:
                // "SELECT t0.EMP_ID FROM EMPLOYEE t0, SALARY t1 WHERE (t1.EMP_ID = t0.EMP_ID)"
                writeSelect(writer, selectCallForNotExist, tableAliasInSelectCallForNotExist, call);
                // closing bracket for EXISTS
                writer.write(")");
            }            

            call.setSQLString(writer.toString());
            
        } catch (IOException exception) {
            throw ValidationException.fileError(exception);
        }
                
        return call;
    }
    
    protected void writeSelect(Writer writer, SQLCall selectCall, String tableAliasInSelectCall, SQLCall call) throws IOException {
        writer.write(selectCall.getSQLString());

        // join
        // Example: AND t0.EMP_ID = EMP_ID
        for(int i=0; i < originalFields.size(); i++) {
            writer.write(" AND ");
            if(tableAliasInSelectCall != null) {
                writer.write(tableAliasInSelectCall);
                writer.write('.');
            }
            writer.write(((DatabaseField)aliasedFields.elementAt(i)).getName());
            writer.write(" = ");
            writer.write(table.getQualifiedName());
            writer.write('.');
            writer.write(((DatabaseField)originalFields.elementAt(i)).getName());
        }
        
        call.getParameters().addAll(selectCall.getParameters());
        call.getParameterTypes().addAll(selectCall.getParameterTypes());            
    }
}
