implemented maintenance tasks
This commit is contained in:
@@ -127,6 +127,8 @@ public class Application extends BaseClass{
|
||||
return plan.controlUnit().process(params);
|
||||
case REALM_LOCO:
|
||||
return Locomotive.action(params,plan);
|
||||
case REALM_MAINTENANCE:
|
||||
return MaintnanceTask.action(params);
|
||||
case REALM_PLAN:
|
||||
return plan.action(params);
|
||||
case REALM_ROUTE:
|
||||
|
||||
@@ -2,6 +2,7 @@ package de.srsoftware.web4rail;
|
||||
|
||||
import java.security.MessageDigest;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.AbstractMap;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
@@ -567,6 +568,11 @@ public abstract class BaseClass implements Constants{
|
||||
return Translation.get(Application.class, txt, fills);
|
||||
}
|
||||
|
||||
public static String time(Date date) {
|
||||
return isSet(date) ? new SimpleDateFormat("YYYY-dd-MM HH:mm").format(date) : null;
|
||||
}
|
||||
|
||||
|
||||
public static long timestamp() {
|
||||
return new Date().getTime();
|
||||
}
|
||||
|
||||
@@ -47,6 +47,7 @@ public interface Constants {
|
||||
public static final String REALM_CONTACT = "contact";
|
||||
public static final String REALM_CU = "cu";
|
||||
public static final String REALM_LOCO = "loco";
|
||||
public static final String REALM_MAINTENANCE = "maintenance";
|
||||
public static final String REALM_ROUTE = "route";
|
||||
public static final String REALM_PLAN = "plan";
|
||||
public static final String REALM_TRAIN = "train";
|
||||
|
||||
150
src/main/java/de/srsoftware/web4rail/MaintnanceTask.java
Normal file
150
src/main/java/de/srsoftware/web4rail/MaintnanceTask.java
Normal file
@@ -0,0 +1,150 @@
|
||||
package de.srsoftware.web4rail;
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
|
||||
import org.json.JSONObject;
|
||||
|
||||
import de.srsoftware.web4rail.moving.Car;
|
||||
import de.srsoftware.web4rail.moving.Train;
|
||||
import de.srsoftware.web4rail.tags.AddSelect;
|
||||
import de.srsoftware.web4rail.tags.Button;
|
||||
import de.srsoftware.web4rail.tiles.Block;
|
||||
|
||||
public class MaintnanceTask extends BaseClass{
|
||||
private static final HashSet<String> tasks = new HashSet<>();
|
||||
|
||||
private static final String NAME = "name";
|
||||
|
||||
public static final String INTERVAL = "interval";
|
||||
|
||||
private static final String LAST_DATE = "last_date";
|
||||
|
||||
private static final String LAST_DIST = "last_dist";
|
||||
|
||||
private long interval;
|
||||
private long lastExecutionDist;
|
||||
private Date lastExecutionDate;
|
||||
private String name;
|
||||
|
||||
public MaintnanceTask(Car car, String name, long interval) {
|
||||
this.name = name;
|
||||
this.interval = interval;
|
||||
parent(car);
|
||||
register();
|
||||
if (isSet(name)) tasks.add(name);
|
||||
}
|
||||
|
||||
public static Object action(HashMap<String, String> params) {
|
||||
String action = params.get(ACTION);
|
||||
if (isNull(action)) return t("No action set!");
|
||||
|
||||
MaintnanceTask task = BaseClass.get(Id.from(params));
|
||||
|
||||
switch (action) {
|
||||
case ACTION_ADD:
|
||||
Car car = BaseClass.get(Id.from(params, REALM_CAR));
|
||||
return car.addTask(createTask(params));
|
||||
case ACTION_DROP:
|
||||
if (isSet(task)) {
|
||||
BaseClass parent = task.parent();
|
||||
task.remove();
|
||||
return parent.properties();
|
||||
}
|
||||
return t("No task!");
|
||||
case ACTION_START:
|
||||
return isSet(task) ? task.executed() : t("No task!");
|
||||
}
|
||||
String err = t("unknown action: {}",action);
|
||||
return (isSet(task)) ? task.parent().properties(err) : err;
|
||||
}
|
||||
|
||||
private static MaintnanceTask createTask(HashMap<String, String> params) {
|
||||
String name = params.get(NAME);
|
||||
long interval = Long.parseLong(params.get(INTERVAL));
|
||||
Car car = BaseClass.get(Id.from(params, REALM_CAR));
|
||||
return new MaintnanceTask(car, name,interval);
|
||||
}
|
||||
|
||||
public Button execBtn() {
|
||||
return button(t("executed"), Map.of(REALM,REALM_MAINTENANCE,ACTION,ACTION_START));
|
||||
}
|
||||
|
||||
private Object executed() {
|
||||
BaseClass parent = parent();
|
||||
if (parent instanceof Car) {
|
||||
Car car = (Car) parent;
|
||||
lastExecutionDate = new Date();
|
||||
lastExecutionDist = car.drivenDistance();
|
||||
Train train = car.train();
|
||||
if (isSet(train)) {
|
||||
Block block = train.currentBlock();
|
||||
if (isSet(block)) plan.place(block);
|
||||
}
|
||||
return car.properties();
|
||||
}
|
||||
return t("parent is not a car!");
|
||||
}
|
||||
|
||||
public long interval() {
|
||||
return interval;
|
||||
}
|
||||
|
||||
public boolean isDue() {
|
||||
return ((Car)parent()).drivenDistance() > lastExecutionDist+interval;
|
||||
}
|
||||
|
||||
@Override
|
||||
public JSONObject json() {
|
||||
JSONObject json = super.json();
|
||||
json.put(NAME, name);
|
||||
json.put(INTERVAL, interval);
|
||||
if (isSet(lastExecutionDate)) {
|
||||
json.put(LAST_DATE, lastExecutionDate.getTime());
|
||||
json.put(LAST_DIST, lastExecutionDist);
|
||||
}
|
||||
return json;
|
||||
}
|
||||
|
||||
public Date lastDate() {
|
||||
return lastExecutionDate;
|
||||
}
|
||||
|
||||
public long lastMileage() {
|
||||
return lastExecutionDist;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MaintnanceTask load(JSONObject json) {
|
||||
json.remove(ID); // we're using the id created by the constructor!
|
||||
super.load(json);
|
||||
name = json.getString(NAME);
|
||||
interval = json.getLong(INTERVAL);
|
||||
if (json.has(LAST_DATE)) lastExecutionDate = new Date(json.getLong(LAST_DATE));
|
||||
if (json.has(LAST_DIST)) lastExecutionDist = json.getLong(LAST_DIST);
|
||||
if (isSet(name)) tasks.add(name);
|
||||
return this;
|
||||
}
|
||||
|
||||
public long nextMileage() {
|
||||
return lastExecutionDist+interval;
|
||||
}
|
||||
|
||||
public Button removeBtn() {
|
||||
return button(t("delete"), Map.of(REALM,REALM_MAINTENANCE,ACTION,ACTION_DROP));
|
||||
}
|
||||
|
||||
public static AddSelect selector() {
|
||||
AddSelect select = new AddSelect(NAME);
|
||||
select.addOption(t("create new task type"));
|
||||
tasks.forEach(task -> select.addOption(task));
|
||||
return select;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return name;
|
||||
}
|
||||
}
|
||||
@@ -492,6 +492,10 @@ public class Route extends BaseClass {
|
||||
return json;
|
||||
}
|
||||
|
||||
public long length() {
|
||||
return path.stream().mapToLong(Tile::length).sum();
|
||||
}
|
||||
|
||||
private Route load(JSONObject json,Plan plan) {
|
||||
if (json.has(ID)) id = Id.from(json);
|
||||
if (json.has(NAME)) name(json.getString(NAME));
|
||||
|
||||
@@ -14,12 +14,14 @@ import java.util.TreeSet;
|
||||
import java.util.Vector;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.json.JSONArray;
|
||||
import org.json.JSONObject;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import de.srsoftware.tools.Tag;
|
||||
import de.srsoftware.web4rail.BaseClass;
|
||||
import de.srsoftware.web4rail.MaintnanceTask;
|
||||
import de.srsoftware.web4rail.Plan;
|
||||
import de.srsoftware.web4rail.tags.Button;
|
||||
import de.srsoftware.web4rail.tags.Fieldset;
|
||||
@@ -45,7 +47,12 @@ public class Car extends BaseClass implements Comparable<Car>{
|
||||
private static final String MAX_SPEED_REVERSE = "max_speed_reverse";
|
||||
private static final String ORDER = "order";
|
||||
private static final String ORIENTATION = "orientation";
|
||||
protected HashSet<String> tags = new HashSet<String>();
|
||||
|
||||
private static final String DRIVEN_DISTANCE = "driven_distance";
|
||||
|
||||
private static final String MAINTENANCE = "maintenance";
|
||||
protected HashSet<String> tags = new HashSet<>();
|
||||
private HashSet<MaintnanceTask> tasks = new HashSet<>();
|
||||
|
||||
private String name;
|
||||
public int length;
|
||||
@@ -54,6 +61,7 @@ public class Car extends BaseClass implements Comparable<Car>{
|
||||
protected int maxSpeedForward = 0;
|
||||
protected int maxSpeedReverse = 0;
|
||||
protected boolean orientation = FORWARD;
|
||||
protected long distanceCounter = 0;
|
||||
|
||||
public Car(String name) {
|
||||
this(name,null);
|
||||
@@ -93,6 +101,11 @@ public class Car extends BaseClass implements Comparable<Car>{
|
||||
return t("Unknown action: {}",params.get(ACTION));
|
||||
}
|
||||
|
||||
public Object addTask(MaintnanceTask newTask) {
|
||||
tasks.add(newTask);
|
||||
return properties();
|
||||
}
|
||||
|
||||
public Car clone() {
|
||||
Car clone = new Car(name);
|
||||
clone.maxSpeedForward = maxSpeedForward;
|
||||
@@ -114,6 +127,14 @@ public class Car extends BaseClass implements Comparable<Car>{
|
||||
public int compareTo(Car o) {
|
||||
return (stockId+":"+name).compareTo(o.stockId+":"+o.name);
|
||||
}
|
||||
|
||||
public Object addDistance(long len) {
|
||||
return distanceCounter+= len;
|
||||
}
|
||||
|
||||
public long drivenDistance() {
|
||||
return distanceCounter;
|
||||
}
|
||||
|
||||
public JSONObject json() {
|
||||
JSONObject json = super.json();
|
||||
@@ -123,7 +144,12 @@ public class Car extends BaseClass implements Comparable<Car>{
|
||||
if (maxSpeedReverse != 0) json.put(MAX_SPEED_REVERSE, maxSpeedReverse);
|
||||
json.put(ORIENTATION, orientation);
|
||||
json.put(STOCK_ID, stockId);
|
||||
if (distanceCounter>0) json.put(DRIVEN_DISTANCE, distanceCounter);
|
||||
if (!tags.isEmpty()) json.put(TAGS, tags);
|
||||
if (!tasks.isEmpty()) {
|
||||
json.put(MAINTENANCE, tasks.stream().map(MaintnanceTask::json).collect(Collectors.toList()));
|
||||
LOG.debug("json: {}",json);
|
||||
}
|
||||
return json;
|
||||
}
|
||||
|
||||
@@ -166,9 +192,38 @@ public class Car extends BaseClass implements Comparable<Car>{
|
||||
if (json.has(STOCK_ID)) stockId = json.getString(STOCK_ID);
|
||||
if (json.has(TAGS)) json.getJSONArray(TAGS).forEach(elem -> { tags.add(elem.toString()); });
|
||||
if (json.has(ORIENTATION)) orientation=json.getBoolean(ORIENTATION);
|
||||
if (json.has(DRIVEN_DISTANCE)) distanceCounter = json.getLong(DRIVEN_DISTANCE);
|
||||
if (json.has(MAINTENANCE)) loadMaintenance(json.getJSONArray(MAINTENANCE));
|
||||
return this;
|
||||
}
|
||||
|
||||
private void loadMaintenance(JSONArray arr) {
|
||||
arr.forEach(o -> {
|
||||
if (o instanceof JSONObject) {
|
||||
tasks.add(new MaintnanceTask(this,null,0).load((JSONObject) o));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private Fieldset maintenance() {
|
||||
Fieldset fieldset = new Fieldset(t("Maintenance")+(needsMaintenance()?NBSP+"⚠":""));
|
||||
Table table = new Table();
|
||||
table.addHead(t("Task"),t("Last execution"),t("due after"),t("Interval"),t("Actions"));
|
||||
for (MaintnanceTask task : tasks) {
|
||||
Tag row = table.addRow(task,time(task.lastDate())+" / "+task.lastMileage()+NBSP+Plan.lengthUnit,task.nextMileage()+NBSP+Plan.lengthUnit,task.interval()+NBSP+Plan.lengthUnit,task.execBtn()+NBSP+task.removeBtn());
|
||||
if (task.isDue()) row.clazz("due");
|
||||
}
|
||||
table.addTo(fieldset);
|
||||
Form form = new Form("create-task");
|
||||
new Input(REALM,REALM_MAINTENANCE).hideIn(form);
|
||||
new Input(ACTION,ACTION_ADD).hideIn(form);
|
||||
new Input(REALM_CAR,id()).hideIn(form);
|
||||
MaintnanceTask.selector().addTo(new Label(t("Task type")+NBSP)).addTo(form);
|
||||
new Input(MaintnanceTask.INTERVAL,1_000_000).numeric().addTo(new Label(t("Interval")+NBSP)).content(NBSP+Plan.lengthUnit).addTo(form);
|
||||
new Button(t("add"), form).addTo(form);
|
||||
return form.addTo(fieldset);
|
||||
}
|
||||
|
||||
public static Object manager(Map<String, String> params) {
|
||||
Window win = new Window("car-manager", t("Car manager"));
|
||||
new Tag("h4").content(t("known cars")).addTo(win);
|
||||
@@ -177,7 +232,7 @@ public class Car extends BaseClass implements Comparable<Car>{
|
||||
String order = params.get(ORDER);
|
||||
|
||||
Tag nameLink = link("span", t("Name"), Map.of(REALM,REALM_CAR,ACTION,ACTION_PROPS,ORDER,NAME));
|
||||
Table table = new Table().addHead(t("Stock ID"),nameLink,t("Max. Speed",speedUnit),t("Length"),t("Train"),t("Tags"),t("Actions"));
|
||||
Table table = new Table().addHead(t("Stock ID"),nameLink,t("Max. Speed",speedUnit),t("Length"),t("Train"),t("Tags"),t("driven distance"),t("Actions"));
|
||||
List<Car> cars = BaseClass.listElements(Car.class)
|
||||
.stream()
|
||||
.filter(car -> !(car instanceof Locomotive))
|
||||
@@ -210,6 +265,7 @@ public class Car extends BaseClass implements Comparable<Car>{
|
||||
car.length+NBSP+lengthUnit,
|
||||
isSet(car.train) ? car.train.link("span", car.train) : "",
|
||||
String.join(", ", car.tags()),
|
||||
car.distanceCounter,
|
||||
actions
|
||||
);
|
||||
}
|
||||
@@ -238,6 +294,12 @@ public class Car extends BaseClass implements Comparable<Car>{
|
||||
return name;
|
||||
}
|
||||
|
||||
boolean needsMaintenance() {
|
||||
for (MaintnanceTask task : tasks) {
|
||||
if (task.isDue()) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
public boolean orientation() {
|
||||
return orientation;
|
||||
}
|
||||
@@ -252,15 +314,17 @@ public class Car extends BaseClass implements Comparable<Car>{
|
||||
new Input(MAX_SPEED, maxSpeedForward).numeric().addTo(new Tag("p")).content(NBSP+speedUnit+NBSP+t("forward")).addTo(div);
|
||||
new Input(MAX_SPEED_REVERSE, maxSpeedReverse).numeric().addTo(new Tag("p")).content(NBSP+speedUnit+NBSP+t("backward")).addTo(div);
|
||||
formInputs.add(t("Maximum Speed"),div);
|
||||
if (train != null) formInputs.add(t("Train"), train.link());
|
||||
if (isSet(train)) formInputs.add(t("Train"), train.link());
|
||||
formInputs.add(t("Current orientation"),new Tag("span").content(orientation ? t("forward") : t("reverse")));
|
||||
|
||||
formInputs.add(t("driven distance"),new Tag("span").content(distanceCounter+" "+Plan.lengthUnit));
|
||||
postForm.add(maintenance());
|
||||
return super.properties(preForm,formInputs,postForm,errors);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected void removeChild(BaseClass child) {
|
||||
if (child == train) train = null;
|
||||
tasks.remove(child);
|
||||
super.removeChild(child);
|
||||
}
|
||||
|
||||
|
||||
@@ -270,14 +270,21 @@ public class Locomotive extends Car implements Constants,Device{
|
||||
|
||||
new Tag("p").content(t("Click on a name to edit the entry.")).addTo(win);
|
||||
|
||||
Table table = new Table().addHead(t("Stock ID"),t("Name"),t("Max. Speed",speedUnit),t("Protocol"),t("Address"),t("Length"),t("Tags"));
|
||||
Table table = new Table().addHead(t("Stock ID"),t("Name"),t("Max. Speed",speedUnit),t("Protocol"),t("Address"),t("Length"),t("driven distance"),t("Tags"));
|
||||
List<Locomotive> locos = BaseClass.listElements(Locomotive.class);
|
||||
locos.sort(Comparator.comparing(loco -> loco.address));
|
||||
locos.sort(Comparator.comparing(loco -> loco.stockId));
|
||||
for (Locomotive loco : locos) {
|
||||
String maxSpeed = (loco.maxSpeedForward == 0 ? "–":""+loco.maxSpeedForward)+NBSP;
|
||||
if (loco.maxSpeedReverse != loco.maxSpeedForward) maxSpeed += "("+loco.maxSpeedReverse+")"+NBSP;
|
||||
table.addRow(loco.stockId,loco.link(),maxSpeed+speedUnit,loco.proto,loco.address,loco.length+NBSP+lengthUnit,String.join(", ", loco.tags()));
|
||||
table.addRow(loco.stockId,
|
||||
loco.link(),
|
||||
maxSpeed+NBSP+speedUnit,
|
||||
loco.proto,
|
||||
loco.address,
|
||||
loco.length+NBSP+lengthUnit,
|
||||
loco.distanceCounter,
|
||||
String.join(", ", loco.tags()));
|
||||
}
|
||||
table.addTo(win);
|
||||
|
||||
|
||||
@@ -229,7 +229,7 @@ public class Train extends BaseClass implements Comparable<Train> {
|
||||
|
||||
boolean first = true;
|
||||
for (Car car : cars) {
|
||||
Tag link = car.link(car.name()+(car.stockId.isEmpty() ? "" : " ("+car.stockId+")"));
|
||||
Tag link = car.link(car.name()+(car.needsMaintenance()?"⚠":"")+(car.stockId.isEmpty() ? "" : " ("+car.stockId+")"));
|
||||
Tag buttons = new Tag("span");
|
||||
|
||||
car.button(t("turn within train"),Map.of(ACTION,ACTION_TURN)).addTo(buttons);
|
||||
@@ -390,6 +390,7 @@ public class Train extends BaseClass implements Comparable<Train> {
|
||||
|
||||
public String directedName() {
|
||||
String result = name();
|
||||
if (needsMainenance()) result+="⚠";
|
||||
String mark = autopilot ? "ⓐ" : "";
|
||||
if (isNull(direction)) return result;
|
||||
switch (direction) {
|
||||
@@ -516,6 +517,9 @@ public class Train extends BaseClass implements Comparable<Train> {
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
long len = endedRoute.length();
|
||||
if (len>0) cars.forEach(car -> car.addDistance(len));
|
||||
}
|
||||
|
||||
private Tag faster(int steps) {
|
||||
@@ -733,6 +737,13 @@ public class Train extends BaseClass implements Comparable<Train> {
|
||||
return this;
|
||||
}
|
||||
|
||||
private boolean needsMainenance() {
|
||||
for (Car car: cars) {
|
||||
if (car.needsMaintenance()) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean onTrace(Tile t) {
|
||||
return trace.contains(t);
|
||||
}
|
||||
@@ -783,7 +794,7 @@ public class Train extends BaseClass implements Comparable<Train> {
|
||||
formInputs.add(t("Tags"), new Input(TAGS,String.join(", ", tags)));
|
||||
|
||||
if (this.hasLoco()) preForm.add(Locomotive.cockpit(this));
|
||||
postForm.add(propList.addTo(new Fieldset(t("other train properties")).id("props-other")));
|
||||
postForm.add(propList.addTo(new Fieldset(t("other train properties")+(needsMainenance()?NBSP+"⚠":"")).id("props-other")));
|
||||
postForm.add(brakeTimes());
|
||||
postForm.add(blockHistory());
|
||||
|
||||
|
||||
26
src/main/java/de/srsoftware/web4rail/tags/AddSelect.java
Normal file
26
src/main/java/de/srsoftware/web4rail/tags/AddSelect.java
Normal file
@@ -0,0 +1,26 @@
|
||||
package de.srsoftware.web4rail.tags;
|
||||
|
||||
import de.srsoftware.tools.Tag;
|
||||
|
||||
public class AddSelect extends Input {
|
||||
private static final long serialVersionUID = -2168654457876014503L;
|
||||
private Tag dataList;
|
||||
|
||||
public AddSelect(String name) {
|
||||
super("select");
|
||||
attr("name",name);
|
||||
attr("list","list-options");
|
||||
dataList = new Tag("datalist").id("list-options");
|
||||
dataList.addTo(this);
|
||||
}
|
||||
|
||||
public Tag addOption(Object value) {
|
||||
return addOption(value, value);
|
||||
}
|
||||
|
||||
public Tag addOption(Object value, Object text) {
|
||||
Tag option = new Tag("option").attr("value", value.toString()).content(text.toString());
|
||||
option.addTo(dataList);
|
||||
return option;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user