diff --git a/resources/js/plan.js b/resources/js/plan.js index aae8203..5f15c59 100644 --- a/resources/js/plan.js +++ b/resources/js/plan.js @@ -19,13 +19,7 @@ function addTile(x,y){ url : PLAN, method: POST, data : {action:mode,tile:selected.id,x:x,y:y}, - success: function(resp){ - var id = 'tile-'+x+'-'+y; - $('#'+id).remove(); - var tile = $(selected).clone().css({left:(30*x)+'px',top:(30*y)+'px','border':''}).attr('id',id); - if (selected.id != 'Eraser') $(BODY).append(tile); - addMessage(resp); - } + success: addMessage }); } @@ -107,19 +101,7 @@ function moveTile(x,y){ url : PLAN, method: POST, data : {action:mode,direction:selected.id,x:x,y:y}, - success: function(resp){ - if (resp.startsWith('<')){ - $(resp).each(function(){ - if (this.id != undefined){ - $('#'+this.id).remove(); - $(BODY).append($(this)); - } - }); - $('#tile-'+x+'-'+y).remove(); - } else { - addMessage(resp); - } - } + success: addMessage }); } @@ -128,6 +110,18 @@ function openRoute(id){ return false; } +function place(data){ + var tag = $(data); + $('#'+tag.attr('id')).remove(); + $(BODY).append(tag); + return false; +} + +function remove(id){ + $('#'+id).remove(); + return false; +} + function request(data){ $.ajax({ url : PLAN, @@ -158,6 +152,8 @@ function runAction(ev){ function stream(ev){ var data = ev.data; if (data.startsWith("heartbeat")) return heartbeat(data); + if (data.startsWith("place ")) return place(data.substring(6)); + if (data.startsWith("remove")) return remove(data.substring(7)); console.log(data); } diff --git a/src/main/java/de/srsoftware/web4rail/Plan.java b/src/main/java/de/srsoftware/web4rail/Plan.java index 1e54ecb..2a5fe2e 100644 --- a/src/main/java/de/srsoftware/web4rail/Plan.java +++ b/src/main/java/de/srsoftware/web4rail/Plan.java @@ -16,6 +16,7 @@ import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Map.Entry; +import java.util.Stack; import java.util.Vector; import org.json.JSONObject; @@ -123,16 +124,21 @@ public class Plan { new Tag("li").clazz("link").attr("onclick", "return clickTile("+tile.x+","+tile.y+");").content(content).addTo(list); } - private Tile addTile(String clazz, String xs, String ys, String configJson) throws ClassNotFoundException, InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException, NoSuchMethodException, SecurityException { + private String addTile(String clazz, String xs, String ys, String configJson) throws ClassNotFoundException, InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException, NoSuchMethodException, SecurityException, IOException { int x = Integer.parseInt(xs); int y = Integer.parseInt(ys); if (clazz == null) throw new NullPointerException(TILE+" must not be null!"); Class tc = Tile.class; clazz = tc.getName().replace(".Tile", "."+clazz); Tile tile = (Tile) tc.getClassLoader().loadClass(clazz).getDeclaredConstructor().newInstance(); + if (tile instanceof Eraser) { + Tile erased = get(x,y,true); + remove(erased); + return erased == null ? null : t("Removed {}.",erased); + } if (configJson != null) tile.configure(new JSONObject(configJson)); - set(x, y, tile); - return tile; + set(x, y, tile); + return t("Added {}",tile.getClass().getSimpleName()); } private String analyze() { @@ -149,7 +155,7 @@ public class Plan { } private Collection follow(Route route, Connector connector) { - Tile tile = get(connector.x,connector.y); + Tile tile = get(connector.x,connector.y,false); Vector results = new Vector<>(); if (tile == null) return results; Tile addedTile = route.add(tile,connector.from); @@ -173,9 +179,11 @@ public class Plan { return results; } - public Tile get(int x, int y) { + public Tile get(int x, int y,boolean resolveShadows) { HashMap column = tiles.get(x); - return column == null ? null : column.get(y); + Tile tile = (column == null) ? null : column.get(y); + if (resolveShadows && tile instanceof Shadow) tile = ((Shadow)tile).overlay(); + return tile; } private Tag heartbeat() { @@ -234,7 +242,7 @@ public class Plan { Route route = new Route(); json.getJSONArray(Route.PATH).forEach(entry -> { JSONObject pos = (JSONObject) entry; - Tile tile = result.get(pos.getInt("x"),pos.getInt("y")); + Tile tile = result.get(pos.getInt("x"),pos.getInt("y"),false); if (route.path().isEmpty()) { route.start((Block) tile); } else { @@ -243,12 +251,12 @@ public class Plan { }); json.getJSONArray(Route.SIGNALS).forEach(entry -> { JSONObject pos = (JSONObject) entry; - Tile tile = result.get(pos.getInt("x"),pos.getInt("y")); + Tile tile = result.get(pos.getInt("x"),pos.getInt("y"),false); route.addSignal((Signal) tile); }); json.getJSONArray(Route.TURNOUTS).forEach(entry -> { JSONObject pos = (JSONObject) entry; - Tile tile = result.get(pos.getInt("x"),pos.getInt("y")); + Tile tile = result.get(pos.getInt("x"),pos.getInt("y"),false); route.addTurnout((Turnout) tile, Turnout.State.valueOf(pos.getString(Turnout.STATE))); }); if (json.has(Route.NAME)) route.name(json.getString(Route.NAME)); @@ -262,10 +270,6 @@ public class Plan { return result; } - private Tag messages() { - return new Tag("div").id("messages").content(""); - } - private Tag menu() throws IOException { Tag menu = new Tag("div").clazz("menu"); actionMenu().addTo(menu); @@ -274,6 +278,10 @@ public class Plan { return menu; } + private Tag messages() { + return new Tag("div").id("messages").content(""); + } + private Tag moveMenu() { Tag tileMenu = new Tag("div").clazz("move").title(t("Move tiles")).content(t("↹")); StringBuffer tiles = new StringBuffer(); @@ -300,7 +308,7 @@ public class Plan { private String moveTile(Direction direction, int x, int y) throws IOException { //LOG.debug("moveTile({},{},{})",direction,x,y); - Vector moved = null; + boolean moved = false; switch (direction) { case EAST: moved = moveTile(x,y,+1,0); @@ -315,26 +323,28 @@ public class Plan { moved = moveTile(x,y,0,+1); break; } - if (!moved.isEmpty()) { - set(x,y,null); - StringBuilder sb = new StringBuilder(); - for (Tile tile : moved) sb.append(tile.tag(null)+"\n"); - return sb.toString(); - } - return null; + return t(moved ? "Tile(s) moved.":"No tile(s) moved."); } - private Vector moveTile(int x, int y,int xstep,int ystep) { - LOG.debug("moveTile({}+{},{}+{})",x,xstep,y,ystep); - if (x+xstep < -1 || y+ystep < -1) { - throw new IndexOutOfBoundsException("Can not move tile out of screen!"); + private boolean moveTile(int x, int y,int xstep,int ystep) throws IOException { + LOG.error("moveTile({}+ {},{}+ {}) not implemented",x,xstep,y,ystep); + Stack stack = new Stack(); + Tile tile = get(x,y,false); + while (tile != null) { + LOG.debug("scheduling tile for movement: {} @ {},{}",tile,x,y); + stack.add(tile); + x+=xstep; + y+=ystep; + tile = get(x,y,false); } - Tile tile = this.get(x, y); - if (tile == null) return new Vector(); - Vector result = moveTile(x+xstep,y+ystep,xstep,ystep); - set(x+xstep,y+ystep, tile); - result.add(tile); - return result; + while (!stack.isEmpty()) { + tile = stack.pop(); + if (!(tile instanceof Shadow)) { + remove(tile); + set(tile.x+xstep,tile.y+ystep,tile); + } + } + return false; } public Object process(HashMap params) { @@ -344,8 +354,7 @@ public class Plan { if (action == null) throw new NullPointerException(ACTION+" should not be null!"); switch (action) { case ACTION_ADD: - Tile tile = addTile(params.get(TILE),params.get(X),params.get(Y),null); - return t("Added {}",tile.getClass().getSimpleName()); + return addTile(params.get(TILE),params.get(X),params.get(Y),null); case ACTION_ANALYZE: return analyze(); case ACTION_MOVE: @@ -375,28 +384,13 @@ public class Plan { return route.properties(); } - private Object update(HashMap params) throws IOException { - if (params.containsKey(ROUTE)) { - Route route = routes.get(params.get(ROUTE)); - if (route == null) return t("Unknown route: {}",params.get(ROUTE)); - route.update(params); - } else update(Integer.parseInt(params.get("x")),Integer.parseInt(params.get("y")),params); - return this.html(); - } - - private void update(int x,int y, HashMap params) throws IOException { - Tile tile = get(x,y); - if (tile != null) set(x,y,tile.update(params)); - } - private Tag propMenu(String x, String y) { return propMenu(Integer.parseInt(x),Integer.parseInt(y)); } private Tag propMenu(int x, int y) { - Tile tile = get(x, y); + Tile tile = get(x, y,true); if (tile == null) return null; - if (tile instanceof Shadow) tile = ((Shadow)tile).overlay(); return tile.propMenu(); } @@ -405,6 +399,20 @@ public class Plan { routes.put(route.id(), route); } + + + private void remove(Tile tile) { + remove_intern(tile.x,tile.y); + for (int i=1; i column = tiles.get(x); + if (column != null) column.remove(y); + } + private String saveTo(String name) throws IOException { if (name == null || name.isEmpty()) throw new NullPointerException("Name must not be empty!"); File file = new File(name+".plan"); @@ -431,27 +439,27 @@ public class Plan { br.close(); return t("Plan saved as \"{}\".",file); } - - public Tile set(int x,int y,Tile tile) { - Tile old = null; + + public void set(int x,int y,Tile tile) throws IOException { + if (tile == null) return; + for (int i=1; i column = tiles.get(x); if (column == null) { - column = new HashMap(); - tiles.put(x, column); + column = new HashMap(); + tiles.put(x,column); } - old = column.remove(y); - if (old instanceof Block) blocks.remove((Block)old); - if (tile != null && !(tile instanceof Eraser)) { - column.put(y,tile.position(x, y)); - for (int i=1; i badClients = null; for (Entry entry : clients.entrySet()) { OutputStreamWriter client = entry.getKey(); @@ -517,4 +525,18 @@ public class Plan { tiles.append(new Eraser().tag(null)); return new Tag("div").clazz("list").content(tiles.toString()).addTo(tileMenu); } + + private Object update(HashMap params) throws IOException { + if (params.containsKey(ROUTE)) { + Route route = routes.get(params.get(ROUTE)); + if (route == null) return t("Unknown route: {}",params.get(ROUTE)); + route.update(params); + } else update(Integer.parseInt(params.get("x")),Integer.parseInt(params.get("y")),params); + return this.html(); + } + + private void update(int x,int y, HashMap params) throws IOException { + Tile tile = get(x,y,true); + if (tile != null) set(x,y,tile.update(params)); + } }