/**
 * 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$
 * --------------------------------------------------------------------------
 */
package org.ow2.jonas.lib.ejb21.sql;

import org.objectweb.medor.query.api.QueryTree;
import org.objectweb.medor.query.jorm.lib.NavigatorNodeFactory;

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

import org.ow2.jonas.deployment.ejb.ejbql.ASTAbstractSchemaName;
import org.ow2.jonas.deployment.ejb.ejbql.ASTAggregateSelectExpression;
import org.ow2.jonas.deployment.ejb.ejbql.ASTArithmeticExpression;
import org.ow2.jonas.deployment.ejb.ejbql.ASTArithmeticFactor;
import org.ow2.jonas.deployment.ejb.ejbql.ASTArithmeticLiteral;
import org.ow2.jonas.deployment.ejb.ejbql.ASTArithmeticTerm;
import org.ow2.jonas.deployment.ejb.ejbql.ASTBetweenExpression;
import org.ow2.jonas.deployment.ejb.ejbql.ASTBooleanExpression;
import org.ow2.jonas.deployment.ejb.ejbql.ASTBooleanLiteral;
import org.ow2.jonas.deployment.ejb.ejbql.ASTCmpPathExpression;
import org.ow2.jonas.deployment.ejb.ejbql.ASTCollectionMemberDeclaration;
import org.ow2.jonas.deployment.ejb.ejbql.ASTCollectionMemberExpression;
import org.ow2.jonas.deployment.ejb.ejbql.ASTCollectionValuedPathExpression;
import org.ow2.jonas.deployment.ejb.ejbql.ASTComparisonExpression;
import org.ow2.jonas.deployment.ejb.ejbql.ASTConditionalExpression;
import org.ow2.jonas.deployment.ejb.ejbql.ASTConditionalFactor;
import org.ow2.jonas.deployment.ejb.ejbql.ASTConditionalTerm;
import org.ow2.jonas.deployment.ejb.ejbql.ASTDatetimeExpression;
import org.ow2.jonas.deployment.ejb.ejbql.ASTEJBQL;
import org.ow2.jonas.deployment.ejb.ejbql.ASTEmptyCollectionComparisonExpression;
import org.ow2.jonas.deployment.ejb.ejbql.ASTEntityBeanExpression;
import org.ow2.jonas.deployment.ejb.ejbql.ASTFloatingPointLiteral;
import org.ow2.jonas.deployment.ejb.ejbql.ASTFromClause;
import org.ow2.jonas.deployment.ejb.ejbql.ASTFunctionsReturningNumerics;
import org.ow2.jonas.deployment.ejb.ejbql.ASTFunctionsReturningStrings;
import org.ow2.jonas.deployment.ejb.ejbql.ASTIdentificationVariable;
import org.ow2.jonas.deployment.ejb.ejbql.ASTIdentifier;
import org.ow2.jonas.deployment.ejb.ejbql.ASTInExpression;
import org.ow2.jonas.deployment.ejb.ejbql.ASTInputParameter;
import org.ow2.jonas.deployment.ejb.ejbql.ASTIntegerLiteral;
import org.ow2.jonas.deployment.ejb.ejbql.ASTLikeExpression;
import org.ow2.jonas.deployment.ejb.ejbql.ASTLimitClause;
import org.ow2.jonas.deployment.ejb.ejbql.ASTLimitExpression;
import org.ow2.jonas.deployment.ejb.ejbql.ASTLiteral;
import org.ow2.jonas.deployment.ejb.ejbql.ASTNullComparisonExpression;
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.ASTRangeVariableDeclaration;
import org.ow2.jonas.deployment.ejb.ejbql.ASTSelectClause;
import org.ow2.jonas.deployment.ejb.ejbql.ASTSelectExpression;
import org.ow2.jonas.deployment.ejb.ejbql.ASTSingleValuedCmrPathExpression;
import org.ow2.jonas.deployment.ejb.ejbql.ASTSingleValuedPathExpression;
import org.ow2.jonas.deployment.ejb.ejbql.ASTStringExpression;
import org.ow2.jonas.deployment.ejb.ejbql.ASTStringLiteral;
import org.ow2.jonas.deployment.ejb.ejbql.ASTWhereClause;
import org.ow2.jonas.deployment.ejb.ejbql.EJBQLVisitor;
import org.ow2.jonas.deployment.ejb.ejbql.SimpleNode;

