001package jmri.managers;
002
003import java.util.ArrayList;
004
005import javax.annotation.CheckForNull;
006import javax.annotation.Nonnull;
007
008import jmri.Block;
009import jmri.InstanceManager;
010import jmri.Manager;
011import jmri.NamedBean;
012import jmri.Section;
013import jmri.SectionManager;
014import jmri.Transit;
015
016/**
017 * Implementation of a Transit Manager
018 * <p>
019 * This doesn't need an interface, since Transits are globaly implemented,
020 * instead of being system-specific.
021 * <p>
022 * Note that Transit system names must begin with system prefix and type character,
023 * usually IZ, and be followed by a string, usually, but not always, a number. This
024 * is enforced when a Transit is created.
025 * <br>
026 * <hr>
027 * This file is part of JMRI.
028 * <p>
029 * JMRI is free software; you can redistribute it and/or modify it under the
030 * terms of version 2 of the GNU General Public License as published by the Free
031 * Software Foundation. See the "COPYING" file for a copy of this license.
032 * <p>
033 * JMRI is distributed in the hope that it will be useful, but WITHOUT ANY
034 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
035 * A PARTICULAR PURPOSE. See the GNU General Public License for more details.
036 *
037 * @author Dave Duchamp Copyright (C) 2008, 2011
038 */
039public class DefaultTransitManager extends AbstractManager<Transit> implements jmri.TransitManager {
040
041    public DefaultTransitManager() {
042        super();
043        addVetoListener();
044    }
045
046    final void addVetoListener(){
047        InstanceManager.getDefault(SectionManager.class).addVetoableChangeListener(this);
048    }
049
050    @Override
051    public int getXMLOrder() {
052        return Manager.TRANSITS;
053    }
054
055    @Override
056    public char typeLetter() {
057        return 'Z';
058    }
059
060    /**
061     * Create a new Transit if the Transit does not exist.
062     * This is NOT a provide method.
063     *
064     * @param systemName the desired system name
065     * @param userName   the desired user name
066     * @return a new Transit
067     * @throws NamedBean.BadNameException if a Transit with the same systemName or
068     *         userName already exists, or if there is trouble creating a new
069     *         Transit.
070     */
071    @Override
072    @Nonnull
073    public Transit createNewTransit(@CheckForNull String systemName, String userName) throws NamedBean.BadNameException {
074        // check system name
075        if ((systemName == null) || (systemName.isEmpty())) {
076            throw new NamedBean.BadSystemNameException("Transit System Name cannot be empty or null.", // NOI18N
077                Bundle.getMessage("InvalidBeanSystemNameEmpty",getBeanTypeHandled(false)));
078        }
079        String sysName = systemName;
080        if (!sysName.startsWith(getSystemNamePrefix())) {
081            sysName = makeSystemName(sysName);
082        }
083        // Check that Transit does not already exist
084        Transit z;
085        if (userName != null && !userName.isEmpty()) {
086            z = getByUserName(userName);
087            if (z != null) {
088                throw new NamedBean.BadUserNameException("Transit UserName \""+userName+"\" Already Exists.", // NOI18N
089                Bundle.getMessage("InvalidUserNameAlreadyExists",getBeanTypeHandled(false),sysName));
090            }
091        }
092        z = getBySystemName(sysName);
093        if (z != null) {
094            throw new NamedBean.DuplicateSystemNameException("Transit SytemName \""+sysName+"\" Already Exists.", // NOI18N
095                Bundle.getMessage("InvalidSytemNameAlreadyExists",getBeanTypeHandled(false),sysName));
096        }
097        // Transit does not exist, create a new Transit
098        z = new jmri.implementation.DefaultTransit(sysName, userName);
099        // save in the maps
100        register(z);
101
102        // Keep track of the last created auto system name
103        updateAutoNumber(systemName);
104
105        return z;
106    }
107
108    /**
109     * For use with User GUI, to allow the auto generation of systemNames, where
110     * the user can optionally supply a username.
111     * <p>
112     * Note: Since system names should be kept short for use in Dispatcher,
113     * automatically generated system names are in the form {@code IZnn}, where
114     * {@code nn} is the first available number.
115     *
116     * @param userName the desired user name
117     * @return a new Transit
118     * @throws NamedBean.BadNameException if userName is already associated with
119     *         another Transit
120     */
121    @Override
122    @Nonnull
123    public Transit createNewTransit(String userName) throws NamedBean.BadNameException {
124        return createNewTransit(getAutoSystemName(), userName);
125    }
126
127    /**
128     * Get an existing Transit.
129     * First looks up assuming that name is a User
130     * Name. If this fails looks up assuming that name is a System Name.
131     * If both fail, returns null.
132     *
133     * @param name User name or system name to match
134     * @return null if no match found
135     */
136    @Override
137    @CheckForNull
138    public Transit getTransit(String name) {
139        Transit z = getByUserName(name);
140        return (z != null ? z : getBySystemName(name));
141    }
142
143    /**
144     * Remove an existing Transit.
145     *
146     * @param z the transit to remove
147     */
148    @Override
149    public void deleteTransit(Transit z) {
150        // delete the Transit
151        deregister(z);
152        z.dispose();
153    }
154
155    /**
156     * Get a list of Transits which use a specified Section.
157     *
158     * @param s the section to check Transits against
159     * @return a list, possibly empty, of Transits using section s.
160     */
161    @Override
162    @Nonnull
163    public ArrayList<Transit> getListUsingSection(Section s) {
164        ArrayList<Transit> list = new ArrayList<>();
165        for (Transit tTransit : getNamedBeanSet()) {
166            if (tTransit.containsSection(s)) {
167                // this Transit uses the specified Section
168                list.add(tTransit);
169            }
170        }
171        return list;
172    }
173
174    @Override
175    @Nonnull
176    public ArrayList<Transit> getListUsingBlock(Block b) {
177        ArrayList<Transit> list = new ArrayList<>();
178        for (Transit tTransit : getNamedBeanSet()) {
179            if (tTransit.containsBlock(b)) {
180                // this Transit uses the specified Section
181                list.add(tTransit);
182            }
183        }
184        return list;
185    }
186
187    @Override
188    @Nonnull
189    public ArrayList<Transit> getListEntryBlock(Block b) {
190        ArrayList<Transit> list = new ArrayList<>();
191        for (Transit tTransit : getNamedBeanSet()) {
192            ArrayList<Block> entryBlock = tTransit.getEntryBlocksList();
193            if (entryBlock.contains(b)) {
194                // this Transit uses the specified Section
195                list.add(tTransit);
196            }
197        }
198        return list;
199    }
200
201    @Override
202    @Nonnull
203    public String getBeanTypeHandled(boolean plural) {
204        return Bundle.getMessage(plural ? "BeanNameTransits" : "BeanNameTransit");
205    }
206
207    /**
208     * {@inheritDoc}
209     */
210    @Override
211    public Class<Transit> getNamedBeanClass() {
212        return Transit.class;
213    }
214
215    @Override
216    public void dispose() {
217        InstanceManager.getDefault(SectionManager.class).removeVetoableChangeListener(this);
218        super.dispose();
219    }
220
221    // private final static org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(DefaultTransitManager.class);
222
223}