001package jmri.jmrit.operations.rollingstock.cars.tools;
002
003import java.io.*;
004
005import jmri.IdTagManager;
006import jmri.InstanceManager;
007import jmri.jmrit.operations.locations.*;
008import jmri.jmrit.operations.locations.divisions.Division;
009import jmri.jmrit.operations.locations.divisions.DivisionManager;
010import jmri.jmrit.operations.rollingstock.ImportCommon;
011import jmri.jmrit.operations.rollingstock.RollingStock;
012import jmri.jmrit.operations.rollingstock.cars.*;
013import jmri.jmrit.operations.setup.Control;
014import jmri.jmrit.operations.setup.Setup;
015import jmri.jmrit.operations.trains.*;
016import jmri.jmrit.operations.trains.trainbuilder.TrainCommon;
017import jmri.util.swing.JmriJOptionPane;
018
019/**
020 * This routine will import cars into the operation database. Each field is
021 * space or comma delimited. Field order: Number Road Type Length Weight Color
022 * Owner Built Location - Track. If a CSV file, the import will accept these
023 * additional fields: Load Kernel Moves Value Comment Miscellaneous Extensions
024 *
025 * @author Dan Boudreau Copyright (C) 2008 2010 2011, 2013, 2016, 2021, 2024
026 */
027public class ImportCars extends ImportCommon {
028
029    CarManager carManager = InstanceManager.getDefault(CarManager.class);
030
031    private int weightResults = JmriJOptionPane.NO_OPTION;
032    private boolean autoCalculate = true;
033    private boolean askAutoCreateTypes = true;
034    private boolean askAutoCreateLocations = true;
035    private boolean askAutoCreateTracks = true;
036    private boolean askAutoLocationType = true;
037    private boolean askAutoIncreaseTrackLength = true;
038    private boolean askAutoForceCar = true;
039
040    private boolean autoCreateTypes = false;
041    private boolean autoCreateLocations = false;
042    private boolean autoCreateTracks = false;
043    private boolean autoAdjustLocationType = false;
044    private boolean autoAdjustTrackLength = false;
045    private boolean autoForceCar = false;
046
047    private final boolean autoCreateRoads = true;
048    private final boolean autoCreateLoads = true;
049    private final boolean autoCreateLengths = true;
050    private final boolean autoCreateColors = true;
051    private final boolean autoCreateOwners = true;
052
053    // see ExportCars for column numbers
054    private static final int CAR_NUMBER = 0;
055    private static final int CAR_ROAD = 1;
056    private static final int CAR_TYPE = 2;
057    private static final int CAR_LENGTH = 3;
058    private static final int CAR_WEIGHT = 4;
059    private static final int CAR_COLOR = 5;
060    private static final int CAR_OWNER = 6;
061    private static final int CAR_BUILT = 7;
062    private static final int CAR_LOCATION = 8;
063    private static final int CAR_LOCATION_TRACK_SEPARATOR = 9;
064    private static final int CAR_TRACK = 10;
065
066    // only for CSV files
067    private static final int CAR_LOAD = 11;
068    private static final int CAR_KERNEL = 12;
069    private static final int CAR_MOVES = 13;
070    private static final int CAR_VALUE = 14;
071    private static final int CAR_COMMENT = 15;
072    private static final int CAR_MISCELLANEOUS = 16;
073    private static final int CAR_EXTENSIONS = 17;
074
075    //    private static final int CAR_WAIT = 18;
076    //    private static final int CAR_PICKUP_SCH = 19;
077    //    private static final int CAR_LAST = 20;
078
079    private static final int CAR_RWE_DESTINATION = 21;
080    private static final int CAR_RWE_TRACK = 23;
081    private static final int CAR_RWE_LOAD = 24;
082
083    private static final int CAR_RWL_DESTINATION = 25;
084    private static final int CAR_RWL_TRACK = 27;
085    private static final int CAR_RWL_LOAD = 28;
086
087    private static final int CAR_DIVISION = 29;
088    private static final int CAR_TRAIN = 30;
089
090    private static final int CAR_DESTINATION = 31;
091    private static final int CAR_DEST_TRACK = 33;
092
093    private static final int CAR_FINAL_DESTINATION = 34;
094    private static final int CAR_FINAL_TRACK = 36;
095    private static final int CAR_SCH_ID = 37;
096
097    private static final int CAR_RFID_TAG = 38;
098
099    // we use a thread so the status frame will work!
100    @Override
101    public void run() {
102        File file = getFile();
103        if (file == null) {
104            return;
105        }
106        BufferedReader in = getBufferedReader(file);
107        if (in == null) {
108            return;
109        }
110
111        createStatusFrame(Bundle.getMessage("ImportCars"));
112
113        // Now read the input file
114        boolean importOkay = false;
115        boolean comma = false;
116        boolean importKernel = false;
117        int lineNum = 0;
118        int carsAdded = 0;
119        String line = " ";
120        String carNumber;
121        String carRoad;
122        String carType;
123        String carLength;
124        String carWeight;
125        String carColor = "";
126        String carOwner = "";
127        String carBuilt = "";
128        String carLocationName = "";
129        String carTrackName = "";
130        String carLoadName = "";
131        String carKernelName = "";
132        int carMoves = 0;
133        String carValue = "";
134        String carComment = "";
135        String[] inputLine;
136
137        // does the file name end with .csv?
138        if (file.getAbsolutePath().endsWith(".csv")) { // NOI18N
139            log.info("Using comma as delimiter for import cars");
140            comma = true;
141        }
142
143        while (true) {
144            lineNumber.setText(Bundle.getMessage("LineNumber") + " " + Integer.toString(++lineNum));
145            try {
146                line = in.readLine();
147            } catch (IOException e) {
148                break;
149            }
150
151            if (line == null) {
152                importOkay = true;
153                break;
154            }
155
156            // has user canceled import?
157            if (!fstatus.isShowing()) {
158                break;
159            }
160
161            line = line.trim();
162            log.debug("Import: {}", line);
163            importLine.setText(line);
164
165            if (line.startsWith(Bundle.getMessage("Number"))) {
166                continue; // skip header
167            }
168            if (line.equalsIgnoreCase("kernel")) { // NOI18N
169                log.info("Importing kernel names");
170                importKernel = true;
171                continue;
172            }
173            if (line.equalsIgnoreCase("comma")) { // NOI18N
174                log.info("Using comma as delimiter for import cars");
175                comma = true;
176                continue;
177            }
178            // use comma as delimiter if found otherwise use spaces
179            if (comma) {
180                inputLine = parseCommaLine(line);
181            } else {
182                inputLine = line.split("\\s+"); // NOI18N
183            }
184            if (inputLine.length < 1 || line.isEmpty()) {
185                log.debug("Skipping blank line");
186                continue;
187            }
188            int base = 1;
189            if (comma || !inputLine[0].isEmpty()) {
190                base--; // skip over any spaces at start of line
191            }
192
193            // The minimum import is car number, road, type and length
194            if (inputLine.length > base + 3) {
195
196                carNumber = inputLine[base + CAR_NUMBER].trim();
197                carRoad = inputLine[base + CAR_ROAD].trim();
198                carType = inputLine[base + CAR_TYPE].trim();
199                carLength = inputLine[base + CAR_LENGTH].trim();
200                carWeight = "0";
201                carColor = "";
202                carOwner = "";
203                carBuilt = "";
204                carLocationName = "";
205                carTrackName = "";
206                carLoadName = InstanceManager.getDefault(CarLoads.class).getDefaultEmptyName();
207                carKernelName = "";
208                carMoves = 0;
209                carValue = "";
210                carComment = "";
211
212                if (inputLine.length > base + CAR_WEIGHT) {
213                    carWeight = inputLine[base + CAR_WEIGHT].trim();
214                }
215                if (inputLine.length > base + CAR_COLOR) {
216                    carColor = inputLine[base + CAR_COLOR].trim();
217                }
218
219                log.debug("Checking car number ({}) road ({}) type ({}) length ({}) weight ({}) color ({})", carNumber,
220                        carRoad, carType, carLength, carWeight, carColor); // NOI18N
221
222                if (carNumber.isEmpty()) {
223                    log.info("Import line {} missing car number", lineNum);
224                    JmriJOptionPane.showMessageDialog(null,
225                            Bundle.getMessage("RoadNumberNotSpecified", lineNum),
226                            Bundle.getMessage("RoadNumberMissing"), JmriJOptionPane.ERROR_MESSAGE);
227                    break;
228                }
229                if (carRoad.isEmpty()) {
230                    log.info("Import line {} missing car road", lineNum);
231                    JmriJOptionPane.showMessageDialog(null,
232                            Bundle.getMessage("RoadNameNotSpecified", lineNum),
233                            Bundle.getMessage("RoadNameMissing"), JmriJOptionPane.ERROR_MESSAGE);
234                    break;
235                }
236                if (carType.isEmpty()) {
237                    log.info("Import line {} missing car type", lineNum);
238                    JmriJOptionPane.showMessageDialog(null,
239                            Bundle.getMessage("CarTypeNotSpecified", carRoad, carNumber, lineNum),
240                            Bundle.getMessage("CarTypeMissing"), JmriJOptionPane.ERROR_MESSAGE);
241                    break;
242                }
243                if (carLength.isEmpty()) {
244                    log.info("Import line {} missing car length", lineNum);
245                    JmriJOptionPane.showMessageDialog(null,
246                            Bundle.getMessage("CarLengthNotSpecified", carRoad, carNumber, lineNum),
247                            Bundle.getMessage("CarLengthMissing"), JmriJOptionPane.ERROR_MESSAGE);
248                    break;
249                }
250                if (TrainCommon.splitString(carNumber).length() > Control.max_len_string_road_number) {
251                    JmriJOptionPane.showMessageDialog(null, Bundle.getMessage("CarRoadNumberTooLong",
252                            carRoad, carNumber, carNumber),
253                            Bundle.getMessage("RoadNumMustBeLess",
254                                    Control.max_len_string_road_number + 1),
255                            JmriJOptionPane.ERROR_MESSAGE);
256                    break;
257                }
258                try {
259                    if (carRoad.split(TrainCommon.HYPHEN)[0].length() > Control.max_len_string_attibute) {
260                        JmriJOptionPane.showMessageDialog(null, Bundle.getMessage("CarRoadNameTooLong",
261                                carRoad, carNumber, carRoad),
262                                Bundle.getMessage("carAttribute",
263                                        Control.max_len_string_attibute),
264                                JmriJOptionPane.ERROR_MESSAGE);
265                        break;
266                    }
267                } catch (ArrayIndexOutOfBoundsException e) {
268                    JmriJOptionPane.showMessageDialog(null, Bundle.getMessage("CarRoadNameWrong",
269                            carRoad, lineNum),
270                            Bundle.getMessage("CarAttributeMissing"),
271                            JmriJOptionPane.ERROR_MESSAGE);
272                    log.error("Road ({}) name not valid line {}", carRoad, lineNum);
273                    break;
274                }
275                try {
276                    if (carType.split(TrainCommon.HYPHEN)[0].length() > Control.max_len_string_attibute) {
277                        JmriJOptionPane.showMessageDialog(null, Bundle.getMessage("CarTypeNameTooLong",
278                                carRoad, carNumber, carType),
279                                Bundle.getMessage("carAttribute",
280                                        Control.max_len_string_attibute),
281                                JmriJOptionPane.ERROR_MESSAGE);
282                        break;
283                    }
284                } catch (ArrayIndexOutOfBoundsException e) {
285                    JmriJOptionPane.showMessageDialog(null, Bundle.getMessage("CarTypeNameWrong",
286                            carType, lineNum),
287                            Bundle.getMessage("CarAttributeMissing"),
288                            JmriJOptionPane.ERROR_MESSAGE);
289                    log.error("Type ({}) name not valid line {}", carType, lineNum);
290                    break;
291                }
292                if (!InstanceManager.getDefault(CarTypes.class).containsName(carType)) {
293                    if (autoCreateTypes) {
294                        log.debug("Adding car type ({})", carType);
295                        InstanceManager.getDefault(CarTypes.class).addName(carType);
296                    } else {
297                        int results = JmriJOptionPane.showConfirmDialog(null, Bundle.getMessage("Car") +
298                                " (" +
299                                carRoad +
300                                " " +
301                                carNumber +
302                                ")" +
303                                NEW_LINE +
304                                Bundle.getMessage("typeNameNotExist", carType),
305                                Bundle.getMessage("carAddType"), JmriJOptionPane.YES_NO_CANCEL_OPTION);
306                        if (results == JmriJOptionPane.YES_OPTION) {
307                            InstanceManager.getDefault(CarTypes.class).addName(carType);
308                            if (askAutoCreateTypes) {
309                                results = JmriJOptionPane.showConfirmDialog(null,
310                                        Bundle.getMessage("DoYouWantToAutoAddCarTypes"),
311                                        Bundle.getMessage("OnlyAskedOnce"),
312                                        JmriJOptionPane.YES_NO_OPTION);
313                                if (results == JmriJOptionPane.YES_OPTION) {
314                                    autoCreateTypes = true;
315                                }
316                            }
317                            askAutoCreateTypes = false;
318                        } else if (results == JmriJOptionPane.CANCEL_OPTION) {
319                            break;
320                        }
321                    }
322                }
323                if (carLength.length() > Control.max_len_string_length_name) {
324                    JmriJOptionPane.showMessageDialog(null, Bundle.getMessage("CarLengthNameTooLong",
325                            carRoad, carNumber, carLength),
326                            Bundle.getMessage("carAttribute",
327                                    Control.max_len_string_length_name),
328                            JmriJOptionPane.ERROR_MESSAGE);
329                    break;
330                }
331                try {
332                    Integer.parseInt(carLength);
333                } catch (NumberFormatException e) {
334                    JmriJOptionPane.showMessageDialog(
335                            null, Bundle.getMessage("CarLengthNameNotNumber",
336                                    carRoad, carNumber, carLength),
337                            Bundle.getMessage("CarLengthMissing"), JmriJOptionPane.ERROR_MESSAGE);
338                    break;
339                }
340                if (carWeight.length() > Control.max_len_string_weight_name) {
341                    JmriJOptionPane.showMessageDialog(null, Bundle.getMessage("CarWeightNameTooLong",
342                            carRoad, carNumber, carWeight),
343                            Bundle.getMessage("carAttribute",
344                                    Control.max_len_string_weight_name),
345                            JmriJOptionPane.ERROR_MESSAGE);
346                    break;
347                }
348                if (carColor.length() > Control.max_len_string_attibute) {
349                    JmriJOptionPane.showMessageDialog(null, Bundle.getMessage("CarColorNameTooLong",
350                            carRoad, carNumber, carColor),
351                            Bundle.getMessage("carAttribute",
352                                    Control.max_len_string_attibute),
353                            JmriJOptionPane.ERROR_MESSAGE);
354                    break;
355                }
356                // calculate car weight if "0"
357                if (carWeight.equals("0")) {
358                    try {
359                        carWeight = CarManager.calculateCarWeight(carLength); // ounces.
360                    } catch (NumberFormatException e) {
361                        JmriJOptionPane.showMessageDialog(null, Bundle.getMessage("carLengthMustBe"), Bundle
362                                .getMessage("carWeigthCanNot"), JmriJOptionPane.ERROR_MESSAGE);
363                    }
364                }
365                Car existingCar = carManager.getByRoadAndNumber(carRoad, carNumber);
366                if (existingCar != null) {
367                    log.info("Can not add, car number ({}) road ({}) already exists!", carNumber, carRoad); // NOI18N
368                    continue;
369                }
370                if (inputLine.length > base + CAR_OWNER) {
371                    carOwner = inputLine[base + CAR_OWNER].trim();
372                    if (carOwner.length() > Control.max_len_string_attibute) {
373                        JmriJOptionPane.showMessageDialog(null, Bundle
374                                .getMessage("CarOwnerNameTooLong",
375                                        carRoad, carNumber, carOwner),
376                                Bundle.getMessage("carAttribute",
377                                        Control.max_len_string_attibute),
378                                JmriJOptionPane.ERROR_MESSAGE);
379                        break;
380                    }
381                }
382                if (inputLine.length > base + CAR_BUILT) {
383                    carBuilt = inputLine[base + CAR_BUILT].trim();
384                    if (carBuilt.length() > Control.max_len_string_built_name) {
385                        JmriJOptionPane.showMessageDialog(
386                                null, Bundle.getMessage("CarBuiltNameTooLong",
387                                        carRoad, carNumber, carBuilt),
388                                Bundle.getMessage("carAttribute",
389                                        Control.max_len_string_built_name),
390                                JmriJOptionPane.ERROR_MESSAGE);
391                        break;
392                    }
393                }
394                if (inputLine.length > base + CAR_LOCATION) {
395                    carLocationName = inputLine[base + CAR_LOCATION].trim();
396                }
397                if (comma && inputLine.length > base + CAR_TRACK) {
398                    carTrackName = inputLine[base + CAR_TRACK].trim();
399                }
400                // Location and track name can be one or more words in a
401                // space delimited file
402                if (!comma) {
403                    int j = 0;
404                    StringBuffer name = new StringBuffer(carLocationName);
405                    for (int i = base + CAR_LOCATION_TRACK_SEPARATOR; i < inputLine.length; i++) {
406                        if (inputLine[i].equals(LOCATION_TRACK_SEPARATOR)) {
407                            j = i + 1;
408                            break;
409                        } else {
410                            name.append(" " + inputLine[i]);
411                        }
412                    }
413                    carLocationName = name.toString();
414                    log.debug("Car ({} {}) has location ({})", carRoad, carNumber, carLocationName);
415                    // now get the track name
416                    name = new StringBuffer();
417                    if (j != 0 && j < inputLine.length) {
418                        name.append(inputLine[j]);
419                        for (int i = j + 1; i < inputLine.length; i++) {
420                            name.append(" " + inputLine[i]);
421                        }
422                        log.debug("Car ({} {}) has track ({})", carRoad, carNumber, carTrackName);
423                    }
424                    carTrackName = name.toString();
425                }
426
427                // is there a load name?
428                if (comma && inputLine.length > CAR_LOAD) {
429                    if (!inputLine[CAR_LOAD].isBlank()) {
430                        carLoadName = inputLine[CAR_LOAD].trim();
431                        log.debug("Car ({} {}) has load ({})", carRoad, carNumber, carLoadName);
432                    }
433                    if (carLoadName.length() > Control.max_len_string_attibute) {
434                        JmriJOptionPane.showMessageDialog(null, Bundle.getMessage("CarLoadNameTooLong",
435                                carRoad, carNumber, carLoadName),
436                                Bundle.getMessage("carAttribute",
437                                        Control.max_len_string_attibute),
438                                JmriJOptionPane.ERROR_MESSAGE);
439                        break;
440                    }
441                }
442                // is there a kernel name?
443                if (comma && inputLine.length > CAR_KERNEL) {
444                    carKernelName = inputLine[CAR_KERNEL].trim();
445                    log.debug("Car ({} {}) has kernel name ({})", carRoad, carNumber, carKernelName);
446                }
447                // is there a move count?
448                if (comma && inputLine.length > CAR_MOVES) {
449                    if (!inputLine[CAR_MOVES].trim().isEmpty()) {
450                        try {
451                            carMoves = Integer.parseInt(inputLine[CAR_MOVES].trim());
452                            log.debug("Car ({} {}) has move count ({})", carRoad, carNumber, carMoves);
453                        } catch (NumberFormatException e) {
454                            log.error("Car ({} {}) has move count ({}) not a number", carRoad, carNumber, carMoves);
455                        }
456                    }
457                }
458                // is there a car value?
459                if (comma && inputLine.length > CAR_VALUE) {
460                    carValue = inputLine[CAR_VALUE].trim();
461                }
462                // is there a car comment?
463                if (comma && inputLine.length > CAR_COMMENT) {
464                    carComment = inputLine[CAR_COMMENT];
465                }
466
467                if (TrainCommon.splitString(carLocationName).length() > Control.max_len_string_location_name) {
468                    JmriJOptionPane.showMessageDialog(
469                            null, Bundle.getMessage("CarLocationNameTooLong",
470                                    carRoad, carNumber, carLocationName),
471                            Bundle.getMessage("carAttribute",
472                                    Control.max_len_string_location_name),
473                            JmriJOptionPane.ERROR_MESSAGE);
474                    break;
475                }
476                if (TrainCommon.splitString(carTrackName).length() > Control.max_len_string_track_name) {
477                    JmriJOptionPane.showMessageDialog(null, Bundle
478                            .getMessage("CarTrackNameTooLong",
479                                    carRoad, carNumber, carTrackName),
480                            Bundle.getMessage("carAttribute",
481                                    Control.max_len_string_track_name),
482                            JmriJOptionPane.ERROR_MESSAGE);
483                    break;
484                }
485                Location location =
486                        InstanceManager.getDefault(LocationManager.class).getLocationByName(carLocationName);
487                Track track = null;
488                if (location == null && !carLocationName.isEmpty()) {
489                    if (autoCreateLocations) {
490                        log.debug("Create location ({})", carLocationName);
491                        location = InstanceManager.getDefault(LocationManager.class).newLocation(carLocationName);
492                    } else {
493                        JmriJOptionPane.showMessageDialog(null, Bundle
494                                .getMessage("CarLocationDoesNotExist",
495                                        carRoad, carNumber, carLocationName),
496                                Bundle.getMessage("carLocation"), JmriJOptionPane.ERROR_MESSAGE);
497                        int results = JmriJOptionPane.showConfirmDialog(null, Bundle
498                                .getMessage("DoYouWantToCreateLoc", carLocationName),
499                                Bundle
500                                        .getMessage("carLocation"),
501                                JmriJOptionPane.YES_NO_OPTION);
502                        if (results == JmriJOptionPane.YES_OPTION) {
503                            log.debug("Create location ({})", carLocationName);
504                            location =
505                                    InstanceManager.getDefault(LocationManager.class).newLocation(carLocationName);
506                            if (askAutoCreateLocations) {
507                                results = JmriJOptionPane.showConfirmDialog(null, Bundle
508                                        .getMessage("DoYouWantToAutoCreateLoc"),
509                                        Bundle.getMessage("OnlyAskedOnce"), JmriJOptionPane.YES_NO_OPTION);
510                                if (results == JmriJOptionPane.YES_OPTION) {
511                                    autoCreateLocations = true;
512                                }
513                            }
514                            askAutoCreateLocations = false;
515                        } else {
516                            break;
517                        }
518                    }
519                }
520                if (location != null && !carTrackName.isEmpty()) {
521                    track = location.getTrackByName(carTrackName, null);
522                    if (track == null) {
523                        if (autoCreateTracks) {
524                            if (!location.isStaging()) {
525                                log.debug("Create 1000 foot yard track ({})", carTrackName);
526                                track = location.addTrack(carTrackName, Track.YARD);
527                            } else {
528                                log.debug("Create 1000 foot staging track ({})", carTrackName);
529                                track = location.addTrack(carTrackName, Track.STAGING);
530                            }
531                            track.setLength(1000);
532                        } else {
533                            JmriJOptionPane.showMessageDialog(
534                                    null, Bundle.getMessage("CarTrackDoesNotExist",
535                                            carRoad, carNumber, carTrackName, carLocationName),
536                                    Bundle.getMessage("carTrack"), JmriJOptionPane.ERROR_MESSAGE);
537                            int results = JmriJOptionPane.showConfirmDialog(null,
538                                    Bundle.getMessage("DoYouWantToCreateTrack",
539                                            carTrackName, carLocationName),
540                                    Bundle.getMessage("carTrack"), JmriJOptionPane.YES_NO_OPTION);
541                            if (results == JmriJOptionPane.YES_OPTION) {
542                                if (!location.isStaging()) {
543                                    log.debug("Create 1000 foot yard track ({})", carTrackName);
544                                    track = location.addTrack(carTrackName, Track.YARD);
545                                } else {
546                                    log.debug("Create 1000 foot staging track ({})", carTrackName);
547                                    track = location.addTrack(carTrackName, Track.STAGING);
548                                }
549                                track.setLength(1000);
550                                if (askAutoCreateTracks) {
551                                    results = JmriJOptionPane.showConfirmDialog(null,
552                                            Bundle.getMessage("DoYouWantToAutoCreateTrack"),
553                                            Bundle.getMessage("OnlyAskedOnce"),
554                                            JmriJOptionPane.YES_NO_OPTION);
555                                    if (results == JmriJOptionPane.YES_OPTION) {
556                                        autoCreateTracks = true;
557                                    }
558                                    askAutoCreateTracks = false;
559                                }
560                            } else {
561                                break;
562                            }
563                        }
564                    }
565                }
566
567                log.debug("Add car ({} {}) owner ({}) built ({}) location ({}, {})", carRoad, carNumber, carOwner,
568                        carBuilt, carLocationName, carTrackName);
569                Car car = carManager.newRS(carRoad, carNumber);
570                car.setTypeName(carType);
571                car.setLength(carLength);
572                car.setWeight(carWeight);
573                car.setColor(carColor);
574                car.setOwnerName(carOwner);
575                car.setBuilt(carBuilt);
576                car.setLoadName(carLoadName);
577                car.setKernel(InstanceManager.getDefault(KernelManager.class).newKernel(carKernelName));
578                car.setMoves(carMoves);
579                car.setValue(carValue);
580                car.setComment(carComment);
581                carsAdded++;
582
583                // if the car's type name is "Caboose" then make it a
584                // caboose
585                car.setCaboose(carType.equals("Caboose"));
586
587                // Out of Service?
588                if (comma && inputLine.length > CAR_MISCELLANEOUS) {
589                    car.setOutOfService(inputLine[CAR_MISCELLANEOUS].equals(Bundle.getMessage("OutOfService")));
590                }
591
592                // determine if there are any car extensions
593                if (comma && inputLine.length > CAR_EXTENSIONS) {
594                    String extensions = inputLine[CAR_EXTENSIONS];
595                    log.debug("Car ({}) has extension ({})", car.toString(), extensions);
596                    String[] ext = extensions.split(Car.EXTENSION_REGEX);
597                    for (int i = 0; i < ext.length; i++) {
598                        if (ext[i].equals(Car.CABOOSE_EXTENSION)) {
599                            car.setCaboose(true);
600                        }
601                        if (ext[i].equals(Car.FRED_EXTENSION)) {
602                            car.setFred(true);
603                        }
604                        if (ext[i].equals(Car.PASSENGER_EXTENSION)) {
605                            car.setPassenger(true);
606                            car.setBlocking(Integer.parseInt(ext[i + 1]));
607                        }
608                        if (ext[i].equals(Car.UTILITY_EXTENSION)) {
609                            car.setUtility(true);
610                        }
611                        if (ext[i].equals(Car.HAZARDOUS_EXTENSION)) {
612                            car.setCarHazardous(true);
613                        }
614                    }
615                }
616
617                // TODO car wait, pick up schedule, last moved
618
619                // Return When Empty
620                if (comma && inputLine.length > CAR_RWE_DESTINATION) {
621                    Location rweDestination =
622                            InstanceManager.getDefault(LocationManager.class)
623                                    .getLocationByName(inputLine[CAR_RWE_DESTINATION]);
624
625                    car.setReturnWhenEmptyDestination(rweDestination);
626                    if (rweDestination != null && inputLine.length > CAR_RWE_TRACK) {
627                        Track rweTrack = rweDestination.getTrackByName(inputLine[CAR_RWE_TRACK], null);
628                        car.setReturnWhenEmptyDestTrack(rweTrack);
629                    }
630                }
631                if (comma && inputLine.length > CAR_RWE_LOAD && !inputLine[CAR_RWE_LOAD].isBlank()) {
632                    car.setReturnWhenEmptyLoadName(inputLine[CAR_RWE_LOAD].trim());
633                }
634
635                // Return When Loaded
636                if (comma && inputLine.length > CAR_RWL_DESTINATION) {
637                    Location rwlDestination =
638                            InstanceManager.getDefault(LocationManager.class)
639                                    .getLocationByName(inputLine[CAR_RWL_DESTINATION]);
640
641                    car.setReturnWhenLoadedDestination(rwlDestination);
642                    if (rwlDestination != null && inputLine.length > CAR_RWL_TRACK) {
643                        Track rweTrack = rwlDestination.getTrackByName(inputLine[CAR_RWL_TRACK], null);
644                        car.setReturnWhenLoadedDestTrack(rweTrack);
645                    }
646                }
647                if (comma && inputLine.length > CAR_RWL_LOAD && !inputLine[CAR_RWL_LOAD].isBlank()) {
648                    car.setReturnWhenLoadedLoadName(inputLine[CAR_RWL_LOAD].trim());
649                }
650
651                if (comma && inputLine.length > CAR_DIVISION) {
652                    Division division = InstanceManager.getDefault(DivisionManager.class)
653                            .getDivisionByName(inputLine[CAR_DIVISION].trim());
654                    car.setDivision(division);
655                }
656
657                if (comma && inputLine.length > CAR_TRAIN) {
658                    Train train = InstanceManager.getDefault(TrainManager.class)
659                            .getTrainByName(inputLine[CAR_TRAIN].trim());
660                    car.setTrain(train);
661                }
662
663                // Destination
664                if (comma && inputLine.length > CAR_DESTINATION) {
665                    Location destination =
666                            InstanceManager.getDefault(LocationManager.class)
667                                    .getLocationByName(inputLine[CAR_DESTINATION]);
668                    if (destination != null && inputLine.length > CAR_DEST_TRACK) {
669                        Track destTrack = destination.getTrackByName(inputLine[CAR_DEST_TRACK], null);
670                        car.setDestination(destination, destTrack);
671                    }
672                }
673
674                // Final Destination
675                if (comma && inputLine.length > CAR_FINAL_DESTINATION) {
676                    Location finalDestination =
677                            InstanceManager.getDefault(LocationManager.class)
678                                    .getLocationByName(inputLine[CAR_FINAL_DESTINATION]);
679
680                    car.setFinalDestination(finalDestination);
681                    if (finalDestination != null && inputLine.length > CAR_FINAL_TRACK) {
682                        Track finalTrack = finalDestination.getTrackByName(inputLine[CAR_FINAL_TRACK], null);
683                        car.setFinalDestinationTrack(finalTrack);
684                    }
685                }
686
687                // Schedule Id
688                if (comma && inputLine.length > CAR_SCH_ID) {
689                    car.setScheduleItemId(inputLine[CAR_SCH_ID]);
690                }
691
692                if (comma && inputLine.length > CAR_RFID_TAG) {
693                    String newTag = inputLine[CAR_RFID_TAG];
694                    if (!newTag.trim().isEmpty()) {
695                        InstanceManager.getDefault(IdTagManager.class).provideIdTag(newTag);
696                        log.debug("New ID tag added - {}", newTag);
697                        car.setRfid(newTag);
698                    }
699                }
700
701                // add new roads
702                if (!InstanceManager.getDefault(CarRoads.class).containsName(carRoad)) {
703                    if (autoCreateRoads) {
704                        log.debug("add car road {}", carRoad);
705                        InstanceManager.getDefault(CarRoads.class).addName(carRoad);
706                    }
707                }
708
709                // add new loads
710                if (!InstanceManager.getDefault(CarLoads.class).containsName(carLoadName)) {
711                    if (autoCreateLoads) {
712                        log.debug("add car load {}", carLoadName);
713                        InstanceManager.getDefault(CarLoads.class).addName(carType, carLoadName);
714                    }
715                }
716
717                // add new lengths
718                if (!InstanceManager.getDefault(CarLengths.class).containsName(carLength)) {
719                    if (autoCreateLengths) {
720                        log.debug("add car length {}", carLength);
721                        InstanceManager.getDefault(CarLengths.class).addName(carLength);
722                    }
723                }
724
725                // add new colors
726                if (!InstanceManager.getDefault(CarColors.class).containsName(carColor)) {
727                    if (autoCreateColors) {
728                        log.debug("add car color {}", carColor);
729                        InstanceManager.getDefault(CarColors.class).addName(carColor);
730                    }
731                }
732
733                // add new owners
734                if (!InstanceManager.getDefault(CarOwners.class).containsName(carOwner)) {
735                    if (autoCreateOwners) {
736                        log.debug("add car owner {}", carOwner);
737                        InstanceManager.getDefault(CarOwners.class).addName(carOwner);
738                    }
739                }
740
741                if (car.getWeight().isEmpty()) {
742                    log.debug("Car ({}) weight not specified", car.toString());
743                    if (weightResults != JmriJOptionPane.CANCEL_OPTION) {
744                        weightResults = JmriJOptionPane.showOptionDialog(null,
745                                Bundle.getMessage("CarWeightNotFound",
746                                        car.toString()),
747                                Bundle.getMessage("CarWeightMissing"),
748                                JmriJOptionPane.DEFAULT_OPTION, // custom buttons
749                                JmriJOptionPane.INFORMATION_MESSAGE, null,
750                                new Object[]{
751                                        Bundle.getMessage("ButtonYes"), Bundle.getMessage("ButtonNo"),
752                                        Bundle.getMessage("ButtonDontShow")},
753                                autoCalculate ? Bundle.getMessage("ButtonYes") : Bundle.getMessage("ButtonNo"));
754                    }
755                    if (weightResults == 1) { // array position 1, ButtonNo
756                        autoCalculate = false;
757                    }
758                    if (weightResults == 0 || // array position 0, ButtonYes
759                            autoCalculate == true && weightResults == 2) { // array position 2 ButtonDontShow
760                        autoCalculate = true;
761                        try {
762                            carWeight = CarManager.calculateCarWeight(carLength);
763                            car.setWeight(carWeight);
764                            int tons = (int) (Double.parseDouble(carWeight) * Setup.getScaleTonRatio());
765                            // adjust weight for caboose
766                            if (car.isCaboose() || car.isPassenger()) {
767                                tons = (int) (Double.parseDouble(car.getLength()) * .9);
768                            }
769                            car.setWeightTons(Integer.toString(tons));
770                        } catch (NumberFormatException e) {
771                            JmriJOptionPane.showMessageDialog(null, Bundle.getMessage("carLengthMustBe"), Bundle
772                                    .getMessage("carWeigthCanNot"), JmriJOptionPane.ERROR_MESSAGE);
773                        }
774                    }
775                }
776
777                if (location != null && track != null) {
778                    String status = car.setLocation(location, track);
779                    if (!status.equals(Track.OKAY)) {
780                        log.debug("Can't set car's location because of {}", status);
781                        if (status.startsWith(Track.TYPE)) {
782                            if (autoAdjustLocationType) {
783                                location.addTypeName(carType);
784                                track.addTypeName(carType);
785                                status = car.setLocation(location, track);
786                            } else {
787                                JmriJOptionPane.showMessageDialog(
788                                        null, Bundle.getMessage("CanNotSetCarAtLocation",
789                                                car.toString(), carType, carLocationName, carTrackName,
790                                                status),
791                                        Bundle.getMessage("rsCanNotLoc"), JmriJOptionPane.ERROR_MESSAGE);
792                                int results = JmriJOptionPane.showConfirmDialog(null, Bundle
793                                        .getMessage("DoYouWantToAllowService",
794                                                carLocationName, carTrackName, car.toString(), carType),
795                                        Bundle.getMessage("ServiceCarType"),
796                                        JmriJOptionPane.YES_NO_OPTION);
797                                if (results == JmriJOptionPane.YES_OPTION) {
798                                    location.addTypeName(carType);
799                                    track.addTypeName(carType);
800                                    status = car.setLocation(location, track);
801                                    log.debug("Set car's location status: {}", status);
802                                    if (askAutoLocationType) {
803                                        results = JmriJOptionPane.showConfirmDialog(null,
804                                                Bundle.getMessage("DoYouWantToAutoAdjustLocations"),
805                                                Bundle.getMessage("OnlyAskedOnce"), JmriJOptionPane.YES_NO_OPTION);
806                                        if (results == JmriJOptionPane.YES_OPTION) {
807                                            autoAdjustLocationType = true;
808                                        }
809                                        askAutoLocationType = false;
810                                    }
811                                } else {
812                                    break;
813                                }
814                            }
815                        }
816                        if (status.startsWith(Track.LENGTH) || status.startsWith(Track.CAPACITY)) {
817                            if (autoAdjustTrackLength) {
818                                track.setLength(track.getLength() + 1000);
819                                status = car.setLocation(location, track);
820                                log.debug("Set track length status: {}", status);
821                            } else {
822                                JmriJOptionPane.showMessageDialog(null, Bundle
823                                        .getMessage("CanNotSetCarAtLocation",
824                                                car.toString(), carType, carLocationName, carTrackName,
825                                                status),
826                                        Bundle.getMessage("rsCanNotLoc"), JmriJOptionPane.ERROR_MESSAGE);
827                                int results = JmriJOptionPane.showConfirmDialog(null, Bundle
828                                        .getMessage("DoYouWantIncreaseLength", carTrackName),
829                                        Bundle
830                                                .getMessage("TrackLength"),
831                                        JmriJOptionPane.YES_NO_OPTION);
832                                if (results == JmriJOptionPane.YES_OPTION) {
833                                    track.setLength(track.getLength() + 1000);
834                                    status = car.setLocation(location, track);
835                                    log.debug("Set track length status: {}", status);
836                                    if (askAutoIncreaseTrackLength) {
837                                        results = JmriJOptionPane.showConfirmDialog(null, Bundle
838                                                .getMessage("DoYouWantToAutoAdjustTrackLength"),
839                                                Bundle.getMessage("OnlyAskedOnce"),
840                                                JmriJOptionPane.YES_NO_OPTION);
841                                        if (results == JmriJOptionPane.YES_OPTION) {
842                                            autoAdjustTrackLength = true;
843                                        }
844                                        askAutoIncreaseTrackLength = false;
845                                    }
846                                } else {
847                                    break;
848                                }
849                            }
850                        }
851                        if (!status.equals(Track.OKAY)) {
852                            if (autoForceCar) {
853                                car.setLocation(location, track, RollingStock.FORCE); // force
854                            } else {
855                                JmriJOptionPane.showMessageDialog(null, Bundle
856                                        .getMessage("CanNotSetCarAtLocation",
857                                                car.toString(), carType, carLocationName, carTrackName,
858                                                status),
859                                        Bundle.getMessage("rsCanNotLoc"), JmriJOptionPane.ERROR_MESSAGE);
860                                int results = JmriJOptionPane.showConfirmDialog(null, Bundle
861                                        .getMessage("DoYouWantToForceCar",
862                                                car.toString(), carLocationName, carTrackName),
863                                        Bundle.getMessage("OverRide"),
864                                        JmriJOptionPane.YES_NO_OPTION);
865                                if (results == JmriJOptionPane.YES_OPTION) {
866                                    car.setLocation(location, track, RollingStock.FORCE); // force
867                                    if (askAutoForceCar) {
868                                        results = JmriJOptionPane.showConfirmDialog(null, Bundle
869                                                .getMessage("DoYouWantToAutoForceCar"),
870                                                Bundle.getMessage("OnlyAskedOnce"),
871                                                JmriJOptionPane.YES_NO_OPTION);
872                                        if (results == JmriJOptionPane.YES_OPTION) {
873                                            autoForceCar = true;
874                                        }
875                                        askAutoForceCar = false;
876                                    }
877                                } else {
878                                    break;
879                                }
880                            }
881                        }
882                    }
883                } else {
884                    // log.debug("No location for car ("+carRoad+"
885                    // "+carNumber+")");
886                }
887            } else if (importKernel && inputLine.length == base + 3) {
888                carNumber = inputLine[base + 0].trim();
889                carRoad = inputLine[base + 1].trim();
890                String kernelName = inputLine[base + 2].trim();
891                Car car = carManager.getByRoadAndNumber(carRoad, carNumber);
892                if (car != null) {
893                    Kernel kernel = InstanceManager.getDefault(KernelManager.class).newKernel(kernelName);
894                    car.setKernel(kernel);
895                    carsAdded++;
896                } else {
897                    log.info("Car number ({}) road ({}) does not exist!", carNumber, carRoad); // NOI18N
898                    break;
899                }
900            } else if (!line.isEmpty()) {
901                log.info("Car import line {} missing attributes: {}", lineNum, line);
902                JmriJOptionPane.showMessageDialog(null, Bundle.getMessage("ImportMissingAttributes",
903                        lineNum) +
904                        NEW_LINE +
905                        line +
906                        NEW_LINE +
907                        Bundle.getMessage("ImportMissingAttributes2"),
908                        Bundle.getMessage("CarAttributeMissing"),
909                        JmriJOptionPane.ERROR_MESSAGE);
910                break;
911            }
912        }
913        try {
914            in.close();
915        } catch (IOException e) {
916            log.error("Import cars failed: {}", e.getLocalizedMessage());
917        }
918
919        if (importOkay) {
920            JmriJOptionPane
921                    .showMessageDialog(null, Bundle.getMessage("ImportCarsAdded",
922                            carsAdded), Bundle.getMessage("SuccessfulImport"),
923                            JmriJOptionPane.INFORMATION_MESSAGE);
924        } else {
925            JmriJOptionPane.showMessageDialog(null, Bundle.getMessage("ImportCarsAdded",
926                    carsAdded), Bundle.getMessage("ImportFailed"), JmriJOptionPane.ERROR_MESSAGE);
927        }
928
929        // kill status panel
930        fstatus.dispose();
931    }
932
933    private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(ImportCars.class);
934}