Package org.geotools.xml.filter

Source Code of org.geotools.xml.filter.FilterOpsComplexTypes$BBOXType

/*
*    GeoTools - The Open Source Java GIS Toolkit
*    http://geotools.org
*
*    (C) 2004-2008, Open Source Geospatial Foundation (OSGeo)
*   
*    This library is free software; you can redistribute it and/or
*    modify it under the terms of the GNU Lesser General Public
*    License as published by the Free Software Foundation;
*    version 2.1 of the License.
*
*    This library is distributed in the hope that it will be useful,
*    but WITHOUT ANY WARRANTY; without even the implied warranty of
*    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
*    Lesser General Public License for more details.
*/
package org.geotools.xml.filter;

import java.io.IOException;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;

import javax.naming.OperationNotSupportedException;

import org.geotools.factory.CommonFactoryFinder;
import org.geotools.filter.FilterCapabilities;
import org.geotools.filter.Filters;
import org.geotools.filter.IllegalFilterException;
import org.geotools.xml.PrintHandler;
import org.geotools.xml.XMLHandlerHints;
import org.geotools.xml.filter.FilterComplexTypes.ExpressionType;
import org.geotools.xml.filter.FilterComplexTypes.LiteralType;
import org.geotools.xml.filter.FilterComplexTypes.PropertyNameType;
import org.geotools.xml.filter.FilterSchema.FilterAttribute;
import org.geotools.xml.filter.FilterSchema.FilterComplexType;
import org.geotools.xml.filter.FilterSchema.FilterElement;
import org.geotools.xml.gml.GMLSchema;
import org.geotools.xml.schema.Attribute;
import org.geotools.xml.schema.Choice;
import org.geotools.xml.schema.ComplexType;
import org.geotools.xml.schema.Element;
import org.geotools.xml.schema.ElementGrouping;
import org.geotools.xml.schema.ElementValue;
import org.geotools.xml.schema.Sequence;
import org.geotools.xml.schema.Type;
import org.geotools.xml.schema.impl.ChoiceGT;
import org.geotools.xml.schema.impl.SequenceGT;
import org.geotools.xml.xsi.XSISimpleTypes;
import org.opengis.filter.BinaryComparisonOperator;
import org.opengis.filter.BinaryLogicOperator;
import org.opengis.filter.FilterFactory2;
import org.opengis.filter.Filter;
import org.opengis.filter.Id;
import org.opengis.filter.Not;
import org.opengis.filter.PropertyIsBetween;
import org.opengis.filter.PropertyIsLike;
import org.opengis.filter.PropertyIsNull;
import org.opengis.filter.expression.Literal;
import org.opengis.filter.expression.Expression;
import org.opengis.filter.identity.FeatureId;
import org.opengis.filter.identity.Identifier;
import org.opengis.filter.spatial.BinarySpatialOperator;
import org.opengis.filter.spatial.Disjoint;
import org.opengis.filter.spatial.DistanceBufferOperator;
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.SAXNotSupportedException;
import org.xml.sax.helpers.AttributesImpl;

import com.vividsolutions.jts.geom.Envelope;
import com.vividsolutions.jts.geom.Geometry;


/**
* Encode/Decode Filter types.
*
* @author dzwiers
*
*
* @source $URL$
*/
public class FilterOpsComplexTypes {   
   
    private static final int SPATIAL_TYPE = 0;
    private static final int COMPARE_TYPE = 1;
    private static final int LOGIC_TYPE = 2;
    private static final int FID_TYPE = 3;
   
    /**
     * Calls the appropriate type for encoding.
     * <p>
     * This mapping from filter to Type is a bit tricky since the filter hierarchy has changed.
     * <p>
     * <ul>
     * <li>LOGIC_TYPE: includes BinaryLogicOperator and Not</li>
     * <li>COMPARE_TYPE: includes BinaryComparisonOperator and PropertyIsBetween</li>
     * <p>
     *
     *
     * @param filter
     * @param output
     * @param hints
     * @throws OperationNotSupportedException
     * @throws IOException
     */
   
    protected static void encodeFilter(org.opengis.filter.Filter filter, PrintHandler output, Map hints) throws OperationNotSupportedException, IOException{
        if (filter instanceof BinaryLogicOperator) {
            FilterType.elems[LOGIC_TYPE].getType().encode(FilterType.elems[LOGIC_TYPE], filter,
                    output, hints);
        } else if (filter instanceof Not) {
            FilterType.elems[LOGIC_TYPE].getType().encode(FilterType.elems[LOGIC_TYPE], filter, output,
                    hints);
        } else if (filter instanceof BinaryComparisonOperator) {
            FilterType.elems[COMPARE_TYPE].getType().encode(FilterType.elems[COMPARE_TYPE], filter, output,
                    hints);
        } else if (filter instanceof PropertyIsBetween) {
            FilterType.elems[COMPARE_TYPE].getType().encode(FilterType.elems[COMPARE_TYPE], filter, output,
                    hints);
        } else if (filter instanceof Id) {
            // deal with multi instance inside the type-writer
            FilterType.elems[FID_TYPE].getType().encode(FilterType.elems[FID_TYPE], filter, output, hints);
        } else if (filter instanceof BinarySpatialOperator) {
            FilterType.elems[SPATIAL_TYPE].getType().encode(FilterType.elems[SPATIAL_TYPE], filter, output,
                    hints);
        } else if (filter instanceof PropertyIsLike) {
            FilterType.elems[COMPARE_TYPE].getType().encode(FilterType.elems[COMPARE_TYPE], filter, output,
                    hints);
        } else if (filter instanceof PropertyIsNull) {
            FilterType.elems[COMPARE_TYPE].getType().encode(FilterType.elems[COMPARE_TYPE], filter, output,
                    hints);
        } else {
            throw new OperationNotSupportedException(
                    "The Filter type is not known: please try again. " + filter == null ? "null"
                            : filter.getClass().getName());
        }
    }

    protected static void encodeExpr(Expression expr, PrintHandler output,
        Map hints) throws OperationNotSupportedException, IOException {
        int i = 0;

        switch (Filters.getExpressionType(expr)) {
        /* Types implemented by ExpressionLiteral */
        case org.geotools.filter.ExpressionType.LITERAL_DOUBLE:
        case org.geotools.filter.ExpressionType.LITERAL_INTEGER:
        case org.geotools.filter.ExpressionType.LITERAL_STRING:
        case org.geotools.filter.ExpressionType.LITERAL_GEOMETRY:
        case org.geotools.filter.ExpressionType.LITERAL_LONG:
            i = 36;

            break;

        /* Types implemented by ExpressionMath. */
        case org.geotools.filter.ExpressionType.MATH_ADD:
            i = 29;

            break;

        case org.geotools.filter.ExpressionType.MATH_SUBTRACT:
            i = 30;

            break;

        case org.geotools.filter.ExpressionType.MATH_MULTIPLY:
            i = 31;

            break;

        case org.geotools.filter.ExpressionType.MATH_DIVIDE:
            i = 32;

            break;

        /* Types implemented by ExpressionAttribute. */

        /**
         * Defines an attribute expression with a declared double type.
         */
        case org.geotools.filter.ExpressionType.ATTRIBUTE_DOUBLE:
        case org.geotools.filter.ExpressionType.ATTRIBUTE_INTEGER:
        case org.geotools.filter.ExpressionType.ATTRIBUTE_STRING:
        case org.geotools.filter.ExpressionType.ATTRIBUTE_GEOMETRY:
        case org.geotools.filter.ExpressionType.ATTRIBUTE_UNDECLARED:
        case org.geotools.filter.ExpressionType.ATTRIBUTE:
          i = 34;

            break;

        case org.geotools.filter.ExpressionType.FUNCTION:
            i = 35;

            break;
        }

        if (i != 0) {
            FilterSchema.getInstance().getElements()[i].getType().
        encode(FilterSchema.getInstance().getElements()[i],
                expr, output, hints);
        }
    }

    public static class ComparisonOpsType extends FilterComplexType implements org.geotools.filter.FilterType {
        private static final ComplexType instance = new ComparisonOpsType();

        public static short findFilterType( String s ){
          if("PropertyIsEqualTo".equalsIgnoreCase( s ) ) return COMPARE_EQUALS;
          if("PropertyIsGreaterThan".equalsIgnoreCase( s ) ) return COMPARE_GREATER_THAN;
          if("PropertyIsGreaterThanOrEqualTo".equalsIgnoreCase( s ) ) return COMPARE_GREATER_THAN_EQUAL;
          if("PropertyIsLessThan".equalsIgnoreCase( s ) ) return COMPARE_LESS_THAN;
          if("PropertyIsLessThanOrEqualTo".equalsIgnoreCase( s ) ) return COMPARE_LESS_THAN_EQUAL;
          if("PropertyIsNotEqualTo".equalsIgnoreCase( s ) ) return COMPARE_NOT_EQUALS;
          if("PropertyIsLike".equalsIgnoreCase( s ) ) return LIKE;
          if("PropertyIsNull".equalsIgnoreCase( s ) ) return NULL;
          if("PropertyIsBetween".equalsIgnoreCase( s ) ) return BETWEEN;
          return 0;
           
        }
        public static String writeFilterType(short filterType) {
          switch (filterType) {
          case COMPARE_EQUALS: return "PropertyIsEqualTo";
          case COMPARE_GREATER_THAN: return "PropertyIsGreaterThan";
          case COMPARE_GREATER_THAN_EQUAL: return "PropertyIsGreaterThanOrEqualTo";
          case COMPARE_LESS_THAN: return "PropertyIsLessThan";
          case COMPARE_LESS_THAN_EQUAL: return "PropertyIsLessThanOrEqualTo";
          case COMPARE_NOT_EQUALS: return "PropertyIsNotEqualTo";
          case LIKE: return "PropertyIsLike";
          case NULL: return "PropertyIsNull";
          case BETWEEN: return "PropertyIsBetween";
          default:
            return "";
          }
        }
         
        public static ComplexType getInstance() {
            return instance;
        }

        //      <xsd:complexType name="ComparisonOpsType" abstract="true"/>
        public boolean isAbstract() {
            return true;
        }

        /**
         * @see org.geotools.xml.schema.ComplexType#getChild()
         */
        public ElementGrouping getChild() {
            return null;
        }

        /**
         * @see org.geotools.xml.schema.ComplexType#getChildElements()
         */
        public Element[] getChildElements() {
            return null;
        }
       
        /**
         * @see org.geotools.xml.schema.Type#getValue(org.geotools.xml.schema.Element,
         *      org.geotools.xml.schema.ElementValue[],
         *      org.xml.sax.Attributes, java.util.Map)
         */
        public Object getValue(Element element, ElementValue[] value, Attributes attrs, Map hints)
                throws SAXException {
            FilterFactory2 factory = FilterSchema.filterFactory(hints);

            try {
                Expression expr1 = (Expression) value[0].getValue();
                Expression expr2 = (Expression) value[1].getValue();

                short type = findFilterType(element.getName());
                switch (type) {
                case FilterType.COMPARE_EQUALS:
                    return factory.equals(expr1, expr2);

                case FilterType.COMPARE_GREATER_THAN:
                    return factory.greater(expr1, expr2);

                case FilterType.COMPARE_GREATER_THAN_EQUAL:
                    return factory.greaterOrEqual(expr1, expr2);

                case FilterType.COMPARE_LESS_THAN:
                    return factory.less(expr1, expr2);

                case FilterType.COMPARE_LESS_THAN_EQUAL:
                    return factory.lessOrEqual(expr1, expr2);

                case FilterType.COMPARE_NOT_EQUALS:
                    return factory.notEqual(expr1, expr2);
                default:
                    throw new SAXException("Illegal filter for " + element);
                }
            } catch (ClassCastException filterRequired) {
                throw new SAXException("Illegal filter for " + element, filterRequired);
            } catch (IllegalFilterException e) {
                throw new SAXException("Illegal filter for " + element);
            }
        }

