001package jmri.jmrit.operations.rollingstock.engines;
002
003import java.beans.PropertyChangeEvent;
004import java.util.*;
005
006import javax.swing.JComboBox;
007
008import org.jdom2.Element;
009import org.slf4j.Logger;
010import org.slf4j.LoggerFactory;
011
012import jmri.*;
013import jmri.jmrit.operations.OperationsPanel;
014import jmri.jmrit.operations.rollingstock.RollingStock;
015import jmri.jmrit.operations.rollingstock.RollingStockManager;
016import jmri.jmrit.operations.setup.OperationsSetupXml;
017import jmri.jmrit.operations.trains.Train;
018import jmri.jmrit.operations.trains.TrainManifestHeaderText;
019
020/**
021 * Manages the engines.
022 *
023 * @author Daniel Boudreau Copyright (C) 2008
024 */
025public class EngineManager extends RollingStockManager<Engine>
026        implements InstanceManagerAutoDefault, InstanceManagerAutoInitialize {
027
028    public EngineManager() {
029    }
030
031    /**
032     * Finds an existing engine or creates a new engine if needed requires engine's
033     * road and number
034     *
035     * @param engineRoad   The engine's road initials
036     * @param engineNumber The engine's road number
037     *
038     * @return new engine or existing engine
039     */
040    @Override
041    public Engine newRS(String engineRoad, String engineNumber) {
042        Engine engine = getByRoadAndNumber(engineRoad, engineNumber);
043        if (engine == null) {
044            engine = new Engine(engineRoad, engineNumber);
045            register(engine);
046        }
047        return engine;
048    }
049
050    @Override
051    public void deregister(Engine engine) {
052        super.deregister(engine);
053        InstanceManager.getDefault(EngineManagerXml.class).setDirty(true);
054    }
055
056    /**
057     * Sort by engine model
058     *
059     * @return list of engines ordered by engine model
060     */
061    public List<Engine> getByModelList() {
062        return getByList(getByRoadNameList(), BY_MODEL);
063    }
064
065    /**
066     * Sort by engine consist
067     *
068     * @return list of engines ordered by engine consist
069     */
070    public List<Engine> getByConsistList() {
071        return getByList(getByRoadNameList(), BY_CONSIST);
072    }
073
074    public List<Engine> getByHpList() {
075        return getByList(getByModelList(), BY_HP);
076    }
077
078    // The special sort options for engines
079    private static final int BY_MODEL = 30;
080    private static final int BY_CONSIST = 31;
081    private static final int BY_HP = 32;
082
083    // add engine options to sort comparator
084    @Override
085    protected java.util.Comparator<Engine> getComparator(int attribute) {
086        switch (attribute) {
087            case BY_MODEL:
088                return (e1, e2) -> (e1.getModel().compareToIgnoreCase(e2.getModel()));
089            case BY_CONSIST:
090                return (e1, e2) -> (e1.getConsistName().compareToIgnoreCase(e2.getConsistName()));
091            case BY_HP:
092                return (e1, e2) -> (e1.getHpInteger() - e2.getHpInteger());
093            default:
094                return super.getComparator(attribute);
095        }
096    }
097
098    /**
099     * return a list available engines (no assigned train) engines are ordered least
100     * recently moved to most recently moved.
101     *
102     * @param train The Train requesting this list.
103     *
104     * @return Ordered list of engines not assigned to a train
105     */
106    public List<Engine> getAvailableTrainList(Train train) {
107        // now build list of available engines for this route
108        List<Engine> out = new ArrayList<>();
109        // get engines by moves list
110        for (RollingStock rs : getByMovesList()) {
111            Engine engine = (Engine) rs;
112            if (engine.getTrack() != null && (engine.getTrain() == null || engine.getTrain() == train)) {
113                out.add(engine);
114            }
115        }
116        return out;
117    }
118
119    /**
120     * Returns a list of locos sorted by blocking number for a train. This returns a
121     * list of consisted locos in the order that they were entered in.
122     *
123     * @param train The Train requesting this list.
124     * @return A list of sorted locos.
125     */
126    public List<Engine> getByTrainBlockingList(Train train) {
127        return getByList(super.getByTrainList(train), BY_BLOCKING);
128    }
129
130    /**
131     * Get a list of engine road names.
132     *
133     * @param model The string model name, can be NONE.
134     *
135     * @return List of engine road names.
136     */
137    public List<String> getEngineRoadNames(String model) {
138        List<String> names = new ArrayList<>();
139        Enumeration<String> en = _hashTable.keys();
140        while (en.hasMoreElements()) {
141            Engine engine = getById(en.nextElement());
142            if ((engine.getModel().equals(model) || model.equals(NONE)) && !names.contains(engine.getRoadName())) {
143                names.add(engine.getRoadName());
144            }
145        }
146        java.util.Collections.sort(names);
147        return names;
148    }
149
150    public void updateEngineRoadComboBox(String engineModel, JComboBox<String> roadEngineBox) {
151        roadEngineBox.removeAllItems();
152        roadEngineBox.addItem(NONE);
153        List<String> roads = getEngineRoadNames(engineModel);
154        for (String roadName : roads) {
155            roadEngineBox.addItem(roadName);
156        }
157        OperationsPanel.padComboBox(roadEngineBox);
158    }
159
160    int _commentLength = 0;
161
162    @edu.umd.cs.findbugs.annotations.SuppressFBWarnings( value="SLF4J_FORMAT_SHOULD_BE_CONST",
163            justification="I18N of Info Message")
164    public int getMaxCommentLength() {
165        if (_commentLength == 0) {
166            _commentLength = TrainManifestHeaderText.getStringHeader_Comment().length();
167            String comment = "";
168            Engine engineMax = null;
169            for (Engine engine : getList()) {
170                if (engine.getComment().length() > _commentLength) {
171                    _commentLength = engine.getComment().length();
172                    comment = engine.getComment();
173                    engineMax = engine;
174                }
175            }
176            if (engineMax != null) {
177                log.info(Bundle.getMessage("InfoMaxComment", engineMax.toString(), comment, _commentLength));
178            }
179        }
180        return _commentLength;
181    }
182
183    public void load(Element root) {
184        if (root.getChild(Xml.ENGINES) != null) {
185            List<Element> engines = root.getChild(Xml.ENGINES).getChildren(Xml.ENGINE);
186            log.debug("readFile sees {} engines", engines.size());
187            for (Element e : engines) {
188                register(new Engine(e));
189            }
190        }
191    }
192
193    /**
194     * Create an XML element to represent this Entry. This member has to remain
195     * synchronized with the detailed DTD in operations-engines.dtd.
196     *
197     * @param root The common Element for operations-engines.dtd.
198     *
199     */
200    public void store(Element root) {
201        Element values;
202        root.addContent(values = new Element(Xml.ENGINES));
203        // add entries
204        for (RollingStock rs : getByRoadNameList()) {
205            Engine eng = (Engine) rs;
206            values.addContent(eng.store());
207        }
208    }
209
210    protected void setDirtyAndFirePropertyChange(String p, Object old, Object n) {
211        // Set dirty
212        InstanceManager.getDefault(EngineManagerXml.class).setDirty(true);
213        super.firePropertyChange(p, old, n);
214    }
215
216    @Override
217    public void propertyChange(PropertyChangeEvent evt) {
218        if (evt.getPropertyName().equals(Engine.COMMENT_CHANGED_PROPERTY)) {
219            _commentLength = 0;
220        }
221        super.propertyChange(evt);
222    }
223
224    private final static Logger log = LoggerFactory.getLogger(EngineManager.class);
225
226    @Override
227    public void initialize() {
228        InstanceManager.getDefault(OperationsSetupXml.class); // load setup
229        // create manager to load engines and their attributes
230        InstanceManager.getDefault(EngineManagerXml.class);
231    }
232}