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            int oldSize = _divisionHashTable.size();
081            _divisionHashTable.put(division.getId(), division);
082            setDirtyAndFirePropertyChange(LISTLENGTH_CHANGED_PROPERTY, oldSize, _divisionHashTable.size());
083        }
084        return division;
085    }
086
087    /**
088     * Remember a NamedBean Object created outside the manager.
089     *
090     * @param division The Division to add.
091     */
092    public void register(Division division) {
093        int oldSize = _divisionHashTable.size();
094        _divisionHashTable.put(division.getId(), division);
095        // find last id created
096        int id = Integer.parseInt(division.getId());
097        if (id > _id) {
098            _id = id;
099        }
100        setDirtyAndFirePropertyChange(LISTLENGTH_CHANGED_PROPERTY, oldSize, _divisionHashTable.size());
101    }
102
103    /**
104     * Forget a NamedBean Object created outside the manager.
105     *
106     * @param division The Division to delete.
107     */
108    public void deregister(Division division) {
109        if (division == null) {
110            return;
111        }
112        int oldSize = _divisionHashTable.size();
113        _divisionHashTable.remove(division.getId());
114        setDirtyAndFirePropertyChange(LISTLENGTH_CHANGED_PROPERTY, oldSize, _divisionHashTable.size());
115    }
116
117    /**
118     * Sort by Division name
119     *
120     * @return list of divisions ordered by name
121     */
122    public List<Division> getDivisionsByNameList() {
123        // first get id list
124        List<Division> sortList = getList();
125        // now re-sort
126        List<Division> out = new ArrayList<Division>();
127        for (Division division : sortList) {
128            for (int j = 0; j < out.size(); j++) {
129                if (division.getName().compareToIgnoreCase(out.get(j).getName()) < 0) {
130                    out.add(j, division);
131                    break;
132                }
133            }
134            if (!out.contains(division)) {
135                out.add(division);
136            }
137        }
138        return out;
139
140    }
141
142    /**
143     * Sort by Division id
144     *
145     * @return list of divisions ordered by id numbers
146     */
147    public List<Division> getDivisionsByIdList() {
148        List<Division> sortList = getList();
149        // now re-sort
150        List<Division> out = new ArrayList<Division>();
151        for (Division Division : sortList) {
152            for (int j = 0; j < out.size(); j++) {
153                try {
154                    if (Integer.parseInt(Division.getId()) < Integer.parseInt(out.get(j).getId())) {
155                        out.add(j, Division);
156                        break;
157                    }
158                } catch (NumberFormatException e) {
159                    log.debug("list id number isn't a number");
160                }
161            }
162            if (!out.contains(Division)) {
163                out.add(Division);
164            }
165        }
166        return out;
167    }
168
169    /**
170     * Gets an unsorted list of all divisions.
171     *
172     * @return All divisions.
173     */
174    public List<Division> getList() {
175        List<Division> out = new ArrayList<Division>();
176        Enumeration<Division> en = _divisionHashTable.elements();
177        while (en.hasMoreElements()) {
178            out.add(en.nextElement());
179        }
180        return out;
181    }
182
183    /**
184     *
185     * @return ComboBox with divisions for this railroad
186     */
187    public JComboBox<Division> getComboBox() {
188        JComboBox<Division> box = new JComboBox<>();
189        updateComboBox(box);
190        OperationsPanel.padComboBox(box);
191        return box;
192    }
193
194    public void updateComboBox(JComboBox<Division> box) {
195        box.removeAllItems();
196        box.addItem(null);
197        for (Division division : getDivisionsByNameList()) {
198            box.addItem(division);
199        }
200    }
201    
202    protected int _maxDivisionNameLength = 0;
203    
204    @edu.umd.cs.findbugs.annotations.SuppressFBWarnings( value="SLF4J_FORMAT_SHOULD_BE_CONST",
205            justification="I18N of Info Message")
206    public int getMaxDivisionNameLength() {
207        String maxName = TrainManifestHeaderText.getStringHeader_Division();
208        for (Division div : getList()) {
209            if (div.getName().length() > maxName.length()) {
210                maxName = div.getName();
211            }
212        }
213        if (maxName.length() != _maxDivisionNameLength) {
214            log.info(Bundle.getMessage("InfoMaxDivisionName", maxName, maxName.length()));
215            _maxDivisionNameLength = maxName.length();
216        }
217        return _maxDivisionNameLength;
218    }
219
220    public void load(Element root) {
221        if (root.getChild(Xml.DIVISIONS) != null) {
222            List<Element> divisions = root.getChild(Xml.DIVISIONS).getChildren(Xml.DIVISION);
223            log.debug("readFile sees {} divisions", divisions.size());
224            for (Element division : divisions) {
225                register(new Division(division));
226            }
227        }
228    }
229
230    public void store(Element root) {
231        Element values;
232        root.addContent(values = new Element(Xml.DIVISIONS));
233        // add entries
234        List<Division> DivisionList = getDivisionsByNameList();
235        for (Division division : DivisionList) {
236            values.addContent(division.store());
237        }
238    }
239
240    protected void setDirtyAndFirePropertyChange(String p, Object old, Object n) {
241        // set dirty
242        InstanceManager.getDefault(LocationManagerXml.class).setDirty(true);
243        firePropertyChange(p, old, n);
244    }
245
246    private static final Logger log = LoggerFactory.getLogger(DivisionManager.class);
247
248    @Override
249    public void initialize() {
250        // do nothing
251    }
252}