        /**
         * @see org.geotools.xml.schema.Type#getName()
         */
        public String getName() {
            return "ComparisonOpsType";
        }

        /**
         * @see org.geotools.xml.schema.Type#getInstanceType()
         */
        public Class getInstanceType() {
            return BinaryComparisonOperator.class;
        }

        /**
         * @see org.geotools.xml.schema.Type#canEncode(org.geotools.xml.schema.Element,
         *      java.lang.Object, java.util.Map)
         */
        public boolean canEncode(Element element, Object value, Map hints) {
            if ((hints != null)
                    && hints.containsKey(FilterSchema.FILTER_CAP_KEY)) {
                FilterCapabilities fc = (FilterCapabilities) hints.get(FilterSchema.FILTER_CAP_KEY);

                if ((fc.getScalarOps() & FilterCapabilities.SIMPLE_COMPARISONS) != FilterCapabilities.SIMPLE_COMPARISONS) {
                    return false;
                }
            }

            return (element.getType() != null)
            && getName().equals(element.getType().getName())
            && (value instanceof BinaryComparisonOperator
            || value instanceof PropertyIsBetween || value instanceof PropertyIsNull
            || value instanceof PropertyIsLike);
        }

        /**
         * @see org.geotools.xml.schema.Type#encode(org.geotools.xml.schema.Element,
         *      java.lang.Object, org.geotools.xml.PrintHandler,
         *      java.util.Map)
         */
        public void encode(Element element, Object value, PrintHandler output,
            Map hints) throws IOException, OperationNotSupportedException {
            if (!canEncode(element, value, hints)) {
                return;
            }

            Filter lf = (Filter) value;

            switch ( Filters.getFilterType( lf )) {
            case COMPARE_EQUALS:
                BinaryComparisonOpType.getInstance().encode(new FilterElement(
                    "PropertyIsEqualTo",
                        BinaryComparisonOpType.getInstance(), element), value,
                    output, hints);

                return;

            case COMPARE_GREATER_THAN:
                BinaryComparisonOpType.getInstance().encode(new FilterElement(
                    "PropertyIsGreaterThan",
                        BinaryComparisonOpType.getInstance(), element), value,
                    output, hints);

                return;

            case COMPARE_GREATER_THAN_EQUAL:
                BinaryComparisonOpType.getInstance().encode(new FilterElement(
                    "PropertyIsGreaterThanOrEqualTo",
                        BinaryComparisonOpType.getInstance(), element), value,
                    output, hints);

                return;

            case COMPARE_LESS_THAN:
                BinaryComparisonOpType.getInstance().encode(new FilterElement(
                        "PropertyIsLessThan",
                        BinaryComparisonOpType.getInstance(), element), value,
                    output, hints);

                return;

            case COMPARE_LESS_THAN_EQUAL:
                BinaryComparisonOpType.getInstance().encode(new FilterElement(
                        "PropertyIsLessThanOrEqualTo",
                        BinaryComparisonOpType.getInstance(), element), value,
                    output, hints);

                return;

            case COMPARE_NOT_EQUALS:
                BinaryComparisonOpType.getInstance().encode(new FilterElement(
                        "PropertyIsNotEqualTo",
                        BinaryComparisonOpType.getInstance(), element), value,
                    output, hints);

                return;

            case LIKE:
                PropertyIsLikeType.getInstance().encode(new FilterElement(
                        "PropertyIsLike", PropertyIsLikeType.getInstance(),
                        element), value, output, hints);

                return;

            case NULL:
                PropertyIsNullType.getInstance().encode(new FilterElement(
                        "PropertyIsNull", PropertyIsNullType.getInstance(),
                        element), value, output, hints);

                return;

            case BETWEEN:
                PropertyIsBetweenType.getInstance().encode(new FilterElement(
                        "PropertyIsBetween",
                        PropertyIsBetweenType.getInstance(), element), value,
                    output, hints);

                return;
            }

            throw new OperationNotSupportedException(
                "Unknown filter type in ComparisonFilter: "
                + lf.getClass().getName());
        }
    }
    public static class SpatialOpsType extends FilterComplexType
        implements org.geotools.filter.FilterType {
        private static final ComplexType instance = new SpatialOpsType();

        public static short findFilterType( String s ){
          if("BBOX".equalsIgnoreCase( s ) ) return GEOMETRY_BBOX;
          if("Equals".equalsIgnoreCase( s ) ) return GEOMETRY_EQUALS;
          if("Disjoint".equalsIgnoreCase( s ) ) return GEOMETRY_DISJOINT;
          if("Intersects".equalsIgnoreCase( s ) ) return GEOMETRY_INTERSECTS;
          if("Touches".equalsIgnoreCase( s ) ) return GEOMETRY_TOUCHES;
          if("Crosses".equalsIgnoreCase( s ) ) return GEOMETRY_CROSSES;
          if("Within".equalsIgnoreCase( s ) ) return GEOMETRY_WITHIN;
          if("Contains".equalsIgnoreCase( s ) ) return GEOMETRY_CONTAINS;
          if("Overlaps".equalsIgnoreCase( s ) ) return GEOMETRY_OVERLAPS;
          if("Beyond".equalsIgnoreCase( s ) ) return GEOMETRY_BEYOND;
          if("DWithin".equalsIgnoreCase( s ) ) return GEOMETRY_DWITHIN;
          return 0;
           
        }
        public static String writeFilterType(short filterType) {
          switch (filterType) {
          case GEOMETRY_BBOX: return "BBOX";
          case GEOMETRY_EQUALS: return "Equals";
          case GEOMETRY_DISJOINT: return "Disjoint";
          case GEOMETRY_INTERSECTS: return "Intersects";
          case GEOMETRY_TOUCHES: return "Touches";
          case GEOMETRY_CROSSES: return "Crosses";
          case GEOMETRY_WITHIN: return "Within";
          case GEOMETRY_CONTAINS: return "Contains";
          case GEOMETRY_OVERLAPS: return "Overlaps";
          case GEOMETRY_BEYOND: return "Beyond";
          case GEOMETRY_DWITHIN: return "DWithin";
          default:
            return "";
          }
        }
       
        public static ComplexType getInstance() {
            return instance;
        }

        //      <xsd:complexType name="SpatialOpsType" abstract="true"/>
        public boolean isAbstract() {
            return true;
        }

        /**
         * @see org.geotools.xml.schema.ComplexType#getChild()
         */
        public ElementGrouping getChild() {
            return null;
        }

        /**
         * @see org.geotools.xml.schema.ComplexType#getChildElements()
         */
        public Element[] getChildElements() {
            return null;
        }

        /**
         * @throws SAXException
         * @see org.geotools.xml.schema.Type#getValue(org.geotools.xml.schema.Element,
         *      org.geotools.xml.schema.ElementValue[],
         *      org.xml.sax.Attributes, java.util.Map)
         */
        public Object getValue(Element element, ElementValue[] value,
            Attributes attrs, Map hints) throws SAXException{
          return null; // child (BBox, BinarySpatialOpType, etc ... ) will handle this
//          FilterFactory factory = FilterSchema.filterFactory( hints );
//         
//          try {
//            short type = (short) findFilterType( element.getName() );
//            GeometryFilter filter = factory.createGeometryFilter( type );
//        filter.addLeftGeometry( (Expression) value[0] );
//        filter.addRightGeometry( (Expression) value[1] );       
//        return filter;
//      }
//          catch( ClassCastException filterRequired ){
//            throw new SAXException("Illegal filter for "+element, filterRequired );
//      }
//          catch (IllegalFilterException e) {
//        throw new SAXException("Illegal filter for "+element );
//      }
        }

        /**
         * @see org.geotools.xml.schema.Type#getName()
         */
        public String getName() {
            return "SpatialOpsType";
        }

        /**
         * @see org.geotools.xml.schema.Type#getInstanceType()
         */
        public Class getInstanceType() {
            return BinarySpatialOperator.class;
        }

        /**
         * @see org.geotools.xml.schema.Type#canEncode(org.geotools.xml.schema.Element,
         *      java.lang.Object, java.util.Map)
         */
        public boolean canEncode(Element element, Object value, Map hints) {
            if ((hints != null)
                    && hints.containsKey(FilterSchema.FILTER_CAP_KEY)) {
                FilterCapabilities fc = (FilterCapabilities) hints.get(FilterSchema.FILTER_CAP_KEY);

                if (fc.getSpatialOps() == 0) {
                    return false;
                }
            }

            return (element.getType() != null)
            && getName().equals(element.getType().getName())
            && value instanceof BinarySpatialOperator;
        }

        /**
         * @see org.geotools.xml.schema.Type#encode(org.geotools.xml.schema.Element,
         *      java.lang.Object, org.geotools.xml.PrintHandler,
         *      java.util.Map)
         */
        public void encode(Element element, Object value, PrintHandler output,
            Map hints) throws IOException, OperationNotSupportedException {
            if (!canEncode(element, value, hints)) {
                return;
            }

            BinarySpatialOperator lf = (BinarySpatialOperator) value;

            switch ( Filters.getFilterType( lf )) {
            case GEOMETRY_BBOX:
                BBOXType.getInstance().encode(new FilterElement("BBOX",
                        BBOXType.getInstance(), element), value, output, hints);

                return;

            case GEOMETRY_BEYOND:
                DistanceBufferType.getInstance().encode(new FilterElement(
                        "Beyond", DistanceBufferType.getInstance(), element),
                    value, output, hints);

                return;

            case GEOMETRY_CONTAINS:
                BinarySpatialOpType.getInstance().encode(new FilterElement(
                        "Contains", BinarySpatialOpType.getInstance(), element),
                    value, output, hints);

                return;

            case GEOMETRY_CROSSES:
                BinarySpatialOpType.getInstance().encode(new FilterElement(
                        "Crosses", BinarySpatialOpType.getInstance(), element),
                    value, output, hints);

                return;

            case GEOMETRY_DISJOINT:
                BinarySpatialOpType.getInstance().encode(new FilterElement(
                        "Disjoint", BinarySpatialOpType.getInstance(), element),
                    value, output, hints);

                return;

            case GEOMETRY_DWITHIN:
                DistanceBufferType.getInstance().encode(new FilterElement(
                        "DWithin", DistanceBufferType.getInstance(), element),
                    value, output, hints);

                return;

            case GEOMETRY_EQUALS:
                BinarySpatialOpType.getInstance().encode(new FilterElement(
                        "Equals", BinarySpatialOpType.getInstance(), element),
                    value, output, hints);

                return;

            case GEOMETRY_INTERSECTS:
                BinarySpatialOpType.getInstance().encode(new FilterElement(
                        "Intersects", BinarySpatialOpType.getInstance(), element),
                    value, output, hints);

                return;

            case GEOMETRY_OVERLAPS:
                BinarySpatialOpType.getInstance().encode(new FilterElement(
                        "Overlaps", BinarySpatialOpType.getInstance(), element),
                    value, output, hints);

                return;

            case GEOMETRY_TOUCHES:
                BinarySpatialOpType.getInstance().encode(new FilterElement(
                        "Touches", BinarySpatialOpType.getInstance(), element),
                    value, output, hints);

                return;

            case GEOMETRY_WITHIN:
                BinarySpatialOpType.getInstance().encode(new FilterElement(
                        "Within", BinarySpatialOpType.getInstance(), element),
                    value, output, hints);

                return;
            }

            throw new OperationNotSupportedException(
                "Unknown filter type in ComparisonFilter: "
                + lf.getClass().getName());
        }
    }

