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