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     *
045     * @param value the desired string value
046     * @throws jmri.JmriException general error when setting the value fails
047     */
048    abstract protected void sendStringToLayout(@Nonnull String value) throws JmriException;
049
050    /**
051     * Set the string of this StringIO.
052     * Called from the implementation class when the layout updates this StringIO.
053     * @param newValue new value to set
054     */
055    protected void setString(@Nonnull String newValue) {
056        Object _old = this._knownString;
057        this._knownString = newValue;
058        firePropertyChange(PROPERTY_STATE, _old, _knownString); // NOI18N
059    }
060
061    /** {@inheritDoc} */
062    @Override
063    public void setCommandedStringValue(@Nonnull String value) throws JmriException {
064        int maxLength = getMaximumLength();
065        if ((maxLength > 0) && (value.length() > maxLength)) {
066            if (cutLongStrings()) {
067                value = value.substring(0, maxLength);
068            } else {
069                throw new JmriException("String too long");
070            }
071        }
072        _commandedString = value;
073        sendStringToLayout(_commandedString);
074    }
075
076    /** {@inheritDoc} */
077    @Override
078    @Nonnull
079    public String getCommandedStringValue() {
080        return _commandedString;
081    }
082
083    /** {@inheritDoc} */
084    @Override
085    public String getKnownStringValue() {
086        return _knownString;
087    }
088
089    /**
090     * Cut long strings instead of throwing an exception?
091     * For example, if the StringIO is a display, it could be desired to
092     * accept too long strings.
093     * On the other hand, if the StringIO is used to send a command, a too
094     * long string is an error.
095     *
096     * @return true if long strings should be cut
097     */
098    abstract protected boolean cutLongStrings();
099
100    /** {@inheritDoc} */
101    @Override
102    public int getState() {
103        // A StringIO doesn't have a state
104        return NamedBean.UNKNOWN;
105    }
106
107    /** {@inheritDoc} */
108    @Override
109    public void setState(int newState) {
110        // A StringIO doesn't have a state
111    }
112
113    /** {@inheritDoc} */
114    @Override
115    @Nonnull
116    public String getBeanType() {
117        return Bundle.getMessage("BeanNameStringIO");
118    }
119
120    /**
121     * {@inheritDoc} 
122     * 
123     * Do a string comparison.
124     */
125    @CheckReturnValue
126    @Override
127    public int compareSystemNameSuffix(@Nonnull String suffix1, @Nonnull String suffix2, @Nonnull NamedBean n) {
128        return suffix1.compareTo(suffix2);
129    }
130
131}