    public static class LogicOpsType extends FilterComplexType
        implements org.geotools.filter.FilterType {
        private static final ComplexType instance = new LogicOpsType();

        public static ComplexType getInstance() {
            return instance;
        }

        //      <xsd:complexType name="LogicOpsType" abstract="true"/>

        /**
         * @see org.geotools.xml.schema.ComplexType#getChild()
         */
        public ElementGrouping getChild() {
            return null;
        }

        /**
         * @see org.geotools.xml.schema.ComplexType#getChildElements()
         */
        public Element[] getChildElements() {
            return null;
        }

        /**
         * @see org.geotools.xml.schema.Type#getValue(org.geotools.xml.schema.Element,
         *      org.geotools.xml.schema.ElementValue[],
         *      org.xml.sax.Attributes, java.util.Map)
         */
        public Object getValue(Element element, ElementValue[] value,
            Attributes attrs, Map hints){
            return null; // subclass will do the right thing (tm)
        }

        /**
         * @see org.geotools.xml.schema.Type#getName()
         */
        public String getName() {
            return "LogicOpsType";
        }

        /**
         * @see org.geotools.xml.schema.Type#getInstanceType()
         */
        public Class getInstanceType() {
            return BinaryLogicOperator.class; // Not?
        }

        /**
         * @see org.geotools.xml.schema.Type#canEncode(org.geotools.xml.schema.Element,
         *      java.lang.Object, java.util.Map)
         */
        public boolean canEncode(Element element, Object value, Map hints) {
            if ((hints != null)
                    && hints.containsKey(FilterSchema.FILTER_CAP_KEY)) {
                FilterCapabilities fc = (FilterCapabilities) hints.get(FilterSchema.FILTER_CAP_KEY);

                if ((fc.getScalarOps() & FilterCapabilities.LOGICAL) != FilterCapabilities.LOGICAL) {
                    return false;
                }
            }

            return (element.getType() != null)
            && getName().equals(element.getType().getName())
            && (value instanceof BinaryLogicOperator || value instanceof Not);
        }

        /**
         * @see org.geotools.xml.schema.Type#encode(org.geotools.xml.schema.Element,
         *      java.lang.Object, org.geotools.xml.PrintHandler,
         *      java.util.Map)
         */
        public void encode(Element element, Object value, PrintHandler output,
            Map hints) throws IOException, OperationNotSupportedException {
            if (!canEncode(element, value, hints)) {
                return;
            }
            if( value instanceof BinaryLogicOperator){
                BinaryLogicOperator lf = (BinaryLogicOperator) value;
   
                switch ( Filters.getFilterType( lf )) {
                case LOGIC_AND:
                    BinaryLogicOpType.getInstance().encode(new FilterElement(
                            "And", BinaryLogicOpType.getInstance(), element),
                        value, output, hints);
   
                    return;
   
                case LOGIC_OR:
   
                    BinaryLogicOpType.getInstance().encode(new FilterElement("Or",
                            BinaryLogicOpType.getInstance(), element), value,
                        output, hints);
   
                    return;
                }
            }
            else if ( value instanceof Not){
                Not lf = (Not) value;
                UnaryLogicOpType.getInstance().encode(new FilterElement("Not",
                        UnaryLogicOpType.getInstance(), element), value,
                    output, hints);
                return;
            }

            throw new OperationNotSupportedException(
                "Unknown filter type in LogicFilter: "
                + value.getClass().getName());
        }

        /* (non-Javadoc)
         * @see org.geotools.xml.schema.ComplexType#isAbstract()
         */
        public boolean isAbstract() {
            return true;
        }
    }

    public static class FilterType extends FilterComplexType
        implements org.geotools.filter.FilterType {
        //      <xsd:complexType name="FilterType">
        //    <xsd:choice>
        //      <xsd:element ref="ogc:spatialOps"/>
        //      <xsd:element ref="ogc:comparisonOps"/>
        //      <xsd:element ref="ogc:logicOps"/>
        //      <xsd:element ref="ogc:FeatureId" maxOccurs="unbounded"/>
        //    </xsd:choice>
        //    </xsd:complexType>
        final static Element[] elems = new Element[] {
                new FilterElement("spatialOps", SpatialOpsType.getInstance()),
                new FilterElement("comparisonOps",
                    ComparisonOpsType.getInstance()),
                new FilterElement("logicOps", LogicOpsType.getInstance()),
                new FilterElement("FeatureId", FeatureIdType.getInstance()) {
                        public int getMaxOccurs() {
                            return Integer.MAX_VALUE;
                        }
                    }
                ,
            };
        private static Choice choice = new ChoiceGT(elems);
        private static final ComplexType instance = new FilterType();

        public static ComplexType getInstance() {
            return instance;
        }

        /**
         * @see org.geotools.xml.schema.ComplexType#getChild()
         */
        public ElementGrouping getChild() {
            return choice;
        }

        /**
         * @see org.geotools.xml.schema.ComplexType#getChildElements()
         */
        public Element[] getChildElements() {
            return elems;
        }

        /**
         * @see org.geotools.xml.schema.Type#getValue(org.geotools.xml.schema.Element,
         *      org.geotools.xml.schema.ElementValue[],
         *      org.xml.sax.Attributes, java.util.Map)
         */
        public Object getValue(Element element, ElementValue[] value,
            Attributes attrs, Map hints){
                if( value.length==1 )
                    return value[0].getValue();
                if( value.length==0 )
                    return Filter.EXCLUDE;
                try{
                    FilterFactory2 fac=CommonFactoryFinder.getFilterFactory2(null);
                    //LogicFilter filter=fac.createLogicFilter(FilterType.LOGIC_OR);
                    List<org.opengis.filter.Filter> filters = new ArrayList<org.opengis.filter.Filter>();
                    Set ids = new HashSet();
                    boolean isOnlyFids = true;
                    for (int i = 0; i < value.length; i++) {
                        org.opengis.filter.Filter value2 = (org.opengis.filter.Filter) value[i].getValue();
                        if( value2 == Filter.EXCLUDE) continue;
                        if( value2 instanceof Id){
                            Id idFilter = (Id) value2;
                            ids.addAll( idFilter.getIdentifiers() );
                        }
                        else {
                            isOnlyFids = false;
                        }                       
                        filters.add( value2 );
                    }                   
                    if( isOnlyFids && !ids.isEmpty()){
                        return fac.id( ids );
                    }
                    else if( filters.isEmpty() ){
                        return Filter.EXCLUDE;
                    }
                    else if( filters.size() == 1 ){
                        return filters.iterator().next();                       
                    }
                    else {
                        return fac.or( filters );                       
                    }
                    //return filter;
                }catch(IllegalFilterException e){
                    return value[0].getValue();
                }
        }

        /**
         * @see org.geotools.xml.schema.Type#getName()
         */
        public String getName() {
            return "FilterType";
        }

        /**
         * @see org.geotools.xml.schema.Type#getInstanceType()
         */
        public Class getInstanceType() {
            return Filter.class;
        }

        /**
         * @see org.geotools.xml.schema.Type#canEncode(org.geotools.xml.schema.Element,
         *      java.lang.Object, java.util.Map)
         */
        public boolean canEncode(Element element, Object value, Map hints) {
            if ((hints != null)
                    && hints.containsKey(FilterSchema.FILTER_CAP_KEY)) {
                FilterCapabilities fc = (FilterCapabilities) hints.get(FilterSchema.FILTER_CAP_KEY);

                if ((fc.getScalarOps() == 0) && (fc.getSpatialOps() == 0)) {
                    return false;
                }
            }

            boolean r = ((element != null) && (element.getType() != null)
                && getName().equals(element.getType().getName()));
            r = (r && (value != null) && value instanceof Filter
                && Filters.getFilterType( (Filter) value) != 0);

            return r;
        }

        /**
         * Note the assumption is that the comparison of this filter with the
         * WFS capabilities document has already been processed
         *
         * @see org.geotools.xml.schema.Type#encode(org.geotools.xml.schema.Element,
         *      java.lang.Object, org.geotools.xml.PrintHandler,
         *      java.util.Map)
         */
        public void encode(Element element, Object value, PrintHandler output,
            Map hints) throws IOException, OperationNotSupportedException {
            if (!canEncode(element, value, hints)) {
                return;
            }
            // we may only encode one type of filter ...
            if (value == null) {
                return;
            }
            if (value == Filter.INCLUDE) {
                return;
            }

            if (value == Filter.EXCLUDE) {
                return;
            }
            Filter filter = (Filter) value;

            if (element != null) {
                output.startElement(element.getNamespace(), element.getName(),
                    null);
//            }else{
//                output.startElement(getNamespace(), FilterSchema.getInstance().getElements()[2].getName(),
//                    null);
            }
            FilterEncodingPreProcessor visitor=getFilterEncodingPreProcessor(hints);
            filter.accept(visitor,null);
            // valid filter can have either a normal "filter" defining an test
            if( !visitor.getFilter().equals(Filter.EXCLUDE) ){
              encodeFilter(visitor.getFilter(),output,hints);
            }
            // or it can have a "selection" of specific feature IDs
            if( !visitor.getFidFilter().getIDs().isEmpty()){
                encodeFilter(visitor.getFidFilter(), output, hints);
            }
            if (element != null) {
                output.endElement(element.getNamespace(), element.getName());
//            }else{
//                output.endElement(getNamespace(), FilterSchema.getInstance().getElements()[2].getName());
                }
        }

    private FilterEncodingPreProcessor getFilterEncodingPreProcessor(Map hints) {
      if( hints!=null && hints.containsKey(XMLHandlerHints.FILTER_COMPLIANCE_STRICTNESS) )
        return new FilterEncodingPreProcessor((Integer) hints.get(XMLHandlerHints.FILTER_COMPLIANCE_STRICTNESS));
      return new FilterEncodingPreProcessor(XMLHandlerHints.VALUE_FILTER_COMPLIANCE_LOW);
    }
    }

    public static class FeatureIdType extends FilterComplexType {
        //      <xsd:complexType name="FeatureIdType">
        //        <xsd:attribute name="fid" type="xsd:anyURI" use="required"/>
        //      </xsd:complexType>
        private static final ComplexType instance = new FeatureIdType();
        private static Attribute[] attrs = new Attribute[] {
                new FilterAttribute("fid", XSISimpleTypes.AnyURI.getInstance(),
                    Attribute.REQUIRED),
            };

        public static ComplexType getInstance() {
            return instance;
        }

        /* (non-Javadoc)
         * @see org.geotools.xml.schema.ComplexType#getAttributes()
         */
        public Attribute[] getAttributes() {
            return attrs;
        }

        /**
         * @see org.geotools.xml.schema.ComplexType#getChild()
         */
        public ElementGrouping getChild() {
            return null;
        }

        /**
         * @see org.geotools.xml.schema.ComplexType#getChildElements()
         */
        public Element[] getChildElements() {
            return null;
        }

