/*
 * $Header: /home/cvspublic/jakarta-slide/proposals/tamino/src/store/org/apache/slide/store/tamino/datastore/search/XPath.java,v 1.3 2004/07/30 06:51:58 ozeigermann Exp $
 * $Revision: 1.3 $
 * $Date: 2004/07/30 06:51:58 $
 *
 * ====================================================================
 *
 * 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.search;

import java.util.StringTokenizer;
import org.apache.slide.search.InvalidQueryException;

/**
 * wraps a tamino xpath expression.
 *
 * @author martin.wallmer@softwareag.com
 *
 * @version $Revision: 1.3 $
 */
public class XPath {

    private String schema;
    private String xPathWithoutSchema;
    private String contentQueryFilter;
    private String sortBy;

    /**
     * Constructor
     *
     * @param    xPath               a  String
     *
     * @throws   InvalidQueryException
     *
     */
    public XPath (String xPath) throws InvalidQueryException {

        xPathWithoutSchema = "";
        contentQueryFilter = "";

        xPath = xPath.trim();

        if (xPath.startsWith ("//")) {
            throw new InvalidQueryException ("query must not start with \"//\"");
        }

        if (!xPath.startsWith ("/")) {
            xPath = "/" + xPath;
        }

        int firstSlash = xPath.indexOf ("/", 1);
        int firstBracket = xPath.indexOf ("[", 1);

        if (firstSlash == -1 && firstBracket == -1) {
            schema = xPath.substring(1);
        }
        else {
            if (firstBracket == -1) firstBracket = Integer.MAX_VALUE;
            if (firstSlash == -1) firstSlash = Integer.MAX_VALUE;

            int queryBeginsAt = Math.min (firstBracket, firstSlash);

            schema = xPath.substring (1, queryBeginsAt);
            xPathWithoutSchema = xPath.substring (queryBeginsAt);
        }
        schema = schema.trim();
        xPathWithoutSchema = xPathWithoutSchema.trim();
    }

    /**
     * returns the last node of a query, for example /a/b/c ==> c.
     * Namespace prefix is ignored.
     *
     * @return   a String
     *
     */
    public String getLastNode() {
        String s = getWithoutFilter();
        String result;
        int lastSlash = s.lastIndexOf("/");

        if (lastSlash == -1)
            result = s;
        else
            result = s.substring (lastSlash + 1);

        int nsPrefix = result.indexOf (":");
        if (nsPrefix != -1)
            result = result.substring (nsPrefix + 1);

        return result;
    }

    /**
     * strips off all filter expressions
     *
     * @return   a String
     *
     */
    private String getWithoutFilter () {
        String s = getXpathString();
        StringBuffer sb = new StringBuffer();

        StringTokenizer st  = new StringTokenizer (s, "[", true);

        while (st.hasMoreTokens()) {
            String token = st.nextToken();
            if (token.equals ("[")) {
                if (st.hasMoreTokens()) {
                    st.nextToken ("]");
                }
            }
            else if (!token.equals ("]"))
                sb.append (token);

        }
        return sb.toString().trim();
    }

    /**
     * add a filter with contentIds to the query
     *
     * @param    contentQueryFilter  an IContentQueryFilter
     *
     */
    public void setContentQueryFilter (IContentQueryFilter contentQueryFilter) {
        if (contentQueryFilter != null)
            this.contentQueryFilter = contentQueryFilter.getXPathFilter (schema);
    }

    /**
     * add a sortBy expression to the query
     *
     * @param    sortBy              a  String
     *
     */
    public void setSortBy (String sortBy) {
        this.sortBy = sortBy;
    }

    /**
     * Method getSchema
     *
     * @return   the schema for this query
     *
     */
    public String getSchema () {
        return schema;
    }

    /**
     * Method getXpathString
     *
     * @return   the comple xPath string
     *
     */
    public String getXpathString () {
        StringBuffer sb = new StringBuffer ("/");
        sb.append (schema);

        sb.append (contentQueryFilter);
        // sortBy = sortBy == null ? "" : " " + sortBy;

        // filter
        if (xPathWithoutSchema.startsWith ("[")) {
            sb.append (xPathWithoutSchema);
            if (sortBy != null)
                sb.append (" ").append (sortBy);
        }
        else {
            if (sortBy != null)
                sb.append (" ").append (sortBy);

            sb.append (xPathWithoutSchema);
        }


        return sb.toString();
    }


    /**
     * Utility method to get a sortBy expression from an xPath.
     * The argument of a sortby / sortall expression must always be relative to
     * current postion in path. So schema is stipped and replaced by "."
     * Example:
     * /mySchema/a/b/c ==> ./a/b/c
     *
     * @return   a String
     *
     */
    public String extractSortAll () throws InvalidQueryException {
        return "." + xPathWithoutSchema;
    }
}
