001package jmri.jmrit.operations.rollingstock.engines.tools; 002 003import java.io.*; 004 005import jmri.InstanceManager; 006import jmri.jmrit.operations.locations.*; 007import jmri.jmrit.operations.rollingstock.ImportRollingStock; 008import jmri.jmrit.operations.rollingstock.RollingStock; 009import jmri.jmrit.operations.rollingstock.engines.*; 010import jmri.jmrit.operations.setup.Control; 011import jmri.jmrit.operations.trains.TrainCommon; 012import jmri.util.swing.JmriJOptionPane; 013 014/** 015 * This routine will import engines into the operation database. Each field is 016 * space or comma delimited. Field order: Number Road Model Length Owner Built 017 * Location - Track Consist HP WeightTons Type 018 * 019 * @author Dan Boudreau Copyright (C) 2008, 2013 020 */ 021public class ImportEngines extends ImportRollingStock { 022 023 private static final String DEFAULT_ENGINE_TYPE = Bundle.getMessage("engineDefaultType"); 024 private static final String DEFAULT_ENGINE_HP = Bundle.getMessage("engineDefaultHp"); 025 026 private static final int ENG_NUMBER = 0; 027 private static final int ENG_ROAD = 1; 028 private static final int ENG_MODEL = 2; 029 private static final int ENG_LENGTH = 3; 030 031 private static final int ENG_OWNER = 4; 032 private static final int ENG_BUILT = 5; 033 private static final int ENG_LOCATION = 6; 034 private static final int ENG_LOCATION_TRACK_SEPARATOR = 7; 035 private static final int ENG_TRACK = 8; 036 037 // only for CSV files 038 private static final int ENG_CONSIST = 9; 039 // private static final int ENG_MOVES = 10; 040 // private static final int ENG_VALUE = 12; 041 private static final int ENG_HP = 13; 042 private static final int ENG_WEIGHT = 14; 043 private static final int ENG_TYPE = 15; 044 // private static final int ENG_COMMENT = 16; 045 // private static final int ENG_MISCELLANEOUS = 17; 046 047 // as of 7/23/2018 there were 18 attributes exported by operations 048 049 EngineManager engineManager = InstanceManager.getDefault(EngineManager.class); 050 051 // we use a thread so the status frame will work! 052 @Override 053 public void run() { 054 File file = getFile(); 055 if (file == null) { 056 return; 057 } 058 BufferedReader in = getBufferedReader(file); 059 if (in == null) { 060 return; 061 } 062 063 createStatusFrame(Bundle.getMessage("ImportEngines")); 064 065 // Now read the input file 066 boolean importOkay = false; 067 boolean comma = false; 068 int lineNum = 0; 069 int enginesAdded = 0; 070 String line = " "; 071 String engineNumber; 072 String engineRoad; 073 String engineModel; 074 String engineLength; 075 String engineOwner = ""; 076 String engineBuilt = ""; 077 String engineLocationName = ""; 078 String engineTrackName = ""; 079 String engineConsistName = ""; 080 String engineHp = ""; 081 String engineWeightTons = ""; 082 String engineType = ""; 083 String[] inputLine; 084 085 // does the file name end with .csv? 086 if (file.getAbsolutePath().endsWith(".csv")) { // NOI18N 087 log.info("Using comma as delimiter for import engines"); 088 comma = true; 089 } 090 091 while (true) { 092 lineNumber.setText(Bundle.getMessage("LineNumber") + " " + Integer.toString(++lineNum)); 093 try { 094 line = in.readLine(); 095 } catch (IOException e) { 096 break; 097 } 098 099 if (line == null) { 100 importOkay = true; 101 break; 102 } 103 104 // has user canceled import? 105 if (!fstatus.isShowing()) { 106 break; 107 } 108 109 line = line.trim(); 110 log.debug("Import: {}", line); 111 importLine.setText(line); 112 113 if (line.startsWith(Bundle.getMessage("Number"))) { 114 continue; // skip header 115 } 116 if (line.equalsIgnoreCase("comma")) { // NOI18N 117 log.info("Using comma as delimiter for import engines"); 118 comma = true; 119 continue; 120 } 121 // use comma as delimiter if found otherwise use spaces 122 if (comma) { 123 inputLine = parseCommaLine(line); 124 } else { 125 inputLine = line.split("\\s+"); // NOI18N 126 } 127 if (inputLine.length < 1 || line.isEmpty()) { 128 log.debug("Skipping blank line"); 129 continue; 130 } 131 int base = 1; 132 if (comma || !inputLine[0].isEmpty()) { 133 base--; // skip over any spaces at start of line 134 } 135 136 if (inputLine.length > base + 3) { 137 engineNumber = inputLine[base + ENG_NUMBER].trim(); 138 engineRoad = inputLine[base + ENG_ROAD].trim(); 139 engineModel = inputLine[base + ENG_MODEL].trim(); 140 engineLength = inputLine[base + ENG_LENGTH].trim(); 141 engineOwner = ""; 142 engineBuilt = ""; 143 engineLocationName = ""; 144 engineTrackName = ""; 145 engineConsistName = ""; 146 engineHp = ""; 147 engineWeightTons = ""; 148 engineType = ""; 149 150 log.debug("Checking engine number ({}) road ({}) model ({}) length ({})", engineNumber, engineRoad, 151 engineModel, engineLength); // NOI18N 152 if (engineNumber.isEmpty()) { 153 log.info("Import line {} missing engine number", lineNum); 154 JmriJOptionPane.showMessageDialog(null, 155 Bundle.getMessage("RoadNumberNotSpecified", lineNum), 156 Bundle.getMessage("RoadNumberMissing"), JmriJOptionPane.ERROR_MESSAGE); 157 break; 158 } 159 if (engineRoad.isEmpty()) { 160 log.info("Import line {} missing engine road", lineNum); 161 JmriJOptionPane.showMessageDialog(null, 162 Bundle.getMessage("RoadNameNotSpecified", lineNum), 163 Bundle.getMessage("RoadNameMissing"), JmriJOptionPane.ERROR_MESSAGE); 164 break; 165 } 166 if (engineModel.isEmpty()) { 167 log.info("Import line {} missing engine model", lineNum); 168 JmriJOptionPane.showMessageDialog(null, 169 Bundle.getMessage("EngineModelNotSpecified", lineNum), 170 Bundle.getMessage("EngineModelMissing"), JmriJOptionPane.ERROR_MESSAGE); 171 break; 172 } 173 if (engineLength.isEmpty()) { 174 log.info("Import line {} missing engine length", lineNum); 175 JmriJOptionPane.showMessageDialog(null, 176 Bundle.getMessage("EngineLengthNotSpecified", lineNum), 177 Bundle.getMessage("EngineLengthMissing"), JmriJOptionPane.ERROR_MESSAGE); 178 break; 179 } 180 if (TrainCommon.splitString(engineNumber).length() > Control.max_len_string_road_number) { 181 JmriJOptionPane.showMessageDialog( 182 null, Bundle.getMessage("EngineRoadNumberTooLong", 183 engineRoad, engineNumber, engineNumber), 184 Bundle.getMessage("RoadNumMustBeLess"), JmriJOptionPane.ERROR_MESSAGE); 185 break; 186 } 187 if (engineRoad.length() > Control.max_len_string_attibute) { 188 JmriJOptionPane.showMessageDialog(null, 189 Bundle.getMessage("EngineRoadNameTooLong", 190 engineRoad, engineNumber, engineRoad), 191 Bundle.getMessage("engineAttribute", 192 Control.max_len_string_attibute), 193 JmriJOptionPane.ERROR_MESSAGE); 194 break; 195 } 196 if (engineModel.length() > Control.max_len_string_attibute) { 197 JmriJOptionPane.showMessageDialog( 198 null, Bundle.getMessage("EngineModelNameTooLong", 199 engineRoad, engineNumber, engineModel), 200 Bundle.getMessage("engineAttribute", 201 Control.max_len_string_attibute), 202 JmriJOptionPane.ERROR_MESSAGE); 203 break; 204 } 205 if (!InstanceManager.getDefault(EngineModels.class).containsName(engineModel)) { 206 int results = JmriJOptionPane.showConfirmDialog(null, Bundle.getMessage("Engine") + 207 " (" + 208 engineRoad + 209 " " + 210 engineNumber + 211 ")" + 212 NEW_LINE + 213 Bundle.getMessage("modelNameNotExist", engineModel), 214 Bundle.getMessage("engineAddModel"), JmriJOptionPane.YES_NO_CANCEL_OPTION); 215 if (results == JmriJOptionPane.YES_OPTION) { 216 InstanceManager.getDefault(EngineModels.class).addName(engineModel); 217 } else if (results == JmriJOptionPane.CANCEL_OPTION ) { 218 break; 219 } 220 } 221 if (engineLength.length() > Control.max_len_string_length_name) { 222 JmriJOptionPane.showMessageDialog( 223 null, Bundle.getMessage("EngineLengthNameTooLong", 224 engineRoad, engineNumber, engineLength), 225 Bundle.getMessage("engineAttribute", 226 Control.max_len_string_length_name), 227 JmriJOptionPane.ERROR_MESSAGE); 228 break; 229 } 230 try { 231 Integer.parseInt(engineLength); 232 } catch (NumberFormatException e) { 233 JmriJOptionPane.showMessageDialog( 234 null, Bundle.getMessage("EngineLengthNameNotNumber", 235 engineRoad, engineNumber, engineLength), 236 Bundle.getMessage("EngineLengthMissing"), JmriJOptionPane.ERROR_MESSAGE); 237 break; 238 } 239 Engine e = engineManager.getByRoadAndNumber(engineRoad, engineNumber); 240 if (e != null) { 241 log.info("Can not add engine number ({}) road ({}) it already exists!", engineNumber, engineRoad); // NOI18N 242 continue; 243 } 244 245 if (inputLine.length > base + ENG_OWNER) { 246 engineOwner = inputLine[base + ENG_OWNER].trim(); 247 if (engineOwner.length() > Control.max_len_string_attibute) { 248 JmriJOptionPane.showMessageDialog(null, 249 Bundle.getMessage("EngineOwnerNameTooLong", 250 engineRoad, engineNumber, engineOwner), 251 Bundle.getMessage("engineAttribute", 252 Control.max_len_string_attibute), 253 JmriJOptionPane.ERROR_MESSAGE); 254 break; 255 } 256 } 257 if (inputLine.length > base + ENG_BUILT) { 258 engineBuilt = inputLine[base + ENG_BUILT].trim(); 259 if (engineBuilt.length() > Control.max_len_string_built_name) { 260 JmriJOptionPane.showMessageDialog(null, 261 Bundle.getMessage("EngineBuiltDateTooLong", 262 engineRoad, engineNumber, engineBuilt), 263 Bundle.getMessage("engineAttribute", 264 Control.max_len_string_built_name), 265 JmriJOptionPane.ERROR_MESSAGE); 266 break; 267 } 268 } 269 if (inputLine.length > base + ENG_LOCATION) { 270 engineLocationName = inputLine[base + ENG_LOCATION].trim(); 271 } 272 if (comma && inputLine.length > base + ENG_TRACK) { 273 engineTrackName = inputLine[base + ENG_TRACK].trim(); 274 } 275 // Location and track name can be one or more words in a 276 // space delimited file 277 if (!comma) { 278 int j = 0; 279 StringBuffer name = new StringBuffer(engineLocationName); 280 for (int i = base + ENG_LOCATION_TRACK_SEPARATOR; i < inputLine.length; i++) { 281 if (inputLine[i].equals(LOCATION_TRACK_SEPARATOR)) { 282 j = i + 1; // skip over separator 283 break; 284 } else { 285 name.append(" " + inputLine[i]); 286 } 287 } 288 engineLocationName = name.toString(); 289 log.debug("Engine ({} {}) has location ({})", engineRoad, engineNumber, engineLocationName); 290 // now get the track name 291 name = new StringBuffer(); 292 if (j != 0 && j < inputLine.length) { 293 name.append(inputLine[j]); 294 for (int i = j + 1; i < inputLine.length; i++) { 295 name.append(" " + inputLine[i]); 296 } 297 log.debug("Engine ({} {}) has track ({})", engineRoad, engineNumber, engineTrackName); 298 } 299 engineTrackName = name.toString(); 300 } 301 302 if (engineLocationName.length() > Control.max_len_string_location_name) { 303 JmriJOptionPane.showMessageDialog(null, 304 Bundle.getMessage("EngineLocationNameTooLong", 305 engineRoad, engineNumber, engineLocationName), 306 Bundle.getMessage("engineAttribute", 307 Control.max_len_string_location_name), 308 JmriJOptionPane.ERROR_MESSAGE); 309 break; 310 } 311 if (engineTrackName.length() > Control.max_len_string_track_name) { 312 JmriJOptionPane.showMessageDialog(null, 313 Bundle.getMessage("EngineTrackNameTooLong", 314 engineRoad, engineNumber, engineTrackName), 315 Bundle.getMessage("engineAttribute", 316 Control.max_len_string_track_name), 317 JmriJOptionPane.ERROR_MESSAGE); 318 break; 319 } 320 Location location = 321 InstanceManager.getDefault(LocationManager.class).getLocationByName(engineLocationName); 322 Track track = null; 323 if (location == null && !engineLocationName.isEmpty()) { 324 JmriJOptionPane.showMessageDialog(null, 325 Bundle.getMessage("EngineLocationDoesNotExist", 326 engineRoad, engineNumber, engineLocationName), 327 Bundle.getMessage("engineLocation"), JmriJOptionPane.ERROR_MESSAGE); 328 int results = JmriJOptionPane.showConfirmDialog(null, 329 Bundle.getMessage("DoYouWantToCreateLoc", 330 engineLocationName), 331 Bundle.getMessage("engineLocation"), JmriJOptionPane.YES_NO_OPTION); 332 if (results == JmriJOptionPane.YES_OPTION) { 333 log.debug("Create location ({})", engineLocationName); 334 location = InstanceManager.getDefault(LocationManager.class).newLocation(engineLocationName); 335 } else { 336 break; 337 } 338 } 339 if (location != null && !engineTrackName.isEmpty()) { 340 track = location.getTrackByName(engineTrackName, null); 341 if (track == null) { 342 JmriJOptionPane.showMessageDialog( 343 null, Bundle.getMessage("EngineTrackDoesNotExist", 344 engineRoad, engineNumber, engineTrackName, 345 engineLocationName), 346 Bundle.getMessage("engineTrack"), JmriJOptionPane.ERROR_MESSAGE); 347 int results = JmriJOptionPane.showConfirmDialog(null, 348 Bundle.getMessage("DoYouWantToCreateTrack", 349 engineTrackName, engineLocationName), 350 Bundle.getMessage("engineTrack"), JmriJOptionPane.YES_NO_OPTION); 351 if (results == JmriJOptionPane.YES_OPTION) { 352 if (!location.isStaging()) { 353 log.debug("Create 1000 foot yard track ({})", engineTrackName); 354 track = location.addTrack(engineTrackName, Track.YARD); 355 } else { 356 log.debug("Create 1000 foot staging track ({})", engineTrackName); 357 track = location.addTrack(engineTrackName, Track.STAGING); 358 } 359 track.setLength(1000); 360 } else { 361 break; 362 } 363 } 364 } 365 // check for consist name 366 if (comma && inputLine.length > base + ENG_CONSIST) { 367 engineConsistName = inputLine[ENG_CONSIST].trim(); 368 log.debug("Consist name ({})", engineConsistName); 369 } 370 // check for HP 371 if (comma && inputLine.length > base + ENG_HP) { 372 engineHp = inputLine[ENG_HP].trim(); 373 log.debug("Engine HP ({})", engineHp); 374 } 375 // check for engine weight tons 376 if (comma && inputLine.length > base + ENG_WEIGHT) { 377 engineWeightTons = inputLine[ENG_WEIGHT].trim(); 378 log.debug("Engine weight tons ({})", engineWeightTons); 379 } 380 // check for engine type 381 if (comma && inputLine.length > base + ENG_TYPE) { 382 engineType = inputLine[ENG_TYPE].trim(); 383 log.debug("Engine type ({})", engineType); 384 } 385 log.debug("Add engine ({} {}) owner ({}) built ({}) location ({}, {})", engineRoad, engineNumber, 386 engineOwner, engineBuilt, engineLocationName, engineTrackName); 387 Engine engine = engineManager.newRS(engineRoad, engineNumber); 388 engine.setModel(engineModel); 389 engine.setLength(engineLength); 390 // does this model already have a type? 391 if (engine.getTypeName().equals(Engine.NONE)) { 392 if (!engineType.isEmpty()) { 393 engine.setTypeName(engineType); 394 } else { 395 engine.setTypeName(DEFAULT_ENGINE_TYPE); 396 } 397 } 398 // does this model already have a HP? 399 if (engine.getHp().equals(Engine.NONE)) { 400 if (!engineHp.isEmpty()) { 401 engine.setHp(engineHp); 402 } else { 403 engine.setHp(DEFAULT_ENGINE_HP); 404 } 405 } 406 // does this model already have a weight in tons? 407 if (engine.getWeightTons().equals(Engine.NONE)) { 408 engine.setWeightTons(engineWeightTons); 409 } 410 engine.setOwnerName(engineOwner); 411 engine.setBuilt(engineBuilt); 412 // consist? 413 if (!engineConsistName.isEmpty()) { 414 Consist consist = InstanceManager.getDefault(ConsistManager.class).newConsist(engineConsistName); 415 engine.setConsist(consist); 416 } 417 418 enginesAdded++; 419 420 if (location != null && track != null) { 421 String status = engine.setLocation(location, track); 422 if (!status.equals(Track.OKAY)) { 423 log.debug("Can't set engine's location because of {}", status); 424 JmriJOptionPane.showMessageDialog( 425 null, Bundle.getMessage("CanNotSetEngineAtLocation", 426 engineRoad, engineNumber, engineModel, engineLocationName, 427 engineTrackName, status), 428 Bundle.getMessage("rsCanNotLoc"), JmriJOptionPane.ERROR_MESSAGE); 429 if (status.startsWith(Track.TYPE)) { 430 int results = JmriJOptionPane.showConfirmDialog( 431 null, Bundle.getMessage("DoYouWantToAllowService", 432 engineLocationName, engineTrackName, 433 engineRoad, engineNumber, engine.getTypeName()), 434 Bundle.getMessage("ServiceEngineType"), 435 JmriJOptionPane.YES_NO_OPTION); 436 if (results == JmriJOptionPane.YES_OPTION) { 437 location.addTypeName(engine.getTypeName()); 438 track.addTypeName(engine.getTypeName()); 439 status = engine.setLocation(location, track); 440 } else { 441 break; 442 } 443 } 444 if (status.startsWith(Track.LENGTH) || status.startsWith(Track.CAPACITY)) { 445 int results = JmriJOptionPane.showConfirmDialog(null, 446 Bundle.getMessage("DoYouWantIncreaseLength", 447 engineTrackName), 448 Bundle.getMessage("TrackLength"), JmriJOptionPane.YES_NO_OPTION); 449 if (results == JmriJOptionPane.YES_OPTION) { 450 track.setLength(track.getLength() + 1000); 451 status = engine.setLocation(location, track); 452 } else { 453 break; 454 } 455 } 456 if (!status.equals(Track.OKAY)) { 457 int results = JmriJOptionPane.showConfirmDialog( 458 null, Bundle.getMessage("DoYouWantToForceEngine", 459 engineRoad, engineNumber, engineLocationName, 460 engineTrackName), 461 Bundle.getMessage("OverRide"), JmriJOptionPane.YES_NO_OPTION); 462 if (results == JmriJOptionPane.YES_OPTION) { 463 engine.setLocation(location, track, RollingStock.FORCE); // force 464 } else { 465 break; 466 } 467 } 468 } 469 } else { 470 // log.debug("No location for engine ("+engineRoad+" 471 // "+engineNumber+")"); 472 } 473 } else if (!line.isEmpty()) { 474 log.info("Engine import line {} missing attributes: {}", lineNum, line); 475 JmriJOptionPane.showMessageDialog(null, Bundle.getMessage("ImportMissingAttributes", 476 lineNum), Bundle.getMessage("EngineAttributeMissing"), 477 JmriJOptionPane.ERROR_MESSAGE); 478 break; 479 } 480 } 481 try { 482 in.close(); 483 } catch (IOException e) { 484 log.error("Import Engines failed: {}", e.getLocalizedMessage()); 485 } 486 487 if (importOkay) { 488 JmriJOptionPane.showMessageDialog(null, Bundle.getMessage("ImportEnginesAdded", 489 enginesAdded), Bundle.getMessage("SuccessfulImport"), 490 JmriJOptionPane.INFORMATION_MESSAGE); 491 } else { 492 JmriJOptionPane.showMessageDialog(null, Bundle.getMessage("ImportEnginesAdded", 493 enginesAdded), Bundle.getMessage("ImportFailed"), JmriJOptionPane.ERROR_MESSAGE); 494 } 495 496 // kill status panel 497 fstatus.dispose(); 498 } 499 500 private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(ImportEngines.class); 501}