        /**
         * @see org.geotools.xml.schema.Type#getValue(org.geotools.xml.schema.Element,
         *      org.geotools.xml.schema.ElementValue[],
         *      org.xml.sax.Attributes, java.util.Map)
         */
        public Object getValue(Element element, ElementValue[] value,
            Attributes attrs1, Map hints)
            throws SAXException, SAXNotSupportedException {
            if ((element == null) || (value == null)
                    || (element.getType() == null)) {
                throw new SAXException("Invalid parameters : null found");
            }

            if (value.length != 0) {
                throw new SAXException("Invalid children: more than 0 ... "+value.length);
            }

            if (!getName().equals(element.getType().getName())) {
                throw new SAXException("Invalid type name for element provided");
            }

            String fid = null;
            fid = attrs1.getValue("", FeatureIdType.attrs[0].getName());

            if ((fid == null) || "".equals(fid)) {
                fid = attrs1.getValue(FeatureIdType.attrs[0].getNamespace()
                                                           .toString(),
                        FeatureIdType.attrs[0].getName());
            }
            FilterFactory2 ff = CommonFactoryFinder.getFilterFactory2(null);
            Set<FeatureId> fids = new HashSet<FeatureId>();
            fids.add( ff.featureId(fid) );
           
            return ff.id( fids );
            //FidFilter r = FilterFactoryFinder.createFilterFactory().createFidFilter(fid);
            //return r;
        }

        /**
         * @see org.geotools.xml.schema.Type#getName()
         */
        public String getName() {
            return "FeatureIdType";
        }

        /**
         * @see org.geotools.xml.schema.Type#getInstanceType()
         */
        public Class getInstanceType() {
            return Id.class;
        }

        /**
         * @see org.geotools.xml.schema.Type#canEncode(org.geotools.xml.schema.Element,
         *      java.lang.Object, java.util.Map)
         */
        public boolean canEncode(Element element, Object value, Map hints) {
            return (element.getType() != null)
            && getName().equals(element.getType().getName())
            && value instanceof Id;
        }

        /**
         * @see org.geotools.xml.schema.Type#encode(org.geotools.xml.schema.Element,
         *      java.lang.Object, org.geotools.xml.PrintHandler,
         *      java.util.Map)
         */
        public void encode(Element element, Object value, PrintHandler output,
            Map hints) throws IOException{
            if (!canEncode(element, value, hints)) {
                return;
            }

            Id ff = (Id) value;
            Set<String> fids = (Set) ff.getIDs();
           
            AttributesImpl att = new AttributesImpl();
            att.addAttribute(null, null, null, null, null);
           
            output.startElement(element.getNamespace(), "Filter", null);

            for (String fid : fids) {
                att.setAttribute(0, element.getNamespace().toString(),
                    attrs[0].getName(), null, "anyUri", fid);
                output.element(element.getNamespace(), element.getName(), att);
            }           
            output.endElement(element.getNamespace(), "Filter" );
        }
    }

    public static class BinaryComparisonOpType extends FilterComplexType
        implements org.geotools.filter.FilterType {
        private static final ComplexType instance = new BinaryComparisonOpType();

        //      <xsd:complexType name="BinaryComparisonOpType">
        //    <xsd:complexContent>
        //      <xsd:extension base="ogc:ComparisonOpsType">
        //        <xsd:sequence>
        //          <xsd:element ref="ogc:expression" minOccurs="2" maxOccurs="2"/>
        //        </xsd:sequence>
        //      </xsd:extension>
        //    </xsd:complexContent>
        //    </xsd:complexType>
        private static Element[] elems = new Element[] {
                new FilterElement("expression", ExpressionType.getInstance()) {
                        /**
                         * @see org.geotools.xml.schema.Element#getMaxOccurs()
                         */
                        public int getMaxOccurs() {
                            return 2;
                        }

                        /**
                         * @see org.geotools.xml.schema.Element#getMinOccurs()
                         */
                        public int getMinOccurs() {
                            return 2;
                        }
                    }
                ,
            };
        private static Sequence seq = new SequenceGT(elems);

        public static ComplexType getInstance() {
            return instance;
        }

        public Type getParent() {
            return ComparisonOpsType.getInstance();
        }

        /**
         * @see org.geotools.xml.schema.ComplexType#getChild()
         */
        public ElementGrouping getChild() {
            return seq;
        }

        /**
         * @see org.geotools.xml.schema.ComplexType#getChildElements()
         */
        public Element[] getChildElements() {
            return elems;
        }

        /**
         * @throws OperationNotSupportedException
         * @see org.geotools.xml.schema.Type#getValue(org.geotools.xml.schema.Element,
         *      org.geotools.xml.schema.ElementValue[],
         *      org.xml.sax.Attributes, java.util.Map)
         */
        public Object getValue(Element element, ElementValue[] value, Attributes attrs, Map hints)
                throws SAXException, OperationNotSupportedException {

            FilterFactory2 factory = FilterSchema.filterFactory(hints);

            try {
                short type = ComparisonOpsType.findFilterType(element.getName());

                Expression expr1 = (Expression) value[0].getValue();
                Expression expr2 = (Expression) value[1].getValue();

                switch (type) {
                case FilterType.COMPARE_EQUALS:
                    return factory.equals(expr1, expr2);

                case FilterType.COMPARE_NOT_EQUALS:
                    return factory.notEqual(expr1, expr2);

                case FilterType.COMPARE_GREATER_THAN:
                    return factory.greater(expr1, expr2);

                case FilterType.COMPARE_GREATER_THAN_EQUAL:
                    return factory.greaterOrEqual(expr1, expr2);

                case FilterType.COMPARE_LESS_THAN:
                    return factory.less(expr1, expr2);

                case FilterType.COMPARE_LESS_THAN_EQUAL:
                    return factory.lessOrEqual(expr1, expr2);

                default:
                    throw new SAXException("Illegal filter for " + element);

                }
            } catch (ClassCastException expressionRequired) {
                throw new SAXException("Illegal filter for " + element, expressionRequired);
            } catch (IllegalFilterException e) {
                throw new SAXException("Illegal filter for " + element);
            }
        }

        /**
         * @see org.geotools.xml.schema.Type#getName()
         */
        public String getName() {
            return "BinaryComparisonOpType";
        }

        /**
         * @see org.geotools.xml.schema.Type#getInstanceType()
         */
        public Class getInstanceType() {
            return BinaryComparisonOperator.class;
        }

        /**
         * @see org.geotools.xml.schema.Type#canEncode(org.geotools.xml.schema.Element,
         *      java.lang.Object, java.util.Map)
         */
        public boolean canEncode(Element element, Object value, Map hints) {
            if ((hints != null)
                    && hints.containsKey(FilterSchema.FILTER_CAP_KEY)) {
                FilterCapabilities fc = (FilterCapabilities) hints.get(FilterSchema.FILTER_CAP_KEY);

                if ((fc.getScalarOps()
                        & (FilterCapabilities.SIMPLE_COMPARISONS
                        | FilterCapabilities.SIMPLE_ARITHMETIC)) != (FilterCapabilities.SIMPLE_COMPARISONS
                        | FilterCapabilities.SIMPLE_ARITHMETIC)) {
                    return false;
                }
            }

            return (element.getType() != null)
            && getName().equals(element.getType().getName())
            && value instanceof BinaryComparisonOperator;
        }

        /**
         * @see org.geotools.xml.schema.Type#encode(org.geotools.xml.schema.Element,
         *      java.lang.Object, org.geotools.xml.PrintHandler,
         *      java.util.Map)
         */
        public void encode(Element element, Object value, PrintHandler output,
            Map hints) throws IOException, OperationNotSupportedException {
            if (!canEncode(element, value, hints)) {
                return;
            }

            BinaryComparisonOperator cf = (BinaryComparisonOperator) value;

            output.startElement(element.getNamespace(), element.getName(), null);

            // TODO is this order dependant?
            encodeExpr(cf.getExpression1(), output, hints);
            encodeExpr(cf.getExpression2(), output, hints);

            output.endElement(element.getNamespace(), element.getName());
        }
    }

    public static class PropertyIsLikeType extends FilterComplexType {
        private static final ComplexType instance = new PropertyIsLikeType();
        private static Element[] elems = new Element[] {
                new FilterElement("PropertyName", PropertyNameType.getInstance()),
                new FilterElement("Literal", LiteralType.getInstance()),
            };
        private static Sequence seq = new SequenceGT(elems);
        private static Attribute[] attr = new Attribute[] {
                new FilterAttribute("wildCard",
                    XSISimpleTypes.String.getInstance(), Attribute.REQUIRED),
                new FilterAttribute("singleChar",
                    XSISimpleTypes.String.getInstance(), Attribute.REQUIRED),
                new FilterAttribute("escape",
                    XSISimpleTypes.String.getInstance(), Attribute.REQUIRED),
            };

        public static ComplexType getInstance() {
            return instance;
        }

        //      <xsd:complexType name="PropertyIsLikeType">
        //        <xsd:complexContent>
        //          <xsd:extension base="ogc:ComparisonOpsType">
        //            <xsd:sequence>
        //              <xsd:element ref="ogc:PropertyName"/>
        //              <xsd:element ref="ogc:Literal"/>
        //            </xsd:sequence>
        //            <xsd:attribute name="wildCard" type="xsd:string" use="required"/>
        //            <xsd:attribute name="singleChar" type="xsd:string" use="required"/>
        //            <xsd:attribute name="escape" type="xsd:string" use="required"/>
        //          </xsd:extension>
        //        </xsd:complexContent>
        //      </xsd:complexType>
        public Type getParent() {
            return ComparisonOpsType.getInstance();
        }

        /**
         * @see org.geotools.xml.schema.ComplexType#getChild()
         */
        public ElementGrouping getChild() {
            return seq;
        }

        /**
         * @see org.geotools.xml.schema.ComplexType#getChildElements()
         */
        public Element[] getChildElements() {
            return elems;
        }

        public Attribute[] getAttributes() {
            return attr;
        }

        /**
         * @throws SAXException
         * @see org.geotools.xml.schema.Type#getValue(org.geotools.xml.schema.Element,
         *      org.geotools.xml.schema.ElementValue[],
         *      org.xml.sax.Attributes, java.util.Map)
         */
        public Object getValue(Element element, ElementValue[] value,
            Attributes attrs, Map hints) throws SAXException{
          FilterFactory2 factory = FilterSchema.filterFactory( hints );
            //          <xsd:extension base="ogc:ComparisonOpsType">
            //            <xsd:sequence>
            //              <xsd:element ref="ogc:PropertyName"/>
            //              <xsd:element ref="ogc:Literal"/>
            //            </xsd:sequence>
            //            <xsd:attribute name="wildCard" type="xsd:string" use="required"/>
            //            <xsd:attribute name="singleChar" type="xsd:string" use="required"/>
            //            <xsd:attribute name="escape" type="xsd:string" use="required"/>
            //          </xsd:extension>         
          try {
           
            Expression expr = (Expression) value[0].getValue();
            String wildCard = attrs.getValue( "wildCard" );
            String singleChar = attrs.getValue( "singleChar" );
            String escape = attrs.getValue( "escape" );
            Literal pattern = (Literal) value[1].getValue();
           
         
            return factory.like(expr, (String) pattern.getValue(), wildCard, singleChar, escape);
                        }
          catch( ClassCastException expressionRequired ){
            throw new SAXException("Illegal filter for "+element, expressionRequired );
      }
          catch (IllegalFilterException e) {
        throw new SAXException("Illegal filter for "+element );
      }
        }

        /**
         * @see org.geotools.xml.schema.Type#getName()
         */
        public String getName() {
            return "PropertyIsLikeType";
        }

        /**
         * @see org.geotools.xml.schema.Type#getInstanceType()
         */
        public Class getInstanceType() {
            return PropertyIsLike.class;
        }

