001package jmri.jmrix.maple;
002
003import java.util.Locale;
004import javax.annotation.Nonnull;
005import jmri.Turnout;
006import jmri.managers.AbstractTurnoutManager;
007import org.slf4j.Logger;
008import org.slf4j.LoggerFactory;
009
010/**
011 * Implement turnout manager for serial systems
012 * <p>
013 * System names are "KTnnn", where K is the user configurable system prefix,
014 * nnn is the turnout number without padding.
015 *
016 * @author Bob Jacobsen Copyright (C) 2003, 2008
017 */
018public class SerialTurnoutManager extends AbstractTurnoutManager {
019
020    public SerialTurnoutManager(MapleSystemConnectionMemo memo) {
021        super(memo);
022    }
023
024    /**
025     * {@inheritDoc}
026     */
027    @Override
028    @Nonnull
029    public MapleSystemConnectionMemo getMemo() {
030        return (MapleSystemConnectionMemo) memo;
031    }
032
033    /**
034     * {@inheritDoc}
035     */
036    @Nonnull
037    @Override
038    protected Turnout createNewTurnout(@Nonnull String systemName, String userName) throws IllegalArgumentException {
039        // validate the system name, and normalize it
040        String sName = SerialAddress.normalizeSystemName(systemName, getSystemPrefix());
041        if (sName.isEmpty()) {
042            // system name is not valid
043            throw new IllegalArgumentException("Cannot create System Name from " + systemName);
044        }
045        // does this turnout already exist
046        Turnout t = getBySystemName(sName);
047        if (t != null) {
048            return t;
049        }
050
051        // check if the addressed output bit is available
052        int bitNum = SerialAddress.getBitFromSystemName(sName, getSystemPrefix());
053        if (bitNum == 0) {
054            throw new IllegalArgumentException("Cannot get Bit from System Name " + systemName + " " + sName);
055        }
056        String conflict = SerialAddress.isOutputBitFree(bitNum, getSystemPrefix());
057        if ((!conflict.isEmpty()) && (!conflict.equals(sName))) {
058            log.error("{} assignment conflict with {}.", sName, conflict);
059            throw new IllegalArgumentException("The output bit " + bitNum + ", is currently assigned to " + conflict + ".");
060        }
061
062        // create the turnout
063        t = new SerialTurnout(sName, userName, getMemo());
064
065        // does system name correspond to configured hardware
066        if (!SerialAddress.validSystemNameConfig(sName, 'T', getMemo())) {
067            // system name does not correspond to configured hardware
068            log.warn("Turnout '{}' refers to an unconfigured output bit.", sName);
069            javax.swing.JOptionPane.showMessageDialog(null, "WARNING - The Turnout just added, "
070                    + sName + ", refers to an unconfigured output bit.", "Configuration Warning",
071                    javax.swing.JOptionPane.INFORMATION_MESSAGE, null);
072        }
073        return t;
074    }
075
076    @Override
077    public boolean allowMultipleAdditions(@Nonnull String systemName) {
078        return true;
079    }
080
081    /**
082     * {@inheritDoc}
083     */
084    @Override
085    @Nonnull
086    public String validateSystemNameFormat(@Nonnull String name, @Nonnull Locale locale) {
087        return SerialAddress.validateSystemNameFormat(name, this, locale);
088    }
089
090    /**
091     * {@inheritDoc}
092     */
093    @Override
094    public NameValidity validSystemNameFormat(@Nonnull String systemName) {
095        return (SerialAddress.validSystemNameFormat(systemName, typeLetter(), getSystemPrefix()));
096    }
097
098    /**
099     * {@inheritDoc}
100     */
101    @Override
102    public String getEntryToolTip() {
103        return Bundle.getMessage("AddOutputEntryToolTip");
104    }
105
106    /**
107     * Get from the user, the number of addressed bits used to control a
108     * turnout. Normally this is 1, and the default routine returns 1
109     * automatically. Turnout Managers for systems that can handle multiple
110     * control bits should override this method with one which asks the user to
111     * specify the number of control bits. If the user specifies more than one
112     * control bit, this method should check if the additional bits are
113     * available (not assigned to another object). If the bits are not
114     * available, this method should return 0 for number of control bits, after
115     * informing the user of the problem. This function is called whenever a new
116     * turnout is defined in the Turnout table. It can also be used to set up
117     * other turnout control options, such as pulsed control of turnout
118     * machines.
119     */
120// Code below to do with having a pulsed turnout type is commented out for current Maple version
121// /**
122//  * Get from the user, the type of output to be used bits to control a turnout.
123//  * Normally this is 0 for 'steady state' control, and the default routine
124//  * returns 0 automatically.
125//  * Turnout Managers for systems that can handle pulsed control as well as
126//  * steady state control should override this method with one which asks
127//  * the user to specify the type of control to be used.  The routine should
128//  * return 0 for 'steady state' control, or n for 'pulsed' control, where n
129//  * specifies the duration of the pulse (normally in seconds).
130// */
131//  public int askControlType(String systemName) {
132//  // ask if user wants 'steady state' output (stall motors, e.g., Tortoises) or
133//  //   'pulsed' output (some turnout controllers).
134//  int iType = selectOutputType();
135//  if (iType == javax.swing.JOptionPane.CLOSED_OPTION) {
136//   /* user cancelled without selecting an output type */
137//   iType = 0;
138//   log.warn("User cancelled without selecting output type. Defaulting to 'steady state'.");
139//  }
140//  // Note: If the user selects 'pulsed', this routine defaults to 1 second.
141//  return (iType);
142// }
143//    /**
144//     * Public method to allow user to specify one or two output bits for turnout control
145//  *  Note: This method returns 1 or 2 if the user selected, or 0 if the user cancelled
146//  *         without selecting.
147//  */
148// public int selectNumberOfControlBits() {
149//  int iNum = 0;
150//  iNum = javax.swing.JOptionPane.showOptionDialog(null,
151//    "How many output bits should be used to control this turnout?",
152//     "Turnout Question",javax.swing.JOptionPane.DEFAULT_OPTION,
153//      javax.swing.JOptionPane.QUESTION_MESSAGE,
154//      null, new String[] {"Use 1 bit", "Use 2 bits"}, "Use 1 bit");
155//  return iNum;
156// }
157//    /**
158//     * Public method to allow user to specify pulsed or steady state for two output bits
159//  * for turnout control
160//  *  Note: This method returns 1 for steady state or 2 for pulsed if the user selected,
161//  *   or 0 if the user cancelled without selecting.
162//  */
163// public int selectOutputType() {
164//  int iType = 0;
165//  iType = javax.swing.JOptionPane.showOptionDialog(null,
166//    "Should the output bit(s) be 'steady state' or 'pulsed'?",
167//     "Output Bits Question",javax.swing.JOptionPane.DEFAULT_OPTION,
168//      javax.swing.JOptionPane.QUESTION_MESSAGE,
169//      null, new String[] {"Steady State Output", "Pulsed Output"}, "Steady State Output");
170//  return iType;
171// }
172//    /**
173//     * Public method to notify user when the second bit of a proposed two output bit turnout
174//  *  has a conflict with another assigned bit
175//     */
176// public void notifySecondBitConflict(String conflict,int bitNum) {
177//  javax.swing.JOptionPane.showMessageDialog(null,"The second output bit, "+bitNum+
178//   ", is currently assigned to "+conflict+". Turnout cannot be created as "+
179//     "you specified.", "Assignment Conflict",
180//       javax.swing.JOptionPane.INFORMATION_MESSAGE,null);
181// }
182
183
184    private final static Logger log = LoggerFactory.getLogger(SerialTurnoutManager.class);
185
186}