001package jmri.jmrix.ecos;
002
003import java.util.HashMap;
004import java.util.List;
005import jmri.LocoAddress;
006import jmri.SpeedStepMode;
007import jmri.beans.Bean;
008import jmri.jmrit.roster.Roster;
009import jmri.jmrit.roster.RosterEntry;
010
011/**
012 * Stores all the loco information from the ECoS into JMRI
013 *
014 * @author Kevin Dickerson
015 */
016public class EcosLocoAddress extends Bean implements jmri.LocoAddress {
017
018    private String _ecosObject = null;
019    private int _dccAddress = 0;
020    private String _ecosDescription = null;
021    private String _rosterId = null;
022    private String _ecosProtocolString = null;
023    private LocoAddress.Protocol _protocol = LocoAddress.Protocol.DCC;
024    private SpeedStepMode _speedSteps = SpeedStepMode.NMRA_DCC_128;
025    boolean direction;
026    int currentSpeed;
027    private boolean doNotAddToRoster = false;
028    public static int MFX_DCCAddressOffset = 20000;
029
030    public EcosLocoAddress(int dCCAddress) {
031        _dccAddress = dCCAddress;
032    }
033
034    public EcosLocoAddress(String ecosObject, String rosterAtt) {
035        _ecosObject = ecosObject;
036        //We see if there is a matching roster entry with out object against it
037        //if so we add the rosterId to the ecoclocoaddress entry.
038        List<RosterEntry> l = Roster.getDefault().getEntriesWithAttributeKeyValue(rosterAtt, ecosObject);
039        //It should be unique
040        if (l.size() > 0) {
041            _rosterId = l.get(0).getId();
042        }
043    }
044
045    HashMap<Integer, Integer> cvValues = new HashMap<Integer, Integer>();
046
047    public void setCV(int cv, int value) {
048        cvValues.put(cv, value);
049    }
050
051    public int getCV(int cv) {
052        if (cvValues.containsKey(cv)) {
053            return cvValues.get(cv);
054        }
055        return -1;
056    }
057
058    public String getCVAsString(int cv) {
059        int val = getCV(cv);
060        if (val == -1) {
061            return null;
062        }
063        return "" + val; //Do correctly
064
065    }
066
067    public void setLocoAddress(int dCCAddress) {
068        _dccAddress = dCCAddress;
069    }
070
071    /**
072     * @return the loco address configured on the ECoS for this loco
073     */
074    @Override
075    public int getNumber() {
076        return _dccAddress;
077    }
078
079    /**
080     * @return the loco object as a string on the ECOS for this loco
081     */
082    public String getEcosObject() {
083        return _ecosObject;
084    }
085
086    /**
087     * @return the loco object as a integer on the ECOS for this loco
088     */
089    public int getEcosObjectAsInt() {
090        return Integer.parseInt(_ecosObject);
091    }
092
093    public void doNotAddToRoster() {
094        doNotAddToRoster = true;
095    }
096
097    public void allowAddToRoster() {
098        doNotAddToRoster = false;
099    }
100
101    public boolean addToRoster() {
102        return !doNotAddToRoster;
103    }
104
105    protected void setSpeed(int speed) {
106        int oldspeed = currentSpeed;
107        currentSpeed = speed;
108        firePropertyChange("Speed", oldspeed, currentSpeed); // NOI18N
109    }
110
111    public int getSpeed() {
112        return currentSpeed;
113    }
114
115    protected void setDirection(String line) {
116        setDirection(getDirection(line));
117    }
118
119    protected void setDirection(boolean dir) {
120        boolean olddir = direction;
121        direction = dir;
122        firePropertyChange("Direction", olddir, direction);
123    }
124
125    public boolean getDirection() {
126        return direction;
127    }
128
129    public String getDirectionAsString() {
130        if (direction) {
131            return Bundle.getMessage("Forward");
132        }
133        return Bundle.getMessage("Reverse");
134    }
135
136    //Should this option be made public? should setting the object only be available when the Loco is created.
137    //It needs a bit of a re-think!
138    //It is set this way because of adhoc locos being created for throttles.
139    public void setEcosObject(String ecosObject) {
140        _ecosObject = ecosObject;
141    }
142
143    /**
144     * @return the loco object description held on the ECOS for this loco
145     */
146    public String getEcosDescription() {
147        return _ecosDescription;
148    }
149
150    public void setEcosDescription(String description) {
151        if (description.startsWith("\"")) description = description.substring(1, description.length());
152        if (description.endsWith("\"")) description = description.substring(0, description.length() - 1);
153        String oldValue = _ecosDescription;
154        _ecosDescription = description;
155        firePropertyChange("name", oldValue, _ecosDescription); // NOI18N
156    }
157
158    /**
159     * @return the JMRI Roster ID for this loco
160     */
161    public String getRosterId() {
162        return _rosterId;
163    }
164
165    public void setRosterId(String roster) {
166        String oldValue = _rosterId;
167        _rosterId = roster;
168        firePropertyChange("RosterId", oldValue, _rosterId); // NOI18N
169    }
170
171    //Protocol is here as it is a potential value from the ecos
172    // We may not actually use it.
173    public String getECOSProtocol() {
174        return _ecosProtocolString;
175    }
176
177    //@TODO Need to udate this to return the new Protocol option from LocoAddress
178    public SpeedStepMode getSpeedStepMode() {
179        return _speedSteps;
180    }
181
182    public void setProtocol(String protocol) {
183        //funcexists
184        String oldValue = _ecosProtocolString;
185        _ecosProtocolString = protocol;
186        firePropertyChange("protocol", oldValue, _ecosProtocolString);
187        if (protocol.startsWith("DCC")) {
188            _protocol = LocoAddress.Protocol.DCC;
189        } else if (protocol.startsWith("MM")) {
190            _protocol = LocoAddress.Protocol.MOTOROLA;
191        } else if (protocol.startsWith("SX")) {  //SX32
192            _protocol = LocoAddress.Protocol.SELECTRIX;
193        } else if (protocol.startsWith("LBG")) {  //LBG14
194            _protocol = LocoAddress.Protocol.SELECTRIX;
195        }
196        if (protocol.endsWith("128")) {
197            _speedSteps = SpeedStepMode.NMRA_DCC_128;
198        } else if (protocol.endsWith("28")) {
199            _speedSteps = SpeedStepMode.NMRA_DCC_28;
200        } else if (protocol.endsWith("27")) {
201            _speedSteps = SpeedStepMode.NMRA_DCC_27;
202        } else if (protocol.endsWith("14")) {
203            _speedSteps = SpeedStepMode.NMRA_DCC_14;
204        }
205    }
206
207    @Override
208    public LocoAddress.Protocol getProtocol() {
209        return _protocol;
210    }
211
212    /*
213     The Temporary Entry Field is used to determine if JMRI has had to create the entry on an ad-hoc basis
214     for the throttle.  If this is set to True, the throttle can evaluate this field to determine if the
215     loco should be removed from the Ecos Database when closing the application.
216     */
217    boolean _tempEntry = false;
218
219    public void setEcosTempEntry(boolean boo) {
220        _tempEntry = boo;
221    }
222
223    public boolean getEcosTempEntry() {
224        return _tempEntry;
225    }
226
227    public void reply(EcosReply m) {
228        String msg = m.toString();
229        if (m.getResultCode() != 0) {
230            return; //The result is not valid therefore we can not set it.
231        }
232        if (msg.startsWith("<REPLY get(" + _ecosObject + ",") || msg.startsWith("<EVENT " + _ecosObject + ">")) {
233            if (msg.contains("speed")) {
234                setSpeed(Integer.parseInt(EcosReply.getContentDetails(msg, "speed")));
235            }
236            if (msg.contains("dir")) {
237                setDirection(getDirection(msg));
238            }
239            if (msg.contains("protocol")) {
240                setProtocol(EcosReply.getContentDetails(msg, "protocol"));
241            }
242            if (msg.contains("name")) {
243                String name = EcosReply.getContentDetails(msg, "name").trim();
244                setEcosDescription(name);
245            }
246        }
247    }
248
249    boolean getDirection(String line) {
250        boolean newDirection = false;
251        if (EcosReply.getContentDetails(line, "dir").equals("0")) {
252            newDirection = true;
253        }
254        return newDirection;
255    }
256
257    public void dispose() {
258        // nothing to do
259    }
260
261}