001package jmri.jmrix.rps;
002
003import java.util.ArrayList;
004import javax.vecmath.Point3d;
005import jmri.Sensor;
006import jmri.implementation.AbstractSensor;
007import org.slf4j.Logger;
008import org.slf4j.LoggerFactory;
009
010/**
011 * Extend jmri.AbstractSensor for RPS systems.
012 * <p>
013 * System names are "RSpppp", where ppp is a representation of the region, for
014 * example "RS(0,0,0);(1,0,0);(1,1,0);(0,1,0)".
015 *
016 * @author Bob Jacobsen Copyright (C) 2007
017 */
018public class RpsSensor extends AbstractSensor
019        implements MeasurementListener {
020
021    public RpsSensor(String systemName, String prefix) {
022        super(systemName);
023        // create Region from all but prefix
024        region = new Region(systemName.substring(prefix.length() + 1)); // multichar prefix from memo
025        Model.instance().addRegion(region);
026    }
027
028    public RpsSensor(String systemName, String userName, String prefix) {
029        super(systemName, userName);
030        // create Region from all but prefix
031        region = new Region(systemName.substring(prefix.length() + 1)); // multichar prefix from memo
032        Model.instance().addRegion(region);
033    }
034
035    @Override
036    public void notify(Measurement r) {
037        Point3d p = new Point3d(r.getX(), r.getY(), r.getZ());
038        Integer id = Integer.valueOf(r.getReading().getId());
039
040        // ignore if code not OK
041        if (!r.isOkPoint()) {
042            return;
043        }
044
045        // ignore if not in Z fiducial volume
046        if (r.getZ() > 20 || r.getZ() < -20) {
047            return;
048        }
049
050        log.debug("starting {}", getSystemName());
051        if (region.isInside(p)) {
052            notifyInRegion(id);
053        } else {
054            notifyOutOfRegion(id);
055        }
056        if (contents.size() > 0) {
057            setOwnState(Sensor.ACTIVE);
058        } else {
059            setOwnState(Sensor.INACTIVE);
060        }
061    }
062
063    // if somebody outside sets state to INACTIVE, clear list
064    @Override
065    public void setOwnState(int state) {
066        if (state == Sensor.INACTIVE) {
067            if (contents.size() > 0) {
068                contents = new ArrayList<Integer>();
069            }
070        }
071        super.setOwnState(state);
072    }
073
074    Region getRegion() {
075        return region;
076    }
077
078    java.util.List<Integer> getContents() {
079        return contents;
080    }
081
082    void notifyInRegion(Integer id) {
083        // make sure region contains this Reading.getId();
084        if (!contents.contains(id)) {
085            contents.add(id);
086            notifyArriving(id);
087        }
088    }
089
090    void notifyOutOfRegion(Integer id) {
091        // make sure region does not contain this Reading.getId();
092        if (contents.contains(id)) {
093            contents.remove(id);
094            notifyLeaving(id);
095        }
096    }
097
098    transient Region region;
099    ArrayList<Integer> contents = new ArrayList<Integer>();
100
101    /**
102     * Notify parameter listeners that a device has left the region covered by
103     * this sensor
104     * @param id Number of region being left
105     */
106    void notifyLeaving(Integer id) {
107        firePropertyChange("Leaving", null, id);
108    }
109
110    /**
111     * Notify parameter listeners that a device has entered the region covered
112     * by this sensor
113     * @param id Number of region being entered
114     */
115    void notifyArriving(Integer id) {
116        firePropertyChange("Arriving", null, id);
117    }
118
119    @Override
120    public void dispose() {
121        Model.instance().removeRegion(region);
122        super.dispose();
123    }
124
125    @Override
126    public void requestUpdateFromLayout() {
127    }
128
129    private final static Logger log = LoggerFactory.getLogger(RpsSensor.class);
130
131}