001// License: GPL. For details, see LICENSE file. 002package org.openstreetmap.josm.data.validation.tests; 003 004import org.openstreetmap.josm.command.ChangePropertyCommand; 005import org.openstreetmap.josm.command.ChangePropertyKeyCommand; 006import org.openstreetmap.josm.command.Command; 007import org.openstreetmap.josm.data.osm.OsmPrimitive; 008import org.openstreetmap.josm.data.osm.Tag; 009import org.openstreetmap.josm.gui.mappaint.Environment; 010import org.openstreetmap.josm.gui.mappaint.mapcss.Expression; 011import org.openstreetmap.josm.gui.mappaint.mapcss.Selector; 012import org.openstreetmap.josm.tools.CheckParameterUtil; 013 014/** 015 * Represents a fix to a validation test. The fixing {@link Command} can be obtained by {@link #createCommand(OsmPrimitive, Selector)}. 016 */ 017@FunctionalInterface 018interface MapCSSTagCheckerFixCommand { 019 /** 020 * Creates the fixing {@link Command} for the given primitive. The {@code matchingSelector} is used to evaluate placeholders 021 * (cf. {@link MapCSSTagCheckerRule#insertArguments(Selector, String, OsmPrimitive)}). 022 * 023 * @param p OSM primitive 024 * @param matchingSelector matching selector 025 * @return fix command, or {@code null} if if cannot be created 026 */ 027 Command createCommand(OsmPrimitive p, Selector matchingSelector); 028 029 /** 030 * Checks that object is either an {@link Expression} or a {@link String}. 031 * 032 * @param obj object to check 033 * @throws IllegalArgumentException if object is not an {@code Expression} or a {@code String} 034 */ 035 static void checkObject(final Object obj) { 036 CheckParameterUtil.ensureThat(obj instanceof Expression || obj instanceof String, 037 () -> "instance of Exception or String expected, but got " + obj); 038 } 039 040 /** 041 * Evaluates given object as {@link Expression} or {@link String} on the matched {@link OsmPrimitive} and {@code matchingSelector}. 042 * 043 * @param obj object to evaluate ({@link Expression} or {@link String}) 044 * @param p OSM primitive 045 * @param matchingSelector matching selector 046 * @return result string 047 */ 048 static String evaluateObject(final Object obj, final OsmPrimitive p, final Selector matchingSelector) { 049 final String s; 050 if (obj instanceof Expression) { 051 s = (String) ((Expression) obj).evaluate(new Environment(p)); 052 } else if (obj instanceof String) { 053 s = (String) obj; 054 } else { 055 return null; 056 } 057 return MapCSSTagCheckerRule.insertArguments(matchingSelector, s, p); 058 } 059 060 /** 061 * Creates a fixing command which executes a {@link ChangePropertyCommand} on the specified tag. 062 * 063 * @param obj object to evaluate ({@link Expression} or {@link String}) 064 * @return created fix command 065 */ 066 static MapCSSTagCheckerFixCommand fixAdd(final Object obj) { 067 checkObject(obj); 068 return new MapCSSTagCheckerFixCommand() { 069 @Override 070 public Command createCommand(OsmPrimitive p, Selector matchingSelector) { 071 final Tag tag = Tag.ofString(MapCSSTagCheckerFixCommand.evaluateObject(obj, p, matchingSelector)); 072 return new ChangePropertyCommand(p, tag.getKey(), tag.getValue()); 073 } 074 075 @Override 076 public String toString() { 077 return "fixAdd: " + obj; 078 } 079 }; 080 } 081 082 /** 083 * Creates a fixing command which executes a {@link ChangePropertyCommand} to delete the specified key. 084 * 085 * @param obj object to evaluate ({@link Expression} or {@link String}) 086 * @return created fix command 087 */ 088 static MapCSSTagCheckerFixCommand fixRemove(final Object obj) { 089 checkObject(obj); 090 return new MapCSSTagCheckerFixCommand() { 091 @Override 092 public Command createCommand(OsmPrimitive p, Selector matchingSelector) { 093 final String key = MapCSSTagCheckerFixCommand.evaluateObject(obj, p, matchingSelector); 094 return new ChangePropertyCommand(p, key, ""); 095 } 096 097 @Override 098 public String toString() { 099 return "fixRemove: " + obj; 100 } 101 }; 102 } 103 104 /** 105 * Creates a fixing command which executes a {@link ChangePropertyKeyCommand} on the specified keys 106 * 107 * @param oldKey old key 108 * @param newKey new key 109 * @return created fix command 110 */ 111 static MapCSSTagCheckerFixCommand fixChangeKey(final String oldKey, final String newKey) { 112 return new MapCSSTagCheckerFixCommand() { 113 @Override 114 public Command createCommand(OsmPrimitive p, Selector matchingSelector) { 115 return new ChangePropertyKeyCommand(p, 116 MapCSSTagCheckerRule.insertArguments(matchingSelector, oldKey, p), 117 MapCSSTagCheckerRule.insertArguments(matchingSelector, newKey, p)); 118 } 119 120 @Override 121 public String toString() { 122 return "fixChangeKey: " + oldKey + " => " + newKey; 123 } 124 }; 125 } 126}