/**
 * Base class with visitor utility class and default implementation of
 * visit methods
 * Created on Sep 12, 2002
 * @author Christophe Ney  [cney@batisseurs.com]: Initial developer
 * @author Helene Joanin: Add the toString() method to IdValue.
 * @author Helene Joanin: Add some utility methods as endsWith(), basePath().
 * @author Helene Joanin: Take into account the ORDER BY clause.
 * @author Helene Joanin: Take into account the EJBQL version 2.1 syntax.
 */
public class EjbqlAbstractVisitor implements EJBQLVisitor {

    /**
     * Values associated with each declared identifiers
     */
    protected class IdValue {
        /**
         * Paths used in the select and where clause starting with the corresponding id
         */
        private ArrayList paths = null;

        /**
         * abstract schema name or collection values path
         */
        private String[] name = null;

        /**
         * The query tree that corresponds to the id and the paths
         */
        private QueryTree qt = null;

        /**
         * Create an IdVAlue for the given path
         * @param pathName an abstract schema name or collection values path
         */
        public IdValue(String pathName) {
            this();
            name = splitPath(pathName);
        }

        /**
         * Default constructor
         */
        public IdValue() {
            paths = new ArrayList();
        }

        /**
         * @return the name
         */
        public String [] getName() {
            return name;
        }

        /**
         * @param name the abstract schema name or collection values path
         */
        public void setName(String [] name) {
            this.name = name;
        }

        /**
         * add a path (if it's not already declared)
         * @param path the path to add
         */
        public void addPath(String path) {
            if (!paths.contains(path)) {
                paths.add(path);
            }
        }

        /**
         * @param idx index of the path
         * @return return the splited path of the specified position
         */
        public String[] getSplitedPath(int idx) {
            return splitPath((String) paths.get(idx));
        }

        /**
         * @param idx index of the path
         * @return return the merged path of the specified position
         */
        public String getMergedPath(int idx) {
            return (String) paths.get(idx);
        }

        /**
         * @return the number of declared path
         */
        public int getDeclaredPathLength() {
            return paths.size();
        }

        /**
         * @return the associated QueryTree
         */
        public QueryTree getQueryTree() {
            return qt;
        }

        /**
         * @param qt QueryTree
         */
        public void setQueryTree(QueryTree qt) {
            this.qt = qt;
        }

        /**
         * @return a string representation for debug
         */
        public String toString() {
            StringBuffer sb = new StringBuffer();
            sb = sb.append("(paths=[");
            Iterator ip = paths.iterator();
            while (ip.hasNext()) {
                sb = sb.append((String) ip.next() + ",");
            }
            if (name == null) {
                sb = sb.append("],name=null");
            } else {
                sb = sb.append("],name=");
                for (int i = 0; i < name.length; i++) {
                    sb = sb.append(name[i] + ".");
                }
            }
            if (qt == null) {
                sb = sb.append(",qt=null)");
            } else {
                sb = sb.append(",qt!=null)");
            }
            return sb.toString();
        }
    }

    /**
     * Runtime Exception used to wrap exceptions thrown in visit methods
     */
    protected class VisitorException extends RuntimeException {

        Exception nestedException;

        VisitorException(Exception nestedException) {
            this.nestedException = nestedException;
        }

        Exception getNestedException() {
            return nestedException;
        }
    }

    /**
     * split a dot separated path into tokens
     * @param path the input path
     * @return the splitted path
     */
    protected String[] splitPath(String path) {
        StringTokenizer st = new StringTokenizer(path, ".");
        String[] ret = new String[st.countTokens()];
        for (int i = 0; i < ret.length; i++) {
            ret[i] = st.nextToken();
        }
        return ret;
    }

