package javax.wvcm;

import javax.wvcm.PropertyNameList.*;

/**
 * NOT YET STANDARD
 * Describes a search request.
 */
public class SearchToken {
    
    private SearchCondition searchCondition;
    private SortCriterion[] sortCriteria;
    private Depth depth;
    private Integer limit;
    
    /**
     * Get the search condition
     *
     * @return   a SearchCondition
     */
    public SearchCondition searchCondition() {
        return searchCondition;
    }
    
    /**
     * Get the sorting criteria
     *
     * @return   a SortCriterion[]
     */
    public SortCriterion[] sortCriteria() {
        return sortCriteria;
    }
    
    /**
     * Get the search depth
     *
     * @return   an int
     */
    public Depth depth() {
        return depth;
    }
    
    /**
     * Get the max. number of results to return
     *
     * @return   the limit
     */
    public Integer limit() {
        return limit;
    }
    
    /**
     * Constructor
     *
     * @param    condition    the search condition
     * @param    sortCriteria the sorting criteria
     * @param    depth        the search depth
     * @param    limit        the max. number of results to return
     */
    public SearchToken(SearchCondition condition) {
        this(condition, null, null, null);
    }
    
    /**
     * Constructor
     *
     * @param    condition    the search condition
     * @param    sortCriteria the sorting criteria
     * @param    depth        the search depth
     * @param    limit        the max. number of results to return
     */
    public SearchToken(SearchCondition condition, SortCriterion[] sortCriteria, Depth depth, Integer limit) {
        this.searchCondition = condition;
        this.sortCriteria = sortCriteria;
        this.depth = depth;
        this.limit = limit;
    }
    
    /**
     * Represents a search condition.
     * Expression and location filters are ANDed al together.
     */
    public static class SearchCondition {
        
        private Expression expression;
        private LocationFilter[] filters;
        
        /**
         * Constructor
         *
         * @param    expression the expression
         */
        public SearchCondition(Expression expression) {
            this.expression = expression;
        }
        
        /**
         * Constructor
         *
         * @param    expression the expression
         */
        public SearchCondition(Expression expression, LocationFilter[] filters) {
            this.expression = expression;
            this.filters = filters;
        }
        
        /**
         * Get the expression
         *
         * @return   a Expression
         */
        public Expression expression() {
            return expression;
        }
        
        public LocationFilter[] filters() {
            return filters;
        }
    }

    /**
     * Represents a filter on the last location segment
     */
    public static class LocationFilter {
        
        private String pattern = null;
        private boolean negated = false;
        
        public LocationFilter(String pattern, boolean negated) {
            this.pattern = pattern;
            this.negated = negated;
        }
        
        public String pattern() {
            return pattern;
        }
        
        public boolean isNegated() {
            return negated;
        }
    }

    /**
     * Represents an expression
     */
    public static abstract class Expression {
        
        private boolean negated = false;
        
        /**
         * Constructor
         */
        public Expression() {
        }
        
        /**
         * @return   true, if this expression is negated
         */
        public boolean isNegated() {
            return negated;
        }
        
        /**
         * Negate the expression. Negating an negated expression unnegates.
         */
        public Expression negate() {
            this.negated = !negated;
            return this;
        }
    }
    
    /**
     * Represents a property expression
     */
    public static final class PropertyExpression extends Expression {
        
        private PropertyName pname;
        private Object value;
        private PropOperator operator;
        private Boolean caseless;
        
        /**
         * Constructor
         *
         * @param    pname               a  PropertyName
         * @param    literal             the value
         * @param    operator            the comparison operator
         * @param    caseles             case-sensitivenes
         */
        public PropertyExpression(PropertyName pname, Object value, PropOperator operator, Boolean caseless) {
            this.pname = pname;
            this.value = value;
            this.operator = operator;
            this.caseless = caseless;
        }
        
        /**
         * Get the PropertyName involved in this expression
         *
         * @return   a PropertyName
         */
        public PropertyName propertyName() {
            return pname;
        }
        
        /**
         * Get the literal (value).
         *
         * @return   an Object
         */
        public Object value() {
            return value;
        }
        
        /**
         * Get the comparison oprator.
         *
         * @return   a CompOperator
         *
         */
        public PropOperator operator() {
            return operator;
        }
        
        /**
         * Get caseles
         *
         * @return   a Boolean
         */
        public Boolean caseless() {
            return caseless;
        }
    }
    
    /**
     * Represents a content-based expression
     */
    public static final class ContentExpression extends Expression {
        
        private String string;
        private ContOperator operator;
        
