// License: GPL. For details, see LICENSE file.
package org.openstreetmap.josm.data.validation.tests;
import static org.openstreetmap.josm.tools.I18n.tr;
import java.util.Arrays;
import java.util.Set;
import java.util.stream.Collectors;
import org.openstreetmap.josm.Main;
import org.openstreetmap.josm.data.osm.OsmPrimitive;
import org.openstreetmap.josm.data.validation.Severity;
import org.openstreetmap.josm.data.validation.Test;
import org.openstreetmap.josm.data.validation.TestError;
import org.openstreetmap.josm.tools.Utils;
/**
* Test that validates {@code lane:} tags.
* @since 6592
*/
public class Lanes extends Test.TagTest {
private static final String[] BLACKLIST = {
"source:lanes",
"note:lanes",
"proposed:lanes",
"piste:lanes",
};
/**
* Constructs a new {@code Lanes} test.
*/
public Lanes() {
super(tr("Lane tags"), tr("Test that validates ''lane:'' tags."));
}
static int getLanesCount(String value) {
return value.isEmpty() ? 0 : value.replaceAll("[^|]", "").length() + 1;
}
protected void checkNumberOfLanesByKey(final OsmPrimitive p, String lanesKey, String message) {
final Set<Integer> lanesCount =
p.keySet().stream()
.filter(x -> x.endsWith(":" + lanesKey))
.filter(x -> !Arrays.asList(BLACKLIST).contains(x))
.map(key -> getLanesCount(p.get(key)))
.collect(Collectors.toSet());
if (lanesCount.size() > 1) {
// if not all numbers are the same
errors.add(TestError.builder(this, Severity.WARNING, 3100)
.message(message)
.primitives(p)
.build());
} else if (lanesCount.size() == 1 && p.hasKey(lanesKey)) {
// ensure that lanes <= *:lanes
try {
if (Integer.parseInt(p.get(lanesKey)) > lanesCount.iterator().next()) {
errors.add(TestError.builder(this, Severity.WARNING, 3100)
.message(tr("Number of {0} greater than {1}", lanesKey, "*:" + lanesKey))
.primitives(p)
.build());
}
} catch (NumberFormatException ignore) {
Main.debug(ignore.getMessage());
}
}
}
protected void checkNumberOfLanes(final OsmPrimitive p) {
final String lanes = p.get("lanes");
if (lanes == null) return;
final String forward = Utils.firstNonNull(p.get("lanes:forward"), "0");
final String backward = Utils.firstNonNull(p.get("lanes:backward"), "0");
try {
if (Integer.parseInt(lanes) < Integer.parseInt(forward) + Integer.parseInt(backward)) {
errors.add(TestError.builder(this, Severity.WARNING, 3101)
.message(tr("Number of {0} greater than {1}", tr("{0}+{1}", "lanes:forward", "lanes:backward"), "lanes"))
.primitives(p)
.build());
}
} catch (NumberFormatException ignore) {
Main.debug(ignore.getMessage());
}
}
@Override
public void check(OsmPrimitive p) {
checkNumberOfLanesByKey(p, "lanes", tr("Number of lane dependent values inconsistent"));
checkNumberOfLanesByKey(p, "lanes:forward", tr("Number of lane dependent values inconsistent in forward direction"));
checkNumberOfLanesByKey(p, "lanes:backward", tr("Number of lane dependent values inconsistent in backward direction"));
checkNumberOfLanes(p);
}
}