    /**
     * @param path the input path
     * @param begin the beginning index
     * @param length the length
     * @return the merge of the tokens (from the begin index to the (begin+length) index into a dot separated path
     */
    protected String mergePath(String[] path, int begin, int length) {
        if (length == 0) {
            return "";
        }
        StringBuffer ret = new StringBuffer();
        for (int i = begin; i < (begin + length); i++) {
            ret.append(path[i]);
            ret.append('.');
        }
        ret.deleteCharAt(ret.length() - 1);
        return ret.toString();
    }

    /**
     * @param path the input path
     * @return the merge tokens into a dot separated path
     */
    protected String mergePath(String[] path) {
        return (mergePath(path, 0, path.length));
    }

    /**
     * @param path the input path
     * @param suffix the input suffix
     * @return true if the last token of the path is equal to the suffix.
     */
    protected boolean endsWith(String[] path, String suffix) {
        return (suffix.equals(path[path.length - 1]));
    }

    /**
     * merge the first tokens into a dot separated path.
     * (The last token is left)
     * @param path the input path
     * @return the base path
     */
    protected String[] basePath(String[] path) {
        String[] base = new String[path.length - 1];
        for (int i = 0; i < path.length - 1; i++) {
            base[i] = new String(path[i]);
        }
        return base;
    }

    /**
     * Visit method to call from constructor.
     * Child node visitors get a <code>java.util.Stack</code> as data parameter.
     * @param node the node to visit
     * @return the stack
     * @throws Exception any nested exception thrown from other visit method
     */
    public Object visit(SimpleNode node) throws Exception {
        try {
            return visit((SimpleNode) node, new Stack());
        } catch (VisitorException e) {
            throw e.getNestedException();
        }
    }

    /**
     * Generic visit method that traverses all child nodes
     * @param node the node to visit
     * @param data the current stack
     * @return the stack
     */
    public Object visit(SimpleNode node, Object data) {
        return node.childrenAccept(this, data);
    }

    /**
     * null implementation of the visit method for the corresponding parameter type
     * @param node the node to visit
     * @param data the current stack
     * @return null
     */
    public Object visit(ASTEJBQL node, Object data) {
        return null;
    }

    /**
     * null implementation of the visit method for the corresponding parameter type
     * @param node the node to visit
     * @param data the current stack
     * @return null
     */
    public Object visit(ASTFromClause node, Object data) {
        return null;
    }

    /**
     * null implementation of the visit method for the corresponding parameter type
     * @param node the node to visit
     * @param data the current stack
     * @return null
     */
    public Object visit(ASTCollectionMemberDeclaration node, Object data) {
        return null;
    }

    /**
     * null implementation of the visit method for the corresponding parameter type
     * @param node the node to visit
     * @param data the current stack
     * @return null
     */
    public Object visit(ASTRangeVariableDeclaration node, Object data) {
        return null;
    }

    /**
     * null implementation of the visit method for the corresponding parameter type
     * @param node the node to visit
     * @param data the current stack
     * @return null
     */
    public Object visit(ASTSingleValuedPathExpression node, Object data) {
        return null;
    }

    /**
     * null implementation of the visit method for the corresponding parameter type
     * @param node the node to visit
     * @param data the current stack
     * @return null
     */
    public Object visit(ASTCmpPathExpression node, Object data) {
        return null;
    }

    /**
     * null implementation of the visit method for the corresponding parameter type
     * @param node the node to visit
     * @param data the current stack
     * @return null
     */
    public Object visit(ASTSingleValuedCmrPathExpression node, Object data) {
        return null;
    }

    /**
     * null implementation of the visit method for the corresponding parameter type
     * @param node the node to visit
     * @param data the current stack
     * @return null
     */
    public Object visit(ASTCollectionValuedPathExpression node, Object data) {
        return null;
    }

    /**
     * null implementation of the visit method for the corresponding parameter type
     * @param node the node to visit
     * @param data the current stack
     * @return null
     */
    public Object visit(ASTSelectClause node, Object data) {
        return null;
    }

    /**
     * null implementation of the visit method for the corresponding parameter type
     * @param node the node to visit
     * @param data the current stack
     * @return null
     */
    public Object visit(ASTSelectExpression node, Object data) {
        return null;
    }

