/*
 * $Header: /home/cvspublic/jakarta-slide/src/share/org/apache/slide/search/basic/BasicExpressionFactory.java,v 1.14 2004/11/01 17:53:42 luetzkendorf Exp $
 * $Revision: 1.14 $
 * $Date: 2004/11/01 17:53:42 $
 *
 * ====================================================================
 *
 * Copyright 1999-2002 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.search.basic;

import java.util.Collection;

import org.apache.slide.content.NodeProperty.NamespaceCache;
import org.apache.slide.search.BadQueryException;
import org.apache.slide.search.InvalidQueryException;
import org.apache.slide.search.PropertyProvider;
import org.apache.slide.search.basic.expression.*;
import org.apache.slide.search.basic.expression.AndExpression;
import org.apache.slide.search.basic.expression.ContainsExpression;
import org.apache.slide.search.basic.expression.EQExpression;
import org.apache.slide.search.basic.expression.EmptyExpression;
import org.apache.slide.search.basic.expression.GTEExpression;
import org.apache.slide.search.basic.expression.GTExpression;
import org.apache.slide.search.basic.expression.GenericBasicExpression;
import org.apache.slide.search.basic.expression.IsCollectionExpression;
import org.apache.slide.search.basic.expression.IsDefinedExpression;
import org.apache.slide.search.basic.expression.IsPrincipalExpression;
import org.apache.slide.search.basic.expression.LTEExpression;
import org.apache.slide.search.basic.expression.LTExpression;
import org.apache.slide.search.basic.expression.NotContainsExpression;
import org.apache.slide.search.basic.expression.NotEQExpression;
import org.apache.slide.search.basic.expression.NotGTEExpression;
import org.apache.slide.search.basic.expression.NotGTExpression;
import org.apache.slide.search.basic.expression.NotIsCollectionExpression;
import org.apache.slide.search.basic.expression.NotIsDefinedExpression;
import org.apache.slide.search.basic.expression.NotIsPrincipalExpression;
import org.apache.slide.search.basic.expression.NotLTEExpression;
import org.apache.slide.search.basic.expression.NotLTExpression;
import org.apache.slide.search.basic.expression.NotPropContainsExpression;
import org.apache.slide.search.basic.expression.OrExpression;
import org.apache.slide.search.basic.expression.PropContainsExpression;
import org.jdom.Element;

/**
 * BasicExpressionFactory.java
 *
 */
public class BasicExpressionFactory implements IBasicExpressionFactory {
    
    // public static final String EXPRESSION_FACTORY = "ExpressionFactory";
    
    /**
     * The pool of resources in the given scope.
     */
    protected ComparableResourcesPool requestedResourcePool = null;
    
    /**
     * The IBasicQuery to use.
     */
    protected IBasicQuery query = null;
    
    /**
     * The PropertyProvider to use.
     */
    protected PropertyProvider propertyProvider = null;
    
    
    
    /**
     * Creates a BasicExpressionFactory.
     */
    public BasicExpressionFactory() {
        this(null);
    }
    
    /**
     * Creates a BasicExpressionFactory with the given
     * <code>requestedResourcePool</code> to use.
     *
     * @param      requestedResourcePool  the RequestedResourcePool to use.
     */
    public BasicExpressionFactory(ComparableResourcesPool requestedResourcePool) {
        this.requestedResourcePool = requestedResourcePool;
    }
    
    /**
     * Initializes the factory. Is called exactly once and before any call
     * to crateExpression ()
     *
     * @param    query               the  IBasicQuery.
     * @param    propertyProvider    the  PropertyProvider to use (may be
     *                               <code>null</code>).
     *
     * @throws   BadQueryException
     */
    public void init (IBasicQuery query, PropertyProvider propertyProvider) throws BadQueryException {
        this.query = query;
        this.propertyProvider = propertyProvider;
    }
    
    /**
     * Returns the IBasicQuery to use (set in method {@link #init init()}).
     *
     * @return     the IBasicQuery to use.
     */
    public IBasicQuery getQuery() {
        return query;
    }
    
    /**
     * Returns the PropertyProvider to use (set in method {@link #init init()}).
     *
     * @return     the PropertyProvider to use.
     */
    public PropertyProvider getPropertyProvider() {
        return propertyProvider;
    }
    
    
    /**
     * Creates a MergeExpression for the given element (AND, OR). The given children
     * are the expressions to merge.
     *
     * @param    name                the name of the Element describing the merge expression.
     * @param    namespace           the namespace of the Element describing the merge expression.
     * @param    expressionsToMerge  the expressions to merge.
     *
     * @return   an IBasicExpression
     *
     * @throws   BadQueryException
     */
    public IBasicExpression createMergeExpression (String name, String namespace, Collection expressionsToMerge) throws BadQueryException {
        
        IBasicExpression result = null;
        if (name == null) {
            result = new EmptyExpression(getRequestedResourcePool());
        }
        else {
            if (NamespaceCache.DEFAULT_URI.equals(namespace)) {
                if (name.equals (Literals.AND))
                    result = new AndExpression (new Element(name, NamespaceCache.getNamespace(namespace)),
                                                expressionsToMerge);
                    
                else if (name.equals (Literals.OR))
                    result = new OrExpression (new Element(name, NamespaceCache.getNamespace(namespace)),
                                               expressionsToMerge);
            }
            if (result == null) {
                throw new InvalidQueryException
                    ("operator <" + NamespaceCache.DEFAULT_URI + ":" + name + "> is an unprocessable entity");
                
            }
        }
        if (result != null) result.setFactory(this);
        return result;
    }
    
