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