/**
 * JOnAS: Java(TM) Open Application Server
 * Copyright (C) 1999-2004 Bull S.A.
 * 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.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: EjbqlOrderByVisitor.java 15428 2008-10-07 11:20:29Z sauthieg $
 * --------------------------------------------------------------------------
 */
package org.ow2.jonas.lib.ejb21.sql;


import java.util.ArrayList;
import java.util.Iterator;
import java.util.Map;
import java.util.Stack;

import org.ow2.jonas.deployment.ejb.ejbql.ASTCmpPathExpression;
import org.ow2.jonas.deployment.ejb.ejbql.ASTEJBQL;
import org.ow2.jonas.deployment.ejb.ejbql.ASTOrderByClause;
import org.ow2.jonas.deployment.ejb.ejbql.ASTOrderByItem;
import org.ow2.jonas.deployment.ejb.ejbql.ASTPath;
import org.ow2.jonas.deployment.ejb.ejbql.SimpleNode;


import org.objectweb.medor.api.Field;
import org.objectweb.medor.query.api.OrderField;
import org.objectweb.medor.query.api.QueryTreeField;
import org.objectweb.medor.query.lib.BasicOrderField;

/**
 * Implementation of a visitor that creates a list of org.objectweb.medor.query.api.OrderField
 * to a given ORDER BY clause.
 * Created on Aug 27, 2003
 * @author Helene Joanin
 */
public class EjbqlOrderByVisitor extends EjbqlAbstractVisitor  {

    Map fields;
    ArrayList orderFields;

    /**
     * Constructor
     * @param ejbql root of the lexical tree of the query
     * @param fields Map with (name,QueryTreeField) pairs of all the variables appear in the query
     */
    public EjbqlOrderByVisitor(ASTEJBQL ejbql, Map _fields) throws Exception {
        orderFields = new ArrayList();
        fields = _fields;
        visit(ejbql);
    }

    /**
     * get the  that was built from visiting the lexical tree
     */
    public OrderField[] getOrderFields() {
        OrderField[] ofs = new OrderField[orderFields.size()];
        Iterator itr = orderFields.iterator();
        for (int i=0; itr.hasNext(); i++) {
            ofs[i] = (OrderField) itr.next();
        }  
        return ofs;
    }


    /**
     *  Visit child node.
     *  ORDER BY OrderByItem() (, OrderByItem() )*
     */
    public Object visit(ASTOrderByClause node, Object data) {
        visit((SimpleNode) node, data);
        return null;
    }

    /**
     *  Visit child node.
     */
    public Object visit(ASTOrderByItem node, Object data) {
        visit((SimpleNode) node, data);
        QueryTreeField qtf = (QueryTreeField) ((Stack) data).pop();
        orderFields.add(new BasicOrderField(qtf, !node.asc));
        return null;
    }

    /**
     * Push corresponding MedorField to the stack.<br>
     * cmp_path_expression ::= path
     * was in initial BNF
     * cmp_path_expression ::= {identification_variable | single_valued_cmr_path_expression}.cmp_field
     */
    public Object visit(ASTCmpPathExpression node, Object data) {
        visit((SimpleNode) node, data);
        try {
            String path = (String) ((ASTPath) ((Stack) data).pop()).value;
            // FIXME check type for cmp field
            ((Stack) data).push((Field) fields.get(path));
        } catch (Exception e) {
            throw new VisitorException(e);
        }
        return null;
    }

    /**
     * Push the Node to the stack
     */
    public Object visit(ASTPath node, Object data) {
        ((Stack) data).push(node);
        return null;
    }

}
