diff --git a/src/main/java/de/srsoftware/web4rail/BaseClass.java b/src/main/java/de/srsoftware/web4rail/BaseClass.java index bf19489..2bcea96 100644 --- a/src/main/java/de/srsoftware/web4rail/BaseClass.java +++ b/src/main/java/de/srsoftware/web4rail/BaseClass.java @@ -120,12 +120,13 @@ public abstract class BaseClass implements Constants{ return train; } - public void train(Train newTrain) { + public Context train(Train newTrain) { train = newTrain; + return this; } } - public static class Id implements Comparable{ + public static class Id implements CharSequence, Comparable{ private String internalId; public Id() { @@ -141,17 +142,19 @@ public abstract class BaseClass implements Constants{ public Id(String id) { internalId = id; } - + @Override - public String toString() { - return internalId; + public int hashCode() { + return internalId.hashCode(); } - + @Override - public int compareTo(Id other) { - return internalId.compareTo(other.internalId); + public boolean equals(Object other) { + if (other == null) return false; + if (this == other) return true; + return internalId.equals(other.toString()); } - + public static Id from(JSONObject json) { return Id.from(json,ID); } @@ -169,6 +172,34 @@ public abstract class BaseClass implements Constants{ String sid = params.get(key); return sid == null ? null : new Id(sid); } + + @Override + public char charAt(int index) { + return internalId.charAt(index); + } + + + @Override + public int length() { + return internalId.length(); + } + + + @Override + public CharSequence subSequence(int begin, int end) { + return internalId.subSequence(begin, end); + } + + @Override + public String toString() { + return internalId; + } + + + @Override + public int compareTo(Id other) { + return internalId.compareTo(other.internalId); + } } public Button button(String text,Map additionalProps) { @@ -179,6 +210,22 @@ public abstract class BaseClass implements Constants{ return button(text,null); } + public Map contextAction(String action){ + String realm = REALM_PLAN; + if (this instanceof Tile) realm = REALM_PLAN; + if (this instanceof Contact) realm = REALM_CONTACT; + + if (this instanceof Car) realm = REALM_CAR; + if (this instanceof Locomotive) realm = REALM_LOCO; + + if (this instanceof Action) realm = REALM_ACTIONS; + if (this instanceof Condition) realm = REALM_CONDITION; + if (this instanceof Route) realm = REALM_ROUTE; + if (this instanceof Train) realm = REALM_TRAIN; + + return Map.of(ACTION,action,CONTEXT,realm+":"+id()); + } + public Id id() { if (isNull(id)) id = new Id(); return id; @@ -192,6 +239,10 @@ public abstract class BaseClass implements Constants{ return o != null; } + public JSONObject json() { + return new JSONObject().put(ID, id().toString()); + } + public Tag link(String tagClass,Object caption) { return link(tagClass,caption,null); } diff --git a/src/main/java/de/srsoftware/web4rail/PathFinder.java b/src/main/java/de/srsoftware/web4rail/PathFinder.java index d386ebb..778db75 100644 --- a/src/main/java/de/srsoftware/web4rail/PathFinder.java +++ b/src/main/java/de/srsoftware/web4rail/PathFinder.java @@ -36,7 +36,7 @@ public class PathFinder extends BaseClass{ if (error) return availableRoutes; Block destination = train.destination(); - Direction direction = context.direction(); + Direction direction = train.direction(); /* if (isSet(direction)) { LOG.debug("{}Looking for {}-bound routes from {}",inset,direction,block); } else { diff --git a/src/main/java/de/srsoftware/web4rail/Plan.java b/src/main/java/de/srsoftware/web4rail/Plan.java index d8da9af..427949a 100644 --- a/src/main/java/de/srsoftware/web4rail/Plan.java +++ b/src/main/java/de/srsoftware/web4rail/Plan.java @@ -731,7 +731,7 @@ public class Plan extends BaseClass{ return t("Plan saved as \"{}\".",name); } - private Object json() { + public JSONObject json() { JSONArray jTiles = new JSONArray(); tiles.values().stream() .filter(tile -> isSet(tile)) @@ -801,6 +801,7 @@ public class Plan extends BaseClass{ switch (realm) { case REALM_ROUTE: return route(id).properties(params); + case REALM_CONTACT: case REALM_PLAN: Tile tile = get(id, false); return isNull(tile) ? null : tile.propMenu(); diff --git a/src/main/java/de/srsoftware/web4rail/Route.java b/src/main/java/de/srsoftware/web4rail/Route.java index 68314ff..5b1c43b 100644 --- a/src/main/java/de/srsoftware/web4rail/Route.java +++ b/src/main/java/de/srsoftware/web4rail/Route.java @@ -167,13 +167,10 @@ public class Route extends BaseClass implements Comparable{ switch (params.get(ACTION)) { case ACTION_DROP: String message = plan.remove(route); - Id tileId = Id.from(params,Tile.class.getSimpleName()); - if (isSet(tileId)) { - Tile tile = plan.get(tileId, false); - if (isSet(tile)) { - plan.stream(message); - return tile.propMenu(); - } + String context = params.get(CONTEXT); + if (isSet(context)) { + plan.stream(message); + return plan.showContext(params); } return message; case ACTION_PROPS: @@ -227,7 +224,7 @@ public class Route extends BaseClass implements Comparable{ } private void addBasicPropertiesTo(Window win) { - if (isSet(train)) link("span",t("Train: {}",train)).addTo(win); + if (isSet(train)) train.link("span",t("Train: {}",train)).addTo(win); new Tag("h4").content(t("Origin and destination")).addTo(win); Tag list = new Tag("ul"); Plan.addLink(startBlock, t("Origin: {} to {}",startBlock.name,startDirection), list); @@ -423,7 +420,7 @@ public class Route extends BaseClass implements Comparable{ traceTrainFrom(contact); ActionList actions = triggers.get(contact.trigger()); if (isNull(actions)) return; - Context context = new Context(contact); + Context context = new Context(contact).route(this).train(train); actions.fire(context); } @@ -492,7 +489,7 @@ public class Route extends BaseClass implements Comparable{ } public Id id() { - if (id == null) id = new Id(generateName()); + if (id == null) id = new Id(md5sum(generateName())); return id; } @@ -507,22 +504,20 @@ public class Route extends BaseClass implements Comparable{ * creates a json representation of this route * @return */ - public String json() { - JSONObject json = new JSONObject(); - - json.put(ID, id()); - Vector tileIds = new Vector(); - for (Tile t : this.path) tileIds.add(t.id()); + public JSONObject json() { + JSONObject json = super.json(); + Vector tileIds = new Vector(); + for (Tile t : this.path) tileIds.add(t.id().toString()); json.put(PATH, tileIds); - Vector signalIds = new Vector(); // list all signals affecting this route - for (Tile t : this.signals) signalIds.add(t.id()); + Vector signalIds = new Vector(); // list all signals affecting this route + for (Tile t : this.signals) signalIds.add(t.id().toString()); json.put(SIGNALS, signalIds); JSONArray turnouts = new JSONArray(); for (Entry entry : this.turnouts.entrySet()) { Turnout t = entry.getKey(); - turnouts.put(new JSONObject(Map.of(Turnout.ID,t.id(),Turnout.STATE,entry.getValue()))); + turnouts.put(new JSONObject(Map.of(Turnout.ID,t.id().toString(),Turnout.STATE,entry.getValue()))); } json.put(TURNOUTS, turnouts); json.put(START_DIRECTION, startDirection); @@ -551,7 +546,7 @@ public class Route extends BaseClass implements Comparable{ if (disabled) json.put(DISABLED, true); - return json.toString(); + return json; } private Route load(JSONObject json,Plan plan) { @@ -710,7 +705,7 @@ public class Route extends BaseClass implements Comparable{ file.write("{\""+ROUTES+"\":[\n"); int count = 0; for (Route route : routes) { - file.write(route.json()); + file.write(route.json().toString()); if (++count < routes.size()) file.write(","); file.write("\n"); } @@ -777,7 +772,7 @@ public class Route extends BaseClass implements Comparable{ public boolean train(Train newTrain) { if (isSet(train) && newTrain != train) return false; train = newTrain; - return isSet(train) ? startActions.fire(new Context(this)) : true; + return isSet(train) ? startActions.fire(new Context(this).train(train)) : true; } public Route unlock() throws IOException { diff --git a/src/main/java/de/srsoftware/web4rail/moving/Car.java b/src/main/java/de/srsoftware/web4rail/moving/Car.java index 399a19f..8fbb8ae 100644 --- a/src/main/java/de/srsoftware/web4rail/moving/Car.java +++ b/src/main/java/de/srsoftware/web4rail/moving/Car.java @@ -98,8 +98,7 @@ public class Car extends BaseClass implements Comparable{ } public JSONObject json() { - JSONObject json = new JSONObject(); - json.put(ID,id); + JSONObject json = super.json(); json.put(NAME, name); json.put(LENGTH, length); if (maxSpeed != 0) json.put(MAX_SPEED, maxSpeed); diff --git a/src/main/java/de/srsoftware/web4rail/moving/Train.java b/src/main/java/de/srsoftware/web4rail/moving/Train.java index 37ac7c8..fbceb64 100644 --- a/src/main/java/de/srsoftware/web4rail/moving/Train.java +++ b/src/main/java/de/srsoftware/web4rail/moving/Train.java @@ -330,9 +330,8 @@ public class Train extends BaseClass implements Comparable { return trace.getFirst(); } - private JSONObject json() { - JSONObject json = new JSONObject(); - json.put(ID, id); + public JSONObject json() { + JSONObject json = super.json(); json.put(PUSH_PULL, pushPull); if (isSet(currentBlock)) json.put(BLOCK, currentBlock.id()); @@ -340,16 +339,16 @@ public class Train extends BaseClass implements Comparable { if (isSet(route)) json.put(ROUTE, route.id()); if (isSet(direction)) json.put(DIRECTION, direction); - Vector locoIds = new Vector(); - for (Locomotive loco : locos) locoIds.add(loco.id()); + Vector locoIds = new Vector(); + for (Locomotive loco : locos) locoIds.add(loco.id().toString()); json.put(LOCOS, locoIds); - Vector carIds = new Vector(); - for (Car car : cars) carIds.add(car.id()); + Vector carIds = new Vector(); + for (Car car : cars) carIds.add(car.id().toString()); json.put(CARS,carIds); - Vector tileIds = new Vector(); - for (Tile tile : trace) tileIds.add(tile.id()); + Vector tileIds = new Vector(); + for (Tile tile : trace) tileIds.add(tile.id().toString()); json.put(TRACE, tileIds); if (!tags.isEmpty()) json.put(TAGS, tags); @@ -535,7 +534,7 @@ public class Train extends BaseClass implements Comparable { locoList().addTo(propList); carList().addTo(propList); - if (isSet(currentBlock)) currentBlock.link(currentBlock.toString(),"span").addTo(new Tag("li").content(t("Current location:")+NBSP)).addTo(propList); + if (isSet(currentBlock)) currentBlock.link("span",currentBlock.toString()).addTo(new Tag("li").content(t("Current location:")+NBSP)).addTo(propList); if (isSet(direction)) new Tag("li").content(t("Direction: heading {}",direction)).addTo(propList); Tag dest = new Tag("li").content(t("Destination:")+NBSP); @@ -701,7 +700,7 @@ public class Train extends BaseClass implements Comparable { if (maxSpeed() == 0) return t("Train has maximum speed of 0 {}, cannot go!",speedUnit); if (isSet(route)) route.reset(); // reset route previously chosen - Context context = new Context(this); + Context context = new Context(this).block(this.currentBlock); String error = null; if (isSet(nextRoute)) { route = nextRoute; @@ -743,6 +742,7 @@ public class Train extends BaseClass implements Comparable { new Thread() { public void run() { for (Tile tile : route.path()) { + if (isNull(route)) break; try { if (tile instanceof Contact) { Contact contact = (Contact) tile; diff --git a/src/main/java/de/srsoftware/web4rail/tags/Button.java b/src/main/java/de/srsoftware/web4rail/tags/Button.java index 6d26a30..8ec438f 100644 --- a/src/main/java/de/srsoftware/web4rail/tags/Button.java +++ b/src/main/java/de/srsoftware/web4rail/tags/Button.java @@ -1,6 +1,7 @@ package de.srsoftware.web4rail.tags; import java.util.Map; +import java.util.stream.Collectors; import org.json.JSONObject; @@ -27,6 +28,8 @@ public class Button extends Tag { } public Button(String text, Map props) { - this(text,"request("+(new JSONObject(props).toString().replace("\"", "'"))+")"); + this(text,"request("+(new JSONObject( + props.entrySet().stream().collect(Collectors.toMap(entry -> entry.getKey(), entry -> entry.getValue().toString())) + ).toString().replace("\"", "'"))+")"); } } diff --git a/src/main/java/de/srsoftware/web4rail/tiles/Block.java b/src/main/java/de/srsoftware/web4rail/tiles/Block.java index 2e09ba2..39a3af7 100644 --- a/src/main/java/de/srsoftware/web4rail/tiles/Block.java +++ b/src/main/java/de/srsoftware/web4rail/tiles/Block.java @@ -349,7 +349,7 @@ public abstract class Block extends StretchableTile implements Comparable if (params.containsKey(NAME)) name=params.get(NAME); if (params.containsKey(Train.class.getSimpleName())) { Id trainId = Id.from(params,Train.class.getSimpleName()); - if (trainId == null) { // TODO: this is rubbish + if (trainId.equals(0)) { // TODO: this is rubbish if (isSet(train)) train.dropTrace(); train = null; } else { diff --git a/src/main/java/de/srsoftware/web4rail/tiles/Bridge.java b/src/main/java/de/srsoftware/web4rail/tiles/Bridge.java index a890233..52afafb 100644 --- a/src/main/java/de/srsoftware/web4rail/tiles/Bridge.java +++ b/src/main/java/de/srsoftware/web4rail/tiles/Bridge.java @@ -3,11 +3,16 @@ package de.srsoftware.web4rail.tiles; import java.io.IOException; import java.util.Map; +import org.json.JSONObject; + import de.srsoftware.tools.Tag; import de.srsoftware.web4rail.Connector; +import de.srsoftware.web4rail.Route; import de.srsoftware.web4rail.Window; +import de.srsoftware.web4rail.moving.Train; public abstract class Bridge extends Tile { + private static final String COUNTERPART = "counterpart"; private static Bridge pendingConnection = null; protected Bridge counterpart = null; @@ -32,6 +37,44 @@ public abstract class Bridge extends Tile { } protected abstract Connector connector(); + + @Override + public JSONObject json() { + JSONObject json = super.json(); + if (isSet(counterpart)) json.put(COUNTERPART, counterpart.id().toString()); + return json; + } + + @Override + protected Tile load(JSONObject json) throws IOException { + if (json.has(COUNTERPART)) { + new Thread() { + @Override + public void run() { + try { + sleep(1000); + } catch (InterruptedException e) { + e.printStackTrace(); + } + counterpart = (Bridge) plan.get(Id.from(json, COUNTERPART), false); + } + }.start(); + } + return super.load(json); + } + + public Tile set(Train train) { + super.set(train); + if (isSet(counterpart) && counterpart.train != train) counterpart.set(train); + return this; + } + + @Override + public Tile setRoute(Route route) { + super.setRoute(route); + if (isSet(counterpart) && counterpart.route != route) counterpart.setRoute(route); + return this; + } @Override public Window propMenu() { diff --git a/src/main/java/de/srsoftware/web4rail/tiles/Tile.java b/src/main/java/de/srsoftware/web4rail/tiles/Tile.java index 48e82ad..80f384d 100644 --- a/src/main/java/de/srsoftware/web4rail/tiles/Tile.java +++ b/src/main/java/de/srsoftware/web4rail/tiles/Tile.java @@ -122,7 +122,7 @@ public abstract class Tile extends BaseClass{ } public JSONObject json() { - JSONObject json = new JSONObject(); + JSONObject json = super.json(); json.put(TYPE, getClass().getSimpleName()); JSONObject pos = new JSONObject(Map.of(X,x,Y,y)); json.put(POS, pos); @@ -234,7 +234,7 @@ public abstract class Tile extends BaseClass{ window.children().insertElementAt(new Tag("h4").content(t("Train:")), 1); } - if (isSet(route)) link("p",t("Locked by {}",route)).addTo(window); + if (isSet(route)) route.link("p",t("Locked by {}",route)).addTo(window); Form form = propForm("tile-properties-"+id()); if (isTrack) { @@ -253,10 +253,8 @@ public abstract class Tile extends BaseClass{ new Tag("h4").content(t("Routes using this tile:")).addTo(window); Tag routeList = new Tag("ol"); for (Route route : routes) { - String json = new JSONObject(Map.of(REALM,ROUTE,ID,route.id(),ACTION,ACTION_PROPS,CONTEXT,REALM_PLAN+":"+id())).toString().replace("\"", "'"); - Tag li = new Tag("span").attr("onclick","return request("+json+");").content(route.name()+(route.isDisabled()?" ["+t("disabled")+"]" : "")+NBSP).addTo(new Tag("li").clazz("link")); - Map params = Map.of(REALM,REALM_ROUTE,ID,route.id(),ACTION,ACTION_DROP,Tile.class.getSimpleName(),id()); - new Button(t("delete route"),params).addTo(li); + Tag li = route.link("span", route.name()+(route.isDisabled()?" ["+t("disabled")+"]" : "")+NBSP).addTo(new Tag("li").clazz("link")); + route.button(t("delete route"),contextAction(ACTION_DROP)).addTo(li); li.addTo(routeList); } routeList.addTo(window);