        /**
         * @see org.geotools.xml.schema.Type#canEncode(org.geotools.xml.schema.Element,
         *      java.lang.Object, java.util.Map)
         */
        public boolean canEncode(Element element, Object value, Map hints) {
            if ((hints != null)
                    && hints.containsKey(FilterSchema.FILTER_CAP_KEY)) {
                FilterCapabilities fc = (FilterCapabilities) hints.get(FilterSchema.FILTER_CAP_KEY);

                if ((fc.getScalarOps() & FilterCapabilities.LIKE) != FilterCapabilities.LIKE) {
                    return false;
                }
            }

            return (element.getType() != null)
            && getName().equals(element.getType().getName())
            && value instanceof PropertyIsLike;
        }

        /**
         * @see org.geotools.xml.schema.Type#encode(org.geotools.xml.schema.Element,
         *      java.lang.Object, org.geotools.xml.PrintHandler,
         *      java.util.Map)
         */
        public void encode(Element element, Object value, PrintHandler output,
            Map hints) throws IOException, OperationNotSupportedException {
            if (!canEncode(element, value, hints)) {
                return;
            }

            PropertyIsLike lf = (PropertyIsLike) value;

            AttributesImpl at = new AttributesImpl();
            at.addAttribute(FilterSchema.NAMESPACE.toString(), "wildCard",
                null, "string", lf.getWildCard());
            at.addAttribute(FilterSchema.NAMESPACE.toString(), "singleChar",
                null, "string", lf.getSingleChar());
            at.addAttribute(FilterSchema.NAMESPACE.toString(), "escape", null,
                "string", lf.getEscape());

            output.startElement(element.getNamespace(), element.getName(), at);
            elems[0].getType().encode(elems[0], lf.getExpression(), output, hints); // PropertyName
            elems[1].getType().encode(elems[1], lf.getLiteral(), output, hints); // Literal
            output.endElement(element.getNamespace(), element.getName());
        }
    }

    public static class PropertyIsNullType extends FilterComplexType {
        private static final ComplexType instance = new PropertyIsNullType();
        private static Element[] elems = new Element[] {
                new FilterElement("PropertyName", PropertyNameType.getInstance()),
                new FilterElement("Literal", LiteralType.getInstance()),
            };
        private static Choice seq = new ChoiceGT(elems);

        public static ComplexType getInstance() {
            return instance;
        }

        //      <xsd:complexType name="PropertyIsNullType">
        //        <xsd:complexContent>
        //          <xsd:extension base="ogc:ComparisonOpsType">
        //            <xsd:choice>
        //              <xsd:element ref="ogc:PropertyName"/>
        //              <xsd:element ref="ogc:Literal"/>
        //            </xsd:choice>
        //          </xsd:extension>
        //        </xsd:complexContent>
        //      </xsd:complexType>
        public Type getParent() {
            return ComparisonOpsType.getInstance();
        }

        /**
         * @see org.geotools.xml.schema.ComplexType#getChild()
         */
        public ElementGrouping getChild() {
            return seq;
        }

        /**
         * @see org.geotools.xml.schema.ComplexType#getChildElements()
         */
        public Element[] getChildElements() {
            return elems;
        }

        /**
         * @see org.geotools.xml.schema.Type#getValue(org.geotools.xml.schema.Element,
         *      org.geotools.xml.schema.ElementValue[],
         *      org.xml.sax.Attributes, java.util.Map)
         */
        public Object getValue(Element element, ElementValue[] value, Attributes attrs, Map hints)
                throws SAXException {
            FilterFactory2 factory = FilterSchema.filterFactory(hints);
            try {
                Expression expr = (Expression) value[0].getValue();

                return factory.isNull(expr);
            } catch (ClassCastException expressionRequired) {
                throw new SAXException("Illegal filter for " + element, expressionRequired);
            } catch (IllegalFilterException e) {
                throw new SAXException("Illegal filter for " + element);
            }
        }

        /**
         * @see org.geotools.xml.schema.Type#getName()
         */
        public String getName() {
            return "PropertyIsNullType";
        }

        /**
         * @see org.geotools.xml.schema.Type#getInstanceType()
         */
        public Class getInstanceType() {
            return PropertyIsNull.class;
        }

        /**
         * @see org.geotools.xml.schema.Type#canEncode(org.geotools.xml.schema.Element,
         *      java.lang.Object, java.util.Map)
         */
        public boolean canEncode(Element element, Object value, Map hints) {
            if ((hints != null)
                    && hints.containsKey(FilterSchema.FILTER_CAP_KEY)) {
                FilterCapabilities fc = (FilterCapabilities) hints.get(FilterSchema.FILTER_CAP_KEY);

                if ((fc.getScalarOps() & FilterCapabilities.NULL_CHECK) != FilterCapabilities.NULL_CHECK) {
                    return false;
                }
            }

            return (element.getType() != null)
            && getName().equals(element.getType().getName())
            && value instanceof PropertyIsNull;
        }

        /**
         * @see org.geotools.xml.schema.Type#encode(org.geotools.xml.schema.Element,
         *      java.lang.Object, org.geotools.xml.PrintHandler,
         *      java.util.Map)
         */
        public void encode(Element element, Object value, PrintHandler output,
            Map hints) throws IOException, OperationNotSupportedException {
            if (!canEncode(element, value, hints)) {
                return;
            }

            PropertyIsNull lf = (PropertyIsNull) value;

            output.startElement(element.getNamespace(), element.getName(), null);
            elems[0].getType().encode(elems[0], lf.getExpression(), output,
                hints); // PropertyName

            //            elems[1].getType().encode(elems[1],lf.getNullCheckValue(),output,hints); // Literal
            output.endElement(element.getNamespace(), element.getName());
        }
    }

    public static class PropertyIsBetweenType extends FilterComplexType {
        private static final ComplexType instance = new PropertyIsBetweenType();
        private static Element[] elems = new Element[] {
                new FilterElement("expression", ExpressionType.getInstance()),
                new FilterElement("LowerBoundary",
                    LowerBoundaryType.getInstance()),
                new FilterElement("UpperBoundary",
                    UpperBoundaryType.getInstance()),
            };
        private static Sequence seq = new SequenceGT(elems);

        public static ComplexType getInstance() {
            return instance;
        }

        //      <xsd:complexType name="PropertyIsBetweenType">
        //        <xsd:complexContent>
        //          <xsd:extension base="ogc:ComparisonOpsType">
        //            <xsd:sequence>
        //              <xsd:element ref="ogc:expression"/>
        //              <xsd:element name="LowerBoundary" type="ogc:LowerBoundaryType"/>
        //              <xsd:element name="UpperBoundary" type="ogc:UpperBoundaryType"/>
        //            </xsd:sequence>
        //          </xsd:extension>
        //        </xsd:complexContent>
        //      </xsd:complexType>
        public Type getParent() {
            return ComparisonOpsType.getInstance();
        }

        /**
         * @see org.geotools.xml.schema.ComplexType#getChild()
         */
        public ElementGrouping getChild() {
            return seq;
        }

        /**
         * @see org.geotools.xml.schema.ComplexType#getChildElements()
         */
        public Element[] getChildElements() {
            return elems;
        }

        /**
         * @see org.geotools.xml.schema.Type#getValue(org.geotools.xml.schema.Element,
         *      org.geotools.xml.schema.ElementValue[],
         *      org.xml.sax.Attributes, java.util.Map)
         */
        public Object getValue(Element element, ElementValue[] value, Attributes attrs, Map hints)
                throws SAXException {
            FilterFactory2 factory = FilterSchema.filterFactory(hints);
            try {
                Expression left = (Expression) value[1].getValue();
                Expression middle = (Expression) value[0].getValue();
                Expression right = (Expression) value[2].getValue();

                return factory.between(middle, left, right);

            } catch (ClassCastException expressionRequired) {
                throw new SAXException("Illegal filter for " + element, expressionRequired);
            } catch (IllegalFilterException e) {
                throw new SAXException("Illegal filter for " + element);
            }
        }

        /**
         * @see org.geotools.xml.schema.Type#getName()
         */
        public String getName() {
            return "PropertyIsBetweenType";
        }

        /**
         * @see org.geotools.xml.schema.Type#getInstanceType()
         */
        public Class getInstanceType() {
            return PropertyIsBetween.class;
        }

        /**
         * @see org.geotools.xml.schema.Type#canEncode(org.geotools.xml.schema.Element,
         *      java.lang.Object, java.util.Map)
         */
        public boolean canEncode(Element element, Object value, Map hints) {
            if ((hints != null)
                    && hints.containsKey(FilterSchema.FILTER_CAP_KEY)) {
                FilterCapabilities fc = (FilterCapabilities) hints.get(FilterSchema.FILTER_CAP_KEY);

                if ((fc.getScalarOps() & FilterCapabilities.BETWEEN) != FilterCapabilities.BETWEEN) {
                    return false;
                }
            }

            return (element.getType() != null)
            && getName().equals(element.getType().getName())
            && value instanceof PropertyIsBetween;
        }

        /**
         * @see org.geotools.xml.schema.Type#encode(org.geotools.xml.schema.Element,
         *      java.lang.Object, org.geotools.xml.PrintHandler,
         *      java.util.Map)
         */
        public void encode(Element element, Object value, PrintHandler output,
            Map hints) throws IOException, OperationNotSupportedException {
            if (!canEncode(element, value, hints)) {
                return;
            }

            PropertyIsBetween lf = (PropertyIsBetween) value;

            output.startElement(element.getNamespace(), element.getName(), null);
            encodeExpr(lf.getExpression(),output,hints);
            elems[1].getType().encode(elems[1], lf.getLowerBoundary(), output, hints); // LowerBoundary
            elems[2].getType().encode(elems[2], lf.getUpperBoundary(), output,
                hints); // UpperBoundary
            output.endElement(element.getNamespace(), element.getName());
        }
    }

    public static class LowerBoundaryType extends FilterComplexType {
        private static final ComplexType instance = new LowerBoundaryType();

        //      <xsd:complexType name="LowerBoundaryType">
        //    <xsd:choice>
        //      <xsd:element ref="ogc:expression"/>
        //    </xsd:choice>
        //    </xsd:complexType>
        private static Element[] elems = new Element[] {
                new FilterElement("expression", ExpressionType.getInstance()),
            };
        private static Choice choice = new ChoiceGT(elems);

        public static ComplexType getInstance() {
            return instance;
        }

        /**
         * @see org.geotools.xml.schema.ComplexType#getChild()
         */
        public ElementGrouping getChild() {
            return choice;
        }

        /**
         * @see org.geotools.xml.schema.ComplexType#getChildElements()
         */
        public Element[] getChildElements() {
            return elems;
        }

        /**
         * @see org.geotools.xml.schema.Type#getValue(org.geotools.xml.schema.Element,
         *      org.geotools.xml.schema.ElementValue[],
         *      org.xml.sax.Attributes, java.util.Map)
         */
        public Object getValue(Element element, ElementValue[] value,
            Attributes attrs, Map hints){
          return (Expression) value[0].getValue();
        }

        /**
         * @see org.geotools.xml.schema.Type#getName()
         */
        public String getName() {
            return "LowerBoundaryType";
        }

        /**
         * @see org.geotools.xml.schema.Type#getInstanceType()
         */
        public Class getInstanceType() {
            return Expression.class;
        }

        public boolean canEncode(Element element, Object value, Map hints) {
            if ((hints != null)
                    && hints.containsKey(FilterSchema.FILTER_CAP_KEY)) {
                FilterCapabilities fc = (FilterCapabilities) hints.get(FilterSchema.FILTER_CAP_KEY);

                if (fc.getScalarOps() == FilterCapabilities.NO_OP) {
                    return false;
                }
            }

            return (element.getType() != null)
            && getName().equals(element.getType().getName())
            && value instanceof Expression;
        }

