001package jmri.server.json.block;
002
003import static jmri.server.json.JSON.VALUE;
004import static jmri.server.json.block.JsonBlock.BLOCK;
005import static jmri.server.json.block.JsonBlock.BLOCKS;
006import static jmri.server.json.idtag.JsonIdTag.IDTAG;
007import static jmri.server.json.reporter.JsonReporter.REPORTER;
008
009import com.fasterxml.jackson.databind.JsonNode;
010import com.fasterxml.jackson.databind.ObjectMapper;
011import com.fasterxml.jackson.databind.node.ArrayNode;
012import com.fasterxml.jackson.databind.node.ObjectNode;
013import javax.servlet.http.HttpServletResponse;
014
015import jmri.BasicRosterEntry;
016import jmri.Block;
017import jmri.BlockManager;
018import jmri.InstanceManager;
019import jmri.JmriException;
020import jmri.NamedBean;
021import jmri.ProvidingManager;
022import jmri.Reporter;
023import jmri.ReporterManager;
024import jmri.Sensor;
025import jmri.SensorManager;
026import jmri.server.json.JSON;
027import jmri.server.json.JsonException;
028import jmri.server.json.JsonNamedBeanHttpService;
029import jmri.server.json.JsonRequest;
030import jmri.server.json.idtag.JsonIdTagHttpService;
031import jmri.server.json.reporter.JsonReporter;
032import jmri.server.json.reporter.JsonReporterHttpService;
033import jmri.server.json.roster.JsonRosterHttpService;
034import jmri.server.json.sensor.JsonSensor;
035
036/**
037 * @author mstevetodd Copyright 2018
038 * @author Randall Wood Copyright 2018, 2019
039 */
040public class JsonBlockHttpService extends JsonNamedBeanHttpService<Block> {
041
042    private final JsonIdTagHttpService idTagService = new JsonIdTagHttpService(mapper);
043    private final JsonReporterHttpService reporterService = new JsonReporterHttpService(mapper);
044    private final JsonRosterHttpService rosterService = new JsonRosterHttpService(mapper);
045
046    public JsonBlockHttpService(ObjectMapper mapper) {
047        super(mapper);
048    }
049
050    @Override
051    public ObjectNode doGet(Block block, String name, String type, JsonRequest request) throws JsonException {
052        ObjectNode root = this.getNamedBean(block, name, getType(), request);
053        ObjectNode data = root.with(JSON.DATA);
054        switch (block.getState()) {
055            case Block.UNDETECTED:
056            case NamedBean.UNKNOWN:
057                data.put(JSON.STATE, JSON.UNKNOWN);
058                break;
059            default:
060                data.put(JSON.STATE, block.getState());
061        }
062        // set block value based on type stored there
063        Object bv = block.getValue();
064        if (bv == null) {
065            data.putNull(VALUE);
066        } else if (bv instanceof jmri.IdTag) {
067            ObjectNode idTagValue = idTagService.doGet((jmri.IdTag) bv, name, IDTAG, request);
068            data.set(VALUE, idTagValue);
069        } else if (bv instanceof jmri.Reporter) {
070            ObjectNode reporterValue = reporterService.doGet((jmri.Reporter) bv, name, REPORTER, request);
071            data.set(VALUE, reporterValue);
072        } else if (bv instanceof jmri.BasicRosterEntry) {
073            ObjectNode rosterValue = (ObjectNode) rosterService.getRosterEntry(
074                request.locale, ((BasicRosterEntry) bv).getId(), request.id);
075            data.set(VALUE, rosterValue);
076        } else {
077            // send string for types not explicitly handled
078            data.put(VALUE, bv.toString());
079        }
080        var sens = block.getSensor();
081        data.put(JsonSensor.SENSOR, sens != null ? sens.getSystemName() : null);
082        var rep = block.getReporter();
083        data.put(JsonReporter.REPORTER, rep != null ? rep.getSystemName() : null);
084        data.put(JSON.SPEED, block.getBlockSpeed());
085        data.put(JsonBlock.CURVATURE, block.getCurvature());
086        data.put(JSON.DIRECTION, block.getDirection());
087        data.put(JSON.LENGTH, block.getLengthMm());
088        data.put(JsonBlock.PERMISSIVE, block.getPermissiveWorking());
089        data.put(JsonBlock.SPEED_LIMIT, block.getSpeedLimit());
090        ArrayNode array = data.putArray(JsonBlock.DENIED);
091        block.getDeniedBlocks().forEach(array::add);
092        return root;
093    }
094
095    @Override
096    public ObjectNode doPost(Block block, String name, String type, JsonNode data, JsonRequest request)
097            throws JsonException {
098        if (!data.path(JSON.VALUE).isMissingNode()) {
099            if (data.path(JSON.VALUE).isNull()) {
100                block.setValue(null);
101            } else {
102                block.setValue(data.path(JSON.VALUE).asText());
103            }
104        }
105        int state = data.path(JSON.STATE).asInt(JSON.UNKNOWN);
106        switch (state) {
107            case JSON.ACTIVE:
108                block.setState(Block.OCCUPIED);
109                break;
110            case JSON.INACTIVE:
111                block.setState(Block.UNOCCUPIED);
112                break;
113            case JSON.UNKNOWN:
114                // leave state alone in this case
115                break;
116            default:
117                throw new JsonException(400, Bundle.getMessage(request.locale, "ErrorUnknownState", BLOCK, state),
118                        request.id);
119        }
120        if (!data.path(JsonSensor.SENSOR).isMissingNode()) {
121            JsonNode node = data.path(JsonSensor.SENSOR);
122            if (node.isNull()) {
123                block.setSensor(null);
124            } else {
125                Sensor sensor = InstanceManager.getDefault(SensorManager.class).getBySystemName(node.asText());
126                if (sensor != null) {
127                    block.setSensor(sensor.getSystemName());
128                } else {
129                    throw new JsonException(404,
130                            Bundle.getMessage(request.locale, JsonException.ERROR_NOT_FOUND, JsonSensor.SENSOR,
131                                    node.asText()),
132                            request.id);
133                }
134            }
135        }
136        if (!data.path(JsonReporter.REPORTER).isMissingNode()) {
137            JsonNode node = data.path(JsonReporter.REPORTER);
138            if (node.isNull()) {
139                block.setReporter(null);
140            } else {
141                Reporter reporter = InstanceManager.getDefault(ReporterManager.class).getBySystemName(node.asText());
142                if (reporter != null) {
143                    block.setReporter(reporter);
144                } else {
145                    throw new JsonException(404,
146                            Bundle.getMessage(request.locale, JsonException.ERROR_NOT_FOUND, JsonReporter.REPORTER,
147                                    node.asText()),
148                            request.id);
149                }
150            }
151        }
152        String text = data.findPath(JSON.SPEED).asText(block.getBlockSpeed());
153        try {
154            block.setBlockSpeed(text);
155        } catch (JmriException ex) {
156            throw new JsonException(HttpServletResponse.SC_BAD_REQUEST,
157                    Bundle.getMessage(request.locale, JsonException.ERROR_BAD_PROPERTY_VALUE, text, JSON.SPEED, type),
158                    request.id);
159        }
160        block.setCurvature(data.path(JsonBlock.CURVATURE).asInt(block.getCurvature()));
161        block.setDirection(data.path(JSON.DIRECTION).asInt(block.getDirection()));
162        if (data.path(JSON.LENGTH).isNumber()) {
163            block.setLength(data.path(JSON.LENGTH).floatValue());
164        }
165        block.setPermissiveWorking(data.path(JsonBlock.PERMISSIVE).asBoolean(block.getPermissiveWorking()));
166        return this.doGet(block, name, type, request);
167    }
168
169    @Override
170    protected void doDelete(Block bean, String name, String type, JsonNode data, JsonRequest request)
171            throws JsonException {
172        deleteBean(bean, name, type, data, request);
173    }
174
175    @Override
176    public JsonNode doSchema(String type, boolean server, JsonRequest request) throws JsonException {
177        switch (type) {
178            case BLOCK:
179            case BLOCKS:
180                return doSchema(type,
181                        server,
182                        "jmri/server/json/block/block-server.json",
183                        "jmri/server/json/block/block-client.json",
184                        request.id);
185            default:
186                throw new JsonException(HttpServletResponse.SC_INTERNAL_SERVER_ERROR,
187                        Bundle.getMessage(request.locale, JsonException.ERROR_UNKNOWN_TYPE, type), request.id);
188        }
189    }
190
191    @Override
192    protected String getType() {
193        return BLOCK;
194    }
195
196    @Override
197    protected ProvidingManager<Block> getProvidingManager() {
198        return InstanceManager.getDefault(BlockManager.class);
199    }
200
201}