    /**
     * null implementation of the visit method for the corresponding parameter type
     * @param node the node to visit
     * @param data the current stack
     * @return null
     */
    public Object visit(ASTAggregateSelectExpression node, Object data) {
        return null;
    }

    /**
     * null implementation of the visit method for the corresponding parameter type
     * @param node the node to visit
     * @param data the current stack
     * @return null
     */
    public Object visit(ASTOrderByClause node, Object data) {
        return null;
    }

    /**
     * null implementation of the visit method for the corresponding parameter type
     * @param node the node to visit
     * @param data the current stack
     * @return null
     */
    public Object visit(ASTOrderByItem node, Object data) {
        return null;
    }

    /**
     * null implementation of the visit method for the corresponding parameter type
     * @param node the node to visit
     * @param data the current stack
     * @return null
     */
    public Object visit(ASTLimitClause node, Object data) {
        return null;
    }

    /**
     * null implementation of the visit method for the corresponding parameter type
     * @param node the node to visit
     * @param data the current stack
     * @return null
     */
    public Object visit(ASTLimitExpression node, Object data) {
        return null;
    }

    /**
     * null implementation of the visit method for the corresponding parameter type
     * @param node the node to visit
     * @param data the current stack
     * @return null
     */
    public Object visit(ASTWhereClause node, Object data) {
        return null;
    }

    /**
     * null implementation of the visit method for the corresponding parameter type
     * @param node the node to visit
     * @param data the current stack
     * @return null
     */
    public Object visit(ASTConditionalExpression node, Object data) {
        return null;
    }

    /**
     * null implementation of the visit method for the corresponding parameter type
     * @param node the node to visit
     * @param data the current stack
     * @return null
     */
    public Object visit(ASTConditionalTerm node, Object data) {
        return null;
    }

    /**
     * null implementation of the visit method for the corresponding parameter type
     * @param node the node to visit
     * @param data the current stack
     * @return null
     */
    public Object visit(ASTConditionalFactor node, Object data) {
        return null;
    }

    /**
     * null implementation of the visit method for the corresponding parameter type
     * @param node the node to visit
     * @param data the current stack
     * @return null
     */
    public Object visit(ASTBetweenExpression node, Object data) {
        return null;
    }

    /**
     * null implementation of the visit method for the corresponding parameter type
     * @param node the node to visit
     * @param data the current stack
     * @return null
     */
    public Object visit(ASTInExpression node, Object data) {
        return null;
    }

    /**
     * null implementation of the visit method for the corresponding parameter type
     * @param node the node to visit
     * @param data the current stack
     * @return null
     */
    public Object visit(ASTLikeExpression node, Object data) {
        return null;
    }

    /**
     * null implementation of the visit method for the corresponding parameter type
     * @param node the node to visit
     * @param data the current stack
     * @return null
     */
    public Object visit(ASTNullComparisonExpression node, Object data) {
        return null;
    }

    /**
     * null implementation of the visit method for the corresponding parameter type
     * @param node the node to visit
     * @param data the current stack
     * @return null
     */
    public Object visit(ASTEmptyCollectionComparisonExpression node, Object data) {
        return null;
    }

    /**
     * null implementation of the visit method for the corresponding parameter type
     * @param node the node to visit
     * @param data the current stack
     * @return null
     */
    public Object visit(ASTCollectionMemberExpression node, Object data) {
        return null;
    }

    /**
     * null implementation of the visit method for the corresponding parameter type
     * @param node the node to visit
     * @param data the current stack
     * @return null
     */
    public Object visit(ASTComparisonExpression node, Object data) {
        return null;
    }

    /**
     * null implementation of the visit method for the corresponding parameter type
     * @param node the node to visit
     * @param data the current stack
     * @return null
     */
    public Object visit(ASTArithmeticExpression node, Object data) {
        return null;
    }

    /**
     * null implementation of the visit method for the corresponding parameter type
     * @param node the node to visit
     * @param data the current stack
     * @return null
     */
    public Object visit(ASTIntegerLiteral node, Object data) {
        return null;
    }

