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.locations.LocationManagerXml;
014import jmri.jmrit.operations.trains.TrainManifestHeaderText;
015
016/**
017 * Manages divisions.
018 *
019 * @author Bob Jacobsen Copyright (C) 2003
020 * @author Daniel Boudreau Copyright (C) 2021
021 */
022public class DivisionManager extends PropertyChangeSupport implements InstanceManagerAutoDefault, InstanceManagerAutoInitialize {
023
024    public static final String LISTLENGTH_CHANGED_PROPERTY = "divisionsListLength"; // NOI18N
025
026    public DivisionManager() {
027    }
028
029    private int _id = 0;
030
031    public void dispose() {
032        _divisionHashTable.clear();
033        _id = 0;
034    }
035
036    protected Hashtable<String, Division> _divisionHashTable = new Hashtable<String, Division>();
037
038    /**
039     * @return Number of divisions
040     */
041    public int getNumberOfdivisions() {
042        return _divisionHashTable.size();
043    }
044
045    /**
046     * @param name The string name of the Division to get.
047     * @return requested Division object or null if none exists
048     */
049    public Division getDivisionByName(String name) {
050        Division Division;
051        Enumeration<Division> en = _divisionHashTable.elements();
052        while (en.hasMoreElements()) {
053            Division = en.nextElement();
054            if (Division.getName().equals(name)) {
055                return Division;
056            }
057        }
058        return null;
059    }
060
061    public Division getDivisionById(String id) {
062        return _divisionHashTable.get(id);
063    }
064
065    /**
066     * Finds an existing Division or creates a new Division if needed requires
067     * Division's name creates a unique id for this Division
068     *
069     * @param name The string name for a new Division.
070     *
071     *
072     * @return new Division or existing Division
073     */
074    public Division newDivision(String name) {
075        Division division = getDivisionByName(name);
076        if (division == null) {
077            _id++;
078            division = new Division(Integer.toString(_id), name);
079            Integer oldSize = Integer.valueOf(_divisionHashTable.size());
080            _divisionHashTable.put(division.getId(), division);
081            setDirtyAndFirePropertyChange(LISTLENGTH_CHANGED_PROPERTY, oldSize,
082                    Integer.valueOf(_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        Integer oldSize = Integer.valueOf(_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, Integer.valueOf(_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        Integer oldSize = Integer.valueOf(_divisionHashTable.size());
113        _divisionHashTable.remove(division.getId());
114        setDirtyAndFirePropertyChange(LISTLENGTH_CHANGED_PROPERTY, oldSize, Integer.valueOf(_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        return box;
191    }
192
193    public void updateComboBox(JComboBox<Division> box) {
194        box.removeAllItems();
195        box.addItem(null);
196        for (Division division : getDivisionsByNameList()) {
197            box.addItem(division);
198        }
199    }
200    
201    protected int _maxDivisionNameLength = 0;
202    
203    @edu.umd.cs.findbugs.annotations.SuppressFBWarnings( value="SLF4J_FORMAT_SHOULD_BE_CONST",
204            justification="I18N of Info Message")
205    public int getMaxDivisionNameLength() {
206        String maxName = TrainManifestHeaderText.getStringHeader_Division();
207        for (Division div : getList()) {
208            if (div.getName().length() > maxName.length()) {
209                maxName = div.getName();
210            }
211        }
212        if (maxName.length() != _maxDivisionNameLength) {
213            log.info(Bundle.getMessage("InfoMaxDivisionName", maxName, maxName.length()));
214            _maxDivisionNameLength = maxName.length();
215        }
216        return _maxDivisionNameLength;
217    }
218
219    public void load(Element root) {
220        if (root.getChild(Xml.DIVISIONS) != null) {
221            List<Element> divisions = root.getChild(Xml.DIVISIONS).getChildren(Xml.DIVISION);
222            log.debug("readFile sees {} divisions", divisions.size());
223            for (Element division : divisions) {
224                register(new Division(division));
225            }
226        }
227    }
228
229    public void store(Element root) {
230        Element values;
231        root.addContent(values = new Element(Xml.DIVISIONS));
232        // add entries
233        List<Division> DivisionList = getDivisionsByNameList();
234        for (Division division : DivisionList) {
235            values.addContent(division.store());
236        }
237    }
238
239    protected void setDirtyAndFirePropertyChange(String p, Object old, Object n) {
240        // set dirty
241        InstanceManager.getDefault(LocationManagerXml.class).setDirty(true);
242        firePropertyChange(p, old, n);
243    }
244
245    private final static Logger log = LoggerFactory.getLogger(DivisionManager.class);
246
247    @Override
248    public void initialize() {
249        // do nothing
250    }
251}