001package jmri.server.json.power;
002
003import static jmri.server.json.JSON.GET;
004import static jmri.server.json.JSON.NAME;
005import static jmri.server.json.JSON.PREFIX;
006import static jmri.server.json.power.JsonPowerServiceFactory.POWER;
007
008import com.fasterxml.jackson.databind.JsonNode;
009import java.beans.PropertyChangeEvent;
010import java.beans.PropertyChangeListener;
011import java.io.IOException;
012import java.util.HashSet;
013import java.util.Set;
014import jmri.InstanceManager;
015import jmri.JmriException;
016import jmri.PowerManager;
017import jmri.SystemConnectionMemo;
018import jmri.jmrix.SystemConnectionMemoManager;
019import jmri.server.json.JsonConnection;
020import jmri.server.json.JsonException;
021import jmri.server.json.JsonRequest;
022import jmri.server.json.JsonSocketService;
023
024/**
025 *
026 * @author Randall Wood
027 */
028public class JsonPowerSocketService extends JsonSocketService<JsonPowerHttpService> implements PropertyChangeListener {
029
030    private final Set<PowerManager> listeningTo = new HashSet<>();
031
032    public JsonPowerSocketService(JsonConnection connection) {
033        this(connection, new JsonPowerHttpService(connection.getObjectMapper()));
034    }
035
036    protected JsonPowerSocketService(JsonConnection connection, JsonPowerHttpService service) {
037        super(connection, service);
038    }
039
040    @Override
041    public void onMessage(String type, JsonNode data, JsonRequest request) throws IOException, JmriException, JsonException {
042        addListener(resolveManager(data));
043        connection.sendMessage(service.doPost(type, data.path(NAME).asText(), data, request), request.id);
044    }
045
046    @Override
047    public void onList(String type, JsonNode data, JsonRequest request) throws JsonException, IOException {
048        InstanceManager.getList(PowerManager.class).forEach(this::addListener);
049        connection.sendMessage(service.doGetList(type, data, request), request.id);
050    }
051
052    private void addListener(PowerManager manager) {
053        if (manager != null && listeningTo.add(manager)) {
054            manager.addPropertyChangeListener(this);
055        }
056    }
057
058    /**
059     * Resolves the PowerManager targeted by a client message, using the same
060     * prefix → name → default fallback order as the HTTP service. Returns null
061     * if no PowerManager is configured.
062     */
063    private PowerManager resolveManager(JsonNode data) {
064        String prefix = data.path(PREFIX).asText();
065        if (!prefix.isEmpty()) {
066            SystemConnectionMemo memo = SystemConnectionMemoManager.getDefault()
067                    .getSystemConnectionMemoForSystemPrefix(prefix);
068            if (memo != null && memo.provides(PowerManager.class)) {
069                return memo.get(PowerManager.class);
070            }
071            return null;
072        }
073        String name = data.path(NAME).asText();
074        if (!name.isEmpty()) {
075            for (PowerManager pm : InstanceManager.getList(PowerManager.class)) {
076                if (pm.getUserName().equals(name)) {
077                    return pm;
078                }
079            }
080        }
081        return InstanceManager.getNullableDefault(PowerManager.class);
082    }
083
084    @Override
085    public void propertyChange(PropertyChangeEvent evt) {
086        try {
087            try {
088                String name = ((PowerManager) evt.getSource()).getUserName();
089                connection.sendMessage(service.doGet(POWER, name, connection.getObjectMapper().createObjectNode(), new JsonRequest(connection.getLocale(), connection.getVersion(), GET, 0)), 0);
090            } catch (JsonException ex) {
091                connection.sendMessage(ex.getJsonMessage(), 0);
092            }
093        } catch (IOException ex) {
094            // do nothing - we can only silently fail at this point
095        }
096    }
097
098    @Override
099    public void onClose() {
100        listeningTo.forEach(manager -> manager.removePropertyChangeListener(JsonPowerSocketService.this));
101    }
102
103}