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