        /**
         * @see org.geotools.xml.schema.Type#encode(org.geotools.xml.schema.Element,
         *      java.lang.Object, org.geotools.xml.PrintHandler,
         *      java.util.Map)
         */
        public void encode(Element element, Object value, PrintHandler output,
            Map hints) throws IOException, OperationNotSupportedException {
            if (!canEncode(element, value, hints)) {
                return;
            }

            Expression lf = (Expression) value;

            output.startElement(element.getNamespace(), element.getName(), null);
            encodeExpr(lf,output,hints);
            output.endElement(element.getNamespace(), element.getName());
        }
    }

    public static class UpperBoundaryType extends FilterComplexType {
        private static final ComplexType instance = new UpperBoundaryType();

        //      <xsd:complexType name="UpperBoundaryType">
        //        <xsd:sequence>
        //          <xsd:element ref="ogc:expression"/>
        //        </xsd:sequence>
        //      </xsd:complexType>
        private static Element[] elems = new Element[] {
                new FilterElement("expression", ExpressionType.getInstance()),
            };
        private static Sequence choice = new SequenceGT(elems);

        public static ComplexType getInstance() {
            return instance;
        }

        /**
         * @see org.geotools.xml.schema.ComplexType#getChild()
         */
        public ElementGrouping getChild() {
            return choice;
        }

        /**
         * @see org.geotools.xml.schema.ComplexType#getChildElements()
         */
        public Element[] getChildElements() {
            return elems;
        }

        /**
         * @see org.geotools.xml.schema.Type#getValue(org.geotools.xml.schema.Element,
         *      org.geotools.xml.schema.ElementValue[],
         *      org.xml.sax.Attributes, java.util.Map)
         */
        public Object getValue(Element element, ElementValue[] value,
            Attributes attrs, Map hints){
          return (Expression) value[0].getValue();
        }

        /**
         * @see org.geotools.xml.schema.Type#getName()
         */
        public String getName() {
            return "UpperBoundaryType";
        }

        /**
         * @see org.geotools.xml.schema.Type#getInstanceType()
         */
        public Class getInstanceType() {
            return Expression.class;
        }

        public boolean canEncode(Element element, Object value, Map hints) {
            if ((hints != null)
                    && hints.containsKey(FilterSchema.FILTER_CAP_KEY)) {
                FilterCapabilities fc = (FilterCapabilities) hints.get(FilterSchema.FILTER_CAP_KEY);

                if (fc.getScalarOps() == FilterCapabilities.NO_OP) {
                    return false;
                }
            }

            return (element.getType() != null)
            && getName().equals(element.getType().getName())
            && value instanceof Expression;
        }

        /**
         * @see org.geotools.xml.schema.Type#encode(org.geotools.xml.schema.Element,
         *      java.lang.Object, org.geotools.xml.PrintHandler,
         *      java.util.Map)
         */
        public void encode(Element element, Object value, PrintHandler output,
            Map hints) throws IOException, OperationNotSupportedException {
            if (!canEncode(element, value, hints)) {
                return;
            }

            Expression lf = (Expression) value;

            output.startElement(element.getNamespace(), element.getName(), null);
            encodeExpr(lf,output,hints);
            output.endElement(element.getNamespace(), element.getName());
        }
    }

    public static class BinarySpatialOpType extends FilterComplexType {
        private static final ComplexType instance = new BinarySpatialOpType();

        //      <xsd:complexType name="BinarySpatialOpType">
        //        <xsd:complexContent>
        //          <xsd:extension base="ogc:SpatialOpsType">
        //            <xsd:sequence>
        //              <xsd:element ref="ogc:PropertyName"/>
        //              <xsd:choice>
        //                <xsd:element ref="gml:_Geometry"/>
        //                <xsd:element ref="gml:Box"/>
        //              </xsd:choice>
        //            </xsd:sequence>
        //          </xsd:extension>
        //        </xsd:complexContent>
        //      </xsd:complexType>
        private static Element[] elems = new Element[] {
                new FilterElement("PropertyName", PropertyNameType.getInstance()),
                GMLSchema.getInstance().getElements()[29], // _Geometry
                GMLSchema.getInstance().getElements()[41]
            };
        private static Sequence child = new SequenceGT(new ElementGrouping[] {
                    elems[0],
                    new ChoiceGT(new Element[] { elems[1], elems[2] })
                });

        public static ComplexType getInstance() {
            return instance;
        }

        public Type getParent() {
            return SpatialOpsType.getInstance();
        }

        /**
         * @see org.geotools.xml.schema.ComplexType#getChild()
         */
        public ElementGrouping getChild() {
            return child;
        }

        /**
         * @see org.geotools.xml.schema.ComplexType#getChildElements()
         */
        public Element[] getChildElements() {
            return elems;
        }

        /**
         * @throws SAXException
         * @see org.geotools.xml.schema.Type#getValue(org.geotools.xml.schema.Element,
         *      org.geotools.xml.schema.ElementValue[],
         *      org.xml.sax.Attributes, java.util.Map)
         */
        public Object getValue(Element element, ElementValue[] value, Attributes attrs, Map hints)
                throws SAXException {
            FilterFactory2 factory = FilterSchema.filterFactory(hints);

            try {
                short type = (short) SpatialOpsType.findFilterType(element.getName());

                Expression geometry1 = (Expression) value[0].getValue();
                Expression geometry2 = (Expression) value[1].getValue();

                // GeometryFilter filter = factory.createGeometryFilter( type );
                switch (type) {
                case FilterType.GEOMETRY_EQUALS:
                    return factory.equal(geometry1, geometry2);

                case FilterType.GEOMETRY_DISJOINT:
                    return factory.disjoint(geometry1, geometry2);

                case FilterType.GEOMETRY_INTERSECTS:
                    return factory.intersects(geometry1, geometry2);

                case FilterType.GEOMETRY_CROSSES:
                    return factory.crosses(geometry1, geometry2);

                case FilterType.GEOMETRY_WITHIN:
                    return factory.within(geometry1, geometry2);

                case FilterType.GEOMETRY_CONTAINS:
                    return factory.contains(geometry1, geometry2);

                case FilterType.GEOMETRY_OVERLAPS:
                    return factory.overlaps(geometry1, geometry2);

                case FilterType.GEOMETRY_TOUCHES:
                    return factory.touches(geometry1, geometry2);

                default:
                    throw new SAXException("Illegal filter for " + element);
                }
            } catch (ClassCastException filterRequired) {
                throw new SAXException("Illegal filter for " + element, filterRequired);
            } catch (IllegalFilterException e) {
                throw new SAXException("Illegal filter for " + element);
            }
        }

        /**
         * @see org.geotools.xml.schema.Type#getName()
         */
        public String getName() {
            return "BinarySpatialOpType";
        }

        /**
         * @see org.geotools.xml.schema.Type#getInstanceType()
         */
        public Class getInstanceType() {
            return BinarySpatialOperator.class;
        }

        public boolean canEncode(Element element, Object value, Map hints) {
            if ((hints != null)
                    && hints.containsKey(FilterSchema.FILTER_CAP_KEY)) {
                FilterCapabilities fc = (FilterCapabilities) hints.get(FilterSchema.FILTER_CAP_KEY);
                FilterCapabilities elementkey = FilterCapabilities.findOperation(element
                        .getName());

                if ((elementkey == null)
                        || !fc.supports(elementkey)) {
                    return false;
                }
            }

            return (element.getType() != null)
            && getName().equals(element.getType().getName())
            && value instanceof BinarySpatialOperator;
        }

        /**
         * @see org.geotools.xml.schema.Type#encode(org.geotools.xml.schema.Element,
         *      java.lang.Object, org.geotools.xml.PrintHandler,
         *      java.util.Map)
         */
        public void encode(Element element, Object value, PrintHandler output,
            Map hints) throws IOException, OperationNotSupportedException {
            if (!canEncode(element, value, hints)) {
                return;
            }

            BinarySpatialOperator lf = (BinarySpatialOperator) value;

            output.startElement(element.getNamespace(), element.getName(), null);
            short type1 = Filters.getExpressionType(lf.getExpression1());
            short type2 = Filters.getExpressionType(lf.getExpression2());
            if ((type1 == org.geotools.filter.ExpressionType.LITERAL_STRING)
                    || (type1 == org.geotools.filter.ExpressionType.ATTRIBUTE_STRING)
                    || (type1 == org.geotools.filter.ExpressionType.ATTRIBUTE)) {
                elems[0].getType().encode(elems[0], lf.getExpression1(),
                    output, hints); // prop name

                if (type2 == org.geotools.filter.ExpressionType.LITERAL_GEOMETRY) {
                    elems[1].getType().encode(elems[1],
                        ((Literal) lf.getExpression2()).getValue(),
                        output, hints); // geom
                } else {
                    elems[2].getType().encode(elems[2],
                        ((Literal) lf.getExpression2()).getValue(),
                        output, hints); // geom
                }
            } else {
               
                if ((type2 == org.geotools.filter.ExpressionType.LITERAL_STRING)
                        || (type2 == org.geotools.filter.ExpressionType.ATTRIBUTE_STRING)
                        || (type2 == org.geotools.filter.ExpressionType.ATTRIBUTE)) {
                    elems[0].getType().encode(elems[0], lf.getExpression2(),
                        output, hints); // prop name

                    if (type1 == org.geotools.filter.ExpressionType.LITERAL_GEOMETRY) {
                        elems[1].getType().encode(elems[1],
                            ((Literal) lf.getExpression1())
                            .getValue(), output, hints); // geom
                    } else {
                        elems[2].getType().encode(elems[2],
                            ((Literal) lf.getExpression1())
                            .getValue(), output, hints); // geom
                    }
                } else {
                    throw new OperationNotSupportedException(
                            "Either the left or right expr must be a literal for the property name l="
                                    + type1 + " r=" + type2);
                }
            }

            output.endElement(element.getNamespace(), element.getName());
        }
    }

    /**
     * The <BBOX> element is defined as a convenient and more compact way
     * of encoding the very common bounding box constraint based on the
     * gml:Box geometry. It is equivalent to the spatial operation
     * <Not><Disjoint> ??? </Disjoint></Not> meaning that the <BBOX> operator
     * should identify all geometries that spatially interact with the box
     * in some manner.
     *
     * @author jgarnett
     *
     * TODO To change the template for this generated type comment go to
     * Window - Preferences - Java - Code Style - Code Templates
     */
    public static class BBOXType extends FilterComplexType {
        private static final ComplexType instance = new BBOXType();

        //      <xsd:complexType name="BBOXType">
        //    <xsd:complexContent>
        //      <xsd:extension base="ogc:SpatialOpsType">
        //        <xsd:sequence>
        //          <xsd:element ref="ogc:PropertyName"/>
        //          <xsd:element ref="gml:Box"/>
        //        </xsd:sequence>
        //      </xsd:extension>
        //    </xsd:complexContent>
        //    </xsd:complexType>
        private static final Element OGC_PROPERTY_NAME = new FilterElement("PropertyName", PropertyNameType.getInstance());
        private static final Element GML_BOX = GMLSchema.getInstance().getElements()[GMLSchema.BOX];
       
        private static Element[] elems = new Element[] {OGC_PROPERTY_NAME,GML_BOX};
       
        private Sequence seq = new SequenceGT(elems);

        public static ComplexType getInstance() {
            return instance;
        }

        public Type getParent() {
            return SpatialOpsType.getInstance();
        }

        /**
         * @see org.geotools.xml.schema.ComplexType#getChild()
         */
        public ElementGrouping getChild() {
            return seq;
        }

