/*
* GeoTools - The Open Source Java GIS Toolkit
* http://geotools.org
*
* (C) 2005-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.filter.visitor;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import org.geotools.factory.CommonFactoryFinder;
import org.geotools.factory.GeoTools;
import org.geotools.filter.AttributeExpressionImpl;
import org.opengis.filter.And;
import org.opengis.filter.ExcludeFilter;
import org.opengis.filter.Filter;
import org.opengis.filter.FilterFactory2;
import org.opengis.filter.FilterVisitor;
import org.opengis.filter.Id;
import org.opengis.filter.IncludeFilter;
import org.opengis.filter.Not;
import org.opengis.filter.Or;
import org.opengis.filter.PropertyIsBetween;
import org.opengis.filter.PropertyIsEqualTo;
import org.opengis.filter.PropertyIsGreaterThan;
import org.opengis.filter.PropertyIsGreaterThanOrEqualTo;
import org.opengis.filter.PropertyIsLessThan;
import org.opengis.filter.PropertyIsLessThanOrEqualTo;
import org.opengis.filter.PropertyIsLike;
import org.opengis.filter.PropertyIsNotEqualTo;
import org.opengis.filter.PropertyIsNull;
import org.opengis.filter.expression.Add;
import org.opengis.filter.expression.Divide;
import org.opengis.filter.expression.Expression;
import org.opengis.filter.expression.ExpressionVisitor;
import org.opengis.filter.expression.Function;
import org.opengis.filter.expression.Literal;
import org.opengis.filter.expression.Multiply;
import org.opengis.filter.expression.NilExpression;
import org.opengis.filter.expression.PropertyName;
import org.opengis.filter.expression.Subtract;
import org.opengis.filter.identity.FeatureId;
import org.opengis.filter.spatial.BBOX;
import org.opengis.filter.spatial.Beyond;
import org.opengis.filter.spatial.Contains;
import org.opengis.filter.spatial.Crosses;
import org.opengis.filter.spatial.DWithin;
import org.opengis.filter.spatial.Disjoint;
import org.opengis.filter.spatial.Equals;
import org.opengis.filter.spatial.Intersects;
import org.opengis.filter.spatial.Overlaps;
import org.opengis.filter.spatial.Touches;
import org.opengis.filter.spatial.Within;
import org.opengis.filter.temporal.After;
import org.opengis.filter.temporal.AnyInteracts;
import org.opengis.filter.temporal.Before;
import org.opengis.filter.temporal.Begins;
import org.opengis.filter.temporal.BegunBy;
import org.opengis.filter.temporal.During;
import org.opengis.filter.temporal.EndedBy;
import org.opengis.filter.temporal.Ends;
import org.opengis.filter.temporal.Meets;
import org.opengis.filter.temporal.MetBy;
import org.opengis.filter.temporal.OverlappedBy;
import org.opengis.filter.temporal.TContains;
import org.opengis.filter.temporal.TEquals;
import org.opengis.filter.temporal.TOverlaps;
/**
* Used to duplication Filters and/or Expressions - returned object is a copy.
* <p>
* Extra data can be used to provide a {@link FilterFactory2} but this is NOT required.
* This class is thread safe.
* </ul>
* @author Jesse
*
*
*
* @source $URL$
*/
public class DuplicatingFilterVisitor implements FilterVisitor, ExpressionVisitor {
protected final FilterFactory2 ff;
public DuplicatingFilterVisitor() {
this(CommonFactoryFinder.getFilterFactory2(GeoTools.getDefaultHints()));
}
public DuplicatingFilterVisitor(FilterFactory2 factory) {
this.ff = factory;
}
protected FilterFactory2 getFactory(Object extraData) {
if( extraData instanceof FilterFactory2)
return (FilterFactory2) extraData;
return ff;
}
public Object visit(ExcludeFilter filter, Object extraData) {
return filter;
}
public Object visit(IncludeFilter filter, Object extraData) {
return filter;
}
/**
* Null safe expression cloning
* @param expression
* @param extraData
* @return
*/
Expression visit(Expression expression, Object extraData) {
if(expression == null)
return null;
return (Expression) expression.accept(this, extraData);
}
public Object visit(And filter, Object extraData) {
List<Filter> children = filter.getChildren();
List<Filter> newChildren = new ArrayList<Filter>();
for (Iterator<Filter> iter = children.iterator(); iter.hasNext();) {
Filter child = iter.next();
if( child!=null ){
Filter newChild = (Filter)child.accept(this, extraData);
newChildren.add( newChild );
}
}
return getFactory(extraData).and(newChildren);
}
public Object visit(Id filter, Object extraData) {
return getFactory(extraData).id(filter.getIdentifiers());
}
public Object visit(Not filter, Object extraData) {
return getFactory(extraData).not((Filter) filter.getFilter().accept(this, extraData));
}
public Object visit(Or filter, Object extraData) {
List<Filter> children = filter.getChildren();
List<Filter> newChildren = new ArrayList<Filter>();
for (Iterator<Filter> iter = children.iterator(); iter.hasNext();) {
Filter child = iter.next();
if( child!=null ){
Filter newChild = (Filter)child.accept(this, extraData);
newChildren.add( newChild );
}
}
return getFactory(extraData).or(newChildren);
}
public Object visit(PropertyIsBetween filter, Object extraData) {
Expression expr= visit(filter.getExpression(), extraData);
Expression lower= visit(filter.getLowerBoundary(), extraData);
Expression upper= visit(filter.getUpperBoundary(), extraData);
return getFactory(extraData).between(expr, lower, upper);
}
public Object visit(PropertyIsEqualTo filter, Object extraData) {
Expression expr1= visit(filter.getExpression1(), extraData);
Expression expr2= visit(filter.getExpression2(), extraData);
boolean matchCase=filter.isMatchingCase();
return getFactory(extraData).equal(expr1, expr2, matchCase);
}
public Object visit(PropertyIsNotEqualTo filter, Object extraData) {
Expression expr1= visit(filter.getExpression1(), extraData);
Expression expr2= visit(filter.getExpression2(), extraData);
boolean matchCase=filter.isMatchingCase();
return getFactory(extraData).notEqual(expr1, expr2, matchCase);
}
public Object visit(PropertyIsGreaterThan filter, Object extraData) {
Expression expr1= visit(filter.getExpression1(), extraData);
Expression expr2= visit(filter.getExpression2(), extraData);
return getFactory(extraData).greater(expr1, expr2);
}
public Object visit(PropertyIsGreaterThanOrEqualTo filter, Object extraData) {
Expression expr1= visit(filter.getExpression1(), extraData);
Expression expr2= visit(filter.getExpression2(), extraData);
return getFactory(extraData).greaterOrEqual(expr1, expr2);
}
public Object visit(PropertyIsLessThan filter, Object extraData) {
Expression expr1= visit(filter.getExpression1(), extraData);
Expression expr2= visit(filter.getExpression2(), extraData);
return getFactory(extraData).less(expr1, expr2);
}
public Object visit(PropertyIsLessThanOrEqualTo filter, Object extraData) {
Expression expr1= visit(filter.getExpression1(), extraData);
Expression expr2= visit(filter.getExpression2(), extraData);
return getFactory(extraData).lessOrEqual(expr1, expr2);
}
public Object visit(PropertyIsLike filter, Object extraData) {
Expression expr= visit(filter.getExpression(), extraData);
String pattern=filter.getLiteral();
String wildcard=filter.getWildCard();
String singleChar=filter.getSingleChar();
String escape=filter.getEscape();
boolean matchCase = filter.isMatchingCase();
return getFactory(extraData).like(expr, pattern, wildcard, singleChar, escape, matchCase);
}
public Object visit(PropertyIsNull filter, Object extraData) {
Expression expr= visit(filter.getExpression(), extraData);
return getFactory(extraData).isNull(expr);
}
public Object visit(BBOX filter, Object extraData) {
Expression propertyName = visit(filter.getExpression1(), extraData);
double minx=filter.getMinX();
double miny=filter.getMinY();
double maxx=filter.getMaxX();
double maxy=filter.getMaxY();
String srs=filter.getSRS();
return getFactory(extraData).bbox(propertyName, minx, miny, maxx, maxy, srs);
}
public Object visit(Beyond filter, Object extraData) {
Expression geometry1= visit(filter.getExpression1(), extraData);
Expression geometry2= visit(filter.getExpression2(), extraData);
double distance=filter.getDistance();
String units=filter.getDistanceUnits();
return getFactory(extraData).beyond(geometry1, geometry2, distance, units);
}
public Object visit(Contains filter, Object extraData) {
Expression geometry1= visit(filter.getExpression1(), extraData);
Expression geometry2= visit(filter.getExpression2(), extraData);
return getFactory(extraData).contains(geometry1, geometry2);
}
public Object visit(Crosses filter, Object extraData) {
Expression geometry1= visit(filter.getExpression1(), extraData);
Expression geometry2= visit(filter.getExpression2(), extraData);
return getFactory(extraData).crosses(geometry1, geometry2);
}
public Object visit(Disjoint filter, Object extraData) {
Expression geometry1= visit(filter.getExpression1(), extraData);
Expression geometry2= visit(filter.getExpression2(), extraData);
return getFactory(extraData).disjoint(geometry1, geometry2);
}
public Object visit(DWithin filter, Object extraData) {
Expression geometry1= visit(filter.getExpression1(), extraData);
Expression geometry2= visit(filter.getExpression2(), extraData);
double distance=filter.getDistance();
String units=filter.getDistanceUnits();
return getFactory(extraData).dwithin(geometry1, geometry2, distance, units);
}
public Object visit(Equals filter, Object extraData) {
Expression geometry1= visit(filter.getExpression1(), extraData);
Expression geometry2= visit(filter.getExpression2(), extraData);
return getFactory(extraData).equal(geometry1, geometry2);
}
public Object visit(Intersects filter, Object extraData) {
Expression geometry1= visit(filter.getExpression1(), extraData);
Expression geometry2= visit(filter.getExpression2(), extraData);
return getFactory(extraData).intersects(geometry1, geometry2);
}
public Object visit(Overlaps filter, Object extraData) {
Expression geometry1= visit(filter.getExpression1(), extraData);
Expression geometry2= visit(filter.getExpression2(), extraData);
return getFactory(extraData).overlaps(geometry1, geometry2);
}
public Object visit(Touches filter, Object extraData) {
Expression geometry1= visit(filter.getExpression1(), extraData);
Expression geometry2= visit(filter.getExpression2(), extraData);
return getFactory(extraData).touches(geometry1, geometry2);
}
public Object visit(Within filter, Object extraData) {
Expression geometry1= visit(filter.getExpression1(), extraData);
Expression geometry2= visit(filter.getExpression2(), extraData);
return getFactory(extraData).within(geometry1, geometry2);
}
public Object visitNullFilter(Object extraData) {
return null;
}
public Object visit(NilExpression expression, Object extraData) {
return expression;
}
public Object visit(Add expression, Object extraData) {
Expression expr1= visit(expression.getExpression1(), extraData);
Expression expr2= visit(expression.getExpression2(), extraData);
return getFactory(extraData).add(expr1, expr2);
}
public Object visit(Divide expression, Object extraData) {
Expression expr1= visit(expression.getExpression1(), extraData);
Expression expr2= visit(expression.getExpression2(), extraData);
return getFactory(extraData).divide(expr1, expr2);
}
public Object visit(Function expression, Object extraData) {
List old = expression.getParameters();
Expression[] args = new Expression[old.size()];
int i = 0;
for (Iterator iter = old.iterator(); iter.hasNext(); i++) {
Expression exp = (Expression) iter.next();
args[i]= visit(exp, extraData);
}
return getFactory(extraData).function(expression.getName(), args);
}
public Object visit(Literal expression, Object extraData) {
return getFactory(extraData).literal(expression.getValue());
}
public Object visit(Multiply expression, Object extraData) {
Expression expr1= visit(expression.getExpression1(), extraData);
Expression expr2= visit(expression.getExpression2(), extraData);
return getFactory(extraData).multiply(expr1, expr2);
}
public Object visit(PropertyName expression, Object extraData) {
//NC - namespace support
return getFactory(extraData).property(expression.getPropertyName(), expression.getNamespaceContext());
}
public Object visit(Subtract expression, Object extraData) {
Expression expr1= visit(expression.getExpression1(), extraData);
Expression expr2= visit(expression.getExpression2(), extraData);
return getFactory(extraData).subtract(expr1, expr2);
}
public Object visit(After after, Object extraData) {
return getFactory(extraData).after(visit(after.getExpression1(), extraData),
visit(after.getExpression2(), extraData));
}
public Object visit(AnyInteracts anyInteracts, Object extraData) {
return getFactory(extraData).anyInteracts(visit(anyInteracts.getExpression1(), extraData),
visit(anyInteracts.getExpression2(), extraData));
};
public Object visit(Before before, Object extraData) {
return getFactory(extraData).before(visit(before.getExpression1(), extraData),
visit(before.getExpression2(), extraData));
}
public Object visit(Begins begins, Object extraData) {
return getFactory(extraData).begins(visit(begins.getExpression1(), extraData),
visit(begins.getExpression2(), extraData));
};
public Object visit(BegunBy begunBy, Object extraData) {
return getFactory(extraData).begunBy(visit(begunBy.getExpression1(), extraData),
visit(begunBy.getExpression2(), extraData));
}
public Object visit(During during, Object extraData) {
return getFactory(extraData).during(visit(during.getExpression1(), extraData),
visit(during.getExpression2(), extraData));
}
public Object visit(EndedBy endedBy, Object extraData) {
return getFactory(extraData).endedBy(visit(endedBy.getExpression1(), extraData),
visit(endedBy.getExpression2(), extraData));
}
public Object visit(Ends ends, Object extraData) {
return getFactory(extraData).ends(visit(ends.getExpression1(), extraData),
visit(ends.getExpression2(), extraData));
}
public Object visit(Meets meets, Object extraData) {
return getFactory(extraData).meets(visit(meets.getExpression1(), extraData),
visit(meets.getExpression2(), extraData));
}
public Object visit(MetBy metBy, Object extraData) {
return getFactory(extraData).metBy(visit(metBy.getExpression1(), extraData),
visit(metBy.getExpression2(), extraData));
}
public Object visit(OverlappedBy overlappedBy, Object extraData) {
return getFactory(extraData).overlappedBy(visit(overlappedBy.getExpression1(), extraData),
visit(overlappedBy.getExpression2(), extraData));
}
public Object visit(TContains contains, Object extraData) {
return getFactory(extraData).contains(visit(contains.getExpression1(), extraData),
visit(contains.getExpression2(), extraData));
}
public Object visit(TEquals equals, Object extraData) {
return getFactory(extraData).tequals(visit(equals.getExpression1(), extraData),
visit(equals.getExpression2(), extraData));
}
public Object visit(TOverlaps contains, Object extraData) {
return getFactory(extraData).tcontains(visit(contains.getExpression1(), extraData),
visit(contains.getExpression2(), extraData));
}
}