/*
* GeoTools - The Open Source Java GIS Toolkit
* http://geotools.org
*
* (C) 2016 Open Source Geospatial Foundation (OSGeo)
* (C) 2014-2016 Boundless Spatial
*
* 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.ysld.parse;
import javax.annotation.Nullable;
import org.geotools.filter.text.cql2.CQLException;
import org.geotools.filter.text.ecql.ECQL;
import org.geotools.ysld.Tuple;
import org.geotools.styling.FeatureTypeStyle;
import org.geotools.styling.Rule;
import org.geotools.ysld.YamlMap;
import org.geotools.ysld.YamlObject;
import org.geotools.ysld.YamlSeq;
/**
* Handles parsing a Ysld "rules" property into {@link Rule} objects for a {@link FeatureTypeStyle}.
*
*/
public class RuleParser extends YsldParseHandler {
FeatureTypeStyle featureStyle;
public RuleParser(FeatureTypeStyle featureStyle, Factory factory) {
super(factory);
this.featureStyle = featureStyle;
}
@Override
public void handle(YamlObject<?> obj, YamlParseContext context) {
YamlSeq seq = obj.seq();
for (YamlObject o : seq) {
YamlMap r = o.map();
Rule rule = factory.style.createRule();
featureStyle.rules().add(rule);
rule.setName(r.str("name"));
if (r.has("title")) {
rule.setTitle(r.str("title"));
}
if (r.has("abstract")) {
rule.setAbstract(r.str("abstract"));
}
rule.setTitle(r.str("title"));
rule.setAbstract(r.str("abstract"));
if (r.has("filter")) {
try {
rule.setFilter(ECQL.toFilter(Util.removeExpressionBrackets(r.str("filter"))));
} catch (CQLException e) {
throw new RuntimeException("Error parsing filter", e);
}
}
rule.setElseFilter(r.boolOr("else", false));
// Prefer scale over zoom
@Nullable
ScaleRange range = Util.defaultForNull(parseScale(r), parseZoom(r, context));
if (range != null) {
range.applyTo(rule);
}
context.push(r, "symbolizers", new SymbolizersParser(rule, factory));
}
}
/**
*
* @param r
* @return The parsed scale, or null if the {@link YamlMap} has no "scale" key.
*/
@Nullable
private ScaleRange parseScale(YamlMap r) {
if (r.has("scale")) {
Object value = r.get("scale");
Tuple t = null;
try {
t = Tuple.of(2).parse(value);
} catch (IllegalArgumentException e) {
throw new IllegalArgumentException(String
.format("Bad scale value: '%s', must be of form [<min>,<max>]", value), e);
}
double min = 0;
double max = Double.POSITIVE_INFINITY;
if (t.at(0) != null) {
if (!t.strAt(0).equalsIgnoreCase("min")) {
min = Double.parseDouble(t.strAt(0));
}
}
if (t.at(1) != null) {
if (!t.strAt(1).equalsIgnoreCase("max")) {
max = Double.parseDouble(t.strAt(1));
}
}
return new ScaleRange(min, max);
} else {
return null;
}
}
private ScaleRange parseZoom(YamlMap r, YamlParseContext context) {
if (r.has("zoom")) {
ZoomContext zCtxt = getZoomContext(context);
Object value = r.get("zoom");
Tuple t = null;
try {
t = Tuple.of(2).parse(value);
} catch (IllegalArgumentException e) {
throw new IllegalArgumentException(
String.format("Bad zoom value: '%s', must be of form [<min>,<max>]", value),
e);
}
@Nullable
Integer min = null;
@Nullable
Integer max = null;
if (t.at(0) != null) {
if (!t.strAt(0).equalsIgnoreCase("min")) {
min = Integer.parseInt(t.strAt(0));
}
}
if (t.at(1) != null) {
if (!t.strAt(1).equalsIgnoreCase("max")) {
max = Integer.parseInt(t.strAt(1));
}
}
return zCtxt.getRange(min, max);
} else {
return null;
}
}
protected ZoomContext getZoomContext(YamlParseContext context) {
return Util.forceDefaultForNull((ZoomContext) context.getDocHint(ZoomContext.HINT_ID),
WellKnownZoomContextFinder.getInstance().get("DEFAULT"));
}
}