001package jmri.implementation;
002
003import javax.annotation.CheckReturnValue;
004import jmri.JmriException;
005import jmri.NamedBean;
006import jmri.StringIO;
007
008import javax.annotation.Nonnull;
009
010/**
011 * Base implementation of the StringIO interface.
012 *
013 * @author Daniel Bergqvist Copyright (c) 2018
014 */
015public abstract class AbstractStringIO extends AbstractNamedBean implements StringIO {
016
017    private String _commandedString = "";
018    private String _knownString = "";
019
020    /**
021     * Abstract constructor for new StringIO with system name
022     *
023     * @param systemName StringIO system name
024     */
025    public AbstractStringIO(@Nonnull String systemName) {
026        super(systemName);
027    }
028
029    /**
030     * Abstract constructor for new StringIO with system name and user name
031     *
032     * @param systemName StringIO system name
033     * @param userName   StringIO user name
034     */
035    public AbstractStringIO(@Nonnull String systemName, String userName) {
036        super(systemName, userName);
037    }
038
039    /**
040     * Sends the string to the layout.
041     * The string [u]must not[/u] be longer than the value of getMaximumLength()
042     * unless that value is zero. Some microcomputers have little memory and
043     * it's very important that this method is never called with too long strings.
044     * <p>
045     * For systems that don't provide another form of feedback, this call is 
046     * responsible for setting the known state to the new commanded state, and 
047     * firing all listeners.
048     *
049     * @param value the desired string value
050     * @throws jmri.JmriException general error when setting the value fails
051     */
052    abstract protected void sendStringToLayout(@Nonnull String value) throws JmriException;
053
054    /**
055     * Set the string of this StringIO.
056     * Called from the implementation class when the layout updates this StringIO.
057     * @param newValue new value to set
058     */
059    protected void setString(@Nonnull String newValue) {
060        Object _old = this._knownString;
061        this._knownString = newValue;
062        firePropertyChange("KnownValue", _old, _knownString); // NOI18N
063    }
064
065    /** {@inheritDoc} */
066    @Override
067    public void setCommandedStringValue(@Nonnull String value) throws JmriException {
068        var _old = _commandedString; 
069        int maxLength = getMaximumLength();
070        if ((maxLength > 0) && (value.length() > maxLength)) {
071            if (cutLongStrings()) {
072                value = value.substring(0, maxLength);
073            } else {
074                throw new JmriException("String too long");
075            }
076        }
077        _commandedString = value;
078        sendStringToLayout(_commandedString);
079        firePropertyChange("CommandedValue", _old, _commandedString); // NOI18N
080    }
081
082    /** {@inheritDoc} */
083    @Override
084    @Nonnull
085    public String getCommandedStringValue() {
086        return _commandedString;
087    }
088
089    /** {@inheritDoc} */
090    @Override
091    public String getKnownStringValue() {
092        return _knownString;
093    }
094
095    /**
096     * Cut long strings instead of throwing an exception?
097     * For example, if the StringIO is a display, it could be desired to
098     * accept too long strings.
099     * On the other hand, if the StringIO is used to send a command, a too
100     * long string is an error.
101     *
102     * @return true if long strings should be cut
103     */
104    abstract protected boolean cutLongStrings();
105
106    /** {@inheritDoc} */
107    @Override
108    public int getState() {
109        // A StringIO doesn't have a state
110        return NamedBean.UNKNOWN;
111    }
112
113    /** {@inheritDoc} */
114    @Override
115    public void setState(int newState) {
116        // A StringIO doesn't have an integer state
117    }
118
119    /** {@inheritDoc} */
120    @Override
121    @Nonnull
122    public String getBeanType() {
123        return Bundle.getMessage("BeanNameStringIO");
124    }
125
126    /**
127     * {@inheritDoc} 
128     * 
129     * Do a string comparison.
130     */
131    @CheckReturnValue
132    @Override
133    public int compareSystemNameSuffix(@Nonnull String suffix1, @Nonnull String suffix2, @Nonnull NamedBean n) {
134        return suffix1.compareTo(suffix2);
135    }
136
137    // private final static org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(AbstractStringIO.class);
138
139}