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.setup.Control;
016import jmri.jmrit.operations.trains.TrainManifestHeaderText;
017
018/**
019 * Manages divisions.
020 *
021 * @author Bob Jacobsen Copyright (C) 2003
022 * @author Daniel Boudreau Copyright (C) 2021
023 */
024public class DivisionManager extends PropertyChangeSupport implements InstanceManagerAutoDefault, InstanceManagerAutoInitialize {
025
026    public static final String LISTLENGTH_CHANGED_PROPERTY = "divisionsListLength"; // NOI18N
027
028    public DivisionManager() {
029    }
030
031    private int _id = 0;
032
033    public void dispose() {
034        _divisionHashTable.clear();
035        _id = 0;
036    }
037
038    protected Hashtable<String, Division> _divisionHashTable = new Hashtable<String, Division>();
039
040    /**
041     * @return Number of divisions
042     */
043    public int getNumberOfdivisions() {
044        return _divisionHashTable.size();
045    }
046
047    /**
048     * @param name The string name of the Division to get.
049     * @return requested Division object or null if none exists
050     */
051    public Division getDivisionByName(String name) {
052        Division Division;
053        Enumeration<Division> en = _divisionHashTable.elements();
054        while (en.hasMoreElements()) {
055            Division = en.nextElement();
056            if (Division.getName().equals(name)) {
057                return Division;
058            }
059        }
060        return null;
061    }
062
063    public Division getDivisionById(String id) {
064        return _divisionHashTable.get(id);
065    }
066
067    /**
068     * Finds an existing Division or creates a new Division if needed requires
069     * Division's name creates a unique id for this Division
070     *
071     * @param name The string name for a new Division.
072     *
073     *
074     * @return new Division or existing Division
075     */
076    public Division newDivision(String name) {
077        Division division = getDivisionByName(name);
078        if (division == null) {
079            _id++;
080            division = new Division(Integer.toString(_id), name);
081            int oldSize = _divisionHashTable.size();
082            _divisionHashTable.put(division.getId(), division);
083            setDirtyAndFirePropertyChange(LISTLENGTH_CHANGED_PROPERTY, oldSize, _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        int oldSize = _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, _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        int oldSize = _divisionHashTable.size();
114        _divisionHashTable.remove(division.getId());
115        setDirtyAndFirePropertyChange(LISTLENGTH_CHANGED_PROPERTY, oldSize, _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, Control.max_len_string_location_name);
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 static final Logger log = LoggerFactory.getLogger(DivisionManager.class);
248
249    @Override
250    public void initialize() {
251        // do nothing
252    }
253}