/*
 * $Header: /home/cvspublic/jakarta-slide/proposals/tamino/src/store/org/apache/slide/store/tamino/datastore/XPathExpression.java,v 1.3 2004/07/30 06:51:54 ozeigermann Exp $
 * $Revision: 1.3 $
 * $Date: 2004/07/30 06:51:54 $
 *
 * ====================================================================
 *
 * Copyright 1999-2004 The Apache Software Foundation.
 *
 * Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0
 *
 * 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 org.apache.slide.store.tamino.datastore;

import com.softwareag.tamino.db.api.accessor.TQuery;
import java.util.StringTokenizer;


/**
 * Base class for generating instances of TXPath
 *
 * @author martin.wallmer@softwareag.com
 * @version $Revision: 1.3 $
 */
public class XPathExpression {
    // options to create a TQuery:
    private static final int           NORMAL_QUERY = 0;
    private static final int      INO_EXPLAIN_QUERY = 1;
    private static final int INO_EXPLAIN_TREE_QUERY = 2;
    private static final int INO_EXPLAIN_PATH_QUERY = 3;
    
    /** the character that serves as a placeholder for parameters in the template */
    private final String placeholder;
    
    /** the raw xpath expression with placeholders for the parameters*/
    private final String template;
    
    private int numberOfParameters = -1;
    private String [] parameters;
    private boolean startsWithParam = false;
    
    
    /**
     * creates an XPathExpression with the default placeholder.
     *
     * @pre        (template != null)
     * @post
     *
     * @param      template the template for this expression
     *
     */
    public XPathExpression (String template) {
        this (template, "?");
    }
    
    /**
     * creates an XPathExpression using a specific placeholder
     *
     * @pre        (template != null)
     * @pre        (placeholder != null)
     * @post       true
     *
     * @param      template the template for this expression
     * @param      placeholder for the parameters
     */
    private XPathExpression (String template, String placeholder) {
        this.template = template;
        this.placeholder = placeholder;

        int pos = 0;
        
        // count number of paramters
        do {
            pos = template.indexOf (placeholder, pos) + 1;
            if (pos == 1)
                startsWithParam = true;
            
            numberOfParameters++;
        } while (pos != 0);
        parameters = new String [numberOfParameters];
    }

    /**
     * Sets the parameter in the query.
     *
     * @pre        (template != null)
     * @post
     *
     * @param      index index of the param
     * @param      param name of the param
     *
     */
    public void setParameter (int index, String param) {
        parameters [index] = param;
    }
    
    
    /**
     * Check for not allowed characters in the string and masks them.
     * Currently only " is checked.
     *
     * @param    s                   the string to check
     *
     * @return   either the unchanged string or the masked string
     */
    public static String mask (String s) {
        String result = new String ();
        
        
        StringTokenizer st = new StringTokenizer (s, "\"", true);
        while (st.hasMoreTokens()) {
            result = result + st.nextToken();
            if (st.hasMoreTokens()) {
                String delim = st.nextToken();
                if (delim.equals ("\""))
                    result = result + "&quot;";
            }
        }
        
        return result;
    }
    
    
    /**
     * creates a TXpath object
     *
     * @return     the new TXpath object
     */
    public TQuery getTQuery() {
        return getTQuery(NORMAL_QUERY);
    }
    
    /**
     * creates a TXpath object with ino:explain
     *
     * @return     the new TXpath object
     */
    public TQuery getTQueryWithInoExplain() {
        return getTQuery(INO_EXPLAIN_QUERY);
    }
    
    /**
     * creates a TXpath object with ino:explain and option "path"
     *
     * @return     the new TXpath object
     */
    public TQuery getTQueryWithInoExplainPath() {
        return getTQuery(INO_EXPLAIN_PATH_QUERY);
    }
    
    /**
     * creates a TXpath object with ino:explain and option "tree"
     *
     * @return     the new TXpath object
     */
    public TQuery getTQueryWithInoExplainTree() {
        return getTQuery(INO_EXPLAIN_TREE_QUERY);
    }
    
    /**
     * creates a TXpath object
     *
     * @pre        parameters[] does not contain null
     * @post
     * @param      option   indicate how the query should be prepared
     * @return     the new TXpath object
     */
    private TQuery getTQuery (int option) {
        String queryAsString = getQueryAsString (option);
        
        return  TQuery.newInstance (queryAsString);
    }

    /**
     * Method getQueryAsString
     *
     * @param    option           NORMAL_QUERY, INO_EXPLAIN_xxx
     *
     * @return   this expression as xpath string
     *
     * @throws   IllegalArgumentException
     *
     */
    private String getQueryAsString (int option)
        throws IllegalArgumentException
    {
        StringBuffer sb = new StringBuffer ();
        StringTokenizer st = new StringTokenizer (template, placeholder);
        
        int i = 0;
        if (startsWithParam) {
            if (parameters [i] == null)
                throw new IllegalArgumentException ("parameter " + i + " not set");
            sb.append (parameters [i++]);
        }
        
        
        while (st.hasMoreTokens()) {
            sb.append (st.nextToken());
            
            if (i < numberOfParameters) {
                if (parameters [i] == null)
                    throw new IllegalArgumentException ("parameter " + i + " not set");
                
                sb.append (parameters [i++]);
            }
        }
        
        if ( option != NORMAL_QUERY ) {
            // prepare logging of ino:explain information:
            sb.insert(0, "ino:explain(");
            if ( option == INO_EXPLAIN_PATH_QUERY ) {
                sb.append(",\"path\"");
            } else if ( option == INO_EXPLAIN_TREE_QUERY ) {
                sb.append(",\"tree\"");
            }
            sb.append(")");
        }
        return sb.toString();
    }
    
    
    /**
     * Method toString
     *
     * @return   string representation of this object
     *
     */
    public String toString () {
        return getQueryAsString (NORMAL_QUERY);
    }
}

