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