001package jmri.jmrit.operations.rollingstock.engines; 002 003import java.beans.PropertyChangeEvent; 004import java.time.LocalDateTime; 005import java.util.*; 006 007import javax.swing.JComboBox; 008 009import jmri.*; 010import jmri.jmrit.operations.OperationsPanel; 011import jmri.jmrit.operations.locations.Track; 012import jmri.jmrit.operations.rollingstock.RollingStock; 013import jmri.jmrit.operations.rollingstock.RollingStockManager; 014import jmri.jmrit.operations.setup.OperationsSetupXml; 015import jmri.jmrit.operations.trains.Train; 016import jmri.jmrit.operations.trains.TrainManifestHeaderText; 017 018import org.jdom2.Element; 019import org.slf4j.Logger; 020import org.slf4j.LoggerFactory; 021 022/** 023 * Manages the engines. 024 * 025 * @author Daniel Boudreau Copyright (C) 2008 026 */ 027public class EngineManager extends RollingStockManager<Engine> implements InstanceManagerAutoDefault, InstanceManagerAutoInitialize { 028 029 public EngineManager() { 030 } 031 032 /** 033 * Finds an existing engine or creates a new engine if needed requires 034 * engine's road and number 035 * 036 * @param engineRoad The engine's road initials 037 * @param engineNumber The engine's road number 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 * Returns a list of available engines (no assigned train). Engines are 100 * ordered by track priority and least recently moved to most recently 101 * moved. 102 * 103 * @param train The Train requesting this list. 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 track priority and moves 110 List<Engine> sortByPriority = sortByTrackPriority(getByMovesList()); 111 for (Engine engine : sortByPriority) { 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 121 * returns a 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 * @return List of engine road names. 135 */ 136 public List<String> getEngineRoadNames(String model) { 137 List<String> names = new ArrayList<>(); 138 Enumeration<String> en = _hashTable.keys(); 139 while (en.hasMoreElements()) { 140 Engine engine = getById(en.nextElement()); 141 if ((engine.getModel().equals(model) || model.equals(NONE)) && !names.contains(engine.getRoadName())) { 142 names.add(engine.getRoadName()); 143 } 144 } 145 java.util.Collections.sort(names); 146 return names; 147 } 148 149 public void updateEngineRoadComboBox(String engineModel, JComboBox<String> roadEngineBox) { 150 roadEngineBox.removeAllItems(); 151 roadEngineBox.addItem(NONE); 152 List<String> roads = getEngineRoadNames(engineModel); 153 for (String roadName : roads) { 154 roadEngineBox.addItem(roadName); 155 } 156 OperationsPanel.padComboBox(roadEngineBox); 157 } 158 159 int _commentLength = 0; 160 161 @edu.umd.cs.findbugs.annotations.SuppressFBWarnings(value = "SLF4J_FORMAT_SHOULD_BE_CONST", 162 justification = "I18N of Info Message") 163 public int getMaxCommentLength() { 164 if (_commentLength == 0) { 165 _commentLength = TrainManifestHeaderText.getStringHeader_Comment().length(); 166 String comment = ""; 167 Engine engineMax = null; 168 for (Engine engine : getList()) { 169 if (engine.getComment().length() > _commentLength) { 170 _commentLength = engine.getComment().length(); 171 comment = engine.getComment(); 172 engineMax = engine; 173 } 174 } 175 if (engineMax != null) { 176 log.info(Bundle.getMessage("InfoMaxComment", engineMax.toString(), comment, _commentLength)); 177 } 178 } 179 return _commentLength; 180 } 181 182 /** 183 * Creates a clone for the engine, and clones if the engine is part of a 184 * consist. Note that a engine have have multiple clones. 185 * 186 * @param engine The engine to clone 187 * @param track The destination track for the clones 188 * @param train The train transporting the clones 189 * @param startTime The date and time the clones were moved 190 * @return clone for this engine 191 */ 192 public Engine createClone(Engine engine, Track track, Train train, LocalDateTime startTime) { 193 Engine clone = createClone(engine); 194 createCloneConsist(engine, track, train, startTime, clone); 195 // move engine to new location for later pick up 196 finshCreateClone(engine, track, train, startTime, clone); 197 return clone; 198 } 199 200 private void createCloneConsist(Engine engine, Track track, Train train, LocalDateTime startTime, Engine cloneEng) { 201 if (engine.getConsist() != null) { 202 String consistName = engine.getConsistName() + Engine.CLONE + padNumber(engine.getCloneOrder()); 203 Consist consist = InstanceManager.getDefault(ConsistManager.class).newConsist(consistName); 204 cloneEng.setConsist(consist); 205 for (Engine e : engine.getConsist().getEngines()) { 206 if (e != engine) { 207 Engine nClone = createClone(e, engine.getCloneOrder()); 208 nClone.setConsist(consist); 209 // move engine to new location for later pick up 210 finshCreateClone(e, track, train, startTime, nClone); 211 } 212 } 213 } 214 } 215 216 public void load(Element root) { 217 if (root.getChild(Xml.ENGINES) != null) { 218 List<Element> engines = root.getChild(Xml.ENGINES).getChildren(Xml.ENGINE); 219 log.debug("readFile sees {} engines", engines.size()); 220 for (Element e : engines) { 221 register(new Engine(e)); 222 } 223 } 224 } 225 226 /** 227 * Create an XML element to represent this Entry. This member has to remain 228 * synchronized with the detailed DTD in operations-engines.dtd. 229 * 230 * @param root The common Element for operations-engines.dtd. 231 */ 232 public void store(Element root) { 233 Element values; 234 root.addContent(values = new Element(Xml.ENGINES)); 235 // add entries 236 for (RollingStock rs : getByRoadNameList()) { 237 Engine eng = (Engine) rs; 238 values.addContent(eng.store()); 239 } 240 } 241 242 protected void setDirtyAndFirePropertyChange(String p, Object old, Object n) { 243 // Set dirty 244 InstanceManager.getDefault(EngineManagerXml.class).setDirty(true); 245 super.firePropertyChange(p, old, n); 246 } 247 248 @Override 249 public void propertyChange(PropertyChangeEvent evt) { 250 if (evt.getPropertyName().equals(Engine.COMMENT_CHANGED_PROPERTY)) { 251 _commentLength = 0; 252 } 253 super.propertyChange(evt); 254 } 255 256 private static final Logger log = LoggerFactory.getLogger(EngineManager.class); 257 258 @Override 259 public void initialize() { 260 InstanceManager.getDefault(OperationsSetupXml.class); // load setup 261 // create manager to load engines and their attributes 262 InstanceManager.getDefault(EngineManagerXml.class); 263 } 264}