    /**
     * null implementation of the visit method for the corresponding parameter type
     * @param node the node to visit
     * @param data the current stack
     * @return null
     */
    public Object visit(ASTFloatingPointLiteral node, Object data) {
        return null;
    }

    /**
     * null implementation of the visit method for the corresponding parameter type
     * @param node the node to visit
     * @param data the current stack
     * @return null
     */
    public Object visit(ASTArithmeticTerm node, Object data) {
        return null;
    }

    /**
     * null implementation of the visit method for the corresponding parameter type
     * @param node the node to visit
     * @param data the current stack
     * @return null
     */
    public Object visit(ASTArithmeticFactor node, Object data) {
        return null;
    }

    /**
     * null implementation of the visit method for the corresponding parameter type
     * @param node the node to visit
     * @param data the current stack
     * @return null
     */
    public Object visit(ASTStringExpression node, Object data) {
        return null;
    }

    /**
     * null implementation of the visit method for the corresponding parameter type
     * @param node the node to visit
     * @param data the current stack
     * @return null
     */
    public Object visit(ASTDatetimeExpression node, Object data) {
        return null;
    }

    /**
     * null implementation of the visit method for the corresponding parameter type
     * @param node the node to visit
     * @param data the current stack
     * @return null
     */
    public Object visit(ASTBooleanExpression node, Object data) {
        return null;
    }

    /**
     * null implementation of the visit method for the corresponding parameter type
     * @param node the node to visit
     * @param data the current stack
     * @return null
     */
    public Object visit(ASTEntityBeanExpression node, Object data) {
        return null;
    }

    /**
     * null implementation of the visit method for the corresponding parameter type
     * @param node the node to visit
     * @param data the current stack
     * @return null
     */
    public Object visit(ASTFunctionsReturningStrings node, Object data) {
        return null;
    }

    /**
     * null implementation of the visit method for the corresponding parameter type
     * @param node the node to visit
     * @param data the current stack
     * @return null
     */
    public Object visit(ASTFunctionsReturningNumerics node, Object data) {
        return null;
    }

    /**
     * null implementation of the visit method for the corresponding parameter type
     * @param node the node to visit
     * @param data the current stack
     * @return null
     */
    public Object visit(ASTAbstractSchemaName node, Object data) {
        return null;
    }

    /**
     * null implementation of the visit method for the corresponding parameter type
     * @param node the node to visit
     * @param data the current stack
     * @return null
     */
    public Object visit(ASTIdentificationVariable node, Object data) {
        return null;
    }

    /**
     * null implementation of the visit method for the corresponding parameter type
     * @param node the node to visit
     * @param data the current stack
     * @return null
     */
    public Object visit(ASTIdentifier node, Object data) {
        return null;
    }

    /**
     * null implementation of the visit method for the corresponding parameter type
     * @param node the node to visit
     * @param data the current stack
     * @return null
     */
    public Object visit(ASTPath node, Object data) {
        return null;
    }

    /**
     * null implementation of the visit method for the corresponding parameter type
     * @param node the node to visit
     * @param data the current stack
     * @return null
     */

    public Object visit(ASTLiteral node, Object data) {
        return null;
    }

    /**
     * null implementation of the visit method for the corresponding parameter type
     * @param node the node to visit
     * @param data the current stack
     * @return null
     */
    public Object visit(ASTStringLiteral node, Object data) {
        return null;
    }

    /**
     * null implementation of the visit method for the corresponding parameter type
     * @param node the node to visit
     * @param data the current stack
     * @return null
     */
    public Object visit(ASTArithmeticLiteral node, Object data) {
        return null;
    }

    /**
     * null implementation of the visit method for the corresponding parameter type
     * @param node the node to visit
     * @param data the current stack
     * @return null
     */
    public Object visit(ASTBooleanLiteral node, Object data) {
        return null;
    }

    /**
     * null implementation of the visit method for the corresponding parameter type
     * @param node the node to visit
     * @param data the current stack
     * @return null
     */
    public Object visit(ASTInputParameter node, Object data) {
        return null;
    }
}
