001package jmri.jmrit.operations.locations.divisions;
002
003import java.util.*;
004
005import javax.swing.JComboBox;
006
007import org.jdom2.Element;
008import org.slf4j.Logger;
009import org.slf4j.LoggerFactory;
010
011import jmri.*;
012import jmri.beans.PropertyChangeSupport;
013import jmri.jmrit.operations.OperationsPanel;
014import jmri.jmrit.operations.locations.LocationManagerXml;
015import jmri.jmrit.operations.trains.TrainManifestHeaderText;
016
017/**
018 * Manages divisions.
019 *
020 * @author Bob Jacobsen Copyright (C) 2003
021 * @author Daniel Boudreau Copyright (C) 2021
022 */
023public class DivisionManager extends PropertyChangeSupport implements InstanceManagerAutoDefault, InstanceManagerAutoInitialize {
024
025    public static final String LISTLENGTH_CHANGED_PROPERTY = "divisionsListLength"; // NOI18N
026
027    public DivisionManager() {
028    }
029
030    private int _id = 0;
031
032    public void dispose() {
033        _divisionHashTable.clear();
034        _id = 0;
035    }
036
037    protected Hashtable<String, Division> _divisionHashTable = new Hashtable<String, Division>();
038
039    /**
040     * @return Number of divisions
041     */
042    public int getNumberOfdivisions() {
043        return _divisionHashTable.size();
044    }
045
046    /**
047     * @param name The string name of the Division to get.
048     * @return requested Division object or null if none exists
049     */
050    public Division getDivisionByName(String name) {
051        Division Division;
052        Enumeration<Division> en = _divisionHashTable.elements();
053        while (en.hasMoreElements()) {
054            Division = en.nextElement();
055            if (Division.getName().equals(name)) {
056                return Division;
057            }
058        }
059        return null;
060    }
061
062    public Division getDivisionById(String id) {
063        return _divisionHashTable.get(id);
064    }
065
066    /**
067     * Finds an existing Division or creates a new Division if needed requires
068     * Division's name creates a unique id for this Division
069     *
070     * @param name The string name for a new Division.
071     *
072     *
073     * @return new Division or existing Division
074     */
075    public Division newDivision(String name) {
076        Division division = getDivisionByName(name);
077        if (division == null) {
078            _id++;
079            division = new Division(Integer.toString(_id), name);
080            Integer oldSize = Integer.valueOf(_divisionHashTable.size());
081            _divisionHashTable.put(division.getId(), division);
082            setDirtyAndFirePropertyChange(LISTLENGTH_CHANGED_PROPERTY, oldSize,
083                    Integer.valueOf(_divisionHashTable.size()));
084        }
085        return division;
086    }
087
088    /**
089     * Remember a NamedBean Object created outside the manager.
090     *
091     * @param division The Division to add.
092     */
093    public void register(Division division) {
094        Integer oldSize = Integer.valueOf(_divisionHashTable.size());
095        _divisionHashTable.put(division.getId(), division);
096        // find last id created
097        int id = Integer.parseInt(division.getId());
098        if (id > _id) {
099            _id = id;
100        }
101        setDirtyAndFirePropertyChange(LISTLENGTH_CHANGED_PROPERTY, oldSize, Integer.valueOf(_divisionHashTable.size()));
102    }
103
104    /**
105     * Forget a NamedBean Object created outside the manager.
106     *
107     * @param division The Division to delete.
108     */
109    public void deregister(Division division) {
110        if (division == null) {
111            return;
112        }
113        Integer oldSize = Integer.valueOf(_divisionHashTable.size());
114        _divisionHashTable.remove(division.getId());
115        setDirtyAndFirePropertyChange(LISTLENGTH_CHANGED_PROPERTY, oldSize, Integer.valueOf(_divisionHashTable.size()));
116    }
117
118    /**
119     * Sort by Division name
120     *
121     * @return list of divisions ordered by name
122     */
123    public List<Division> getDivisionsByNameList() {
124        // first get id list
125        List<Division> sortList = getList();
126        // now re-sort
127        List<Division> out = new ArrayList<Division>();
128        for (Division division : sortList) {
129            for (int j = 0; j < out.size(); j++) {
130                if (division.getName().compareToIgnoreCase(out.get(j).getName()) < 0) {
131                    out.add(j, division);
132                    break;
133                }
134            }
135            if (!out.contains(division)) {
136                out.add(division);
137            }
138        }
139        return out;
140
141    }
142
143    /**
144     * Sort by Division id
145     *
146     * @return list of divisions ordered by id numbers
147     */
148    public List<Division> getDivisionsByIdList() {
149        List<Division> sortList = getList();
150        // now re-sort
151        List<Division> out = new ArrayList<Division>();
152        for (Division Division : sortList) {
153            for (int j = 0; j < out.size(); j++) {
154                try {
155                    if (Integer.parseInt(Division.getId()) < Integer.parseInt(out.get(j).getId())) {
156                        out.add(j, Division);
157                        break;
158                    }
159                } catch (NumberFormatException e) {
160                    log.debug("list id number isn't a number");
161                }
162            }
163            if (!out.contains(Division)) {
164                out.add(Division);
165            }
166        }
167        return out;
168    }
169
170    /**
171     * Gets an unsorted list of all divisions.
172     *
173     * @return All divisions.
174     */
175    public List<Division> getList() {
176        List<Division> out = new ArrayList<Division>();
177        Enumeration<Division> en = _divisionHashTable.elements();
178        while (en.hasMoreElements()) {
179            out.add(en.nextElement());
180        }
181        return out;
182    }
183
184    /**
185     *
186     * @return ComboBox with divisions for this railroad
187     */
188    public JComboBox<Division> getComboBox() {
189        JComboBox<Division> box = new JComboBox<>();
190        updateComboBox(box);
191        OperationsPanel.padComboBox(box);
192        return box;
193    }
194
195    public void updateComboBox(JComboBox<Division> box) {
196        box.removeAllItems();
197        box.addItem(null);
198        for (Division division : getDivisionsByNameList()) {
199            box.addItem(division);
200        }
201    }
202    
203    protected int _maxDivisionNameLength = 0;
204    
205    @edu.umd.cs.findbugs.annotations.SuppressFBWarnings( value="SLF4J_FORMAT_SHOULD_BE_CONST",
206            justification="I18N of Info Message")
207    public int getMaxDivisionNameLength() {
208        String maxName = TrainManifestHeaderText.getStringHeader_Division();
209        for (Division div : getList()) {
210            if (div.getName().length() > maxName.length()) {
211                maxName = div.getName();
212            }
213        }
214        if (maxName.length() != _maxDivisionNameLength) {
215            log.info(Bundle.getMessage("InfoMaxDivisionName", maxName, maxName.length()));
216            _maxDivisionNameLength = maxName.length();
217        }
218        return _maxDivisionNameLength;
219    }
220
221    public void load(Element root) {
222        if (root.getChild(Xml.DIVISIONS) != null) {
223            List<Element> divisions = root.getChild(Xml.DIVISIONS).getChildren(Xml.DIVISION);
224            log.debug("readFile sees {} divisions", divisions.size());
225            for (Element division : divisions) {
226                register(new Division(division));
227            }
228        }
229    }
230
231    public void store(Element root) {
232        Element values;
233        root.addContent(values = new Element(Xml.DIVISIONS));
234        // add entries
235        List<Division> DivisionList = getDivisionsByNameList();
236        for (Division division : DivisionList) {
237            values.addContent(division.store());
238        }
239    }
240
241    protected void setDirtyAndFirePropertyChange(String p, Object old, Object n) {
242        // set dirty
243        InstanceManager.getDefault(LocationManagerXml.class).setDirty(true);
244        firePropertyChange(p, old, n);
245    }
246
247    private final static Logger log = LoggerFactory.getLogger(DivisionManager.class);
248
249    @Override
250    public void initialize() {
251        // do nothing
252    }
253}