        /**
         * Constructor
         *
         * @param    string              a  String
         * @param    operator            a  ContOperator
         */
        public ContentExpression(String string, ContOperator operator) {
            this.string = string;
            this.operator = operator;
        }
        
        /**
         * Get the string
         *
         * @return   a String
         */
        public String string() {
            return string;
        }
        
        /**
         * Get the operator
         *
         * @return   a ContOperator
         */
        public ContOperator operator() {
            return operator;
        }
        
    }
    
    /**
     * Represents a nested AND or OR expression.
     */
    public static final class NestedExpression extends Expression {
        
        private Expression[] terms;
        private LogOperator operator;
        
        /**
         * Constructor
         *
         * @param    terms               the terms of this expression
         * @param    operator            the logical operator
         */
        public NestedExpression(Expression[] terms, LogOperator operator) {
            this.terms = terms;
            this.operator = operator;
        }
        
        /**
         * Get the terms
         *
         * @return   an Expression[]
         */
        public Expression[] terms() {
            return terms;
        }
        
        /**
         * Get the logical operator
         *
         * @return   a LogOperator
         */
        public LogOperator operator() {
            return operator;
        }
        
    }
    
    /**
     * Represents a sorting criterion
     */
    public static final class SortCriterion {
        
        private PropertyName pname;
        private OrderDirection direction;
        private Boolean caseless;
        
        /**
         * Constructor
         *
         * @param    pname               a  PropertyName
         * @param    direction           an OrderDirection
         * @param    caseless            a  Boolean
         */
        public SortCriterion(PropertyName pname, OrderDirection direction, Boolean caseless) {
            this.pname = pname;
            this.direction = direction;
            this.caseless = caseless;
        }
        
        /**
         * Get caseless
         *
         * @return   a Boolean
         */
        public Boolean caseless() {
            return caseless;
        }
        
        /**
         * Get the property name
         *
         * @return   a PropertyName
         */
        public PropertyName propertyName() {
            return pname;
        }
        
        /**
         * Get the direction
         *
         * @return   a OrderDirection
         */
        public OrderDirection direction() {
            return direction;
        }
    }
    
    /**
     * Discrete values for parameter "depth".
     */
    public static class Depth {
        public static final Depth ZERO = new Depth(){public String toString(){return "0";}};
        public static final Depth ONE = new Depth(){public String toString(){return "1";}};
        public static final Depth INFINITY = new Depth(){public String toString(){return "infinity";}};
    }
    
    /**
     * Discrete values for parameter "direction" (ascending, descending).
     */
    public static class OrderDirection {
        public static final OrderDirection ASCENDING = new OrderDirection(){public String toString(){return "ascending";}};
        public static final OrderDirection DESCENDING = new OrderDirection(){public String toString(){return "descending";}};
    }
    
    /**
     * Discrete values for logical operators.
     */
    public static class LogOperator {
        public static final LogOperator AND = new LogOperator(){public String toString(){return "and";}};
        public static final LogOperator OR = new LogOperator(){public String toString(){return "or";}};
    }
    
    /**
     * Discrete values for property operators.
     */
    public static class PropOperator {
        public static final PropOperator EQ = new PropOperator(){public String toString(){return "eq";}};
        public static final PropOperator LT = new PropOperator(){public String toString(){return "lt";}};
        public static final PropOperator GT = new PropOperator(){public String toString(){return "gt";}};
        public static final PropOperator LTE = new PropOperator(){public String toString(){return "lte";}};
        public static final PropOperator GTE = new PropOperator(){public String toString(){return "gte";}};
        public static final PropOperator LIKE = new PropOperator(){public String toString(){return "like";}};
        public static final PropOperator CONTAINS = new PropOperator(){public String toString(){return "propcontains";}};
    }
    
    /**
     * Discrete values for content operators.
     */
    public static class ContOperator {
        public static final ContOperator CONTAINS = new ContOperator(){public String toString(){return "contains";}};
        public static final ContOperator XPATH = new ContOperator(){public String toString(){return "xpath";}};
    }
    
    /**
     * XPath-based pseudo-attribute
     */
    public static class XPathAttributeName extends AttributeName {
        
        String _xpath;
        
        /**
         * Constructor
         * @param    namespace           a  String
         * @param    name                a  String
         * @param    xpath               a  String
         */
        public XPathAttributeName( String namespace, String name, String xpath ) {
            super( namespace, name );
            this._xpath = xpath;
        }
        
        /**
         * Get the xpath expression of this pseudo-attribute
         * @return   a String
         */
        public String getXpath() {
            return _xpath;
        }
    }
}

