001package jmri.jmrit.operations.trains;
002
003import java.awt.Frame;
004import java.io.*;
005import java.nio.charset.StandardCharsets;
006
007import org.slf4j.Logger;
008import org.slf4j.LoggerFactory;
009
010import jmri.InstanceManager;
011import jmri.jmrit.operations.setup.Setup;
012import jmri.jmrit.operations.trains.trainbuilder.TrainCommon;
013import jmri.util.davidflanagan.HardcopyWriter;
014
015/**
016 * Used for train build reports.
017 *
018 * @author Daniel Boudreau (C) 2025
019 */
020public class TrainPrintBuildReport extends TrainCommon {
021
022    /**
023     * Print or preview a build report.
024     *
025     * @param file      File to be printed or previewed
026     * @param name      Title of document
027     * @param isPreview true if preview
028     */
029    public static void printReport(File file, String name, boolean isPreview) {
030        // obtain a OriginalHardcopyWriter to do this
031
032        String printerName = "";
033        int fontSize = Setup.getBuildReportFontSize();
034        boolean isLandScape = false;
035
036        try (HardcopyWriter writer = new HardcopyWriter(new Frame(), name, null, null, fontSize, .5 * 72, .5 * 72,
037                .5 * 72, .5 * 72, isPreview, printerName, isLandScape, true, null, null);
038                BufferedReader in = new BufferedReader(new InputStreamReader(
039                        new FileInputStream(file), StandardCharsets.UTF_8));) {
040
041            String line;
042            while (true) {
043                try {
044                    line = in.readLine();
045                } catch (IOException e) {
046                    log.debug("Print read failed");
047                    break;
048                }
049                if (line == null) {
050                    if (isPreview) {
051                        // need to do this in case the input file was empty to create preview
052                        writer.write(" ");
053                    }
054                    break;
055                }
056                // check for build report print level
057                line = filterBuildReport(line, false); // no indent
058                if (line.isEmpty()) {
059                    continue;
060                }
061                writer.write(line + NEW_LINE);
062            }
063        } catch (FileNotFoundException e) {
064            log.error("Build file doesn't exist", e);
065        } catch (HardcopyWriter.PrintCanceledException ex) {
066            log.debug("Print canceled");
067        } catch (IOException e) {
068            log.warn("Exception printing: {}", e.getLocalizedMessage());
069        }
070    }
071
072    /**
073     * Creates a new build report file with the print detail numbers replaced by
074     * indentations. Then calls open desktop editor.
075     *
076     * @param file build file
077     * @param name train name
078     */
079    public static void editReport(File file, String name) {
080        // make a new file with the build report levels removed
081        File buildReport = InstanceManager.getDefault(TrainManagerXml.class)
082                .createTrainBuildReportFile(Bundle.getMessage("Report") + " " + name);
083        editReport(file, buildReport);
084        // open the file
085        TrainUtilities.openDesktop(buildReport);
086    }
087
088    /**
089     * Creates a new build report file with the print detail numbers replaced by
090     * indentations.
091     * 
092     * @param file    Raw file with detail level numbers
093     * @param fileOut Formated file with indentations
094     */
095    public static void editReport(File file, File fileOut) {
096        try (BufferedReader in = new BufferedReader(new InputStreamReader(
097                new FileInputStream(file), StandardCharsets.UTF_8));
098                PrintWriter out = new PrintWriter(new BufferedWriter(new OutputStreamWriter(
099                        new FileOutputStream(fileOut), StandardCharsets.UTF_8)), true);) {
100
101            String line;
102            while (true) {
103                try {
104                    line = in.readLine();
105                    if (line == null) {
106                        break;
107                    }
108                    line = filterBuildReport(line, Setup.isBuildReportIndentEnabled());
109                    if (line.isEmpty()) {
110                        continue;
111                    }
112                    out.println(line); // indent lines for each level
113                } catch (IOException e) {
114                    log.debug("Print read failed");
115                    break;
116                }
117            }
118        } catch (FileNotFoundException e) {
119            log.error("Build file doesn't exist: {}", e.getLocalizedMessage());
120        } catch (IOException e) {
121            log.error("Can not create build report file: {}", e.getLocalizedMessage());
122        }
123    }
124
125    /*
126     * Removes the print levels from the build report
127     */
128    private static String filterBuildReport(String line, boolean indent) {
129        String[] inputLine = line.split("\\s+"); // NOI18N
130        if (inputLine.length == 0) {
131            return "";
132        }
133        if (inputLine[0].equals(Setup.BUILD_REPORT_VERY_DETAILED + BUILD_REPORT_CHAR) ||
134                inputLine[0].equals(Setup.BUILD_REPORT_DETAILED + BUILD_REPORT_CHAR) ||
135                inputLine[0].equals(Setup.BUILD_REPORT_NORMAL + BUILD_REPORT_CHAR) ||
136                inputLine[0].equals(Setup.BUILD_REPORT_MINIMAL + BUILD_REPORT_CHAR)) {
137
138            if (Setup.getBuildReportLevel().equals(Setup.BUILD_REPORT_MINIMAL)) {
139                if (inputLine[0].equals(Setup.BUILD_REPORT_NORMAL + BUILD_REPORT_CHAR) ||
140                        inputLine[0].equals(Setup.BUILD_REPORT_DETAILED + BUILD_REPORT_CHAR) ||
141                        inputLine[0].equals(Setup.BUILD_REPORT_VERY_DETAILED + BUILD_REPORT_CHAR)) {
142                    return ""; // don't print this line
143                }
144            }
145            if (Setup.getBuildReportLevel().equals(Setup.BUILD_REPORT_NORMAL)) {
146                if (inputLine[0].equals(Setup.BUILD_REPORT_DETAILED + BUILD_REPORT_CHAR) ||
147                        inputLine[0].equals(Setup.BUILD_REPORT_VERY_DETAILED + BUILD_REPORT_CHAR)) {
148                    return ""; // don't print this line
149                }
150            }
151            if (Setup.getBuildReportLevel().equals(Setup.BUILD_REPORT_DETAILED)) {
152                if (inputLine[0].equals(Setup.BUILD_REPORT_VERY_DETAILED + BUILD_REPORT_CHAR)) {
153                    return ""; // don't print this line
154                }
155            }
156            // do not indent if false
157            int start = 0;
158            if (indent) {
159                // indent lines based on level
160                if (inputLine[0].equals(Setup.BUILD_REPORT_VERY_DETAILED + BUILD_REPORT_CHAR)) {
161                    inputLine[0] = "   ";
162                } else if (inputLine[0].equals(Setup.BUILD_REPORT_DETAILED + BUILD_REPORT_CHAR)) {
163                    inputLine[0] = "  ";
164                } else if (inputLine[0].equals(Setup.BUILD_REPORT_NORMAL + BUILD_REPORT_CHAR)) {
165                    inputLine[0] = " ";
166                } else if (inputLine[0].equals(Setup.BUILD_REPORT_MINIMAL + BUILD_REPORT_CHAR)) {
167                    inputLine[0] = "";
168                }
169            } else {
170                start = 1;
171            }
172            // rebuild line
173            StringBuffer buf = new StringBuffer();
174            for (int i = start; i < inputLine.length; i++) {
175                buf.append(inputLine[i] + " ");
176            }
177            // blank line?
178            if (buf.length() == 0) {
179                return " ";
180            }
181            return buf.toString();
182        } else {
183            log.debug("ERROR first characters of build report not valid ({})", line);
184            return "ERROR " + line; // NOI18N
185        }
186    }
187
188    private final static Logger log = LoggerFactory.getLogger(TrainPrintBuildReport.class);
189}