    /**
     * Creates a (non-merge) expression (compare...) for the given Element.
     *
     * @param    element             an Element describing the expression.
     *
     * @return   an IBasicExpression
     *
     * @throws   BadQueryException
     *
     */
    public IBasicExpression createExpression (Element element) throws BadQueryException {
        
        IBasicExpression result = null;
        if (element == null) {
            result = new EmptyExpression(getRequestedResourcePool());
        }
        else {
            String namespace = element.getNamespace().getURI();
            String name = element.getName();
            if (namespace.equals (NamespaceCache.DEFAULT_URI)) {
                result = createDAVExpression(element);
            }
            else if (namespace.equals (NamespaceCache.SLIDE_URI)) {
                result = createNonDAVExpression(element, namespace);
            }
            else {
                throw new InvalidQueryException
                    ("operator <" + namespace + ":" + name + "> is an unprocessable entity");
                
            }
        }
        
        if (result != null) result.setFactory(this);
        return result;
    }
    
    
    private GenericBasicExpression createDAVExpression
        (Element e) throws BadQueryException
    {
        String name = e.getName();
        GenericBasicExpression result = null;
        
        
        if (name.equals (Literals.GT))
            result = new GTExpression (e, getRequestedResourcePool());
            
        else if (name.equals (Literals.NOT_GT))
            result = new NotGTExpression (e, getRequestedResourcePool());
            
        else if (name.equals (Literals.GTE))
            result = new GTEExpression (e, getRequestedResourcePool());
            
        else if (name.equals (Literals.NOT_GTE))
            result = new NotGTEExpression (e, getRequestedResourcePool());
            
        else if (name.equals (Literals.LT))
            result = new LTExpression (e, getRequestedResourcePool());
            
        else if (name.equals (Literals.NOT_LT))
            result = new NotLTExpression (e, getRequestedResourcePool());
            
        else if (name.equals (Literals.LTE))
            result = new LTEExpression (e, getRequestedResourcePool());
            
        else if (name.equals (Literals.NOT_LTE))
            result = new NotLTEExpression (e, getRequestedResourcePool());
            
        else if (name.equals (Literals.EQ))
            result = new EQExpression (e, getRequestedResourcePool());
            
        else if (name.equals (Literals.NOT_EQ))
            result = new NotEQExpression (e, getRequestedResourcePool());
            
        else if (name.equals (Literals.CONTAINS))
            result = new ContainsExpression (e, getRequestedResourcePool());
            
        else if (name.equals (Literals.NOT_CONTAINS))
            result = new NotContainsExpression (e, getRequestedResourcePool());
            
        else if (name.equals (Literals.ISCOLLECTION))
            result = new IsCollectionExpression (e, getRequestedResourcePool());
            
        else if (name.equals (Literals.NOT_ISCOLLECTION))
            result = new NotIsCollectionExpression (e, getRequestedResourcePool());
            
        else if (name.equals (Literals.ISDEFINED))
            result = new IsDefinedExpression (e, getRequestedResourcePool());
            
        else if (name.equals (Literals.NOT_ISDEFINED))
            result = new NotIsDefinedExpression (e, getRequestedResourcePool());
        
        else if (name.equals (Literals.LIKE)) 
            result = new LikeExpression (e, getRequestedResourcePool());

        else if (name.equals (Literals.NOT_LIKE)) 
            result = new NotLikeExpression (e, getRequestedResourcePool());

        else
            throw new InvalidQueryException
                ("operator <" + NamespaceCache.DEFAULT_URI + ":" + name + "> is an unprocessable entity");
        
        return result;
    }
    
    private GenericBasicExpression createNonDAVExpression
        (Element e, String namespace) throws BadQueryException
    {
        
        String name = e.getName();
        GenericBasicExpression result = null;
        
        if (namespace.equals (NamespaceCache.SLIDE_URI)
            && name.equals (Literals.ISPRINCIPAL))
            
            result = new IsPrincipalExpression (e, getRequestedResourcePool());
            
        else if (namespace.equals (NamespaceCache.SLIDE_URI)
                 && name.equals (Literals.NOT_ISPRINCIPAL))
            
            result = new NotIsPrincipalExpression (e, getRequestedResourcePool());
            
        else if (namespace.equals (NamespaceCache.SLIDE_URI)
                 && name.equals (Literals.PROPCONTAINS))
            
            result = new PropContainsExpression (e, getRequestedResourcePool());
            
        else if (namespace.equals (NamespaceCache.SLIDE_URI)
                 && name.equals (Literals.NOT_PROPCONTAINS))
            
            result = new NotPropContainsExpression (e, getRequestedResourcePool());
            
        else
            throw new InvalidQueryException
                ("operator <" + namespace + ":" + name + "> is an unprocessable entity");
        
        return result;
    }
    
    
    /**
     * Returns the RequestedResourcesPool to use for the query. The pool will
     * be created lazily, means the first time it is requested. If creation fails,
     * a SearchException is thrown.
     *
     * @return     the RequestedResourcesPool to use for the query.
     *
     * @throws     SerachException if creation of the pool failed.
     */
    protected ComparableResourcesPool getRequestedResourcePool() throws BadQueryException {
        
        if (requestedResourcePool == null) {
            requestedResourcePool =
                new ComparableResourcesPoolImpl(query.getSearchToken(), query.getScope(), getPropertyProvider());
        }
        return requestedResourcePool;
    }
}

