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     * Public method to notify user of Turnout creation error.
083     * @param conflict string of the turnout which is in conflict.
084     * @param bitNum the bit number in conflict.
085     * @deprecated  since 4.23.4;
086     */
087    @Deprecated
088    public void notifyTurnoutCreationError(String conflict, int bitNum) {
089        javax.swing.JOptionPane.showMessageDialog(null, "ERROR - The output bit, "
090                + bitNum + ", is currently assigned to " + conflict + ". Turnout can not be "
091                + "created as you specified.", " Assignment Conflict",
092                javax.swing.JOptionPane.INFORMATION_MESSAGE, null);
093    }
094
095    /**
096     * {@inheritDoc}
097     */
098    @Override
099    @Nonnull
100    public String validateSystemNameFormat(@Nonnull String name, @Nonnull Locale locale) {
101        return SerialAddress.validateSystemNameFormat(name, this, locale);
102    }
103
104    /**
105     * {@inheritDoc}
106     */
107    @Override
108    public NameValidity validSystemNameFormat(@Nonnull String systemName) {
109        return (SerialAddress.validSystemNameFormat(systemName, typeLetter(), getSystemPrefix()));
110    }
111
112    /**
113     * {@inheritDoc}
114     */
115    @Override
116    public String getEntryToolTip() {
117        return Bundle.getMessage("AddOutputEntryToolTip");
118    }
119
120    /**
121     * Get from the user, the number of addressed bits used to control a
122     * turnout. Normally this is 1, and the default routine returns 1
123     * automatically. Turnout Managers for systems that can handle multiple
124     * control bits should override this method with one which asks the user to
125     * specify the number of control bits. If the user specifies more than one
126     * control bit, this method should check if the additional bits are
127     * available (not assigned to another object). If the bits are not
128     * available, this method should return 0 for number of control bits, after
129     * informing the user of the problem. This function is called whenever a new
130     * turnout is defined in the Turnout table. It can also be used to set up
131     * other turnout control options, such as pulsed control of turnout
132     * machines.
133     */
134// Code below to do with having a pulsed turnout type is commented out for current Maple version
135// /**
136//  * Get from the user, the type of output to be used bits to control a turnout. 
137//  * Normally this is 0 for 'steady state' control, and the default routine 
138//  * returns 0 automatically.  
139//  * Turnout Managers for systems that can handle pulsed control as well as  
140//  * steady state control should override this method with one which asks 
141//  * the user to specify the type of control to be used.  The routine should 
142//  * return 0 for 'steady state' control, or n for 'pulsed' control, where n
143//  * specifies the duration of the pulse (normally in seconds).  
144// */
145//  public int askControlType(String systemName) {
146//  // ask if user wants 'steady state' output (stall motors, e.g., Tortoises) or 
147//  //   'pulsed' output (some turnout controllers).
148//  int iType = selectOutputType();
149//  if (iType == javax.swing.JOptionPane.CLOSED_OPTION) {
150//   /* user cancelled without selecting an output type */
151//   iType = 0;
152//   log.warn("User cancelled without selecting output type. Defaulting to 'steady state'.");
153//  }
154//  // Note: If the user selects 'pulsed', this routine defaults to 1 second.
155//  return (iType);
156// }
157//    /**
158//     * Public method to allow user to specify one or two output bits for turnout control
159//  *  Note: This method returns 1 or 2 if the user selected, or 0 if the user cancelled
160//  *         without selecting.
161//  */
162// public int selectNumberOfControlBits() {
163//  int iNum = 0;
164//  iNum = javax.swing.JOptionPane.showOptionDialog(null,
165//    "How many output bits should be used to control this turnout?",
166//     "Turnout Question",javax.swing.JOptionPane.DEFAULT_OPTION,
167//      javax.swing.JOptionPane.QUESTION_MESSAGE,
168//      null, new String[] {"Use 1 bit", "Use 2 bits"}, "Use 1 bit");
169//  return iNum;
170// }
171//    /**
172//     * Public method to allow user to specify pulsed or steady state for two output bits 
173//  * for turnout control
174//  *  Note: This method returns 1 for steady state or 2 for pulsed if the user selected, 
175//  *   or 0 if the user cancelled without selecting.
176//  */
177// public int selectOutputType() {
178//  int iType = 0;
179//  iType = javax.swing.JOptionPane.showOptionDialog(null,
180//    "Should the output bit(s) be 'steady state' or 'pulsed'?",
181//     "Output Bits Question",javax.swing.JOptionPane.DEFAULT_OPTION,
182//      javax.swing.JOptionPane.QUESTION_MESSAGE,
183//      null, new String[] {"Steady State Output", "Pulsed Output"}, "Steady State Output");
184//  return iType;
185// }
186//    /**
187//     * Public method to notify user when the second bit of a proposed two output bit turnout 
188//  *  has a conflict with another assigned bit
189//     */
190// public void notifySecondBitConflict(String conflict,int bitNum) {
191//  javax.swing.JOptionPane.showMessageDialog(null,"The second output bit, "+bitNum+
192//   ", is currently assigned to "+conflict+". Turnout cannot be created as "+
193//     "you specified.", "Assignment Conflict",
194//       javax.swing.JOptionPane.INFORMATION_MESSAGE,null);
195// }
196
197
198    private final static Logger log = LoggerFactory.getLogger(SerialTurnoutManager.class);
199
200}