        /**
         * @see org.geotools.xml.schema.ComplexType#getChildElements()
         */
        public Element[] getChildElements() {
            return elems;
        }

        /**
         * @throws SAXException 
         * @see org.geotools.xml.schema.Type#getValue(org.geotools.xml.schema.Element,
         *      org.geotools.xml.schema.ElementValue[],
         *      org.xml.sax.Attributes, java.util.Map)
         */
        public Object getValue(Element element, ElementValue[] value, Attributes attrs, Map hints)
                throws SAXException {

            if (value == null || value.length != 2) {
                throw new SAXException("ogc:propertyName or gml:box required for bbox filter");
            }
            FilterFactory2 factory = FilterSchema.filterFactory(hints);
            try {
                Expression geometry1 = (Expression) value[0].getValue();
                Expression geometry2 = (Expression) value[1].getValue();
                if( geometry2 instanceof Literal ){
                    Object literal = ((Literal) geometry2).getValue();
                    if( literal instanceof Geometry){
                        Geometry geometry = (Geometry) literal;
                        Envelope env = geometry.getEnvelopeInternal();
                        return factory.bbox(geometry1, env.getMinX(), env.getMinY(), env.getMaxX(), env.getMaxY(), null );
                    }
                }
                Disjoint disjoint = factory.disjoint(geometry1, geometry2);
                return factory.not( disjoint );
               
            } catch (ClassCastException wrong) {
                throw new SAXException("ogc:propertyName or gml:box required for bbox filter",
                        wrong);
            } catch (IllegalFilterException illegalFilterException) {
                throw new SAXException("Could not create bbox filter", illegalFilterException);
            }
        }

        /**
         * @see org.geotools.xml.schema.Type#getName()
         */
        public String getName() {
            return "BBOXType";
        }

        /**
         * @see org.geotools.xml.schema.Type#getInstanceType()
         */
        public Class getInstanceType() {
            return Filter.class; // was GeometryFilter.class but use of Disjoint.not() limits this to Filte
        }

        public boolean canEncode(Element element, Object value, Map hints) {
            if ((hints != null)
                    && hints.containsKey(FilterSchema.FILTER_CAP_KEY)) {
                FilterCapabilities fc = (FilterCapabilities) hints.get(FilterSchema.FILTER_CAP_KEY);

                if ((fc.getSpatialOps() & FilterCapabilities.SPATIAL_BBOX) != FilterCapabilities.SPATIAL_BBOX) {
                    return false;
                }
            }

            return (element.getType() != null)
            && getName().equals(element.getType().getName())
            && value instanceof BinarySpatialOperator;
        }

        /**
         * @see org.geotools.xml.schema.Type#encode(org.geotools.xml.schema.Element,
         *      java.lang.Object, org.geotools.xml.PrintHandler,
         *      java.util.Map)
         */
        public void encode(Element element, Object value, PrintHandler output,
            Map hints) throws IOException, OperationNotSupportedException {
            if (!canEncode(element, value, hints)) {
                return;
            }

            BinarySpatialOperator lf = (BinarySpatialOperator) value;

            output.startElement(element.getNamespace(), element.getName(), null);
            short TYPE1 = Filters.getExpressionType(lf.getExpression1());
            short TYPE2 = Filters.getExpressionType(lf.getExpression2());
            if (TYPE1 == org.geotools.filter.ExpressionType.LITERAL_GEOMETRY) {
                elems[0].getType().encode(elems[0], lf.getExpression2(),
                    output, hints); // prop name

                Geometry g = ((Geometry) ((Literal) lf
                    .getExpression1()).getValue()).getEnvelope();
                elems[1].getType().encode(elems[1], g, output, hints); // geom
            } else {
                if (TYPE2 == org.geotools.filter.ExpressionType.LITERAL_GEOMETRY) {
                    elems[0].getType().encode(elems[0], lf.getExpression1(),
                        output, hints); // prop name

                    Geometry g = ((Geometry) ((Literal) lf
                        .getExpression2()).getValue()).getEnvelope();
                    elems[1].getType().encode(elems[1], g, output, hints); // geom
                } else {
                    throw new OperationNotSupportedException(
                        "Either the left or right expr must be a literal for the property name : BBOXType");
                }
            }
            output.endElement(element.getNamespace(), element.getName());
        }
    }

    public static class DistanceBufferType extends FilterComplexType {
        private static final ComplexType instance = new DistanceBufferType();

        //      <xsd:complexType name="DistanceBufferType">
        //        <xsd:complexContent>
        //          <xsd:extension base="ogc:SpatialOpsType">
        //            <xsd:sequence>
        //              <xsd:element ref="ogc:PropertyName"/>
        //              <xsd:element ref="gml:_Geometry"/>
        //              <xsd:element name="Distance" type="ogc:DistanceType"/>
        //            </xsd:sequence>
        //          </xsd:extension>
        //        </xsd:complexContent>
        //      </xsd:complexType>
        private static Element[] elems = new Element[] {
                new FilterElement("PropertyName", PropertyNameType.getInstance()),
                GMLSchema.getInstance().getElements()[29], // _Geometry
                new FilterElement("Distance", DistanceType.getInstance())
            };
        private Sequence seq = new SequenceGT(elems);

        public static ComplexType getInstance() {
            return instance;
        }

        public Type getParent() {
            return SpatialOpsType.getInstance();
        }

        /**
         * @see org.geotools.xml.schema.ComplexType#getChild()
         */
        public ElementGrouping getChild() {
            return seq;
        }

        /**
         * @see org.geotools.xml.schema.ComplexType#getChildElements()
         */
        public Element[] getChildElements() {
            return elems;
        }

        /**
         * @throws SAXException
         * @see org.geotools.xml.schema.Type#getValue(org.geotools.xml.schema.Element,
         *      org.geotools.xml.schema.ElementValue[],
         *      org.xml.sax.Attributes, java.util.Map)
         */
        public Object getValue(Element element, ElementValue[] value,
            Attributes attrs, Map hints) throws SAXException {
                   
          FilterFactory2 factory = FilterSchema.filterFactory( hints );
          try {
            Expression geometry1 =  (Expression) value[0].getValue();
            Expression geometry2 = (Expression) value[1].getValue();
            Literal literal = (Literal) value[2];
            double distance = ((Number)literal.getValue()).doubleValue();           
            return factory.beyond(geometry1, geometry2, distance, null)
          }
          catch( ClassCastException wrong){
            throw new SAXException( wrong );
          } catch (IllegalFilterException illegalFilterException) {
            throw new SAXException( illegalFilterException );
      }
        }

        /**
         * @see org.geotools.xml.schema.Type#getName()
         */
        public String getName() {
            return "DistanceBufferType";
        }

        /**
         * @see org.geotools.xml.schema.Type#getInstanceType()
         */
        public Class getInstanceType() {
            return DistanceBufferOperator.class;
        }

        public boolean canEncode(Element element, Object value, Map hints) {
            if ((hints != null)
                    && hints.containsKey(FilterSchema.FILTER_CAP_KEY)) {
                FilterCapabilities fc = (FilterCapabilities) hints.get(FilterSchema.FILTER_CAP_KEY);

                if ((fc.getSpatialOps()
                        & (FilterCapabilities.SPATIAL_BEYOND
                        | FilterCapabilities.SPATIAL_DWITHIN)) != (FilterCapabilities.SPATIAL_BEYOND
                        | FilterCapabilities.SPATIAL_DWITHIN)) {
                    return false;
                }
            }

            return (element.getType() != null)
            && getName().equals(element.getType().getName())
            && value instanceof DistanceBufferOperator;
        }

        /**
         * @see org.geotools.xml.schema.Type#encode(org.geotools.xml.schema.Element,
         *      java.lang.Object, org.geotools.xml.PrintHandler,
         *      java.util.Map)
         */
        public void encode(Element element, Object value, PrintHandler output,
            Map hints) throws IOException, OperationNotSupportedException {
            if (!canEncode(element, value, hints)) {
                return;
            }

            DistanceBufferOperator lf = (DistanceBufferOperator) value;

            output.startElement(element.getNamespace(), element.getName(), null);

            if (Filters.getExpressionType(lf.getExpression1()) == org.geotools.filter.ExpressionType.ATTRIBUTE) {
                elems[0].getType().encode(elems[0], lf.getExpression1(),
                    output, hints); // prop name
                elems[1].getType().encode(elems[1], lf.getExpression2().evaluate(null, Geometry.class),
                    output, hints); // geom
                elems[2].getType().encode(elems[2], lf, output, hints); // distancetype
            } else {
                if (Filters.getExpressionType(lf.getExpression2()) == org.geotools.filter.ExpressionType.ATTRIBUTE) {
                    elems[0].getType().encode(elems[0], lf.getExpression2(),
                        output, hints); // prop name
                    elems[1].getType().encode(elems[1], lf.getExpression1().evaluate(null,Geometry.class),
                        output, hints); // geom
                    elems[2].getType().encode(elems[2], lf, output, hints); // distancetype
                } else {
                    throw new OperationNotSupportedException(
                        "Either the left or right expr must be a literal for the property name");
                }
            }

            output.endElement(element.getNamespace(), element.getName());
        }
    }

    public static class DistanceType extends FilterComplexType {
        private static final ComplexType instance = new DistanceType();

        //      <xsd:complexType name="DistanceType" mixed="true">
        //        <xsd:attribute name="units" type="xsd:string" use="required"/>
        //      </xsd:complexType>
        private static Attribute[] attrs = new Attribute[] {
                new FilterAttribute("units",
                    XSISimpleTypes.String.getInstance(), Attribute.REQUIRED),
            };

        public static ComplexType getInstance() {
            return instance;
        }

        public boolean isMixed() {
            return true;
        }

        public Attribute[] getAttributes() {
            return attrs;
        }

        /**
         * @see org.geotools.xml.schema.ComplexType#getChild()
         */
        public ElementGrouping getChild() {
            return null;
        }

        /**
         * @see org.geotools.xml.schema.ComplexType#getChildElements()
         */
        public Element[] getChildElements() {
            return null;
        }

        /**
         * @see org.geotools.xml.schema.Type#getValue(org.geotools.xml.schema.Element,
         *      org.geotools.xml.schema.ElementValue[],
         *      org.xml.sax.Attributes, java.util.Map)
         */
        public Object getValue(Element element, ElementValue[] value,
            Attributes attrs, Map hints) throws SAXException {
         
          FilterFactory2 factory = FilterSchema.filterFactory( hints );
          try {
              Expression geometry1 =  (Expression) value[0].getValue();
                    Expression geometry2 = (Expression) value[1].getValue();
                    Literal literal = (Literal) value[2];
                    double distance = ((Number)literal.getValue()).doubleValue();
                    return factory.dwithin(geometry1, geometry2, distance, null );
          }
          catch( ClassCastException wrong){
            throw new SAXException( wrong );
          } catch (IllegalFilterException illegalFilterException) {
            throw new SAXException( illegalFilterException );
      }
        }

        /**
         * @see org.geotools.xml.schema.Type#getName()
         */
        public String getName() {
            return "DistanceType";
        }

        /**
         * @see org.geotools.xml.schema.Type#getInstanceType()
         */
        public Class getInstanceType() {
            return DistanceBufferOperator.class;
        }

