implemented maintenance tasks

This commit is contained in:
Stephan Richter
2021-04-04 17:42:55 +02:00
parent 941c96f5e7
commit 69d33e60c1
12 changed files with 295 additions and 10 deletions

View File

@@ -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:

View File

@@ -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();
}

View File

@@ -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";

View 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;
}
}

View File

@@ -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));

View File

@@ -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);
}

View File

@@ -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);

View File

@@ -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());

View 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;
}
}