001package jmri.jmrit.operations.rollingstock;
002
003import java.io.*;
004import java.nio.charset.StandardCharsets;
005import java.util.Arrays;
006
007import javax.swing.*;
008import javax.swing.filechooser.FileNameExtensionFilter;
009
010import org.apache.commons.csv.*;
011import org.slf4j.Logger;
012import org.slf4j.LoggerFactory;
013
014import jmri.jmrit.operations.setup.Control;
015
016/**
017 * Provides common routes for importing cars and locomotives
018 *
019 * @author Dan Boudreau Copyright (C) 2013, 2025
020 */
021public abstract class ImportCommon extends Thread {
022
023    protected static final String NEW_LINE = "\n"; // NOI18N
024
025    protected JLabel lineNumber = new JLabel();
026    protected JLabel importLine = new JLabel();
027
028    protected boolean importOkay = false;
029    protected static final String[] BREAK = new String[0];
030    protected int lineNum = 0;
031
032    protected static final String LOCATION_TRACK_SEPARATOR = "-";
033
034    protected jmri.util.JmriJFrame fstatus;
035
036    // Get file to read from
037    protected File getFile() {
038        JFileChooser fc = new jmri.util.swing.JmriJFileChooser(jmri.jmrit.operations.OperationsXml.getFileLocation());
039        fc.setFileFilter(new FileNameExtensionFilter(Bundle.getMessage("Text&CSV"), "txt", "csv")); // NOI18N
040        int retVal = fc.showOpenDialog(null);
041        if (retVal != JFileChooser.APPROVE_OPTION) {
042            return null; // canceled
043        }
044        log.info("Importing from file: {}", fc.getSelectedFile());
045        return fc.getSelectedFile();
046    }
047
048    protected BufferedReader getBufferedReader(File file) {
049        try {
050            return new BufferedReader(new InputStreamReader(new FileInputStream(file), StandardCharsets.UTF_8));
051        } catch (FileNotFoundException e) {
052            return null;
053        }
054    }
055
056    // create a status frame showing line number and imported text
057    protected void createStatusFrame(String title) {
058        JPanel ps = new JPanel();
059        ps.setLayout(new BoxLayout(ps, BoxLayout.Y_AXIS));
060        fstatus = new jmri.util.JmriJFrame(title);
061        fstatus.setLocation(10, 10);
062        fstatus.setSize(Control.panelWidth1025, 100);
063
064        ps.add(lineNumber);
065        ps.add(importLine);
066
067        fstatus.getContentPane().add(ps);
068        fstatus.setVisible(true);
069    }
070
071    /*
072     * Needs to handle empty lines
073     */
074    protected String[] parseCommaLine(String line) {
075        String[] outLine = new String[0];
076        try {
077            CSVRecord record = CSVParser.parse(line, CSVFormat.DEFAULT).getRecords().get(0);
078            outLine = new String[record.size()];
079            // load output array to prevent NPE
080            for (int i = 0; i < outLine.length; i++) {
081                outLine[i] = record.get(i);
082            }
083        } catch (IndexOutOfBoundsException e) {
084            // do nothing blank line
085        } catch (IOException ex) {
086            log.error("Error parsing CSV: {}, {}", line, ex.getLocalizedMessage());
087            Arrays.fill(outLine, ""); // NOI18N
088        }
089        return outLine;
090    }
091
092    protected String[] readNextLine(BufferedReader rdr) {
093        String line = " ";
094        try {
095            line = rdr.readLine();
096        } catch (IOException e) {
097            return BREAK;
098        }
099        if (line == null) {
100            importOkay = true;
101            return BREAK;
102        }
103        if (!fstatus.isShowing()) {
104            //user canceled input!
105            return BREAK;
106        }
107        lineNumber.setText(Bundle.getMessage("LineNumber", Integer.toString(++lineNum)));
108        line = line.trim();
109        importLine.setText(line);
110
111        String[] inputLine = parseCommaLine(line);
112        log.debug("Import line number {} has {} elements", lineNum, inputLine.length);
113
114        return inputLine;
115    }
116
117    private final static Logger log = LoggerFactory.getLogger(ImportCommon.class);
118}