        public boolean canEncode(Element element, Object value, Map hints) {
            if ((hints != null)
                    && hints.containsKey(FilterSchema.FILTER_CAP_KEY)) {
                FilterCapabilities fc = (FilterCapabilities) hints.get(FilterSchema.FILTER_CAP_KEY);

                if ((fc.getSpatialOps()
                        & (FilterCapabilities.SPATIAL_BEYOND
                        | FilterCapabilities.SPATIAL_DWITHIN)) != (FilterCapabilities.SPATIAL_BEYOND
                        | FilterCapabilities.SPATIAL_DWITHIN)) {
                    return false;
                }
            }

            return (element.getType() != null)
            && getName().equals(element.getType().getName())
            && value instanceof DistanceBufferOperator;
        }

        /**
         * @see org.geotools.xml.schema.Type#encode(org.geotools.xml.schema.Element,
         *      java.lang.Object, org.geotools.xml.PrintHandler,
         *      java.util.Map)
         */
        public void encode(Element element, Object value, PrintHandler output,
            Map hints) throws IOException{
            if (!canEncode(element, value, hints)) {
                return;
            }

            DistanceBufferOperator distanceFilter = (DistanceBufferOperator) value;

            AttributesImpl ai = new AttributesImpl();

            String name = attrs[0].getName();
            String uri = getNamespace().toString();
           
            if (Filters.getExpressionType( distanceFilter.getExpression1() ) == ExpressionType.LITERAL_GEOMETRY) {
                Geometry geometry = distanceFilter.getExpression1().evaluate(null,Geometry.class);
                if( geometry.getUserData() != null ){
                    // code assume user data is an srsName see GEOT-693
                    String srsName = String.valueOf( geometry.getUserData() );
                    ai.addAttribute(uri, name, null, "string", srsName);
                }
            } else {
                Geometry geometry = distanceFilter.getExpression2().evaluate(null,Geometry.class);
                if( geometry.getUserData() != null ){
                    // code assume user data is an srsName see GEOT-693
                    String srsName = String.valueOf( geometry.getUserData() );
                    ai.addAttribute(uri, name, null, "string", srsName);
                }
            }

            output.startElement(element.getNamespace(), element.getName(), null);
            output.characters("" + distanceFilter.getDistance());
            output.endElement(element.getNamespace(), element.getName());
        }
    }

    public static class BinaryLogicOpType extends FilterComplexType {
        private static final ComplexType instance = new BinaryLogicOpType();

        //      <xsd:complexType name="BinaryLogicOpType">
        //        <xsd:complexContent>
        //          <xsd:extension base="ogc:LogicOpsType">
        //            <xsd:choice minOccurs="2" maxOccurs="unbounded">
        //              <xsd:element ref="ogc:comparisonOps"/>
        //              <xsd:element ref="ogc:spatialOps"/>
        //              <xsd:element ref="ogc:logicOps"/>
        //            </xsd:choice>
        //          </xsd:extension>
        //        </xsd:complexContent>
        //      </xsd:complexType>
        private static Element[] elems = new Element[] {
                new FilterElement("comparisonOps",
                    ComparisonOpsType.getInstance()),
                new FilterElement("spatialOps", SpatialOpsType.getInstance()),
                new FilterElement("logicOps", LogicOpsType.getInstance())
            };
        private static Choice choice = new ChoiceGT(null, 2,
                Integer.MAX_VALUE, elems);

        public static ComplexType getInstance() {
            return instance;
        }

        /* (non-Javadoc)
         * @see org.geotools.xml.schema.ComplexType#getParent()
         */
        public Type getParent() {
            return LogicOpsType.getInstance();
        }

        /**
         * @see org.geotools.xml.schema.ComplexType#getChild()
         */
        public ElementGrouping getChild() {
            return choice;
        }

        /**
         * @see org.geotools.xml.schema.ComplexType#getChildElements()
         */
        public Element[] getChildElements() {
            return elems;
        }

        /**
         * @see org.geotools.xml.schema.Type#getValue(org.geotools.xml.schema.Element,
         *      org.geotools.xml.schema.ElementValue[],
         *      org.xml.sax.Attributes, java.util.Map)
         */
        public Object getValue(Element element, ElementValue[] value,
            Attributes attrs, Map hints) throws SAXException {
         
          FilterFactory2 factory = FilterSchema.filterFactory( hints );
          String name = element.getName();
          short type;
          if( "and".equalsIgnoreCase( name )){
            type = FilterType.LOGIC_AND;
          }
          else if( "or".equalsIgnoreCase( name )){
            type = FilterType.LOGIC_OR;
          }
          else {
            throw new SAXException("Expected AND or OR logic filter" );
          }
          try {
              ArrayList<org.opengis.filter.Filter> children = new ArrayList<org.opengis.filter.Filter>( value.length );
              Set<Identifier> ids = new HashSet<Identifier>( value.length );
              boolean fidOnly = true;
             
        //LogicFilter filter = factory.createLogicFilter( type );
        for( int i=0; i<value.length; i++){
            Filter filter = (Filter) value[i];
            if( filter instanceof Id ){
                Id id = (Id) filter;
                ids.addAll( id.getIdentifiers() );
            }
            else {
                fidOnly = false;
            }
            children.add( filter );
        }
          if( type == FilterType.LOGIC_OR ){
            if( fidOnly ){
                return factory.id( ids );
            }
            else {
                return factory.or( children );
            }           
        }
          else {
              return factory.and( children );
          }       
      }
          catch( ClassCastException filterRequired ){
            throw new SAXException("Illegal filter for "+element, filterRequired );
      }
          catch (IllegalFilterException e) {
        throw new SAXException("Illegal filter for "+element );
      }           
        }

        /**
         * @see org.geotools.xml.schema.Type#getName()
         */
        public String getName() {
            return "BinaryLogicOpType";
        }

        /**
         * @see org.geotools.xml.schema.Type#getInstanceType()
         */
        public Class getInstanceType() {
            return BinaryLogicOperator.class;
        }

        /**
         * @see org.geotools.xml.schema.Type#canEncode(org.geotools.xml.schema.Element,
         *      java.lang.Object, java.util.Map)
         */
        public boolean canEncode(Element element, Object value, Map hints) {
            if ((hints != null)
                    && hints.containsKey(FilterSchema.FILTER_CAP_KEY)) {
                FilterCapabilities fc = (FilterCapabilities) hints.get(FilterSchema.FILTER_CAP_KEY);

                if ((fc.getScalarOps() & FilterCapabilities.LOGICAL) != FilterCapabilities.LOGICAL) {
                    return false;
                }
            }

            return (element.getType() != null)
            && getName().equals(element.getType().getName())
            && value instanceof BinaryLogicOperator;
        }

        /**
         * @see org.geotools.xml.schema.Type#encode(org.geotools.xml.schema.Element,
         *      java.lang.Object, org.geotools.xml.PrintHandler,
         *      java.util.Map)
         */
        public void encode(Element element, Object value, PrintHandler output,
            Map hints) throws IOException, OperationNotSupportedException {
            if (!canEncode(element, value, hints)) {
                return;
            }
            BinaryLogicOperator lf = (BinaryLogicOperator) value;
            output.startElement(element.getNamespace(), element.getName(), null);
            for( org.opengis.filter.Filter f : lf.getChildren() ){
                encodeFilter(f, output, hints);
            }
            output.endElement(element.getNamespace(), element.getName());
        }
    }

    public static class UnaryLogicOpType extends FilterComplexType {
        private static final ComplexType instance = new UnaryLogicOpType();

        //      <xsd:complexType name="UnaryLogicOpType">
        //        <xsd:complexContent>
        //          <xsd:extension base="ogc:LogicOpsType">
        //            <xsd:sequence>
        //              <xsd:choice>
        //                <xsd:element ref="ogc:comparisonOps"/>
        //                <xsd:element ref="ogc:spatialOps"/>
        //                <xsd:element ref="ogc:logicOps"/>
        //              </xsd:choice>
        //            </xsd:sequence>
        //          </xsd:extension>
        //        </xsd:complexContent>
        //      </xsd:complexType>
        private static Element[] elems = new Element[] {
                new FilterElement("comparisonOps",
                    ComparisonOpsType.getInstance()),
                new FilterElement("spatialOps", SpatialOpsType.getInstance()),
                new FilterElement("logicOps", LogicOpsType.getInstance())
            };
        private static Choice choice = new ChoiceGT(elems);

        public static ComplexType getInstance() {
            return instance;
        }

        /* (non-Javadoc)
         * @see org.geotools.xml.schema.ComplexType#getParent()
         */
        public Type getParent() {
            return LogicOpsType.getInstance();
        }

        /**
         * @see org.geotools.xml.schema.ComplexType#getChild()
         */
        public ElementGrouping getChild() {
            return choice;
        }

        /**
         * @see org.geotools.xml.schema.ComplexType#getChildElements()
         */
        public Element[] getChildElements() {
            return elems;
        }

        /**
         * @throws SAXException
         * @see org.geotools.xml.schema.Type#getValue(org.geotools.xml.schema.Element,
         *      org.geotools.xml.schema.ElementValue[],
         *      org.xml.sax.Attributes, java.util.Map)
         */
        public Object getValue(Element element, ElementValue[] value, Attributes attrs, Map hints)
                throws SAXException {
            FilterFactory2 factory = FilterSchema.filterFactory(hints);
            String name = element.getName();
            short type;
            if ("and".equalsIgnoreCase(name)) {
                type = FilterType.LOGIC_AND;
            } else if ("or".equalsIgnoreCase(name)) {
                type = FilterType.LOGIC_OR;
            } else if ("not".equalsIgnoreCase(name)) {
                type = FilterType.LOGIC_NOT;
            } else {
                throw new SAXException("Expected AND or OR logic filter");
            }
            if (value == null || value.length != 1) {
                throw new SAXException("Require a single filter for " + element);
            }
            try {

                Filter filter = (Filter) value[0].getValue();

                return factory.not(filter);
            } catch (ClassCastException filterRequired) {
                throw new SAXException("Require a single filter for " + element, filterRequired);
            } catch (IllegalFilterException e) {
                throw new SAXException("Illegal filter for " + element);
            }
        }

        /**
         * @see org.geotools.xml.schema.Type#getName()
         */
        public String getName() {
            return "UnaryLogicOpType";
        }

        /**
         * @see org.geotools.xml.schema.Type#getInstanceType()
         */
        public Class getInstanceType() {
            return Not.class;
        }

        /**
         * @see org.geotools.xml.schema.Type#canEncode(org.geotools.xml.schema.Element,
         *      java.lang.Object, java.util.Map)
         */
        public boolean canEncode(Element element, Object value, Map hints) {
            if ((hints != null)
                    && hints.containsKey(FilterSchema.FILTER_CAP_KEY)) {
                FilterCapabilities fc = (FilterCapabilities) hints.get(FilterSchema.FILTER_CAP_KEY);

                if ((fc.getScalarOps() & FilterCapabilities.LOGICAL) != FilterCapabilities.LOGICAL) {
                    return false;
                }
            }

            return (element.getType() != null)
            && getName().equals(element.getType().getName())
            && value instanceof Not;
        }

        /**
         * @see org.geotools.xml.schema.Type#encode(org.geotools.xml.schema.Element,
         *      java.lang.Object, org.geotools.xml.PrintHandler,
         *      java.util.Map)
         */
        public void encode(Element element, Object value, PrintHandler output,
            Map hints) throws IOException, OperationNotSupportedException {
            if (!canEncode(element, value, hints)) {
                return;
            }
            Not lf = (Not) value;
           
            output.startElement(element.getNamespace(), element.getName(), null);
            encodeFilter(lf.getFilter(), output, hints);
            output.endElement(element.getNamespace(), element.getName());
        }
    }
}
TOP

Related Classes of org.geotools.xml.filter.FilterOpsComplexTypes$BBOXType

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.