/*
 * $Header: /home/cvspublic/jakarta-slide/proposals/tamino/src/store/org/apache/slide/store/tamino/datastore/search/XOrderBy.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 org.apache.slide.store.tamino.common.XGlobals;
import org.apache.slide.common.PropertyName;
import org.apache.slide.search.CompareHint;
import org.apache.slide.search.InvalidQueryException;
import org.apache.slide.search.basic.OrderBy;
import org.jdom.Element;

/**
 * <p>Represents the &lt;ORDERBY&gt; section in the DASL query. Generates the
 * CompareHints and supplies a sortall() expression for the query engine.</p>
 * <p> An XOrderBy may be of type "XPathPropertyOrder" or "MetaPropertyOrder".
 * Depends on the type of the PropertyName of the most significant
 * order expression.</p>
 * <p>Limitation: If you order by more than one property of different type AND
 * limit is specified, it is not guaranteed, that you get the first n resources
 * that match the query. For example you orderby the author (xpath) and then by
 * displayname (meta), limit = 3 and there are more than 3 docs of this author in
 * the store, you might not get the first 3 docs ordered by displayname of
 * this author. If there is only one order element, having the first n docs
 * according to orderby is guaranteed.
 * </p>Performance hint: If the &lt;WHERE&gt; clause contains a different
 * property type than orderby (for example: where contenttype="text/xml" order by
 * xpath[author]), internally no limit is set in the tamino queries. If you
 * use same type, the limit is set to tamino query.
 *</p
 *
 * @author martin.wallmer@softwareag.com
 *
 * @version $Revision: 1.3 $
 */
public class XOrderBy extends OrderBy {

    /** the query to which this query belongs */
    private XBasicQueryImpl    query;

    private CompareHint topHint;
    private Element orderByElement;

    private XPathContentQuery contentQuery;

//    private static Namespace davNamespace = Namespace.getNamespace (
//        "DAV:");
//    private static Namespace xsvNamespace = Namespace.getNamespace
//        ("http://namespaces.softwareag.com/tamino/webdav");



    /**
     * Must be called after construction
     *
     * @param    orderByElement      an Element
     * @param    query               a  XBasicQueryImpl
     *
     * @throws   InvalidQueryException
     *
     */
    public void init (Element orderByElement, XBasicQueryImpl query)
        throws InvalidQueryException {
        this.query = query;
        this.orderByElement = orderByElement;
        super.init (orderByElement);
        topHint = getTopCompareHint();
    }

    /**
     * Method createProperty
     *
     * @param    propElem            contains the property on which to order by
     *
     * @return   a _Property
     *
     */
    protected PropertyName createProperty (Element propElem)
        throws InvalidQueryException
    {
        PropertyName result;

        String name = propElem.getName();
        String nameSpace = propElem.getNamespace().getURI();
        //System.out.println(nameSpace);

        if (name.equals (XLiterals.XPATH)
            && nameSpace.equals (XGlobals.TAMINO_NAMESPACE_URI))
        {

            contentQuery = query.getContentQuery (propElem);

            PropertyName pn = contentQuery.getQueryName();
            result = new XComparedPropertyName (pn.getName(),
                                            pn.getNamespace(),
                                            contentQuery);
        }
        else {
            result = new PropertyName (name, nameSpace);
        }
        return result;
    }

    /**
     * Method getMetaSortByExpression
     *
     * @return   a String
     *
     */
    public String getMetaSortByExpression () {
        return getSortByExpression
            (createMetaSortExpression (topHint.getComparedProperty()));
    }

    /**
     * Method getXPathSortByExpression
     *
     * @return   a String
     *
     */
    public String getXPathSortByExpression () {
        String result = "";
        if (isXPathPropertyOrder())
            result = getSortByExpression (((XCompareHint) topHint).getSortBy());

        return result;
    }

    /**
     * Method getSortByExpression
     *
     * @return   a String
     *
     */
    private String getSortByExpression (String sortBy) {
        StringBuffer sb = new StringBuffer ("sortall (");

        sb.append (sortBy);

        sb.append(" ");
        if (topHint.isAscending())
            sb.append ("ascending");
        else
            sb.append ("descending");

        sb.append (")");
        String result = sb.toString();
        return result;
    }

    private CompareHint getTopCompareHint () {
        return (CompareHint)orderByElements.get(0);
    }

    boolean isXPathPropertyOrder () {
        return (topHint.getComparedProperty() instanceof XComparedPropertyName);
    }

    boolean isMetaPropertyOrder () {
        return !(topHint.getComparedProperty() instanceof XComparedPropertyName);
    }

    /**
     * Method createCompareHint
     *
     * @param    prop                a  PropertyName
     * @param    isAscending         a  boolean
     * @param    isCaseSensitive     a  boolean
     *
     * @return   a CompareHint
     *
     */
    protected CompareHint createCompareHint (PropertyName prop,
                                             boolean isAscending, boolean isCaseSensitive) {

        return new XCompareHint (prop, isAscending, isCaseSensitive) ;
    }

    private String createMetaSortExpression (PropertyName p) {
        StringBuffer sb = new StringBuffer (".//propertyList/nodeProperty [@name=\"");
        sb.append (p.getName());
        sb.append ("\" and @namespace=\"");
        sb.append (p.getNamespace());
        sb.append ("\"]/shadow");
        return sb.toString();
    }
}

